0

我正在编写能够恢复工作进程的守护进程CentOS release 5.7 (Final)

这是代码示例:

#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 信号,但我也想在父进程中接收另一个信号。

有任何想法吗?

4

2 回答 2

0

我的猜测,第一次分叉之前没有安装信号处理程序?

于 2013-07-21T09:38:24.327 回答
0

你 SIG_BLOCK SIGCHLD 所以不会收到任何信号。但这没关系,因为您继续使用 sigwaitinfo() 但是在执行 wait() 时未能使用 siginfo.si_pid,由于通过 sigwaitinfo 同步接收信号,您应该对要清理的 PID 使用 waitpid() ()。

您使用 WEXITSTATUS() 而不先检查 WIFEXITED(status) 。请参阅 wait() 手册页。

您的监视器和工作进程似乎使用与您执行 fork() 后没有 exec() 相同的可执行文件。所以要小心,因为您可能会恢复子进程中的信号处理程序状态,以使子进程中的代码正常运行。比如监控进程是父进程?因此,要获得一个孩子,它会执行 fork(),然后调用 WorkProc()。在 WorkProc() 内部,它继续阻塞一堆信号(但不是 SIGCLD)。然而执行是来自 MonitorProc() 的 sigprocmask(SIG_BLOCK, ...) 将在 WorkProc() 中仍然处于活动状态。

我不确定“if (siginfo.si_signo == 0)”是什么意思。

因此,对于另一个您的主要查询,SIGCHLD 未从运行 WorkProc() 函数的进程传递的原因是因为您已经在 MonitorProc() 中阻止了该信号。所以修复这个问题,使用 sigprocmask() 的第三个参数来保存 MonitorProc() 中的原始块/取消块掩码,当你 fork() 和跳转到 WorkProc() 之前恢复块/取消块掩码。

于 2015-05-28T01:01:27.320 回答