diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2019-12-03 13:48:55 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2019-12-03 14:05:32 +0100 |
commit | 356f23de20b48382f5a2c5db29dc4f6dc9d10289 (patch) | |
tree | 9e1658b4c6930c713f7fe417832a586a2b9e5a55 | |
parent | 113c776f4d2ce4ead7c2d11a3ca62adeec9a2e34 (diff) | |
download | busybox-w32-356f23de20b48382f5a2c5db29dc4f6dc9d10289.tar.gz busybox-w32-356f23de20b48382f5a2c5db29dc4f6dc9d10289.tar.bz2 busybox-w32-356f23de20b48382f5a2c5db29dc4f6dc9d10289.zip |
init: improve handling of signals racing with each other
Before this change, a request to reboot could be "overwritten" by e.g.
SIGHUP.
function old new delta
init_main 709 793 +84
packed_usage 33273 33337 +64
run_actions 109 117 +8
stop_handler 87 88 +1
check_delayed_sigs 340 335 -5
run 214 198 -16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/2 up/down: 157/-21) Total: 136 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | init/init.c | 278 |
1 files changed, 119 insertions, 159 deletions
diff --git a/init/init.c b/init/init.c index db1d99add..28775a65c 100644 --- a/init/init.c +++ b/init/init.c | |||
@@ -210,6 +210,8 @@ struct globals { | |||
210 | #if !ENABLE_FEATURE_INIT_SYSLOG | 210 | #if !ENABLE_FEATURE_INIT_SYSLOG |
211 | const char *log_console; | 211 | const char *log_console; |
212 | #endif | 212 | #endif |
213 | sigset_t delayed_sigset; | ||
214 | struct timespec zero_ts; | ||
213 | } FIX_ALIASING; | 215 | } FIX_ALIASING; |
214 | #define G (*(struct globals*)bb_common_bufsiz1) | 216 | #define G (*(struct globals*)bb_common_bufsiz1) |
215 | #define INIT_G() do { \ | 217 | #define INIT_G() do { \ |
@@ -411,14 +413,8 @@ static int open_stdio_to_tty(const char* tty_name) | |||
411 | static void reset_sighandlers_and_unblock_sigs(void) | 413 | static void reset_sighandlers_and_unblock_sigs(void) |
412 | { | 414 | { |
413 | bb_signals(0 | 415 | bb_signals(0 |
414 | + (1 << SIGUSR1) | 416 | | (1 << SIGTSTP) |
415 | + (1 << SIGUSR2) | 417 | | (1 << SIGSTOP) |
416 | + (1 << SIGTERM) | ||
417 | + (1 << SIGQUIT) | ||
418 | + (1 << SIGINT) | ||
419 | + (1 << SIGHUP) | ||
420 | + (1 << SIGTSTP) | ||
421 | + (1 << SIGSTOP) | ||
422 | , SIG_DFL); | 418 | , SIG_DFL); |
423 | sigprocmask_allsigs(SIG_UNBLOCK); | 419 | sigprocmask_allsigs(SIG_UNBLOCK); |
424 | } | 420 | } |
@@ -484,16 +480,13 @@ static pid_t run(const struct init_action *a) | |||
484 | { | 480 | { |
485 | pid_t pid; | 481 | pid_t pid; |
486 | 482 | ||
487 | /* Careful: don't be affected by a signal in vforked child */ | ||
488 | sigprocmask_allsigs(SIG_BLOCK); | ||
489 | if (BB_MMU && (a->action_type & ASKFIRST)) | 483 | if (BB_MMU && (a->action_type & ASKFIRST)) |
490 | pid = fork(); | 484 | pid = fork(); |
491 | else | 485 | else |
492 | pid = vfork(); | 486 | pid = vfork(); |
493 | if (pid < 0) | ||
494 | message(L_LOG | L_CONSOLE, "can't fork"); | ||
495 | if (pid) { | 487 | if (pid) { |
496 | sigprocmask_allsigs(SIG_UNBLOCK); | 488 | if (pid < 0) |
489 | message(L_LOG | L_CONSOLE, "can't fork"); | ||
497 | return pid; /* Parent or error */ | 490 | return pid; /* Parent or error */ |
498 | } | 491 | } |
499 | 492 | ||
@@ -587,9 +580,11 @@ static void waitfor(pid_t pid) | |||
587 | while (1) { | 580 | while (1) { |
588 | pid_t wpid = wait(NULL); | 581 | pid_t wpid = wait(NULL); |
589 | mark_terminated(wpid); | 582 | mark_terminated(wpid); |
590 | /* Unsafe. SIGTSTP handler might have wait'ed it already */ | 583 | if (wpid == pid) /* this was the process we waited for */ |
591 | /*if (wpid == pid) break;*/ | 584 | break; |
592 | /* More reliable: */ | 585 | /* The above is not reliable enough: SIGTSTP handler might have |
586 | * wait'ed it already. Double check, exit if process is gone: | ||
587 | */ | ||
593 | if (kill(pid, 0)) | 588 | if (kill(pid, 0)) |
594 | break; | 589 | break; |
595 | } | 590 | } |
@@ -798,23 +793,17 @@ static void run_shutdown_and_kill_processes(void) | |||
798 | * Delayed handlers just set a flag variable. The variable is checked | 793 | * Delayed handlers just set a flag variable. The variable is checked |
799 | * in the main loop and acted upon. | 794 | * in the main loop and acted upon. |
800 | * | 795 | * |
801 | * halt/poweroff/reboot and restart have immediate handlers. | ||
802 | * They only traverse linked list of struct action's, never modify it, | ||
803 | * this should be safe to do even in signal handler. Also they | ||
804 | * never return. | ||
805 | * | ||
806 | * SIGSTOP and SIGTSTP have immediate handlers. They just wait | 796 | * SIGSTOP and SIGTSTP have immediate handlers. They just wait |
807 | * for SIGCONT to happen. | 797 | * for SIGCONT to happen. |
808 | * | 798 | * |
799 | * halt/poweroff/reboot and restart have delayed handlers. | ||
800 | * | ||
809 | * SIGHUP has a delayed handler, because modifying linked list | 801 | * SIGHUP has a delayed handler, because modifying linked list |
810 | * of struct action's from a signal handler while it is manipulated | 802 | * of struct action's from a signal handler while it is manipulated |
811 | * by the program may be disastrous. | 803 | * by the program may be disastrous. |
812 | * | 804 | * |
813 | * Ctrl-Alt-Del has a delayed handler. Not a must, but allowing | 805 | * Ctrl-Alt-Del has a delayed handler. Not a must, but allowing |
814 | * it to happen even somewhere inside "sysinit" would be a bit awkward. | 806 | * it to happen even somewhere inside "sysinit" would be a bit awkward. |
815 | * | ||
816 | * There is a tiny probability that SIGHUP and Ctrl-Alt-Del will collide | ||
817 | * and only one will be remembered and acted upon. | ||
818 | */ | 807 | */ |
819 | 808 | ||
820 | /* The SIGPWR/SIGUSR[12]/SIGTERM handler */ | 809 | /* The SIGPWR/SIGUSR[12]/SIGTERM handler */ |
@@ -898,11 +887,9 @@ static void exec_restart_action(void) | |||
898 | */ | 887 | */ |
899 | static void stop_handler(int sig UNUSED_PARAM) | 888 | static void stop_handler(int sig UNUSED_PARAM) |
900 | { | 889 | { |
901 | smallint saved_bb_got_signal; | 890 | int saved_errno = errno; |
902 | int saved_errno; | ||
903 | 891 | ||
904 | saved_bb_got_signal = bb_got_signal; | 892 | bb_got_signal = 0; |
905 | saved_errno = errno; | ||
906 | signal(SIGCONT, record_signo); | 893 | signal(SIGCONT, record_signo); |
907 | 894 | ||
908 | while (1) { | 895 | while (1) { |
@@ -916,12 +903,12 @@ static void stop_handler(int sig UNUSED_PARAM) | |||
916 | */ | 903 | */ |
917 | wpid = wait_any_nohang(NULL); | 904 | wpid = wait_any_nohang(NULL); |
918 | mark_terminated(wpid); | 905 | mark_terminated(wpid); |
919 | sleep(1); | 906 | if (wpid <= 0) /* no processes exited? sleep a bit */ |
907 | sleep(1); | ||
920 | } | 908 | } |
921 | 909 | ||
922 | signal(SIGCONT, SIG_DFL); | 910 | signal(SIGCONT, SIG_DFL); |
923 | errno = saved_errno; | 911 | errno = saved_errno; |
924 | bb_got_signal = saved_bb_got_signal; | ||
925 | } | 912 | } |
926 | 913 | ||
927 | #if ENABLE_FEATURE_USE_INITTAB | 914 | #if ENABLE_FEATURE_USE_INITTAB |
@@ -986,43 +973,39 @@ static void reload_inittab(void) | |||
986 | } | 973 | } |
987 | #endif | 974 | #endif |
988 | 975 | ||
989 | static int check_delayed_sigs(void) | 976 | static void check_delayed_sigs(struct timespec *ts) |
990 | { | 977 | { |
991 | int sigs_seen = 0; | 978 | int sig = sigtimedwait(&G.delayed_sigset, /* siginfo_t */ NULL, ts); |
979 | if (sig <= 0) | ||
980 | return; | ||
992 | 981 | ||
993 | while (1) { | 982 | /* The signal "sig" was caught */ |
994 | smallint sig = bb_got_signal; | ||
995 | 983 | ||
996 | if (!sig) | ||
997 | return sigs_seen; | ||
998 | bb_got_signal = 0; | ||
999 | sigs_seen = 1; | ||
1000 | #if ENABLE_FEATURE_USE_INITTAB | 984 | #if ENABLE_FEATURE_USE_INITTAB |
1001 | if (sig == SIGHUP) | 985 | if (sig == SIGHUP) |
1002 | reload_inittab(); | 986 | reload_inittab(); |
1003 | #endif | 987 | #endif |
1004 | if (sig == SIGINT) | 988 | if (sig == SIGINT) |
1005 | run_actions(CTRLALTDEL); | 989 | run_actions(CTRLALTDEL); |
1006 | if (sig == SIGQUIT) { | 990 | if (sig == SIGQUIT) { |
1007 | exec_restart_action(); | 991 | exec_restart_action(); |
1008 | /* returns only if no restart action defined */ | 992 | /* returns only if no restart action defined */ |
1009 | } | 993 | } |
1010 | if ((1 << sig) & (0 | 994 | if ((1 << sig) & (0 |
1011 | #ifdef SIGPWR | 995 | #ifdef SIGPWR |
1012 | + (1 << SIGPWR) | 996 | | (1 << SIGPWR) |
1013 | #endif | 997 | #endif |
1014 | + (1 << SIGUSR1) | 998 | | (1 << SIGUSR1) |
1015 | + (1 << SIGUSR2) | 999 | | (1 << SIGUSR2) |
1016 | + (1 << SIGTERM) | 1000 | | (1 << SIGTERM) |
1017 | )) { | 1001 | )) { |
1018 | halt_reboot_pwoff(sig); | 1002 | halt_reboot_pwoff(sig); |
1019 | } | ||
1020 | } | 1003 | } |
1004 | /* if (sig == SIGCHLD) do nothing */ | ||
1021 | } | 1005 | } |
1022 | 1006 | ||
1023 | #if DEBUG_SEGV_HANDLER | 1007 | #if DEBUG_SEGV_HANDLER |
1024 | static | 1008 | static void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) |
1025 | void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) | ||
1026 | { | 1009 | { |
1027 | long ip; | 1010 | long ip; |
1028 | ucontext_t *uc; | 1011 | ucontext_t *uc; |
@@ -1049,50 +1032,62 @@ void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) | |||
1049 | 1032 | ||
1050 | static void sleep_much(void) | 1033 | static void sleep_much(void) |
1051 | { | 1034 | { |
1052 | sleep(30 * 24*60*60); | 1035 | sleep(30 * 24*60*60); |
1053 | } | 1036 | } |
1054 | 1037 | ||
1055 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1038 | int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1056 | int init_main(int argc UNUSED_PARAM, char **argv) | 1039 | int init_main(int argc UNUSED_PARAM, char **argv) |
1057 | { | 1040 | { |
1041 | struct sigaction sa; | ||
1042 | |||
1058 | INIT_G(); | 1043 | INIT_G(); |
1059 | 1044 | ||
1045 | /* Some users send poweroff signals to init VERY early. | ||
1046 | * To handle this, mask signals early. | ||
1047 | */ | ||
1048 | /* sigemptyset(&G.delayed_sigset); - done by INIT_G() */ | ||
1049 | sigaddset(&G.delayed_sigset, SIGINT); /* Ctrl-Alt-Del */ | ||
1050 | sigaddset(&G.delayed_sigset, SIGQUIT); /* re-exec another init */ | ||
1051 | #ifdef SIGPWR | ||
1052 | sigaddset(&G.delayed_sigset, SIGPWR); /* halt */ | ||
1053 | #endif | ||
1054 | sigaddset(&G.delayed_sigset, SIGUSR1); /* halt */ | ||
1055 | sigaddset(&G.delayed_sigset, SIGTERM); /* reboot */ | ||
1056 | sigaddset(&G.delayed_sigset, SIGUSR2); /* poweroff */ | ||
1057 | #if ENABLE_FEATURE_USE_INITTAB | ||
1058 | sigaddset(&G.delayed_sigset, SIGHUP); /* reread /etc/inittab */ | ||
1059 | #endif | ||
1060 | sigaddset(&G.delayed_sigset, SIGCHLD); /* make sigtimedwait() exit on SIGCHLD */ | ||
1061 | sigprocmask(SIG_BLOCK, &G.delayed_sigset, NULL); | ||
1062 | |||
1063 | #if DEBUG_SEGV_HANDLER | ||
1064 | memset(&sa, 0, sizeof(sa)); | ||
1065 | sa.sa_sigaction = handle_sigsegv; | ||
1066 | sa.sa_flags = SA_SIGINFO; | ||
1067 | sigaction_set(SIGSEGV, &sa); | ||
1068 | sigaction_set(SIGILL, &sa); | ||
1069 | sigaction_set(SIGFPE, &sa); | ||
1070 | sigaction_set(SIGBUS, &sa); | ||
1071 | #endif | ||
1072 | |||
1060 | if (argv[1] && strcmp(argv[1], "-q") == 0) { | 1073 | if (argv[1] && strcmp(argv[1], "-q") == 0) { |
1061 | return kill(1, SIGHUP); | 1074 | return kill(1, SIGHUP); |
1062 | } | 1075 | } |
1063 | 1076 | ||
1064 | #if DEBUG_SEGV_HANDLER | 1077 | #if !DEBUG_INIT |
1065 | { | 1078 | /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ |
1066 | struct sigaction sa; | 1079 | if (getpid() != 1 |
1067 | memset(&sa, 0, sizeof(sa)); | 1080 | && (!ENABLE_LINUXRC || applet_name[0] != 'l') /* not linuxrc? */ |
1068 | sa.sa_sigaction = handle_sigsegv; | 1081 | ) { |
1069 | sa.sa_flags = SA_SIGINFO; | 1082 | bb_simple_error_msg_and_die("must be run as PID 1"); |
1070 | sigaction(SIGSEGV, &sa, NULL); | ||
1071 | sigaction(SIGILL, &sa, NULL); | ||
1072 | sigaction(SIGFPE, &sa, NULL); | ||
1073 | sigaction(SIGBUS, &sa, NULL); | ||
1074 | } | 1083 | } |
1075 | #endif | ||
1076 | |||
1077 | if (!DEBUG_INIT) { | ||
1078 | /* Some users send poweroff signals to init VERY early. | ||
1079 | * To handle this, mask signals early, | ||
1080 | * and unmask them only after signal handlers are installed. | ||
1081 | */ | ||
1082 | sigprocmask_allsigs(SIG_BLOCK); | ||
1083 | 1084 | ||
1084 | /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ | 1085 | # ifdef RB_DISABLE_CAD |
1085 | if (getpid() != 1 | 1086 | /* Turn off rebooting via CTL-ALT-DEL - we get a |
1086 | && (!ENABLE_LINUXRC || applet_name[0] != 'l') /* not linuxrc? */ | 1087 | * SIGINT on CAD so we can shut things down gracefully... */ |
1087 | ) { | 1088 | reboot(RB_DISABLE_CAD); /* misnomer */ |
1088 | bb_simple_error_msg_and_die("must be run as PID 1"); | 1089 | # endif |
1089 | } | ||
1090 | #ifdef RB_DISABLE_CAD | ||
1091 | /* Turn off rebooting via CTL-ALT-DEL - we get a | ||
1092 | * SIGINT on CAD so we can shut things down gracefully... */ | ||
1093 | reboot(RB_DISABLE_CAD); /* misnomer */ | ||
1094 | #endif | 1090 | #endif |
1095 | } | ||
1096 | 1091 | ||
1097 | /* If, say, xmalloc would ever die, we don't want to oops kernel | 1092 | /* If, say, xmalloc would ever die, we don't want to oops kernel |
1098 | * by exiting. | 1093 | * by exiting. |
@@ -1156,106 +1151,65 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
1156 | } | 1151 | } |
1157 | #endif | 1152 | #endif |
1158 | 1153 | ||
1159 | if (ENABLE_FEATURE_INIT_MODIFY_CMDLINE) { | 1154 | #if ENABLE_FEATURE_INIT_MODIFY_CMDLINE |
1160 | /* Make the command line just say "init" - that's all, nothing else */ | 1155 | /* Make the command line just say "init" - that's all, nothing else */ |
1161 | strncpy(argv[0], "init", strlen(argv[0])); | 1156 | strncpy(argv[0], "init", strlen(argv[0])); |
1162 | /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ | 1157 | /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ |
1163 | while (*++argv) | 1158 | while (*++argv) |
1164 | nuke_str(*argv); | 1159 | nuke_str(*argv); |
1165 | } | ||
1166 | |||
1167 | /* Set up signal handlers */ | ||
1168 | if (!DEBUG_INIT) { | ||
1169 | struct sigaction sa; | ||
1170 | |||
1171 | /* Stop handler must allow only SIGCONT inside itself */ | ||
1172 | memset(&sa, 0, sizeof(sa)); | ||
1173 | sigfillset(&sa.sa_mask); | ||
1174 | sigdelset(&sa.sa_mask, SIGCONT); | ||
1175 | sa.sa_handler = stop_handler; | ||
1176 | /* NB: sa_flags doesn't have SA_RESTART. | ||
1177 | * It must be able to interrupt wait(). | ||
1178 | */ | ||
1179 | sigaction_set(SIGTSTP, &sa); /* pause */ | ||
1180 | /* Does not work as intended, at least in 2.6.20. | ||
1181 | * SIGSTOP is simply ignored by init: | ||
1182 | */ | ||
1183 | sigaction_set(SIGSTOP, &sa); /* pause */ | ||
1184 | |||
1185 | /* These signals must interrupt wait(), | ||
1186 | * setting handler without SA_RESTART flag. | ||
1187 | */ | ||
1188 | bb_signals_recursive_norestart(0 | ||
1189 | + (1 << SIGINT) /* Ctrl-Alt-Del */ | ||
1190 | + (1 << SIGQUIT) /* re-exec another init */ | ||
1191 | #ifdef SIGPWR | ||
1192 | + (1 << SIGPWR) /* halt */ | ||
1193 | #endif | ||
1194 | + (1 << SIGUSR1) /* halt */ | ||
1195 | + (1 << SIGTERM) /* reboot */ | ||
1196 | + (1 << SIGUSR2) /* poweroff */ | ||
1197 | #if ENABLE_FEATURE_USE_INITTAB | ||
1198 | + (1 << SIGHUP) /* reread /etc/inittab */ | ||
1199 | #endif | 1160 | #endif |
1200 | , record_signo); | ||
1201 | 1161 | ||
1202 | sigprocmask_allsigs(SIG_UNBLOCK); | 1162 | /* Set up STOP signal handlers */ |
1203 | } | 1163 | /* Stop handler must allow only SIGCONT inside itself */ |
1164 | memset(&sa, 0, sizeof(sa)); | ||
1165 | sigfillset(&sa.sa_mask); | ||
1166 | sigdelset(&sa.sa_mask, SIGCONT); | ||
1167 | sa.sa_handler = stop_handler; | ||
1168 | sa.sa_flags = SA_RESTART; | ||
1169 | sigaction_set(SIGTSTP, &sa); /* pause */ | ||
1170 | /* Does not work as intended, at least in 2.6.20. | ||
1171 | * SIGSTOP is simply ignored by init | ||
1172 | * (NB: behavior might differ under strace): | ||
1173 | */ | ||
1174 | sigaction_set(SIGSTOP, &sa); /* pause */ | ||
1204 | 1175 | ||
1205 | /* Now run everything that needs to be run */ | 1176 | /* Now run everything that needs to be run */ |
1206 | /* First run the sysinit command */ | 1177 | /* First run the sysinit command */ |
1207 | run_actions(SYSINIT); | 1178 | run_actions(SYSINIT); |
1208 | check_delayed_sigs(); | 1179 | check_delayed_sigs(&G.zero_ts); |
1209 | /* Next run anything that wants to block */ | 1180 | /* Next run anything that wants to block */ |
1210 | run_actions(WAIT); | 1181 | run_actions(WAIT); |
1211 | check_delayed_sigs(); | 1182 | check_delayed_sigs(&G.zero_ts); |
1212 | /* Next run anything to be run only once */ | 1183 | /* Next run anything to be run only once */ |
1213 | run_actions(ONCE); | 1184 | run_actions(ONCE); |
1214 | 1185 | ||
1215 | /* Now run the looping stuff for the rest of forever. | 1186 | /* Now run the looping stuff for the rest of forever */ |
1216 | */ | ||
1217 | while (1) { | 1187 | while (1) { |
1218 | int maybe_WNOHANG; | ||
1219 | |||
1220 | maybe_WNOHANG = check_delayed_sigs(); | ||
1221 | |||
1222 | /* (Re)run the respawn/askfirst stuff */ | 1188 | /* (Re)run the respawn/askfirst stuff */ |
1223 | run_actions(RESPAWN | ASKFIRST); | 1189 | run_actions(RESPAWN | ASKFIRST); |
1224 | maybe_WNOHANG |= check_delayed_sigs(); | ||
1225 | 1190 | ||
1226 | /* Don't consume all CPU time - sleep a bit */ | 1191 | /* Wait for any signal (typically it's SIGCHLD) */ |
1227 | sleep(1); | 1192 | check_delayed_sigs(NULL); /* NULL timespec makes it wait */ |
1228 | maybe_WNOHANG |= check_delayed_sigs(); | 1193 | |
1229 | 1194 | /* Wait for any child process(es) to exit */ | |
1230 | /* Wait for any child process(es) to exit. | ||
1231 | * | ||
1232 | * If check_delayed_sigs above reported that a signal | ||
1233 | * was caught, wait will be nonblocking. This ensures | ||
1234 | * that if SIGHUP has reloaded inittab, respawn and askfirst | ||
1235 | * actions will not be delayed until next child death. | ||
1236 | */ | ||
1237 | if (maybe_WNOHANG) | ||
1238 | maybe_WNOHANG = WNOHANG; | ||
1239 | while (1) { | 1195 | while (1) { |
1240 | pid_t wpid; | 1196 | pid_t wpid; |
1241 | struct init_action *a; | 1197 | struct init_action *a; |
1242 | 1198 | ||
1243 | /* If signals happen _in_ the wait, they interrupt it, | 1199 | wpid = waitpid(-1, NULL, WNOHANG); |
1244 | * bb_signals_recursive_norestart set them up that way | ||
1245 | */ | ||
1246 | wpid = waitpid(-1, NULL, maybe_WNOHANG); | ||
1247 | if (wpid <= 0) | 1200 | if (wpid <= 0) |
1248 | break; | 1201 | break; |
1249 | 1202 | ||
1250 | a = mark_terminated(wpid); | 1203 | a = mark_terminated(wpid); |
1251 | if (a) { | 1204 | if (a) { |
1252 | message(L_LOG, "process '%s' (pid %d) exited. " | 1205 | message(L_LOG, "process '%s' (pid %u) exited. " |
1253 | "Scheduling for restart.", | 1206 | "Scheduling for restart.", |
1254 | a->command, wpid); | 1207 | a->command, (unsigned)wpid); |
1255 | } | 1208 | } |
1256 | /* See if anyone else is waiting to be reaped */ | ||
1257 | maybe_WNOHANG = WNOHANG; | ||
1258 | } | 1209 | } |
1210 | |||
1211 | /* Don't consume all CPU time - sleep a bit */ | ||
1212 | sleep(1); | ||
1259 | } /* while (1) */ | 1213 | } /* while (1) */ |
1260 | } | 1214 | } |
1261 | 1215 | ||
@@ -1268,11 +1222,17 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
1268 | //usage: "Init is the first process started during boot. It never exits." | 1222 | //usage: "Init is the first process started during boot. It never exits." |
1269 | //usage: IF_FEATURE_USE_INITTAB( | 1223 | //usage: IF_FEATURE_USE_INITTAB( |
1270 | //usage: "\n""It (re)spawns children according to /etc/inittab." | 1224 | //usage: "\n""It (re)spawns children according to /etc/inittab." |
1225 | //usage: "\n""Signals:" | ||
1226 | //usage: "\n""HUP: reload /etc/inittab" | ||
1271 | //usage: ) | 1227 | //usage: ) |
1272 | //usage: IF_NOT_FEATURE_USE_INITTAB( | 1228 | //usage: IF_NOT_FEATURE_USE_INITTAB( |
1273 | //usage: "\n""This version of init doesn't use /etc/inittab," | 1229 | //usage: "\n""This version of init doesn't use /etc/inittab," |
1274 | //usage: "\n""has fixed set of processed to run." | 1230 | //usage: "\n""has fixed set of processed to run." |
1231 | //usage: "\n""Signals:" | ||
1275 | //usage: ) | 1232 | //usage: ) |
1233 | //usage: "\n""TSTP: stop respawning until CONT" | ||
1234 | //usage: "\n""QUIT: re-exec another init" | ||
1235 | //usage: "\n""USR1/TERM/USR2/INT: run halt/reboot/poweroff/Ctrl-Alt-Del script" | ||
1276 | //usage: | 1236 | //usage: |
1277 | //usage:#define init_notes_usage | 1237 | //usage:#define init_notes_usage |
1278 | //usage: "This version of init is designed to be run only by the kernel.\n" | 1238 | //usage: "This version of init is designed to be run only by the kernel.\n" |