2013-02-20 4 views
1

У меня есть длительный процесс (node.js), который вызывает fork (как часть модуля C++). Это создает новый процесс как дочерний процесс node.js. Тем не менее, нет ничего, что будет ждать/waitpid для этого дочернего процесса, поэтому он остается зомби после его завершения.развивает длительный процесс и не требует вызова waitpid для очистки зомби?

Можно ли использовать fork() процесс без текущего процесса, являющегося его родительским, так что после его завершения он не остается в состоянии зомби, а очищается?

Если нет, могу ли я как-то указать, что я не буду называть waitpid на ребенка и не волнует, когда он закончится?

В противном случае все, что я могу написать/найти собственный модуль, который может выполнять waitpid, но я должен быть уверен, что это будет:

  1. Не блокировать родительский процесс (Node.js)
  2. Не оставляйте зомби после того, как функция модуля называется

Спасибо!

+1

Просто 'fork' дважды. У длительно работающего процесса теперь будет родиться родительский (первый ребенок) и наследуется 'init', [который будет пожинать его] (http://stackoverflow.com/a/881434/721269). –

+1

Или на некоторых Unixes вы можете установить 'SIGCHLD' на' SIG_IGN', и ядро ​​интерпретирует это как значение, которое вы хотите, чтобы зомби ушел немедленно, и вы не заинтересованы в его статусе выхода. – zwol

+2

@David: Итак, первая вилка создаст дочерний C1 (родительский процесс node.js), а затем fork C1 для создания C2, который является процессом, который я хочу наследовать init? C1 умрет почти мгновенно, node.js тогда должен ждать wait на C1 (который, как мы знаем, будет быстрым), а C2 затем наследуется init. Правильно ли я понял? – Pavel

ответ

3

Вот код, который я использую для создания демона. Комментарии описывают почему каждый шаг сделан.

Status daemon_init(void) 
{ 
    pid_t pid; 
    int fh; 

    /*----------------------------------------------------------------------- 
    ; From the Unix Programming FAQ (corraborated by Stevens): 
    ; 
    ; 1. 'fork()' so the parent can exit, this returns control to the command 
    ; line or shell invoking your program. This step is required so that 
    ; the new process is guaranteed not to be a process group leader. The 
    ; next step, 'setsid()', fails if you're a process group leader. 
    ;---------------------------------------------------------------------*/ 

    pid = fork(); 
    if (pid == (pid_t)-1) 
    return retstatus(false,errno,"fork()"); 
    else if (pid != 0) /* parent goes bye bye */ 
    _exit(EXIT_SUCCESS); 

    /*------------------------------------------------------------------------- 
    ; 2. 'setsid()' to become a process group and session group leader. Since 
    ; a controlling terminal is associated with a session, and this new 
    ; session has not yet acquired a controlling terminal our process now 
    ; has no controlling terminal, which is a Good Thing for daemons. 
    ; 
    ; _Advanced Programming in the Unix Environment_, 2nd Edition, also 
    ; ignores SIGHUP. So adding that here as well. 
    ;-----------------------------------------------------------------------*/ 

    setsid(); 
    set_signal_handler(SIGHUP,SIG_IGN); /* ignore this signal for now */ 

    /*------------------------------------------------------------------------- 
    ; 3. 'fork()' again so the parent, (the session group leader), can exit. 
    ; This means that we, as a non-session group leader, can never regain a 
    ; controlling terminal. 
    ;------------------------------------------------------------------------*/ 

    pid = fork(); 
    if (pid == (pid_t)-1) 
    return retstatus(false,errno,"fork(2)"); 
    else if (pid != 0) /* parent goes bye bye */ 
    _exit(EXIT_SUCCESS); 

    /*------------------------------------------------------------------------- 
    ; 4. 'chdir("/")' to ensure that our process doesn't keep any directory in 
    ; use. Failure to do this could make it so that an administrator 
    ; couldn't unmount a filesystem, because it was our current directory. 
    ; 
    ; [Equivalently, we could change to any directory containing files 
    ; important to the daemon's operation.] 
    ; 
    ; I just made sure the name of the script we are using contains the full 
    ; path. 
    ;-------------------------------------------------------------------------*/ 

    chdir("/"); 

    /*----------------------------------------------------------------------- 
    ; 5. 'umask(022)' so that we have complete control over the permissions of 
    ; anything we write. We don't know what umask we may have inherited. 
    ;-----------------------------------------------------------------------*/ 

    umask(022); 

    /*----------------------------------------------------------------------- 
    ; 6. 'close()' fds 0, 1, and 2. This releases the standard in, out, and 
    ; error we inherited from our parent process. We have no way of knowing 
    ; where these fds might have been redirected to. Note that many daemons 
    ; use 'sysconf()' to determine the limit '_SC_OPEN_MAX'. 
    ; '_SC_OPEN_MAX' tells you the maximun open files/process. Then in a 
    ; loop, the daemon can close all possible file descriptors. You have to 
    ; decide if you need to do this or not. If you think that there might 
    ; be file-descriptors open you should close them, since there's a limit 
    ; on number of concurrent file descriptors. 
    ; 
    ; 7. Establish new open descriptors for stdin, stdout and stderr. Even if 
    ; you don't plan to use them, it is still a good idea to have them 
    ; open. The precise handling of these is a matter of taste; if you 
    ; have a logfile, for example, you might wish to open it as stdout or 
    ; stderr, and open '/dev/null' as stdin; alternatively, you could open 
    ; '/dev/console' as stderr and/or stdout, and '/dev/null' as stdin, or 
    ; any other combination that makes sense for your particular daemon. 
    ; 
    ; We do this here via dup2(), which combines steps 6 & 7. 
    ;------------------------------------------------------------------------*/ 

    fh = open(DEV_NULL,O_RDWR); 
    if (fh == -1) 
    return retstatus(false,errno,"open(" DEV_NULL ")"); 

    assert(fh > 2); 

    dup2(fh,STDIN_FILENO); 
    dup2(fh,STDOUT_FILENO); 
    dup2(fh,STDERR_FILENO); 

    close(fh); 

    return c_okay; 
} 

Если вы хотите увидеть эту функцию в контексте, вы можете увидеть его здесь: https://github.com/spc476/syslogintr/blob/master/syslogintr.c

+0

Этапы 6 и 7 должны выполняться между этапами 1 и 2; кроме того, вы должны выпустить 'closefrom (3)' или эквивалент в этой точке. В некоторых (более старых) системах 'setsid' терпит неудачу, если у вас есть открытый fd, ссылающийся на терминал. – zwol

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