Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
billiegoose committed Sep 29, 2015
2 parents eabd2d1 + c9341a3 commit 96ed23e
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 99 deletions.
1 change: 1 addition & 0 deletions .npmignore
@@ -0,0 +1 @@
test
17 changes: 12 additions & 5 deletions README.md
100755 → 100644
Expand Up @@ -3,24 +3,29 @@ Tree Kill

Kill all processes in the process tree, including the root process.

Example
Examples
=======

Kill all the children processes of the process with pid `1`, including the process with pid `1` itself:
Kill all the descendent processes of the process with pid `1`, including the process with pid `1` itself:
```js
var kill = require('tree-kill');
kill(1);
```

Send a signal other than SIGTERM.:
```js
var kill = require('tree-kill');
kill(1, 'SIGKILL');
```

Supports callbacks with error handling:
Run a callback when done killing the processes. Passes an error argument if there was an error.
```js
var kill = require('tree-kill');
kill(1, 'SIGKILL', function(err) {
// Do things
});
```


Methods
=======

Expand All @@ -30,7 +35,9 @@ Sends signal `signal` to all children processes of the process with pid `pid`, i

For Linux, this uses `ps -o pid --no-headers --ppid PID` to find the parent pids of `PID`.

For Windows, this uses `'taskkill /pid PID /T /F'` to kill the process tree.
For Darwin/OSX, this uses `pgrep -P PID` to find the parent pids of `PID`.

For Windows, this uses `'taskkill /pid PID /T /F'` to kill the process tree. Note that on Windows, sending the different kinds of POSIX signals is not possible.

Install
=======
Expand Down
120 changes: 62 additions & 58 deletions index.js
@@ -1,49 +1,66 @@
'use strict';

var childProcess = require('child_process');
var spawn = childProcess.spawn;
var exec = childProcess.exec;
var once = require('once');
var isWindows = process.platform === 'win32';

module.exports = function (pid, signal, callback) {
if (isWindows) {
var tree = {};
var pidsToProcess = {};
tree[pid] = [];
pidsToProcess[pid] = 1;

switch (process.platform) {
case 'win32':
exec('taskkill /pid ' + pid + ' /T /F', callback);
} else {
var tree = {};
tree[pid] = [];
var pidsToProcess = {};
pidsToProcess[pid] = 1;
buildProcessTree(pid, tree, pidsToProcess, function () {
try {
killAll(tree, signal);
}
catch (err) {
if (callback) {
return callback(err);
} else {
throw err;
}
}
if (callback) {
return callback();
}
break;
case 'darwin':
buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
return spawn('pgrep', ['-P', parentPid]);
}, function () {
killAll(tree, signal, callback);
});
break;
// case 'sunos':
// buildProcessTreeSunOS(pid, tree, pidsToProcess, function () {
// killAll(tree, signal, callback);
// });
// break;
default: // Linux
buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid]);
}, function () {
killAll(tree, signal, callback);
});
break;
}
}
};

function killAll (tree, signal) {
function killAll (tree, signal, callback) {
var killed = {};
Object.keys(tree).forEach(function (pid) {
tree[pid].forEach(function (pidpid) {
if (!killed[pidpid]) {
killPid(pidpid, signal);
killed[pidpid] = 1;
try {
Object.keys(tree).forEach(function (pid) {
tree[pid].forEach(function (pidpid) {
if (!killed[pidpid]) {
killPid(pidpid, signal);
killed[pidpid] = 1;
}
});
if (!killed[pid]) {
killPid(pid, signal);
killed[pid] = 1;
}
});
if (!killed[pid]) {
killPid(pid, signal);
killed[pid] = 1;
} catch (err) {
if (callback) {
return callback(err);
} else {
throw err;
}
});
}
if (callback) {
return callback();
}
}

function killPid(pid, signal) {
Expand All @@ -55,46 +72,33 @@ function killPid(pid, signal) {
}
}

function buildProcessTree (parentPid, tree, pidsToProcess, cb) {
var ps = spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid]);
function buildProcessTree (parentPid, tree, pidsToProcess, spawnChildProcessesList, cb) {
var ps = spawnChildProcessesList(parentPid);
var allData = '';
ps.stdout.on('data', function (data) {
var data = data.toString('ascii');
allData += data;
});

var onExitClose = once(function (code) {
var onClose = function (code) {
delete pidsToProcess[parentPid];

if (code != 0) {
// no more parent processes
if (Object.keys(pidsToProcess).length == 0) {
cb();
}
return
return;
}

pids = [];
pid = '';
for (i = 0; i < allData.length; i++) {
if (allData[i] == '\n') {
pids.push(parseInt(pid, 10));
pid = '';
continue;
}
if (allData[i] != ' ') {
pid += allData[i];
}
}

pids.forEach(function (pid) {
tree[parentPid].push(pid)
tree[pid] = [];
pidsToProcess[pid] = 1;
buildProcessTree(pid, tree, pidsToProcess, cb);
allData.match(/\d+/g).forEach(function (pid) {
pid = parseInt(pid, 10);
tree[parentPid].push(pid);
tree[pid] = [];
pidsToProcess[pid] = 1;
buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, cb);
});
});
};

ps.on('exit', onExitClose);
ps.on('close', onExitClose);
ps.on('close', onClose);
}
76 changes: 40 additions & 36 deletions package.json
@@ -1,40 +1,44 @@
{
"name" : "tree-kill",
"version" : "0.1.1",
"description" : "kill trees of processes",
"main" : "index.js",
"repository" : {
"type" : "git",
"url" : "git://github.com/pkrumins/node-tree-kill.git"
"name": "tree-kill",
"version": "1.0.0",
"description": "kill trees of processes",
"main": "index.js",
"repository": {
"type": "git",
"url": "git://github.com/pkrumins/node-tree-kill.git"
},
"homepage": "https://github.com/pkrumins/node-tree-kill",
"keywords": [
"tree",
"trees",
"process",
"processes",
"kill",
"signal"
],
"author": {
"name": "Peteris Krumins",
"email": "peteris.krumins@gmail.com",
"url": "http://www.catonmat.net"
},
"contributors": [
{
"name": "Todd Wolfson",
"email": "todd@twolfson.com",
"url": "http://twolfson.com/"
},
"homepage" : "https://github.com/pkrumins/node-tree-kill",
"dependencies" : {
"once" : "1.1.1"
{
"name": "William Hilton",
"email": "wmhilton@gmail.com",
"url": "http://wmhilton.com/"
},
"keywords" : [
"tree",
"trees",
"process",
"processes",
"kill",
"signal"
],
"author" : {
"name" : "Peteris Krumins",
"email" : "peteris.krumins@gmail.com",
"url" : "http://www.catonmat.net"
},
"contributors" : [
{
"name" : "Todd Wolfson",
"email" : "todd@twolfson.com",
"url" : "http://twolfson.com/"
},
{
"name" : "William Hilton",
"email" : "wmhilton@gmail.com",
"url" : "http://wmhilton.com/"
}
],
"license" : "MIT"
{
"name": "Fabrício Matté",
"url": "http://ultcombo.js.org/"
}
],
"license": "MIT",
"devDependencies": {
"mocha": "^2.2.5"
}
}
3 changes: 3 additions & 0 deletions test/spin.js
@@ -0,0 +1,3 @@
setInterval(function(){
// Do nothing
}, 100);
25 changes: 25 additions & 0 deletions test/test.js
@@ -0,0 +1,25 @@
var assert = require('assert');
var fork = require('child_process').fork;
var kill = require('tree-kill');

describe('kill()', function(){
it('should kill a process', function(done){
var p = fork('./test/spin')
assert.ok(p.pid)

p.on('exit', function(code, signal){
assert.ok(code || signal, 'should return an exit code')
return done()
});
kill(p.pid)
})

it('should call a callback', function(done){
var p = fork('./test/spin')
assert.ok(p.pid)

kill(p.pid, null, function() {
return done()
})
})
})

0 comments on commit 96ed23e

Please sign in to comment.