mail.c: more robust handling of SIGCHLD
init: more robust signal handling
This commit is contained in:
parent
245f91b649
commit
4774179cb9
41
init/init.c
41
init/init.c
@ -336,20 +336,22 @@ static pid_t run(const struct init_action *a)
|
|||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
/* Careful: don't be affected by a signal in vforked child */
|
||||||
|
sigprocmask_allsigs(SIG_BLOCK);
|
||||||
if (BB_MMU && (a->action_type & ASKFIRST))
|
if (BB_MMU && (a->action_type & ASKFIRST))
|
||||||
pid = fork();
|
pid = fork();
|
||||||
else
|
else
|
||||||
pid = vfork();
|
pid = vfork();
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
message(L_LOG | L_CONSOLE, "can't fork");
|
message(L_LOG | L_CONSOLE, "can't fork");
|
||||||
if (pid)
|
if (pid) {
|
||||||
|
sigprocmask_allsigs(SIG_UNBLOCK);
|
||||||
return pid; /* Parent or error */
|
return pid; /* Parent or error */
|
||||||
|
}
|
||||||
|
|
||||||
/* Child */
|
/* Child */
|
||||||
|
|
||||||
/* Reset signal handlers that were set by the parent process */
|
/* Reset signal handlers that were set by the parent process */
|
||||||
//TODO: block signals across fork(), prevent them to affect child before
|
|
||||||
//signals are reset?
|
|
||||||
bb_signals(0
|
bb_signals(0
|
||||||
+ (1 << SIGUSR1)
|
+ (1 << SIGUSR1)
|
||||||
+ (1 << SIGUSR2)
|
+ (1 << SIGUSR2)
|
||||||
@ -359,6 +361,7 @@ static pid_t run(const struct init_action *a)
|
|||||||
+ (1 << SIGHUP)
|
+ (1 << SIGHUP)
|
||||||
+ (1 << SIGTSTP)
|
+ (1 << SIGTSTP)
|
||||||
, SIG_DFL);
|
, SIG_DFL);
|
||||||
|
sigprocmask_allsigs(SIG_UNBLOCK);
|
||||||
|
|
||||||
/* Create a new session and make ourself the process group leader */
|
/* Create a new session and make ourself the process group leader */
|
||||||
setsid();
|
setsid();
|
||||||
@ -982,40 +985,42 @@ int init_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
* NB: if delayed signal happened, avoid blocking in wait().
|
* NB: if delayed signal happened, avoid blocking in wait().
|
||||||
*/
|
*/
|
||||||
while (1) {
|
while (1) {
|
||||||
pid_t wpid;
|
int maybe_WNOHANG;
|
||||||
int got_sigs;
|
|
||||||
|
|
||||||
got_sigs = check_delayed_sigs();
|
maybe_WNOHANG = check_delayed_sigs();
|
||||||
|
|
||||||
/* (Re)run the respawn/askfirst stuff */
|
/* (Re)run the respawn/askfirst stuff */
|
||||||
run_actions(RESPAWN | ASKFIRST);
|
run_actions(RESPAWN | ASKFIRST);
|
||||||
|
maybe_WNOHANG |= check_delayed_sigs();
|
||||||
got_sigs |= check_delayed_sigs();
|
|
||||||
|
|
||||||
/* Don't consume all CPU time - sleep a bit */
|
/* Don't consume all CPU time - sleep a bit */
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
maybe_WNOHANG |= check_delayed_sigs();
|
||||||
|
|
||||||
got_sigs |= check_delayed_sigs();
|
/* Wait for any child process(es) to exit.
|
||||||
|
|
||||||
if (got_sigs)
|
|
||||||
goto dont_block;
|
|
||||||
/* Wait for any child process to exit.
|
|
||||||
* NB: "delayed" signals will also interrupt this wait(),
|
* NB: "delayed" signals will also interrupt this wait(),
|
||||||
* bb_signals_recursive_norestart() set them up for that.
|
* bb_signals_recursive_norestart() set them up for that.
|
||||||
* This guarantees we won't be stuck here
|
* This guarantees we won't be stuck here
|
||||||
* till next orphan dies.
|
* till next orphan dies.
|
||||||
*/
|
*/
|
||||||
wpid = wait(NULL);
|
if (maybe_WNOHANG)
|
||||||
while (wpid > 0) {
|
maybe_WNOHANG = WNOHANG;
|
||||||
struct init_action *a = mark_terminated(wpid);
|
while (1) {
|
||||||
|
pid_t wpid;
|
||||||
|
struct init_action *a;
|
||||||
|
|
||||||
|
wpid = waitpid(-1, NULL, maybe_WNOHANG);
|
||||||
|
if (wpid <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
a = mark_terminated(wpid);
|
||||||
if (a) {
|
if (a) {
|
||||||
message(L_LOG, "process '%s' (pid %d) exited. "
|
message(L_LOG, "process '%s' (pid %d) exited. "
|
||||||
"Scheduling for restart.",
|
"Scheduling for restart.",
|
||||||
a->command, wpid);
|
a->command, wpid);
|
||||||
}
|
}
|
||||||
/* See if anyone else is waiting to be reaped */
|
/* See if anyone else is waiting to be reaped */
|
||||||
dont_block:
|
maybe_WNOHANG = WNOHANG;
|
||||||
wpid = wait_any_nohang(NULL);
|
|
||||||
}
|
}
|
||||||
} /* while (1) */
|
} /* while (1) */
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,12 @@ void FAST_FUNC launch_helper(const char **argv)
|
|||||||
xpipe(pipes);
|
xpipe(pipes);
|
||||||
xpipe(pipes + 2);
|
xpipe(pipes + 2);
|
||||||
|
|
||||||
|
// NB: handler must be installed before vfork
|
||||||
|
bb_signals(0
|
||||||
|
+ (1 << SIGCHLD)
|
||||||
|
+ (1 << SIGALRM)
|
||||||
|
, signal_handler);
|
||||||
|
|
||||||
G.helper_pid = vfork();
|
G.helper_pid = vfork();
|
||||||
if (G.helper_pid < 0)
|
if (G.helper_pid < 0)
|
||||||
bb_perror_msg_and_die("vfork");
|
bb_perror_msg_and_die("vfork");
|
||||||
@ -60,15 +66,12 @@ void FAST_FUNC launch_helper(const char **argv)
|
|||||||
|
|
||||||
if (!G.helper_pid) {
|
if (!G.helper_pid) {
|
||||||
// child: try to execute connection helper
|
// child: try to execute connection helper
|
||||||
|
// NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec
|
||||||
BB_EXECVP(*argv, (char **)argv);
|
BB_EXECVP(*argv, (char **)argv);
|
||||||
_exit(127);
|
_exit(127);
|
||||||
}
|
}
|
||||||
|
|
||||||
// parent
|
// parent
|
||||||
bb_signals(0
|
|
||||||
+ (1 << SIGCHLD)
|
|
||||||
+ (1 << SIGALRM)
|
|
||||||
, signal_handler);
|
|
||||||
// check whether child is alive
|
// check whether child is alive
|
||||||
//redundant:signal_handler(SIGCHLD);
|
//redundant:signal_handler(SIGCHLD);
|
||||||
// child seems OK -> parent goes on
|
// child seems OK -> parent goes on
|
||||||
|
Loading…
Reference in New Issue
Block a user