SIGCHLD не доставлен в дереве процессов - PullRequest
2 голосов
/ 03 октября 2011

Я пытаюсь создать процесс, который управляет каким-то другим процессом таким образом, что если ребенок умирает, то родитель перезапускает процесс и процесс, который от него зависит.

Проблема в том, что я заметил, чтоесли я создаю древовидную структуру процесса при перезапуске процесса в середине этой структуры, я не могу получить сигнал, когда новый дочерний процесс завершается.

Я пишу пример;Предположим, что у нас есть 3 процесса, бабушка и дедушка, родитель и ребенок.Разбираем дедушку и запускаем родительскую вилку и начинаем дочернюю (я поместил код в конец этого поста).Теперь, если я убиваю child, все работает хорошо, child перезапускается правильно.

Проблема возникает, если я убиваю parent ... Перезапускает родительский дед, который перезапускает child, но если я уничтожаю child, процесс остается в состоянии Zombie.и SIGCHLD не доставляется в родительский процесс.

Другими словами:

  • Запустите процесс бабушки и дедушки и подождите, пока все 3 процесса были запущены
  • Kill parentобработать и подождать, пока родительский родитель перезапустит родительский перезапуск
  • теперь убивает дочерний процесс, процесс остается в состоянии зомби.

Я не могу понять это поведение ...Я прочитал множество примеров и документации о сигнале и ожидании, попробуйте сбросить обработчик по умолчанию перед разветвлением в parent и grandparent, но, похоже, ничего не работает ... Вот пример кода ...

grandparent.cpp

#include <cstdio>
#include <string>
#include <cstring>

#include <stdlib.h>
#include <signal.h>
#include <wait.h>

using namespace std;

void startProcess(string processFile);
void childDieHandler(int sig, siginfo_t *child_info, void *context);

FILE            *logFile;
int         currentChildPid;

int main(int argc, char** argv)
{
    currentChildPid = 0;
    logFile = stdout;

    daemon(1,1);


    struct sigaction sa;
    bzero(&sa, sizeof(sa));
    sa.sa_sigaction = childDieHandler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGCHLD, &sa, NULL);

    startProcess("parent");

    while(true) {
        sleep(60);
    }

    return 0;
}

void startProcess(string processFile)
{
    fprintf(logFile, "\nGP:Starting new process %s\n",processFile.c_str());
    // Get process field and start a new process via fork + execl
    int pid = fork();
    if (pid == -1){
        fprintf(logFile,"GP:*** FORK ERROR on process %s !!!\n",processFile.c_str());
        fflush(logFile);
        return;
    }

    // New child process
    if (pid == 0) {

        string execString = get_current_dir_name()+(string)"/"+processFile;
        fprintf(logFile, "GP: %s \n",execString.c_str());

    execl(execString.c_str(), processFile.c_str(), NULL);

        fprintf(logFile, "GP:*** ERROR on execv for process %s\n",processFile.c_str());
        fflush(logFile);
        exit(1);
    } else {
        // Parent process
        fprintf(logFile, "GP:New process %s pid is %d .\n", processFile.c_str(), pid);
        fflush(logFile);
    currentChildPid = pid;
        sleep(2);
    }
}

// Intercept a signal SIGCHLD
void childDieHandler(int sig, siginfo_t *child_info, void *context){
    int status;
    pid_t childPid;
    while((childPid = waitpid(-1,&status, WNOHANG)) > 0) {
        int pid = (int) childPid;
        fprintf(logFile,"GP:*** PROCESS KILLED [pid %d]\n",pid);

    sigset_t set;
    sigpending(&set);
    if(sigismember(&set, SIGCHLD)){
        fprintf(logFile, "GP: SIGCHLD is pending or blocked!!!!\n");
        fflush(logFile);
    }

        fflush(logFile);

        // identify exited process and then restart it
        if(currentChildPid == childPid){
        // kill any child 
        system("killall child");
        fprintf(logFile,"GP: Restarting parent process...\n");
        fflush(logFile);
        startProcess("parent");
    }

    }

    fprintf(logFile,"GP:End of childDieHandler()... [%d]\n\n",(int)childPid);
    fflush(logFile);
}

parent.cpp

#include <cstdio>
#include <string>
#include <cstring>

#include <stdlib.h>
#include <signal.h>
#include <wait.h>

using namespace std;

void startProcess(string processFile);
void childDieHandler(int sig, siginfo_t *child_info, void *context);

FILE            *logFile;
int         currentChildPid;

int main(int argc, char** argv)
{
    currentChildPid = 0;
    logFile = stdout;

    struct sigaction sa;
    bzero(&sa, sizeof(sa));
    sa.sa_sigaction = childDieHandler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGCHLD, &sa, NULL);

    startProcess("child");

    while(true) {
        sleep(60);
    }

    return 0;
}

void startProcess(string processFile)
{
    fprintf(logFile, "\nP : Starting new process %s\n",processFile.c_str());
    // Get process field and start a new process via fork + execl
    int pid = fork();
    if (pid == -1){
        fprintf(logFile,"P : *** FORK ERROR on process %s !!!\n",processFile.c_str());
        fflush(logFile);
        return;
    }

    // New child process
    if (pid == 0) {
    string execString = get_current_dir_name()+(string)"/"+processFile;
        execl(execString.c_str(), processFile.c_str(), NULL);

        fprintf(logFile, "P : *** ERROR on execv for process %s\n",processFile.c_str());
        fflush(logFile);
        exit(1);
    } else {
        // Parent process
        fprintf(logFile, "P : New process %s pid is %d .\n", processFile.c_str(), pid);
        fflush(logFile);
    currentChildPid = pid;
        sleep(2);
    }
}

// Intercept a signal SIGCHLD
void childDieHandler(int sig, siginfo_t *child_info, void *context){
    int status;
    pid_t childPid;
    while((childPid = waitpid(-1,&status, WNOHANG)) > 0) {
        int pid = (int) childPid;
        fprintf(logFile,"P : *** PROCESS KILLED [pid %d]\n",pid);

    sigset_t set;
    sigpending(&set);
    if(sigismember(&set, SIGCHLD)){
        fprintf(logFile, "P : SIGCHLD is pending or blocked!!!!\n");
        fflush(logFile);
    }

        fflush(logFile);

    // identify exited process and then restart it
    if(currentChildPid == childPid){
        fprintf(logFile,"P :  Restarting child process...\n");
        fflush(logFile);
        startProcess("child");
    }

    }

    fprintf(logFile,"P : End of childDieHandler()... [%d]\n\n",(int)childPid);
    fflush(logFile);
}

child.cpp

#include <cstdio>
#include <string>
#include <cstring>

int main(int argc, char** argv)
{
    printf("\nC : I'm born...\n\n");

    while(true) {
        sleep(60);
    }

    return 0;
}

1 Ответ

2 голосов
/ 03 октября 2011

Ну, у меня есть предположение ...

Внутри обработчика сигнала сигнал SIGCHLD заблокирован (т. Е. Он является частью маски сигнала процесса).

Поэтому, когда дедушка вызывает execl из обработчика сигнала, новый родитель запускается с заблокированным SIGCHLD.Таким образом, он никогда не видит сигнал и никогда не ждет нового потомка.

Попробуйте позвонить sigprocmask в начале parent.cpp, чтобы (а) проверить эту теорию и (б) разблокировать SIGCHLD.

...