node pty.js产生一个进程,它自己产生子进程,当节点被杀死时,子进程不会死

时间:2014-03-19 17:59:35

标签: c linux node.js child-process pty

使用Ubuntu 13.10并运行节点v0.10.0。我正在使用pty.js v0.2.4来生成一个程序(需要在交互式环境中运行)。该程序是用C语言编写的,并且本身就是一个子进程。

我已经编写了一个非常简化的C程序版本(我称之为'forktest'),它具有产生此问题所需的最低要求,并包含以下内容:

#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>

int main(void)
{
    pid_t childPID;
    childPID = fork();
    if(childPID >= 0) {
        if(childPID == 0) {
            signal(SIGHUP, SIG_IGN);
            while(1) {
              printf("Child Process\n");
              fflush(stdout);
              usleep(500000);
            }
        } else {
            printf("Parent process\n");
            fflush(stdout);
            getchar();
        }
    } else {
        printf("Fork failed, exiting\n");
        return 1;
    }
    return 0;
}

我还整理了一个用coffeescript(test.coffee)编写的最小节点脚本,该脚本运行程序,如下所示:

pty = require 'pty.js'

command = './forktest'
example = pty.spawn command, null
example.on 'data', (data) ->
  console.log data
example.on 'exit', ->
  console.log 'example exited'

运行节点脚本'coffee test.coffee'时,会看到输出('Parent Process'和'Child Process')。此外,进程的层次结构在ps('ps faux')中正确显示:

lightdm
 \_ /usr/bin/X -core :0 -auth /var/run/lightdm/root/:0 -no
 \_ lightdm --session-child 12 21
     \_ init --user
         \_ gnome-terminal
             \_ bash
                 \_ node /usr/local/bin/coffee test.coffee
                     \_ ./forktest
                         \_ ./forktest

但是当退出coffeescript(使用ctrl-c)时,父forktest进程也会按预期退出,但是子forktest进程会被抛弃,'ps faux'的输出则如下所示:

lightdm
 \_ /usr/bin/X -core :
 \_ lightdm --session-
     \_ init --user
         \_ ./forktest

我调查过这是因为在子进程中忽略了挂起信号:

signal(SIGHUP, SIG_IGN);

如果我在node:

中使用child_process模块​​中的spawn
{spawn} = require 'child_process'

command = './forktest'
example = spawn command

example.stdout.on 'data', (data) ->
  console.log String data
example.on 'exit', ->
  console.log 'example exited'

以同样的方式退出coffeescript应用程序(ctrl-c),当它退出forktest的父进程和子进程时消失,所以它看起来与pty.js如何以某种方式工作有关。

我无法编辑(删除忽略信号)并将原始C程序分发给用户,所以我正在寻找解决此问题的方法。

一种解决方法是使用以下方法捕获节点的中断信号:

process.on 'SIGINT', (data) ->
  # kill the parent / child process manually

无论如何我应该做什么..但如果coffeescript过程被杀死而不是被打断,它仍将遭受同样的问题并让孩子落后。据我所知,没有办法在节点中捕获SIGKILL?

当节点被杀死时,有没有原因导致用pty.js生成的程序的子进程没有被销毁?

1 个答案:

答案 0 :(得分:2)

您正遇到一个关于POSIX系统如何处理终止进程的细微问题。

当进程被终止时,内核redefines who the parent is。与子进程退出并通知其父进程不同,如果父进程在退出时没有向子进程发送信号,则子进程不会收到通知。内核只是将其父ID重新定义为init进程。

因此,默认情况下当父级退出时,不会退出任何子级。那么当父母退出时,孩子怎么会被杀?好吧,每个进程都有一个进程组ID。这默认为启动时它的父进程组ID。如果进程死亡的进程组becomes orphaned,那么内核可能会向进程组的所有成员发送SIGHUPSIGCONT。这让孩子有机会退出,但他们不必这样做。如果他们没有退出,那么他们就是孤立的进程,并将他们的父id设置为init进程。

巧合的是,这就是分支创建守护进程的方法。

因此,要解决您的问题,请确保孙子是同一进程组ID的一部分。这应该让他们收到杀死子进程的信号。但是,如果他们忽略了信号,那么你真的只有一个选项。

生成一个包装器程序,除了生成你的实际进程之外什么都不做,并在&#34; real&#34;之间来回传递所有内容。父母和&#34;真实&#34;儿童。然后,如果SIGHUP被发送到您的包装器,请向该子项发送SIGKILL以强制退出。

相关问题