summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-04-13 19:48:59 -0700
committerColin Cross <ccross@android.com>2010-04-13 22:52:10 -0700
commit9c5366ba55b1553b2d66f48e3d14fbd274a2944d (patch)
tree96a9e0bc8ba44febbf824600b708598340cc1e63
parent504bc5175a8fe5a2f2552903afee761a86283cf4 (diff)
downloadsystem_core-9c5366ba55b1553b2d66f48e3d14fbd274a2944d.zip
system_core-9c5366ba55b1553b2d66f48e3d14fbd274a2944d.tar.gz
system_core-9c5366ba55b1553b2d66f48e3d14fbd274a2944d.tar.bz2
init: Move signal handling to signal_handler.c
Change-Id: I3a24afa28a1cd279c749d6f384f687b8de56067e
-rw-r--r--init/Android.mk3
-rwxr-xr-xinit/init.c117
-rw-r--r--init/init.h2
-rw-r--r--init/signal_handler.c154
-rw-r--r--init/signal_handler.h24
5 files changed, 188 insertions, 112 deletions
diff --git a/init/Android.mk b/init/Android.mk
index e107bbb..3233883 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -11,7 +11,8 @@ LOCAL_SRC_FILES:= \
util.c \
parser.c \
logo.c \
- keychords.c
+ keychords.c \
+ signal_handler.c
ifeq ($(strip $(INIT_BOOTCHART)),true)
LOCAL_SRC_FILES += bootchart.c
diff --git a/init/init.c b/init/init.c
index 008c513..b76fa66 100755
--- a/init/init.c
+++ b/init/init.c
@@ -31,7 +31,6 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/reboot.h>
#include <cutils/sockets.h>
#include <cutils/iosched_policy.h>
@@ -43,6 +42,7 @@
#include "init.h"
#include "property_service.h"
#include "bootchart.h"
+#include "signal_handler.h"
#include "keychords.h"
#include "parser.h"
@@ -62,7 +62,7 @@ static char hardware[32];
static unsigned revision = 0;
static char qemu[32];
-static void notify_service_state(const char *name, const char *state)
+void notify_service_state(const char *name, const char *state)
{
char pname[PROP_NAME_MAX];
int len = strlen(name);
@@ -306,86 +306,6 @@ void property_changed(const char *name, const char *value)
}
}
-#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */
-#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/
-
-static int wait_for_one_process(int block)
-{
- pid_t pid;
- int status;
- struct service *svc;
- struct socketinfo *si;
- time_t now;
- struct listnode *node;
- struct command *cmd;
-
- while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
- if (pid <= 0) return -1;
- INFO("waitpid returned pid %d, status = %08x\n", pid, status);
-
- svc = service_find_by_pid(pid);
- if (!svc) {
- ERROR("untracked pid %d exited\n", pid);
- return 0;
- }
-
- NOTICE("process '%s', pid %d exited\n", svc->name, pid);
-
- if (!(svc->flags & SVC_ONESHOT)) {
- kill(-pid, SIGKILL);
- NOTICE("process '%s' killing any children in process group\n", svc->name);
- }
-
- /* remove any sockets we may have created */
- for (si = svc->sockets; si; si = si->next) {
- char tmp[128];
- snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
- unlink(tmp);
- }
-
- svc->pid = 0;
- svc->flags &= (~SVC_RUNNING);
-
- /* oneshot processes go into the disabled state on exit */
- if (svc->flags & SVC_ONESHOT) {
- svc->flags |= SVC_DISABLED;
- }
-
- /* disabled processes do not get restarted automatically */
- if (svc->flags & SVC_DISABLED) {
- notify_service_state(svc->name, "stopped");
- return 0;
- }
-
- now = gettime();
- if (svc->flags & SVC_CRITICAL) {
- if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
- if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
- ERROR("critical process '%s' exited %d times in %d minutes; "
- "rebooting into recovery mode\n", svc->name,
- CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
- sync();
- __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, "recovery");
- return 0;
- }
- } else {
- svc->time_crashed = now;
- svc->nr_crashed = 1;
- }
- }
-
- svc->flags |= SVC_RESTARTING;
-
- /* Execute all onrestart commands for this service. */
- list_for_each(node, &svc->onrestart.commands) {
- cmd = node_to_item(node, struct command, clist);
- cmd->func(cmd->nargs, cmd->args);
- }
- notify_service_state(svc->name, "restarting");
- return 0;
-}
-
static void restart_service_if_needed(struct service *svc)
{
time_t next_start_time = svc->time_started + 5;
@@ -409,13 +329,6 @@ static void restart_processes()
restart_service_if_needed);
}
-static int signal_fd = -1;
-
-static void sigchld_handler(int s)
-{
- write(signal_fd, &s, 1);
-}
-
static void msg_start(const char *name)
{
struct service *svc;
@@ -620,7 +533,6 @@ void open_devnull_stdio(void)
int main(int argc, char **argv)
{
- int signal_recv_fd = -1;
int fd_count;
int s[2];
int fd;
@@ -630,12 +542,6 @@ int main(int argc, char **argv)
char *tmpdev;
char* debuggable;
- act.sa_handler = sigchld_handler;
- act.sa_flags = SA_NOCLDSTOP;
- act.sa_mask = 0;
- act.sa_restorer = NULL;
- sigaction(SIGCHLD, &act, 0);
-
/* clear the umask */
umask(0);
@@ -753,20 +659,12 @@ int main(int argc, char **argv)
*/
start_property_service();
- /* create a signalling mechanism for the sigchld handler */
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
- signal_fd = s[0];
- signal_recv_fd = s[1];
- fcntl(s[0], F_SETFD, FD_CLOEXEC);
- fcntl(s[0], F_SETFL, O_NONBLOCK);
- fcntl(s[1], F_SETFD, FD_CLOEXEC);
- fcntl(s[1], F_SETFL, O_NONBLOCK);
- }
+ signal_init();
/* make sure we actually have all the pieces we need */
if ((get_device_fd() < 0) ||
(get_property_set_fd() < 0) ||
- (signal_recv_fd < 0)) {
+ (get_signal_fd() < 0)) {
ERROR("init startup failure\n");
return 1;
}
@@ -787,7 +685,7 @@ int main(int argc, char **argv)
ufds[0].events = POLLIN;
ufds[1].fd = get_property_set_fd();
ufds[1].events = POLLIN;
- ufds[2].fd = signal_recv_fd;
+ ufds[2].fd = get_signal_fd();
ufds[2].events = POLLIN;
fd_count = 3;
@@ -841,10 +739,7 @@ int main(int argc, char **argv)
continue;
if (ufds[2].revents == POLLIN) {
- /* we got a SIGCHLD - reap and restart as needed */
- read(signal_recv_fd, tmp, sizeof(tmp));
- while (!wait_for_one_process(0))
- ;
+ handle_signal();
continue;
}
diff --git a/init/init.h b/init/init.h
index 8210238..4d0593d 100644
--- a/init/init.h
+++ b/init/init.h
@@ -157,6 +157,8 @@ struct service {
int parse_config_file(const char *fn);
+void notify_service_state(const char *name, const char *state);
+
struct service *service_find_by_name(const char *name);
struct service *service_find_by_pid(pid_t pid);
struct service *service_find_by_keychord(int keychord_id);
diff --git a/init/signal_handler.c b/init/signal_handler.c
new file mode 100644
index 0000000..56352f1
--- /dev/null
+++ b/init/signal_handler.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <cutils/sockets.h>
+#include <sys/reboot.h>
+
+#include "init.h"
+
+static int signal_fd = -1;
+static int signal_recv_fd = -1;
+
+static void sigchld_handler(int s)
+{
+ write(signal_fd, &s, 1);
+}
+
+void signal_init(void)
+{
+ int s[2];
+
+ struct sigaction act;
+
+ act.sa_handler = sigchld_handler;
+ act.sa_flags = SA_NOCLDSTOP;
+ act.sa_mask = 0;
+ act.sa_restorer = NULL;
+ sigaction(SIGCHLD, &act, 0);
+
+ /* create a signalling mechanism for the sigchld handler */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
+ signal_fd = s[0];
+ signal_recv_fd = s[1];
+ fcntl(s[0], F_SETFD, FD_CLOEXEC);
+ fcntl(s[0], F_SETFL, O_NONBLOCK);
+ fcntl(s[1], F_SETFD, FD_CLOEXEC);
+ fcntl(s[1], F_SETFL, O_NONBLOCK);
+ }
+}
+
+#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */
+#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/
+
+static int wait_for_one_process(int block)
+{
+ pid_t pid;
+ int status;
+ struct service *svc;
+ struct socketinfo *si;
+ time_t now;
+ struct listnode *node;
+ struct command *cmd;
+
+ while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
+ if (pid <= 0) return -1;
+ INFO("waitpid returned pid %d, status = %08x\n", pid, status);
+
+ svc = service_find_by_pid(pid);
+ if (!svc) {
+ ERROR("untracked pid %d exited\n", pid);
+ return 0;
+ }
+
+ NOTICE("process '%s', pid %d exited\n", svc->name, pid);
+
+ if (!(svc->flags & SVC_ONESHOT)) {
+ kill(-pid, SIGKILL);
+ NOTICE("process '%s' killing any children in process group\n", svc->name);
+ }
+
+ /* remove any sockets we may have created */
+ for (si = svc->sockets; si; si = si->next) {
+ char tmp[128];
+ snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
+ unlink(tmp);
+ }
+
+ svc->pid = 0;
+ svc->flags &= (~SVC_RUNNING);
+
+ /* oneshot processes go into the disabled state on exit */
+ if (svc->flags & SVC_ONESHOT) {
+ svc->flags |= SVC_DISABLED;
+ }
+
+ /* disabled processes do not get restarted automatically */
+ if (svc->flags & SVC_DISABLED) {
+ notify_service_state(svc->name, "stopped");
+ return 0;
+ }
+
+ now = gettime();
+ if (svc->flags & SVC_CRITICAL) {
+ if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
+ if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
+ ERROR("critical process '%s' exited %d times in %d minutes; "
+ "rebooting into recovery mode\n", svc->name,
+ CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
+ sync();
+ __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+ LINUX_REBOOT_CMD_RESTART2, "recovery");
+ return 0;
+ }
+ } else {
+ svc->time_crashed = now;
+ svc->nr_crashed = 1;
+ }
+ }
+
+ svc->flags |= SVC_RESTARTING;
+
+ /* Execute all onrestart commands for this service. */
+ list_for_each(node, &svc->onrestart.commands) {
+ cmd = node_to_item(node, struct command, clist);
+ cmd->func(cmd->nargs, cmd->args);
+ }
+ notify_service_state(svc->name, "restarting");
+ return 0;
+}
+
+void handle_signal(void)
+{
+ char tmp[32];
+
+ /* we got a SIGCHLD - reap and restart as needed */
+ read(signal_recv_fd, tmp, sizeof(tmp));
+ while (!wait_for_one_process(0))
+ ;
+}
+
+int get_signal_fd()
+{
+ return signal_recv_fd;
+}
diff --git a/init/signal_handler.h b/init/signal_handler.h
new file mode 100644
index 0000000..b092ccb
--- /dev/null
+++ b/init/signal_handler.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_SIGNAL_HANDLER_H_
+#define _INIT_SIGNAL_HANDLER_H_
+
+void signal_init(void);
+void handle_signal(void);
+int get_signal_fd(void);
+
+#endif