summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2012-07-31 16:14:34 +0200
committerBen Noordhuis <info@bnoordhuis.nl>2012-09-22 03:48:59 +0200
commit212466bea23a8f92153cec0d009175cd94c7360d (patch)
treed44a6d21513f8060e03965dc31261365df611a8f
parent56668f54d11225b0bcdf93dc2fba846febdbb19f (diff)
downloadnode-212466bea23a8f92153cec0d009175cd94c7360d.tar.gz
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.
-rw-r--r--lib/child_process.js8
-rw-r--r--test/fixtures/child-process-spawn-node.js8
-rw-r--r--test/simple/test-child-process-fork3.js25
3 files changed, 37 insertions, 4 deletions
diff --git a/lib/child_process.js b/lib/child_process.js
index e1af90fb4..728b26b9b 100644
--- a/lib/child_process.js
+++ b/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();
+ });
};
diff --git a/test/fixtures/child-process-spawn-node.js b/test/fixtures/child-process-spawn-node.js
index 9bc6c1987..01a494ee5 100644
--- a/test/fixtures/child-process-spawn-node.js
+++ b/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' });
diff --git a/test/simple/test-child-process-fork3.js b/test/simple/test-child-process-fork3.js
new file mode 100644
index 000000000..0f75b029e
--- /dev/null
+++ b/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