thread_kill.js 2.9 KB

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