thread_kill.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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. if (typeof callback === 'function') {
  73. return callback();
  74. }
  75. }
  76. }
  77. function killPid(pid, signal){
  78. try {
  79. process.kill(parseInt(pid, 10), signal);
  80. } catch (error) {
  81. if (error.code !== 'ESRCH') throw error;
  82. }
  83. }
  84. function buildProcessTree(parentPid, tree, pidsToProcess, spawnChildProcessesList, callback){
  85. var allData = '';
  86. var ps = spawnChildProcessesList(parentPid);
  87. ps.stdout.on('data', function (data){
  88. allData += data.toString('ascii');
  89. });
  90. var onClose = function (code){
  91. delete pidsToProcess[parentPid];
  92. if (code !== 0) {
  93. // no more parent processes
  94. if (Object.keys(pidsToProcess).length === 0) {
  95. callback();
  96. }
  97. return;
  98. }
  99. allData.match(/\d+/g).forEach(function (pid){
  100. pid = parseInt(pid, 10);
  101. tree[parentPid].push(pid);
  102. tree[pid] = [];
  103. pidsToProcess[pid] = 1;
  104. buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, callback);
  105. });
  106. };
  107. ps.on('close', onClose);
  108. }