diff options
author | Colin Cross <ccross@android.com> | 2010-04-13 19:48:59 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2010-04-13 22:52:10 -0700 |
commit | 9c5366ba55b1553b2d66f48e3d14fbd274a2944d (patch) | |
tree | 96a9e0bc8ba44febbf824600b708598340cc1e63 | |
parent | 504bc5175a8fe5a2f2552903afee761a86283cf4 (diff) | |
download | system_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.mk | 3 | ||||
-rwxr-xr-x | init/init.c | 117 | ||||
-rw-r--r-- | init/init.h | 2 | ||||
-rw-r--r-- | init/signal_handler.c | 154 | ||||
-rw-r--r-- | init/signal_handler.h | 24 |
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 |