time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

index.js (5708B)


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