child_process: Separate 'close' event from 'exit'
Currently, a child process does not emit the 'exit' event until 'close' events have been received on all three of the child's stdio streams. This change makes the child object emit 'exit' when the child exits, and a new 'close' event when all stdio streams are closed.
This commit is contained in:
parent
928ea564d1
commit
c7b8073afc
@ -341,7 +341,7 @@ exports.execFile = function(file /* args, options, callback */) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
child.addListener('exit', exithandler);
|
child.addListener('close', exithandler);
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
};
|
};
|
||||||
@ -373,11 +373,11 @@ var spawn = exports.spawn = function(file, args, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function maybeExit(subprocess) {
|
function maybeClose(subprocess) {
|
||||||
subprocess._closesGot++;
|
subprocess._closesGot++;
|
||||||
|
|
||||||
if (subprocess._closesGot == subprocess._closesNeeded) {
|
if (subprocess._closesGot == subprocess._closesNeeded) {
|
||||||
subprocess.emit('exit', subprocess.exitCode, subprocess.signalCode);
|
subprocess.emit('close', subprocess.exitCode, subprocess.signalCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,7 +413,9 @@ function ChildProcess() {
|
|||||||
self._internal.close();
|
self._internal.close();
|
||||||
self._internal = null;
|
self._internal = null;
|
||||||
|
|
||||||
maybeExit(self);
|
self.emit('exit', self.exitCode, self.signalCode);
|
||||||
|
|
||||||
|
maybeClose(self);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
util.inherits(ChildProcess, EventEmitter);
|
util.inherits(ChildProcess, EventEmitter);
|
||||||
@ -474,7 +476,7 @@ ChildProcess.prototype.spawn = function(options) {
|
|||||||
this.stdout = createSocket(options.stdoutStream, true);
|
this.stdout = createSocket(options.stdoutStream, true);
|
||||||
this._closesNeeded++;
|
this._closesNeeded++;
|
||||||
this.stdout.on('close', function() {
|
this.stdout.on('close', function() {
|
||||||
maybeExit(self);
|
maybeClose(self);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,7 +484,7 @@ ChildProcess.prototype.spawn = function(options) {
|
|||||||
this.stderr = createSocket(options.stderrStream, true);
|
this.stderr = createSocket(options.stderrStream, true);
|
||||||
this._closesNeeded++;
|
this._closesNeeded++;
|
||||||
this.stderr.on('close', function() {
|
this.stderr.on('close', function() {
|
||||||
maybeExit(self);
|
maybeClose(self);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ var assert = require('assert');
|
|||||||
var spawn = require('child_process').spawn;
|
var spawn = require('child_process').spawn;
|
||||||
|
|
||||||
var pwd_called = false;
|
var pwd_called = false;
|
||||||
|
var childClosed = false;
|
||||||
|
var childExited = false;
|
||||||
|
|
||||||
function pwd(callback) {
|
function pwd(callback) {
|
||||||
var output = '';
|
var output = '';
|
||||||
@ -39,8 +41,13 @@ function pwd(callback) {
|
|||||||
child.on('exit', function(c) {
|
child.on('exit', function(c) {
|
||||||
console.log('exit: ' + c);
|
console.log('exit: ' + c);
|
||||||
assert.equal(0, c);
|
assert.equal(0, c);
|
||||||
|
childExited = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('close', function () {
|
||||||
callback(output);
|
callback(output);
|
||||||
pwd_called = true;
|
pwd_called = true;
|
||||||
|
childClosed = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,4 +60,6 @@ pwd(function(result) {
|
|||||||
|
|
||||||
process.on('exit', function() {
|
process.on('exit', function() {
|
||||||
assert.equal(true, pwd_called);
|
assert.equal(true, pwd_called);
|
||||||
|
assert.equal(true, childExited);
|
||||||
|
assert.equal(true, childClosed);
|
||||||
});
|
});
|
||||||
|
@ -44,8 +44,11 @@ function testCwd(options, forCode, forData) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
child.on('exit', function(code, signal) {
|
child.on('exit', function(code, signal) {
|
||||||
forData && assert.strictEqual(forData, data.replace(/[\s\r\n]+$/, ''));
|
|
||||||
assert.strictEqual(forCode, code);
|
assert.strictEqual(forCode, code);
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('close', function () {
|
||||||
|
forData && assert.strictEqual(forData, data.replace(/[\s\r\n]+$/, ''));
|
||||||
returns--;
|
returns--;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ cat.stdin.end();
|
|||||||
|
|
||||||
var response = '';
|
var response = '';
|
||||||
var exitStatus = -1;
|
var exitStatus = -1;
|
||||||
|
var closed = false;
|
||||||
|
|
||||||
var gotStdoutEOF = false;
|
var gotStdoutEOF = false;
|
||||||
|
|
||||||
@ -66,6 +67,10 @@ cat.stderr.on('end', function(chunk) {
|
|||||||
cat.on('exit', function(status) {
|
cat.on('exit', function(status) {
|
||||||
console.log('exit event');
|
console.log('exit event');
|
||||||
exitStatus = status;
|
exitStatus = status;
|
||||||
|
});
|
||||||
|
|
||||||
|
cat.on('close', function () {
|
||||||
|
closed = true;
|
||||||
if (is_windows) {
|
if (is_windows) {
|
||||||
assert.equal('hello world\r\n', response);
|
assert.equal('hello world\r\n', response);
|
||||||
} else {
|
} else {
|
||||||
@ -75,6 +80,7 @@ cat.on('exit', function(status) {
|
|||||||
|
|
||||||
process.on('exit', function() {
|
process.on('exit', function() {
|
||||||
assert.equal(0, exitStatus);
|
assert.equal(0, exitStatus);
|
||||||
|
assert(closed);
|
||||||
if (is_windows) {
|
if (is_windows) {
|
||||||
assert.equal('hello world\r\n', response);
|
assert.equal('hello world\r\n', response);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user