Browse Source

Make sure Error object on exec() gets killed member

Also default to SIGTERM for destruction when exceeding timeout or buffer on
exec()
v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
9bf2975f78
  1. 4
      doc/api.markdown
  2. 20
      lib/child_process.js
  3. 6
      test/simple/test-exec.js

4
doc/api.markdown

@ -1068,14 +1068,14 @@ There is a second optional argument to specify several options. The default opti
{ encoding: 'utf8' { encoding: 'utf8'
, timeout: 0 , timeout: 0
, maxBuffer: 200*1024 , maxBuffer: 200*1024
, killSignal: 'SIGKILL' , killSignal: 'SIGTERM'
, cwd: null , cwd: null
, env: null , env: null
} }
If `timeout` is greater than 0, then it will kill the child process If `timeout` is greater than 0, then it will kill the child process
if it runs longer than `timeout` milliseconds. The child process is killed with if it runs longer than `timeout` milliseconds. The child process is killed with
`killSignal` (default: `'SIGKILL'`). `maxBuffer` specifies the largest `killSignal` (default: `'SIGTERM'`). `maxBuffer` specifies the largest
amount of data allowed on stdout or stderr - if this value is exceeded then amount of data allowed on stdout or stderr - if this value is exceeded then
the child process is killed. the child process is killed.

20
lib/child_process.js

@ -28,7 +28,7 @@ exports.execFile = function (file /* args, options, callback */) {
var options = { encoding: 'utf8' var options = { encoding: 'utf8'
, timeout: 0 , timeout: 0
, maxBuffer: 200*1024 , maxBuffer: 200*1024
, killSignal: 'SIGKILL' , killSignal: 'SIGTERM'
, cwd: null , cwd: null
, env: null , env: null
}; };
@ -62,18 +62,24 @@ exports.execFile = function (file /* args, options, callback */) {
var stderr = ""; var stderr = "";
var killed = false; var killed = false;
var exited = false; var exited = false;
var timeoutId;
function exithandler (code, signal) { function exithandler (code, signal) {
if (timeoutId) clearTimeout(timeoutId);
if (exited) return; if (exited) return;
exited = true; exited = true;
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
if (!callback) return; if (!callback) return;
if (code === 0 && signal === null) { if (code === 0 && signal === null) {
callback(null, stdout, stderr); callback(null, stdout, stderr);
} else { } else {
var e = new Error("Command failed: " + stderr); var e = new Error("Command failed: " + stderr);
e.killed = killed; e.killed = child.killed || killed;
e.code = code; e.code = code;
e.signal = signal; e.signal = signal;
callback(e, stdout, stderr); callback(e, stdout, stderr);
@ -81,14 +87,13 @@ exports.execFile = function (file /* args, options, callback */) {
} }
function kill () { function kill () {
var c = child.kill(options.killSignal);
killed = true; killed = true;
child.kill(options.killSignal);
process.nextTick(function () { process.nextTick(function () {
exithandler(null, options.killSignal) exithandler(null, options.killSignal)
}); });
} }
var timeoutId;
if (options.timeout > 0) { if (options.timeout > 0) {
timeoutId = setTimeout(function () { timeoutId = setTimeout(function () {
kill(); kill();
@ -113,8 +118,6 @@ exports.execFile = function (file /* args, options, callback */) {
} }
}); });
var pid = child.pid;
child.addListener("exit", exithandler); child.addListener("exit", exithandler);
return child; return child;
@ -126,6 +129,8 @@ function ChildProcess () {
var self = this; var self = this;
this.killed = false;
var gotCHLD = false; var gotCHLD = false;
var exitCode; var exitCode;
var termSignal; var termSignal;
@ -172,6 +177,7 @@ util.inherits(ChildProcess, EventEmitter);
ChildProcess.prototype.kill = function (sig) { ChildProcess.prototype.kill = function (sig) {
if (this._internal.pid) { if (this._internal.pid) {
this.killed = true;
if (!constants) constants = process.binding("constants"); if (!constants) constants = process.binding("constants");
sig = sig || 'SIGTERM'; sig = sig || 'SIGTERM';
if (!constants[sig]) throw new Error("Unknown signal: " + sig); if (!constants[sig]) throw new Error("Unknown signal: " + sig);

6
test/simple/test-exec.js

@ -44,7 +44,7 @@ exec("sleep 3", { timeout: 50 }, function (err, stdout, stderr) {
assert.ok(diff < 500); assert.ok(diff < 500);
assert.ok(err); assert.ok(err);
assert.ok(err.killed); assert.ok(err.killed);
assert.equal(err.signal, 'SIGKILL'); assert.equal(err.signal, 'SIGTERM');
}); });
@ -69,7 +69,7 @@ function killMeTwiceCallback(err, stdout, stderr) {
// parameters. // parameters.
assert.ok(err); assert.ok(err);
assert.ok(err.killed); assert.ok(err.killed);
assert.equal(err.signal, 'SIGKILL'); assert.equal(err.signal, 'SIGTERM');
// the timeout should still be in effect // the timeout should still be in effect
console.log("'sleep 3' was already killed. Took %d ms", diff); console.log("'sleep 3' was already killed. Took %d ms", diff);
@ -81,7 +81,7 @@ function killMeTwiceCallback(err, stdout, stderr) {
exec('python -c "print 200000*\'C\'"', { maxBuffer: 1000 }, function (err, stdout, stderr) { exec('python -c "print 200000*\'C\'"', { maxBuffer: 1000 }, function (err, stdout, stderr) {
assert.ok(err); assert.ok(err);
assert.ok(err.killed); assert.ok(err.killed);
assert.equal(err.signal, 'SIGKILL'); assert.equal(err.signal, 'SIGTERM');
}); });
process.addListener("exit", function () { process.addListener("exit", function () {

Loading…
Cancel
Save