Permalink
Browse files

child_process: make .fork()'d child auto-exit

A child process created with .fork() needed to call `process.exit()` explicitly
because the communication channel with the parent kept the event loop alive.

Fix that by only ref'ing the channel when there are 'message' event listeners.

Fixes #3799.
  • Loading branch information...
1 parent 56668f5 commit 212466bea23a8f92153cec0d009175cd94c7360d @bnoordhuis bnoordhuis committed Jul 31, 2012
Showing with 37 additions and 4 deletions.
  1. +8 −0 lib/child_process.js
  2. +4 −4 test/fixtures/child-process-spawn-node.js
  3. +25 −0 test/simple/test-child-process-fork3.js
View
8 lib/child_process.js
@@ -452,7 +452,15 @@ exports._forkChild = function(fd) {
// set process.send()
var p = createPipe(true);
p.open(fd);
+ p.unref();
setupChannel(process, p);
+
+ process.on('newListener', function(name) {
+ if (name == 'message' && this.listeners('message').length == 0) p.ref();
+ });
+ process.on('removeListener', function(name) {
+ if (name == 'message' && this.listeners('message').length == 0) p.unref();
+ });
};
View
8 test/fixtures/child-process-spawn-node.js
@@ -1,10 +1,10 @@
var assert = require('assert');
-process.on('message', function(m) {
+function onmessage(m) {
console.log('CHILD got message:', m);
assert.ok(m.hello);
- // Note that we have to force exit.
- process.exit();
-});
+ process.removeListener('message', onmessage);
+}
+process.on('message', onmessage);
process.send({ foo: 'bar' });
View
25 test/simple/test-child-process-fork3.js
@@ -0,0 +1,25 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var common = require('../common');
+var child_process = require('child_process');
+
+child_process.fork(common.fixturesDir + '/empty.js'); // should not hang

0 comments on commit 212466b

Please sign in to comment.