3 // WARNING: THIS MODULE IS PENDING DEPRECATION.
5 // No new pull requests targeting this module will be accepted
6 // unless they address existing, critical bugs.
8 const util = require('util');
9 const EventEmitter = require('events');
10 const inherits = util.inherits;
12 // communicate with events module, but don't require that
13 // module to have to load this one, since this module has
14 // a few side effects.
15 EventEmitter.usingDomains = true;
17 // overwrite process.domain with a getter/setter that will allow for more
18 // effective optimizations
20 Object.defineProperty(process, 'domain', {
26 return _domain[0] = arg;
30 // It's possible to enter one domain while already inside
31 // another one. the stack is each entered domain.
33 exports._stack = stack;
35 // let the process know we're using domains
36 const _domain_flag = process._setupDomainUse(_domain, stack);
38 exports.Domain = Domain;
40 exports.create = exports.createDomain = function() {
44 // the active domain is always the one that we're currently in.
45 exports.active = null;
48 inherits(Domain, EventEmitter);
51 EventEmitter.call(this);
56 Domain.prototype.members = undefined;
57 Domain.prototype._disposed = undefined;
60 // Called by process._fatalException in case an error was thrown.
61 Domain.prototype._errorHandler = function errorHandler(er) {
65 function emitError() {
66 var handled = self.emit('error', er);
68 // Exit all domains on the stack. Uncaught exceptions end the
69 // current tick and no domains should be left on the stack
72 exports.active = process.domain = null;
77 // ignore errors on disposed domains.
79 // XXX This is a bit stupid. We should probably get rid of
80 // domain.dispose() altogether. It's almost always a terrible
85 if (!util.isPrimitive(er)) {
87 er.domainThrown = true;
90 // The top-level domain-handler is handled separately.
92 // The reason is that if V8 was passed a command line option
93 // asking it to abort on an uncaught exception (currently
94 // "--abort-on-uncaught-exception"), we want an uncaught exception
95 // in the top-level domain error handler to make the
96 // process abort. Using try/catch here would always make V8 think
97 // that these exceptions are caught, and thus would prevent it from
98 // aborting in these cases.
99 if (stack.length === 1) {
100 // If there's no error handler, do not emit an 'error' event
101 // as this would throw an error, make the process exit, and thus
102 // prevent the process 'uncaughtException' event from being emitted
103 // if a listener is set.
104 if (EventEmitter.listenerCount(self, 'error') > 0) {
106 // Set the _emittingTopLevelDomainError so that we know that, even
107 // if technically the top-level domain is still active, it would
108 // be ok to abort on an uncaught exception at this point
109 process._emittingTopLevelDomainError = true;
110 caught = emitError();
112 process._emittingTopLevelDomainError = false;
116 // wrap this in a try/catch so we don't get infinite throwing
118 // One of three things will happen here.
120 // 1. There is a handler, caught = true
121 // 2. There is no handler, caught = false
122 // 3. It throws, caught = false
124 // If caught is false after this, then there's no need to exit()
125 // the domain, because we're going to crash the process anyway.
126 caught = emitError();
128 // The domain error handler threw! oh no!
129 // See if another domain can catch THIS error,
130 // or else crash on the original one.
131 // If the user already exited it, then don't double-exit.
132 if (this === exports.active) {
136 exports.active = process.domain = stack[stack.length - 1];
137 caught = process._fatalException(er2);
148 Domain.prototype.enter = function() {
149 if (this._disposed) return;
151 // note that this might be a no-op, but we still need
152 // to push it onto the stack so that we can pop it later.
153 exports.active = process.domain = this;
155 _domain_flag[0] = stack.length;
159 Domain.prototype.exit = function() {
160 // skip disposed domains, as usual, but also don't do anything if this
161 // domain is not on the stack.
162 var index = stack.lastIndexOf(this);
163 if (this._disposed || index === -1) return;
165 // exit all domains until this one.
167 _domain_flag[0] = stack.length;
169 exports.active = stack[stack.length - 1];
170 process.domain = exports.active;
174 // note: this works for timers as well.
175 Domain.prototype.add = function(ee) {
176 // If the domain is disposed or already added, then nothing left to do.
177 if (this._disposed || ee.domain === this)
180 // has a domain already - remove it first.
182 ee.domain.remove(ee);
184 // check for circular Domain->Domain links.
185 // This causes bad insanity!
188 // var d = domain.create();
189 // var e = domain.create();
192 // e.emit('error', er); // RangeError, stack overflow!
193 if (this.domain && (ee instanceof Domain)) {
194 for (var d = this.domain; d; d = d.domain) {
195 if (ee === d) return;
200 this.members.push(ee);
204 Domain.prototype.remove = function(ee) {
206 var index = this.members.indexOf(ee);
208 this.members.splice(index, 1);
212 Domain.prototype.run = function(fn) {
219 if (arguments.length >= 2) {
220 var len = arguments.length;
221 var args = new Array(len - 1);
223 for (var i = 1; i < len; i++)
224 args[i - 1] = arguments[i];
226 ret = fn.apply(this, args);
236 function intercepted(_this, self, cb, fnargs) {
240 if (fnargs[0] && fnargs[0] instanceof Error) {
247 self.emit('error', er);
255 if (fnargs.length > 1) {
256 for (i = 1; i < fnargs.length; i++)
257 args.push(fnargs[i]);
258 ret = cb.apply(_this, args);
260 ret = cb.call(_this);
268 Domain.prototype.intercept = function(cb) {
271 function runIntercepted() {
272 return intercepted(this, self, cb, arguments);
275 return runIntercepted;
279 function bound(_this, self, cb, fnargs) {
286 if (fnargs.length > 0)
287 ret = cb.apply(_this, fnargs);
289 ret = cb.call(_this);
296 Domain.prototype.bind = function(cb) {
299 function runBound() {
300 return bound(this, self, cb, arguments);
303 runBound.domain = this;
309 Domain.prototype.dispose = util.deprecate(function() {
310 if (this._disposed) return;
312 // if we're the active domain, then get out now.
315 // remove from parent domain, if there is one.
316 if (this.domain) this.domain.remove(this);
318 // kill the references so that they can be properly gc'ed.
319 this.members.length = 0;
321 // mark this domain as 'no longer relevant'
322 // so that it can't be entered or activated.
323 this._disposed = true;