diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-10 16:01:57 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-10 16:01:57 +0000 |
| commit | 4774179cb9e04030485773adf2b7b1055a10faeb (patch) | |
| tree | 91bb5c51f9f4e3036298d7bb5490621b3e7a3ee6 | |
| parent | 245f91b6494063c5fa1f3f586771e2ac100a69a9 (diff) | |
| download | busybox-w32-4774179cb9e04030485773adf2b7b1055a10faeb.tar.gz busybox-w32-4774179cb9e04030485773adf2b7b1055a10faeb.tar.bz2 busybox-w32-4774179cb9e04030485773adf2b7b1055a10faeb.zip | |
mail.c: more robust handling of SIGCHLD
init: more robust signal handling
| -rw-r--r-- | init/init.c | 41 | ||||
| -rw-r--r-- | mailutils/mail.c | 11 |
2 files changed, 30 insertions, 22 deletions
diff --git a/init/init.c b/init/init.c index 5b9820b4a..5c344cb63 100644 --- a/init/init.c +++ b/init/init.c | |||
| @@ -336,20 +336,22 @@ static pid_t run(const struct init_action *a) | |||
| 336 | { | 336 | { |
| 337 | pid_t pid; | 337 | pid_t pid; |
| 338 | 338 | ||
| 339 | /* Careful: don't be affected by a signal in vforked child */ | ||
| 340 | sigprocmask_allsigs(SIG_BLOCK); | ||
| 339 | if (BB_MMU && (a->action_type & ASKFIRST)) | 341 | if (BB_MMU && (a->action_type & ASKFIRST)) |
| 340 | pid = fork(); | 342 | pid = fork(); |
| 341 | else | 343 | else |
| 342 | pid = vfork(); | 344 | pid = vfork(); |
| 343 | if (pid < 0) | 345 | if (pid < 0) |
| 344 | message(L_LOG | L_CONSOLE, "can't fork"); | 346 | message(L_LOG | L_CONSOLE, "can't fork"); |
| 345 | if (pid) | 347 | if (pid) { |
| 348 | sigprocmask_allsigs(SIG_UNBLOCK); | ||
| 346 | return pid; /* Parent or error */ | 349 | return pid; /* Parent or error */ |
| 350 | } | ||
| 347 | 351 | ||
| 348 | /* Child */ | 352 | /* Child */ |
| 349 | 353 | ||
| 350 | /* Reset signal handlers that were set by the parent process */ | 354 | /* Reset signal handlers that were set by the parent process */ |
| 351 | //TODO: block signals across fork(), prevent them to affect child before | ||
| 352 | //signals are reset? | ||
| 353 | bb_signals(0 | 355 | bb_signals(0 |
| 354 | + (1 << SIGUSR1) | 356 | + (1 << SIGUSR1) |
| 355 | + (1 << SIGUSR2) | 357 | + (1 << SIGUSR2) |
| @@ -359,6 +361,7 @@ static pid_t run(const struct init_action *a) | |||
| 359 | + (1 << SIGHUP) | 361 | + (1 << SIGHUP) |
| 360 | + (1 << SIGTSTP) | 362 | + (1 << SIGTSTP) |
| 361 | , SIG_DFL); | 363 | , SIG_DFL); |
| 364 | sigprocmask_allsigs(SIG_UNBLOCK); | ||
| 362 | 365 | ||
| 363 | /* Create a new session and make ourself the process group leader */ | 366 | /* Create a new session and make ourself the process group leader */ |
| 364 | setsid(); | 367 | setsid(); |
| @@ -982,40 +985,42 @@ int init_main(int argc UNUSED_PARAM, char **argv) | |||
| 982 | * NB: if delayed signal happened, avoid blocking in wait(). | 985 | * NB: if delayed signal happened, avoid blocking in wait(). |
| 983 | */ | 986 | */ |
| 984 | while (1) { | 987 | while (1) { |
| 985 | pid_t wpid; | 988 | int maybe_WNOHANG; |
| 986 | int got_sigs; | ||
| 987 | 989 | ||
| 988 | got_sigs = check_delayed_sigs(); | 990 | maybe_WNOHANG = check_delayed_sigs(); |
| 989 | 991 | ||
| 990 | /* (Re)run the respawn/askfirst stuff */ | 992 | /* (Re)run the respawn/askfirst stuff */ |
| 991 | run_actions(RESPAWN | ASKFIRST); | 993 | run_actions(RESPAWN | ASKFIRST); |
| 992 | 994 | maybe_WNOHANG |= check_delayed_sigs(); | |
| 993 | got_sigs |= check_delayed_sigs(); | ||
| 994 | 995 | ||
| 995 | /* Don't consume all CPU time - sleep a bit */ | 996 | /* Don't consume all CPU time - sleep a bit */ |
| 996 | sleep(1); | 997 | sleep(1); |
| 998 | maybe_WNOHANG |= check_delayed_sigs(); | ||
| 997 | 999 | ||
| 998 | got_sigs |= check_delayed_sigs(); | 1000 | /* Wait for any child process(es) to exit. |
| 999 | |||
| 1000 | if (got_sigs) | ||
| 1001 | goto dont_block; | ||
| 1002 | /* Wait for any child process to exit. | ||
| 1003 | * NB: "delayed" signals will also interrupt this wait(), | 1001 | * NB: "delayed" signals will also interrupt this wait(), |
| 1004 | * bb_signals_recursive_norestart() set them up for that. | 1002 | * bb_signals_recursive_norestart() set them up for that. |
| 1005 | * This guarantees we won't be stuck here | 1003 | * This guarantees we won't be stuck here |
| 1006 | * till next orphan dies. | 1004 | * till next orphan dies. |
| 1007 | */ | 1005 | */ |
| 1008 | wpid = wait(NULL); | 1006 | if (maybe_WNOHANG) |
| 1009 | while (wpid > 0) { | 1007 | maybe_WNOHANG = WNOHANG; |
| 1010 | struct init_action *a = mark_terminated(wpid); | 1008 | while (1) { |
| 1009 | pid_t wpid; | ||
| 1010 | struct init_action *a; | ||
| 1011 | |||
| 1012 | wpid = waitpid(-1, NULL, maybe_WNOHANG); | ||
| 1013 | if (wpid <= 0) | ||
| 1014 | break; | ||
| 1015 | |||
| 1016 | a = mark_terminated(wpid); | ||
| 1011 | if (a) { | 1017 | if (a) { |
| 1012 | message(L_LOG, "process '%s' (pid %d) exited. " | 1018 | message(L_LOG, "process '%s' (pid %d) exited. " |
| 1013 | "Scheduling for restart.", | 1019 | "Scheduling for restart.", |
| 1014 | a->command, wpid); | 1020 | a->command, wpid); |
| 1015 | } | 1021 | } |
| 1016 | /* See if anyone else is waiting to be reaped */ | 1022 | /* See if anyone else is waiting to be reaped */ |
| 1017 | dont_block: | 1023 | maybe_WNOHANG = WNOHANG; |
| 1018 | wpid = wait_any_nohang(NULL); | ||
| 1019 | } | 1024 | } |
| 1020 | } /* while (1) */ | 1025 | } /* while (1) */ |
| 1021 | } | 1026 | } |
diff --git a/mailutils/mail.c b/mailutils/mail.c index 71f46c86f..68883ff42 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c | |||
| @@ -48,6 +48,12 @@ void FAST_FUNC launch_helper(const char **argv) | |||
| 48 | xpipe(pipes); | 48 | xpipe(pipes); |
| 49 | xpipe(pipes + 2); | 49 | xpipe(pipes + 2); |
| 50 | 50 | ||
| 51 | // NB: handler must be installed before vfork | ||
| 52 | bb_signals(0 | ||
| 53 | + (1 << SIGCHLD) | ||
| 54 | + (1 << SIGALRM) | ||
| 55 | , signal_handler); | ||
| 56 | |||
| 51 | G.helper_pid = vfork(); | 57 | G.helper_pid = vfork(); |
| 52 | if (G.helper_pid < 0) | 58 | if (G.helper_pid < 0) |
| 53 | bb_perror_msg_and_die("vfork"); | 59 | bb_perror_msg_and_die("vfork"); |
| @@ -60,15 +66,12 @@ void FAST_FUNC launch_helper(const char **argv) | |||
| 60 | 66 | ||
| 61 | if (!G.helper_pid) { | 67 | if (!G.helper_pid) { |
| 62 | // child: try to execute connection helper | 68 | // child: try to execute connection helper |
| 69 | // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec | ||
| 63 | BB_EXECVP(*argv, (char **)argv); | 70 | BB_EXECVP(*argv, (char **)argv); |
| 64 | _exit(127); | 71 | _exit(127); |
| 65 | } | 72 | } |
| 66 | 73 | ||
| 67 | // parent | 74 | // parent |
| 68 | bb_signals(0 | ||
| 69 | + (1 << SIGCHLD) | ||
| 70 | + (1 << SIGALRM) | ||
| 71 | , signal_handler); | ||
| 72 | // check whether child is alive | 75 | // check whether child is alive |
| 73 | //redundant:signal_handler(SIGCHLD); | 76 | //redundant:signal_handler(SIGCHLD); |
| 74 | // child seems OK -> parent goes on | 77 | // child seems OK -> parent goes on |
