index.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. 'use strict';
  2. var childProcess = require('child_process');
  3. var spawn = childProcess.spawn;
  4. var exec = childProcess.exec;
  5. module.exports = function (pid, signal, callback) {
  6. var tree = {};
  7. var pidsToProcess = {};
  8. tree[pid] = [];
  9. pidsToProcess[pid] = 1;
  10. if (typeof signal === 'function' && callback === undefined) {
  11. callback = signal;
  12. signal = undefined;
  13. }
  14. switch (process.platform) {
  15. case 'win32':
  16. exec('taskkill /pid ' + pid + ' /T /F', callback);
  17. break;
  18. case 'darwin':
  19. buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
  20. return spawn('pgrep', ['-P', parentPid]);
  21. }, function () {
  22. killAll(tree, signal, callback);
  23. });
  24. break;
  25. // case 'sunos':
  26. // buildProcessTreeSunOS(pid, tree, pidsToProcess, function () {
  27. // killAll(tree, signal, callback);
  28. // });
  29. // break;
  30. default: // Linux
  31. buildProcessTree(pid, tree, pidsToProcess, function (parentPid) {
  32. return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid]);
  33. }, function () {
  34. killAll(tree, signal, callback);
  35. });
  36. break;
  37. }
  38. };
  39. function killAll (tree, signal, callback) {
  40. var killed = {};
  41. try {
  42. Object.keys(tree).forEach(function (pid) {
  43. tree[pid].forEach(function (pidpid) {
  44. if (!killed[pidpid]) {
  45. killPid(pidpid, signal);
  46. killed[pidpid] = 1;
  47. }
  48. });
  49. if (!killed[pid]) {
  50. killPid(pid, signal);
  51. killed[pid] = 1;
  52. }
  53. });
  54. } catch (err) {
  55. if (callback) {
  56. return callback(err);
  57. } else {
  58. throw err;
  59. }
  60. }
  61. if (callback) {
  62. return callback();
  63. }
  64. }
  65. function killPid(pid, signal) {
  66. try {
  67. process.kill(parseInt(pid, 10), signal);
  68. }
  69. catch (err) {
  70. if (err.code !== 'ESRCH') throw err;
  71. }
  72. }
  73. function buildProcessTree (parentPid, tree, pidsToProcess, spawnChildProcessesList, cb) {
  74. var ps = spawnChildProcessesList(parentPid);
  75. var allData = '';
  76. ps.stdout.on('data', function (data) {
  77. var data = data.toString('ascii');
  78. allData += data;
  79. });
  80. var onClose = function (code) {
  81. delete pidsToProcess[parentPid];
  82. if (code != 0) {
  83. // no more parent processes
  84. if (Object.keys(pidsToProcess).length == 0) {
  85. cb();
  86. }
  87. return;
  88. }
  89. allData.match(/\d+/g).forEach(function (pid) {
  90. pid = parseInt(pid, 10);
  91. tree[parentPid].push(pid);
  92. tree[pid] = [];
  93. pidsToProcess[pid] = 1;
  94. buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, cb);
  95. });
  96. };
  97. ps.on('close', onClose);
  98. }