2013-07-21 23 views
0

我正在編寫守護進程,能夠恢復工作進程CentOS release 5.7 (Final)C++守護進程將不會收到SIGCHLD信號

下面是示例的代碼:

#define CHILD_NEED_WORK     1 
#define CHILD_NEED_TERMINATE 2 

int ReloadConfig() 
{ 
    .... 
    return 0; 
} 

void DestroyWorkThread() 
{...} 

int InitWorkThread() 
{ 
    ... 
    return 0; 
} 

int LoadConfig(char* FileName) 
{ 
    ... 
    return 0; 
} 

void SetPidFile(char* Filename) 
{ 
    FILE* f; 
    f = fopen(Filename, "w+"); 
    if (f) 
    { 
     fprintf(f, "%u\n", getpid()); 
     fclose(f); 
    } 
} 

int SetFdLimit(int MaxFd) 
{ 
    struct rlimit lim; 
    int   status; 

    lim.rlim_cur = MaxFd; 
    lim.rlim_max = MaxFd; 

    status = setrlimit(RLIMIT_NOFILE, &lim); 

    return status; 
} 

//Monitor process 
int MonitorProc() 
{ 
    int  pid; 
    int  status; 
    int  need_start = 1; 
    sigset_t sigset; 
    siginfo_t siginfo; 

    parent_pid = getpid(); 

    sigemptyset(&sigset); 

    sigaddset(&sigset, SIGQUIT); 

    sigaddset(&sigset, SIGINT); 

    sigaddset(&sigset, SIGTERM); 

    sigaddset(&sigset, SIGCHLD); 

    sigaddset(&sigset, SIGUSR1); 

    sigprocmask(SIG_BLOCK, &sigset, NULL); 

    SetPidFile(PID_FILE); 

    for (;;) 
    { 
     if (need_start) 
     { 
      pid = fork(); 
     } 

     need_start = 1; 

     if (pid == -1) 
     { 

     } 
     else if (!pid) 
     { 
      status = WorkProc(); 

      exit(status); 
     } 
     else 
     { 
      sigwaitinfo(&sigset, &siginfo); 

      if (siginfo.si_signo == SIGCHLD) 
      { 
       wait(&status); 

       status = WEXITSTATUS(status); 

       if (status == CHILD_NEED_TERMINATE) 
       { 
        Write("[MONITOR] Child stopped"); 
        break; 
       } 
       else if (status == CHILD_NEED_WORK) 
       { 
        Write("[MONITOR] Child restart"); 
       } 
      } 
      else if (siginfo.si_signo == SIGUSR1) 
      { 
       kill(pid, SIGUSR1); 
       need_start = 0; 
      } 
      else if (siginfo.si_signo == 0) 
      { 
       need_start = 0; 
       continue; 
      } 
      else 
      { 
       Write("[MONITOR] Signal ", strsignal(siginfo.si_signo)); 
       kill(pid, SIGTERM); 
       status = 0; 
       break; 
      } 
     } 
    } 

    Write("[MONITOR] Stop"); 

    unlink(PID_FILE); 

    return status; 
} 

//Work process 
int WorkProc() 
{ 
    struct sigaction sigact; 
    sigset_t   sigset; 
    int    signo; 
    int    status; 

    sigact.sa_flags = SA_SIGINFO; 

    sigact.sa_sigaction = signal_error_for_backtrace; 

    sigemptyset(&sigact.sa_mask); 


    sigaction(SIGFPE, &sigact, 0); 
    sigaction(SIGILL, &sigact, 0); 
    sigaction(SIGSEGV, &sigact, 0); 
    sigaction(SIGBUS, &sigact, 0); 

    sigemptyset(&sigset); 

    sigaddset(&sigset, SIGQUIT); 

    sigaddset(&sigset, SIGINT); 

    sigaddset(&sigset, SIGTERM); 

    sigaddset(&sigset, SIGUSR1); 
    sigprocmask(SIG_BLOCK, &sigset, NULL); 

    SetFdLimit(FD_LIMIT); 


    status = InitWorkThread(); 


    if (!status) 
    { 
     for (;;) 
     { 
      sigwait(&sigset, &signo); 

      if (signo == SIGUSR1) 
      { 
       status = ReloadConfig(); 
       if (status) 
       { 
        Write("[DAEMON] Reload config failed"); 
       } 
       else 
       { 
        Write("[DAEMON] Reload config OK"); 
       } 
      } 
      else 
      { 
       break; 
      } 
     } 

     DestroyWorkThread(); 
    } 
    else 
    { 
     Write("[DAEMON] Create work thread failed"); 
    } 

    Write("[DAEMON] Stopped"); 


    return CHILD_NEED_TERMINATE; 
} 


int main(int argc , char *argv[]) 
{ 

    if (argc != 2) 
    { 
     printf("Usage: ./test_daemon.conf failed!\n"); 
     return -1; 
    } 

    status = LoadConfig(argv[1]); 
    if (status) 
    { 
     printf("Error: Load config failed\n"); 
     return -1; 
    } 

    if (CheckForAnotherInstance()) 
    { 
    printf("Daemon is already running!\n"); 
    return 1; 
    } 

    pid = fork(); 
    if (pid == -1) 
    { 
     printf("Error: Start Daemon failed (%s)\n", strerror(errno)); 
     return -1; 
    } 
    else if (!pid) 
    { 
     umask(0); 
     setsid(); 

     close(STDIN_FILENO); 
     close(STDOUT_FILENO); 
     close(STDERR_FILENO); 
     //Monitor process startup 
     status = MonitorProc(); 
     return status; 
    } 
    else 
    { 
     return 0; 
    } 
    return 0; 
} 

我使用兩個過程:工作過程中,其產生主要工作和監控方法,其等待來自工作過程的信號,並重新啓動它們,如果它接收到所需要的信號。當我嘗試向父進程發送一個信號 - 監視進程 - 用命令kill -s SIGCHLD,它收到這個信號。

當我嘗試終止子進程時,父進程沒有收到SIGCHLD信號 - 它等待信號,並且子進程轉換爲殭屍。

但是當我用父級進程使用實用程序strace時,所有工作正常的子進程終止成功,並且父進程接收到SIGCHLD信號。

我讀了關於函數waitpid(),它用來接收SIGCHLD信號,但我想在父進程中接收另一個信號。

任何想法?

+0

如果你想自我守護進程,看到這個帖子瞭如何正確地做到這一點:http://stackoverflow.com/questions/17954432/creating-a-daemon-in-linux – kfsone

回答

0

我的猜測,信號處理程序沒有安裝在第一個叉之前?

0

您SIG_BLOCK SIGCHLD,所以不會收到任何信號。但是,這是不錯的方法,你去使用sigwaitinfo(),但你失敗了,當你做一個wait(使用siginfo.si_pid),你應該使用waitpid函數()爲PID您正在清理因通過sigwaitinfo同步接收到信號()。

您使用WEXITSTATUS()而不先檢查WIFEXITED(狀態)。請參閱wait()手冊頁。

您的監視器和工作進程似乎使用相同的可執行文件,因爲您之後使用out exec()執行fork()。因此,請小心,因爲您可能已恢復子級中的信號處理程序狀態,以使子級中的代碼正常運行。 例如監控進程是父進程?爲了得到一個孩子,它做了一個fork(),然後調用WorkProc()。在WorkProc()內部,它繼續阻止一堆信號(但不是SIGCLD)。然而,執行是來自MonitorProc()的sigprocmask(SIG_BLOCK,...)在WorkProc()內仍然是活動的。

我不知道什麼是 「如果(siginfo.si_signo == 0)」 是怎麼一回事。

因此,對於另一個主要查詢,爲什麼SIGCHLD沒有從正在運行WorkProc()函數的進程傳遞的原因是因爲您已經在MonitorProc()內部阻止了該信號。因此,解決這個問題使用第三個參數來sigprocmask()執行保存在MonitorProc原始塊/疏通面膜(),當你fork()和跳進WorkProc()之前恢復塊/疏通面膜。