Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
Add disconnect method to forked child processes
Browse files Browse the repository at this point in the history
This disconnect method allows the child to exit gracefully.
This also adds a disconnect event and connect property.
  • Loading branch information
AndreasMadsen authored and piscisaureus committed Jan 30, 2012
1 parent 52bd0f9 commit 836344c
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 9 deletions.
14 changes: 13 additions & 1 deletion doc/api/child_processes.markdown
Expand Up @@ -24,6 +24,13 @@ of the signal, otherwise `null`.

See `waitpid(2)`.

### Event: 'disconnect'

This event is emitted after using the `.disconnect()` method in the parent or
in the child. After disconnecting it is no longer possible to send messages.
An alternative way to check if you can send messages is to see if the
`child.connected` property is `true`.

### child.stdin

A `Writable Stream` that represents the child process's `stdin`.
Expand Down Expand Up @@ -264,7 +271,12 @@ processes:
}
});


To close the IPC connection between parent and child use the
`child.disconnect()` method. This allows the child to exit gracefully since
there is no IPC channel keeping it alive. When calling this method the
`disconnect` event will be emitted in both parent and child, and the
`connected` flag will be set to `false`. Please note that you can also call
`process.disconnect()` in the child process.

### child.kill([signal])

Expand Down
43 changes: 35 additions & 8 deletions lib/child_process.js
Expand Up @@ -85,6 +85,7 @@ function setupChannel(target, channel) {
}
}

channel.buffering = false;
channel.onread = function(pool, offset, length, recvHandle) {
if (recvHandle && setSimultaneousAccepts) {
// Update simultaneous accepts on Windows
Expand Down Expand Up @@ -117,10 +118,11 @@ function setupChannel(target, channel) {
start = i + 1;
}
jsonBuffer = jsonBuffer.slice(start);
this.buffering = jsonBuffer.length !== 0;

} else {
channel.close();
target._channel = null;
this.buffering = false;
target.disconnect();
}
};

Expand All @@ -129,7 +131,7 @@ function setupChannel(target, channel) {
throw new TypeError('message cannot be undefined');
}

if (!target._channel) throw new Error("channel closed");
if (!this.connected) throw new Error("channel closed");

// For overflow protection don't write if channel queue is too deep.
if (channel.writeQueueSize > 1024 * 1024) {
Expand All @@ -154,6 +156,34 @@ function setupChannel(target, channel) {
return true;
};

target.connected = true;
target.disconnect = function() {
if (!this.connected) return;

// do not allow messages to be written
this.connected = false;
this._channel = null;

var fired = false;
function finish() {
if (fired) return;
fired = true;

channel.close();
target.emit('disconnect');
}

// If a message is being read, then wait for it to complete.
if (channel.buffering) {
this.once('message', finish);
this.once('internalMessage', finish);

return;
}

finish();
};

channel.readStart();
}

Expand Down Expand Up @@ -201,11 +231,8 @@ exports.fork = function(modulePath /*, args, options*/) {

if (!options.thread) setupChannel(child, options.stdinStream);

child.on('exit', function() {
if (child._channel) {
child._channel.close();
}
});
// Disconnect when the child process exits.
child.once('exit', child.disconnect.bind(child));

This comment has been minimized.

Copy link
@igorzi

igorzi Jan 31, 2012

This breaks when child is an isolate (there's no disconnect method).

This comment has been minimized.

Copy link
@AndreasMadsen

AndreasMadsen Jan 31, 2012

Author Member

Reported in #2647


return child;
};
Expand Down

0 comments on commit 836344c

Please sign in to comment.