2013-07-08 2 views
0

У меня есть программа на C, которая работает, реагируя на сигналы. Некоторые сигналы вызывают разветвление родителя. Это позволяет выполнять другую обработку, в то время как родитель продолжает реагировать на сигналы.SIGTERM для всех дочерних процессов, но не для родителя

Когда родитель отправляется SIGTERM, я хочу, чтобы раздвоенные дети получили SIGTERM. Не важно, чтобы дети закончили обработку SIGTERM до выхода родителя.

Однако, с приведенным ниже кодом, дети не получают SIGTERM, когда я вызываю kill(0, SIGTERM) от родителя. Из kill manpage, похоже, все дети должны получить этот SIGTERM.

У меня есть настройка обработчика сигнала для родителя.

static volatile sig_atomic_t done = 0; 
const int handled_signals[] = {SIGINT, SIGTERM, 0}; 

static void set_flag(int signum) { 
    switch (signum) { 
    /* Intentionally exclude SIGQUIT/SIGABRT/etc. as we want to exit 
    * without cleaning up to help with debugging */ 
    case SIGTERM: 
    case SIGINT: 
     done = 1; 
     break; 
    default: 
     /* Should be unreachable, but just in case */ 
     if (signal(signum, SIG_DFL) != SIG_ERR) { 
      raise(signum); 
     } 
    } 
} 

static int setup_handlers() { 
    struct sigaction sa; 
    sigset_t block_all; 
    int i; 

    /* Block all other signals while handling a signal. This is okay as 
    * our handler is very brief */ 
    sigfillset(&block_all); 
    sa.sa_mask = block_all; 

    sa.sa_handler = set_flag; 
    for (i = 0; handled_signals[i] != 0; i++) { 
     if (sigaction(handled_signals[i], &sa, NULL)) { 
      err_log("Unable to set sigaction"); 
      return 1; 
     } 
    } 

    /* Ignore SIGCHLD as we don't keep track of child success */ 
    sa.sa_handler = SIG_IGN; 
    if (sigaction(SIGCHLD, &sa, NULL)) { 
     err_log("Unable to ignore SIGCHLD"); 
     return 1; 
    } 

    return 0; 
} 

int main() { 
    int i; 
    sigset_t block_mask, orig_mask; 

    setup_handlers(); 

    /* Block all of our handled signals as we will be using 
    * sigsuspend in the loop below */ 
    sigemptyset(&block_mask); 
    for (i = 0; handled_signals[i] != 0; i++) { 
     sigaddset(&block_mask, handled_signals[i]); 
    } 

    if (sigprocmask(SIG_BLOCK, &block_mask, &orig_mask)) { 
     err_log("Error blocking signals"); 
    } 

    while (!done) { 
     if (sigsuspend(&orig_mask) && errno != EINTR) { 
      err_log("sigsuspend"); 
     } 
    } 

    /* Kill all children */ 
    if (kill(0, SIGTERM)) { 
     err_log("kill(0, SIGTERM))"); 
    } 
} 

После получения сигнала, который требует вилки, я следующий

static int unregister_handlers() { 
    struct sigaction sa; 
    int i; 

    sa.sa_handler = SIG_DFL; 

    for (i = 0; handled_signals[i] != 0; i++) { 
     if (sigaction(handled_signals[i], &sa, NULL)) { 
      err_log("sigaction unregister"); 
      return 1; 
     } 
    } 

    if (sigaction(SIGCHLD, &sa, NULL)) { 
     err_log("sigaction SIGCHLD unregister"); 
     return 1; 
    } 

    return 0; 
} 

void do_fork() { 

    switch(fork()) { 
    /* Error */ 
    case -1: 
     err_log("fork"); 
     break; 

    /* Child */ 
    case 0: 
     if (unregister_handlers()) { 
      _exit(1); 
     } 
     do_fork_stuff(); 
     _exit(0); 
     break; 

    /* Parent */ 
    default: 
     break; 
    } 
} 

В do_fork_stuff, ребенок спит в течение 30 секунд. Затем я вызываю kill(0, SIGTERM) из родителя. Дети не заканчиваются.

По какой причине дети не получают SIGTERM?

ответ

3

Ах, небольшая помощь от /proc/[PID]/status решила это.

$ cat /proc/31171/status 
Name: myprog 
SigQ: 2/16382 
SigPnd: 0000000000000000 
ShdPnd: 0000000000000000 
SigBlk: 0000000000004203 
SigIgn: 0000000000000000 
SigCgt: 0000000180000000 

Были заблокированы сигналы (SigBlk). Пока обработчики были незарегистрированы, дети блокировали SIGTERM. Устранение заблокированных сигналов решило проблему.

Смежные вопросы