1 |
|
2 |
|
3 |
|
4 | var assert = require('assert')
|
5 | var signals = require('./signals.js')
|
6 |
|
7 | var EE = require('events')
|
8 |
|
9 | if (typeof EE !== 'function') {
|
10 | EE = EE.EventEmitter
|
11 | }
|
12 |
|
13 | var emitter
|
14 | if (process.__signal_exit_emitter__) {
|
15 | emitter = process.__signal_exit_emitter__
|
16 | } else {
|
17 | emitter = process.__signal_exit_emitter__ = new EE()
|
18 | emitter.count = 0
|
19 | emitter.emitted = {}
|
20 | }
|
21 |
|
22 | module.exports = function (cb, opts) {
|
23 | assert.equal(typeof cb, 'function', 'a callback must be provided for exit handler')
|
24 |
|
25 | if (loaded === false) {
|
26 | load()
|
27 | }
|
28 |
|
29 | var ev = 'exit'
|
30 | if (opts && opts.alwaysLast) {
|
31 | ev = 'afterexit'
|
32 | }
|
33 |
|
34 | var remove = function () {
|
35 | emitter.removeListener(ev, cb)
|
36 | if (emitter.listeners('exit').length === 0 &&
|
37 | emitter.listeners('afterexit').length === 0) {
|
38 | unload()
|
39 | }
|
40 | }
|
41 | emitter.on(ev, cb)
|
42 |
|
43 | return remove
|
44 | }
|
45 |
|
46 | module.exports.unload = unload
|
47 | function unload () {
|
48 | if (!loaded) {
|
49 | return
|
50 | }
|
51 | loaded = false
|
52 |
|
53 | signals.forEach(function (sig) {
|
54 | try {
|
55 | process.removeListener(sig, sigListeners[sig])
|
56 | } catch (er) {}
|
57 | })
|
58 | process.emit = originalProcessEmit
|
59 | process.reallyExit = originalProcessReallyExit
|
60 | emitter.count -= 1
|
61 | }
|
62 |
|
63 | function emit (event, code, signal) {
|
64 | if (emitter.emitted[event]) {
|
65 | return
|
66 | }
|
67 | emitter.emitted[event] = true
|
68 | emitter.emit(event, code, signal)
|
69 | }
|
70 |
|
71 |
|
72 | var sigListeners = {}
|
73 | signals.forEach(function (sig) {
|
74 | sigListeners[sig] = function listener () {
|
75 |
|
76 |
|
77 |
|
78 |
|
79 | var listeners = process.listeners(sig)
|
80 | if (listeners.length === emitter.count) {
|
81 | unload()
|
82 | emit('exit', null, sig)
|
83 |
|
84 | emit('afterexit', null, sig)
|
85 |
|
86 | process.kill(process.pid, sig)
|
87 | }
|
88 | }
|
89 | })
|
90 |
|
91 | module.exports.signals = function () {
|
92 | return signals
|
93 | }
|
94 |
|
95 | module.exports.load = load
|
96 |
|
97 | var loaded = false
|
98 |
|
99 | function load () {
|
100 | if (loaded) {
|
101 | return
|
102 | }
|
103 | loaded = true
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 | emitter.count += 1
|
110 |
|
111 | signals = signals.filter(function (sig) {
|
112 | try {
|
113 | process.on(sig, sigListeners[sig])
|
114 | return true
|
115 | } catch (er) {
|
116 | return false
|
117 | }
|
118 | })
|
119 |
|
120 | process.emit = processEmit
|
121 | process.reallyExit = processReallyExit
|
122 | }
|
123 |
|
124 | var originalProcessReallyExit = process.reallyExit
|
125 | function processReallyExit (code) {
|
126 | process.exitCode = code || 0
|
127 | emit('exit', process.exitCode, null)
|
128 |
|
129 | emit('afterexit', process.exitCode, null)
|
130 |
|
131 | originalProcessReallyExit.call(process, process.exitCode)
|
132 | }
|
133 |
|
134 | var originalProcessEmit = process.emit
|
135 | function processEmit (ev, arg) {
|
136 | if (ev === 'exit') {
|
137 | if (arg !== undefined) {
|
138 | process.exitCode = arg
|
139 | }
|
140 | var ret = originalProcessEmit.apply(this, arguments)
|
141 | emit('exit', process.exitCode, null)
|
142 |
|
143 | emit('afterexit', process.exitCode, null)
|
144 | return ret
|
145 | } else {
|
146 | return originalProcessEmit.apply(this, arguments)
|
147 | }
|
148 | }
|