No Description

index.js 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Note: since nyc uses this module to output coverage, any lines
  2. // that are in the direct sync flow of nyc's outputCoverage are
  3. // ignored, since we can never get coverage for them.
  4. // grab a reference to node's real process object right away
  5. var process = global.process
  6. // some kind of non-node environment, just no-op
  7. if (typeof process !== 'object' || !process) {
  8. module.exports = function () {}
  9. } else {
  10. var assert = require('assert')
  11. var signals = require('./signals.js')
  12. var isWin = /^win/i.test(process.platform)
  13. var EE = require('events')
  14. /* istanbul ignore if */
  15. if (typeof EE !== 'function') {
  16. EE = EE.EventEmitter
  17. }
  18. var emitter
  19. if (process.__signal_exit_emitter__) {
  20. emitter = process.__signal_exit_emitter__
  21. } else {
  22. emitter = process.__signal_exit_emitter__ = new EE()
  23. emitter.count = 0
  24. emitter.emitted = {}
  25. }
  26. // Because this emitter is a global, we have to check to see if a
  27. // previous version of this library failed to enable infinite listeners.
  28. // I know what you're about to say. But literally everything about
  29. // signal-exit is a compromise with evil. Get used to it.
  30. if (!emitter.infinite) {
  31. emitter.setMaxListeners(Infinity)
  32. emitter.infinite = true
  33. }
  34. module.exports = function (cb, opts) {
  35. if (global.process !== process) {
  36. return
  37. }
  38. assert.equal(typeof cb, 'function', 'a callback must be provided for exit handler')
  39. if (loaded === false) {
  40. load()
  41. }
  42. var ev = 'exit'
  43. if (opts && opts.alwaysLast) {
  44. ev = 'afterexit'
  45. }
  46. var remove = function () {
  47. emitter.removeListener(ev, cb)
  48. if (emitter.listeners('exit').length === 0 &&
  49. emitter.listeners('afterexit').length === 0) {
  50. unload()
  51. }
  52. }
  53. emitter.on(ev, cb)
  54. return remove
  55. }
  56. var unload = function unload () {
  57. if (!loaded || global.process !== process) {
  58. return
  59. }
  60. loaded = false
  61. signals.forEach(function (sig) {
  62. try {
  63. process.removeListener(sig, sigListeners[sig])
  64. } catch (er) {}
  65. })
  66. process.emit = originalProcessEmit
  67. process.reallyExit = originalProcessReallyExit
  68. emitter.count -= 1
  69. }
  70. module.exports.unload = unload
  71. var emit = function emit (event, code, signal) {
  72. if (emitter.emitted[event]) {
  73. return
  74. }
  75. emitter.emitted[event] = true
  76. emitter.emit(event, code, signal)
  77. }
  78. // { <signal>: <listener fn>, ... }
  79. var sigListeners = {}
  80. signals.forEach(function (sig) {
  81. sigListeners[sig] = function listener () {
  82. if (process !== global.process) {
  83. return
  84. }
  85. // If there are no other listeners, an exit is coming!
  86. // Simplest way: remove us and then re-send the signal.
  87. // We know that this will kill the process, so we can
  88. // safely emit now.
  89. var listeners = process.listeners(sig)
  90. if (listeners.length === emitter.count) {
  91. unload()
  92. emit('exit', null, sig)
  93. /* istanbul ignore next */
  94. emit('afterexit', null, sig)
  95. /* istanbul ignore next */
  96. if (isWin && sig === 'SIGHUP') {
  97. // "SIGHUP" throws an `ENOSYS` error on Windows,
  98. // so use a supported signal instead
  99. sig = 'SIGINT'
  100. }
  101. process.kill(process.pid, sig)
  102. }
  103. }
  104. })
  105. module.exports.signals = function () {
  106. return signals
  107. }
  108. var loaded = false
  109. var load = function load () {
  110. if (loaded || process !== global.process) {
  111. return
  112. }
  113. loaded = true
  114. // This is the number of onSignalExit's that are in play.
  115. // It's important so that we can count the correct number of
  116. // listeners on signals, and don't wait for the other one to
  117. // handle it instead of us.
  118. emitter.count += 1
  119. signals = signals.filter(function (sig) {
  120. try {
  121. process.on(sig, sigListeners[sig])
  122. return true
  123. } catch (er) {
  124. return false
  125. }
  126. })
  127. process.emit = processEmit
  128. process.reallyExit = processReallyExit
  129. }
  130. module.exports.load = load
  131. var originalProcessReallyExit = process.reallyExit
  132. var processReallyExit = function processReallyExit (code) {
  133. if (process !== global.process) {
  134. return
  135. }
  136. process.exitCode = code || 0
  137. emit('exit', process.exitCode, null)
  138. /* istanbul ignore next */
  139. emit('afterexit', process.exitCode, null)
  140. /* istanbul ignore next */
  141. originalProcessReallyExit.call(process, process.exitCode)
  142. }
  143. var originalProcessEmit = process.emit
  144. var processEmit = function processEmit (ev, arg) {
  145. if (ev === 'exit' && process === global.process) {
  146. if (arg !== undefined) {
  147. process.exitCode = arg
  148. }
  149. var ret = originalProcessEmit.apply(this, arguments)
  150. emit('exit', process.exitCode, null)
  151. /* istanbul ignore next */
  152. emit('afterexit', process.exitCode, null)
  153. return ret
  154. } else {
  155. return originalProcessEmit.apply(this, arguments)
  156. }
  157. }
  158. }