mirror of
https://github.com/Unitech/pm2.git
synced 2025-12-08 20:35:53 +00:00
116 lines
2.8 KiB
JavaScript
116 lines
2.8 KiB
JavaScript
/**
|
|
* Copyright 2013 the PM2 project authors. All rights reserved.
|
|
* Use of this source code is governed by a license that
|
|
* can be found in the LICENSE file.
|
|
*/
|
|
/**
|
|
*
|
|
* Reference: https://github.com/pkrumins/node-tree-kill
|
|
* Author : pkrumins
|
|
*
|
|
* Update : PM2 team
|
|
*
|
|
*/
|
|
|
|
var exec = require('child_process').exec,
|
|
isWin = (process.platform === 'win32' || process.platform === 'win64'),
|
|
downgradePs = false;
|
|
|
|
module.exports = function(pid, signal){
|
|
if (isWin) {
|
|
exec('taskkill /pid ' + pid + ' /T /F');
|
|
} else {
|
|
var tree = {}, pidsToProcess = {};
|
|
buildProcessTree(pid, tree, pidsToProcess, function(){
|
|
killAll(tree, signal);
|
|
});
|
|
}
|
|
}
|
|
|
|
function killAll(tree, signal){
|
|
var killed = {};
|
|
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;
|
|
}
|
|
});
|
|
}
|
|
|
|
function killPid(pid, signal){
|
|
try {
|
|
process.kill(parseInt(pid, 10), signal);
|
|
}
|
|
catch (err) {
|
|
if (err.code == 'EINVAL'){
|
|
throw new Error('The value of the sig argument is an invalid or unsupported signal number.');
|
|
}
|
|
if(err.code == 'EPERM'){
|
|
throw new Error('The process does not have permission to send the signal to any receiving process.');
|
|
}
|
|
if (err.code !== 'ESRCH'){
|
|
throw err;
|
|
}
|
|
}
|
|
}
|
|
|
|
function buildProcessTree(ppid, tree, pidsToProcess, cb){
|
|
pidsToProcess[ppid] = 1;
|
|
tree[ppid] = [];
|
|
|
|
function isFinish(){
|
|
delete pidsToProcess[ppid];
|
|
if(Object.keys(pidsToProcess).length == 0){
|
|
return cb();
|
|
}
|
|
}
|
|
|
|
var args = downgradePs ? '-eo pid,ppid | grep -w ' : '-o pid --no-headers --ppid ';
|
|
var ps = exec('ps ' + args + ppid, function(err, stdout, stderr){
|
|
if (err) {
|
|
// illegal option --, try to use basic `ps` instead of it.
|
|
if (/illegal/.test(err.message) && !downgradePs) {
|
|
downgradePs = true;
|
|
return buildProcessTree(ppid, tree, pidsToProcess, cb);
|
|
}
|
|
|
|
// Avoid pipe close error - dynamic self-closing process.
|
|
if(/Command failed/.test(err.message)) {
|
|
return isFinish();
|
|
}
|
|
throw err;
|
|
}
|
|
|
|
var pids = stdout.split('\n');
|
|
|
|
// remove parentPid if necessary.
|
|
downgradePs && pids.shift();
|
|
|
|
pids = pids.filter(function(pid){
|
|
return !!pid;
|
|
}).map(function(pid){
|
|
pid = pid.trim();
|
|
return parseInt(downgradePs ? pid.slice(0, pid.search(/\s/)) : pid, 10);
|
|
});
|
|
|
|
if(pids.length > 0){
|
|
tree[ppid] = tree[ppid].concat(pids);
|
|
pids.forEach(function(pid){
|
|
if(!tree[pid]) {
|
|
buildProcessTree(pid, tree, pidsToProcess, cb);
|
|
}else{
|
|
delete pidsToProcess[pid];
|
|
}
|
|
});
|
|
}
|
|
|
|
isFinish();
|
|
});
|
|
}
|