11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors.
21cb0ef41Sopenharmony_ci//
31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a
41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the
51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including
61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish,
71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit
81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the
91cb0ef41Sopenharmony_ci// following conditions:
101cb0ef41Sopenharmony_ci//
111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included
121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software.
131cb0ef41Sopenharmony_ci//
141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE.
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci'use strict';
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci// WARNING: THIS MODULE IS PENDING DEPRECATION.
251cb0ef41Sopenharmony_ci//
261cb0ef41Sopenharmony_ci// No new pull requests targeting this module will be accepted
271cb0ef41Sopenharmony_ci// unless they address existing, critical bugs.
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ciconst {
301cb0ef41Sopenharmony_ci  ArrayPrototypeEvery,
311cb0ef41Sopenharmony_ci  ArrayPrototypeIndexOf,
321cb0ef41Sopenharmony_ci  ArrayPrototypeLastIndexOf,
331cb0ef41Sopenharmony_ci  ArrayPrototypePush,
341cb0ef41Sopenharmony_ci  ArrayPrototypeSlice,
351cb0ef41Sopenharmony_ci  ArrayPrototypeSplice,
361cb0ef41Sopenharmony_ci  Error,
371cb0ef41Sopenharmony_ci  FunctionPrototypeCall,
381cb0ef41Sopenharmony_ci  ObjectDefineProperty,
391cb0ef41Sopenharmony_ci  Promise,
401cb0ef41Sopenharmony_ci  ReflectApply,
411cb0ef41Sopenharmony_ci  SafeMap,
421cb0ef41Sopenharmony_ci  SafeWeakMap,
431cb0ef41Sopenharmony_ci  Symbol,
441cb0ef41Sopenharmony_ci} = primordials;
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ciconst EventEmitter = require('events');
471cb0ef41Sopenharmony_ciconst {
481cb0ef41Sopenharmony_ci  ERR_DOMAIN_CALLBACK_NOT_AVAILABLE,
491cb0ef41Sopenharmony_ci  ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE,
501cb0ef41Sopenharmony_ci  ERR_UNHANDLED_ERROR,
511cb0ef41Sopenharmony_ci} = require('internal/errors').codes;
521cb0ef41Sopenharmony_ciconst { createHook } = require('async_hooks');
531cb0ef41Sopenharmony_ciconst { useDomainTrampoline } = require('internal/async_hooks');
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci// TODO(addaleax): Use a non-internal solution for this.
561cb0ef41Sopenharmony_ciconst kWeak = Symbol('kWeak');
571cb0ef41Sopenharmony_ciconst { WeakReference } = internalBinding('util');
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci// Overwrite process.domain with a getter/setter that will allow for more
601cb0ef41Sopenharmony_ci// effective optimizations
611cb0ef41Sopenharmony_ciconst _domain = [null];
621cb0ef41Sopenharmony_ciObjectDefineProperty(process, 'domain', {
631cb0ef41Sopenharmony_ci  __proto__: null,
641cb0ef41Sopenharmony_ci  enumerable: true,
651cb0ef41Sopenharmony_ci  get: function() {
661cb0ef41Sopenharmony_ci    return _domain[0];
671cb0ef41Sopenharmony_ci  },
681cb0ef41Sopenharmony_ci  set: function(arg) {
691cb0ef41Sopenharmony_ci    return _domain[0] = arg;
701cb0ef41Sopenharmony_ci  },
711cb0ef41Sopenharmony_ci});
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ciconst vmPromises = new SafeWeakMap();
741cb0ef41Sopenharmony_ciconst pairing = new SafeMap();
751cb0ef41Sopenharmony_ciconst asyncHook = createHook({
761cb0ef41Sopenharmony_ci  init(asyncId, type, triggerAsyncId, resource) {
771cb0ef41Sopenharmony_ci    if (process.domain !== null && process.domain !== undefined) {
781cb0ef41Sopenharmony_ci      // If this operation is created while in a domain, let's mark it
791cb0ef41Sopenharmony_ci      pairing.set(asyncId, process.domain[kWeak]);
801cb0ef41Sopenharmony_ci      // Promises from other contexts, such as with the VM module, should not
811cb0ef41Sopenharmony_ci      // have a domain property as it can be used to escape the sandbox.
821cb0ef41Sopenharmony_ci      if (type !== 'PROMISE' || resource instanceof Promise) {
831cb0ef41Sopenharmony_ci        ObjectDefineProperty(resource, 'domain', {
841cb0ef41Sopenharmony_ci          __proto__: null,
851cb0ef41Sopenharmony_ci          configurable: true,
861cb0ef41Sopenharmony_ci          enumerable: false,
871cb0ef41Sopenharmony_ci          value: process.domain,
881cb0ef41Sopenharmony_ci          writable: true,
891cb0ef41Sopenharmony_ci        });
901cb0ef41Sopenharmony_ci      // Because promises from other contexts don't get a domain field,
911cb0ef41Sopenharmony_ci      // the domain needs to be held alive another way. Stuffing it in a
921cb0ef41Sopenharmony_ci      // weakmap connected to the promise lifetime can fix that.
931cb0ef41Sopenharmony_ci      } else {
941cb0ef41Sopenharmony_ci        vmPromises.set(resource, process.domain);
951cb0ef41Sopenharmony_ci      }
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci  },
981cb0ef41Sopenharmony_ci  before(asyncId) {
991cb0ef41Sopenharmony_ci    const current = pairing.get(asyncId);
1001cb0ef41Sopenharmony_ci    if (current !== undefined) { // Enter domain for this cb
1011cb0ef41Sopenharmony_ci      // We will get the domain through current.get(), because the resource
1021cb0ef41Sopenharmony_ci      // object's .domain property makes sure it is not garbage collected.
1031cb0ef41Sopenharmony_ci      // However, we do need to make the reference to the domain non-weak,
1041cb0ef41Sopenharmony_ci      // so that it cannot be garbage collected before the after() hook.
1051cb0ef41Sopenharmony_ci      current.incRef();
1061cb0ef41Sopenharmony_ci      current.get().enter();
1071cb0ef41Sopenharmony_ci    }
1081cb0ef41Sopenharmony_ci  },
1091cb0ef41Sopenharmony_ci  after(asyncId) {
1101cb0ef41Sopenharmony_ci    const current = pairing.get(asyncId);
1111cb0ef41Sopenharmony_ci    if (current !== undefined) { // Exit domain for this cb
1121cb0ef41Sopenharmony_ci      const domain = current.get();
1131cb0ef41Sopenharmony_ci      current.decRef();
1141cb0ef41Sopenharmony_ci      domain.exit();
1151cb0ef41Sopenharmony_ci    }
1161cb0ef41Sopenharmony_ci  },
1171cb0ef41Sopenharmony_ci  destroy(asyncId) {
1181cb0ef41Sopenharmony_ci    pairing.delete(asyncId); // cleaning up
1191cb0ef41Sopenharmony_ci  },
1201cb0ef41Sopenharmony_ci});
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci// When domains are in use, they claim full ownership of the
1231cb0ef41Sopenharmony_ci// uncaught exception capture callback.
1241cb0ef41Sopenharmony_ciif (process.hasUncaughtExceptionCaptureCallback()) {
1251cb0ef41Sopenharmony_ci  throw new ERR_DOMAIN_CALLBACK_NOT_AVAILABLE();
1261cb0ef41Sopenharmony_ci}
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci// Get the stack trace at the point where `domain` was required.
1291cb0ef41Sopenharmony_ci// eslint-disable-next-line no-restricted-syntax
1301cb0ef41Sopenharmony_ciconst domainRequireStack = new Error('require(`domain`) at this point').stack;
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ciconst { setUncaughtExceptionCaptureCallback } = process;
1331cb0ef41Sopenharmony_ciprocess.setUncaughtExceptionCaptureCallback = function(fn) {
1341cb0ef41Sopenharmony_ci  const err = new ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE();
1351cb0ef41Sopenharmony_ci  err.stack = err.stack + '\n' + '-'.repeat(40) + '\n' + domainRequireStack;
1361cb0ef41Sopenharmony_ci  throw err;
1371cb0ef41Sopenharmony_ci};
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_cilet sendMakeCallbackDeprecation = false;
1411cb0ef41Sopenharmony_cifunction emitMakeCallbackDeprecation({ target, method }) {
1421cb0ef41Sopenharmony_ci  if (!sendMakeCallbackDeprecation) {
1431cb0ef41Sopenharmony_ci    process.emitWarning(
1441cb0ef41Sopenharmony_ci      'Using a domain property in MakeCallback is deprecated. Use the ' +
1451cb0ef41Sopenharmony_ci      'async_context variant of MakeCallback or the AsyncResource class ' +
1461cb0ef41Sopenharmony_ci      'instead. ' +
1471cb0ef41Sopenharmony_ci      `(Triggered by calling ${method?.name || '<anonymous>'} ` +
1481cb0ef41Sopenharmony_ci      `on ${target?.constructor?.name}.)`,
1491cb0ef41Sopenharmony_ci      'DeprecationWarning', 'DEP0097');
1501cb0ef41Sopenharmony_ci    sendMakeCallbackDeprecation = true;
1511cb0ef41Sopenharmony_ci  }
1521cb0ef41Sopenharmony_ci}
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_cifunction topLevelDomainCallback(cb, ...args) {
1551cb0ef41Sopenharmony_ci  const domain = this.domain;
1561cb0ef41Sopenharmony_ci  if (exports.active && domain)
1571cb0ef41Sopenharmony_ci    emitMakeCallbackDeprecation({ target: this, method: cb });
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci  if (domain)
1601cb0ef41Sopenharmony_ci    domain.enter();
1611cb0ef41Sopenharmony_ci  const ret = ReflectApply(cb, this, args);
1621cb0ef41Sopenharmony_ci  if (domain)
1631cb0ef41Sopenharmony_ci    domain.exit();
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci  return ret;
1661cb0ef41Sopenharmony_ci}
1671cb0ef41Sopenharmony_ci
1681cb0ef41Sopenharmony_ci// It's possible to enter one domain while already inside
1691cb0ef41Sopenharmony_ci// another one. The stack is each entered domain.
1701cb0ef41Sopenharmony_cilet stack = [];
1711cb0ef41Sopenharmony_ciexports._stack = stack;
1721cb0ef41Sopenharmony_ciuseDomainTrampoline(topLevelDomainCallback);
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_cifunction updateExceptionCapture() {
1751cb0ef41Sopenharmony_ci  if (ArrayPrototypeEvery(stack,
1761cb0ef41Sopenharmony_ci                          (domain) => domain.listenerCount('error') === 0)) {
1771cb0ef41Sopenharmony_ci    setUncaughtExceptionCaptureCallback(null);
1781cb0ef41Sopenharmony_ci  } else {
1791cb0ef41Sopenharmony_ci    setUncaughtExceptionCaptureCallback(null);
1801cb0ef41Sopenharmony_ci    setUncaughtExceptionCaptureCallback((er) => {
1811cb0ef41Sopenharmony_ci      return process.domain._errorHandler(er);
1821cb0ef41Sopenharmony_ci    });
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci}
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ciprocess.on('newListener', (name, listener) => {
1881cb0ef41Sopenharmony_ci  if (name === 'uncaughtException' &&
1891cb0ef41Sopenharmony_ci      listener !== domainUncaughtExceptionClear) {
1901cb0ef41Sopenharmony_ci    // Make sure the first listener for `uncaughtException` always clears
1911cb0ef41Sopenharmony_ci    // the domain stack.
1921cb0ef41Sopenharmony_ci    process.removeListener(name, domainUncaughtExceptionClear);
1931cb0ef41Sopenharmony_ci    process.prependListener(name, domainUncaughtExceptionClear);
1941cb0ef41Sopenharmony_ci  }
1951cb0ef41Sopenharmony_ci});
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ciprocess.on('removeListener', (name, listener) => {
1981cb0ef41Sopenharmony_ci  if (name === 'uncaughtException' &&
1991cb0ef41Sopenharmony_ci      listener !== domainUncaughtExceptionClear) {
2001cb0ef41Sopenharmony_ci    // If the domain listener would be the only remaining one, remove it.
2011cb0ef41Sopenharmony_ci    const listeners = process.listeners('uncaughtException');
2021cb0ef41Sopenharmony_ci    if (listeners.length === 1 && listeners[0] === domainUncaughtExceptionClear)
2031cb0ef41Sopenharmony_ci      process.removeListener(name, domainUncaughtExceptionClear);
2041cb0ef41Sopenharmony_ci  }
2051cb0ef41Sopenharmony_ci});
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_cifunction domainUncaughtExceptionClear() {
2081cb0ef41Sopenharmony_ci  stack.length = 0;
2091cb0ef41Sopenharmony_ci  exports.active = process.domain = null;
2101cb0ef41Sopenharmony_ci  updateExceptionCapture();
2111cb0ef41Sopenharmony_ci}
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ciclass Domain extends EventEmitter {
2151cb0ef41Sopenharmony_ci  constructor() {
2161cb0ef41Sopenharmony_ci    super();
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci    this.members = [];
2191cb0ef41Sopenharmony_ci    this[kWeak] = new WeakReference(this);
2201cb0ef41Sopenharmony_ci    asyncHook.enable();
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci    this.on('removeListener', updateExceptionCapture);
2231cb0ef41Sopenharmony_ci    this.on('newListener', updateExceptionCapture);
2241cb0ef41Sopenharmony_ci  }
2251cb0ef41Sopenharmony_ci}
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ciexports.Domain = Domain;
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ciexports.create = exports.createDomain = function createDomain() {
2301cb0ef41Sopenharmony_ci  return new Domain();
2311cb0ef41Sopenharmony_ci};
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci// The active domain is always the one that we're currently in.
2341cb0ef41Sopenharmony_ciexports.active = null;
2351cb0ef41Sopenharmony_ciDomain.prototype.members = undefined;
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci// Called by process._fatalException in case an error was thrown.
2381cb0ef41Sopenharmony_ciDomain.prototype._errorHandler = function(er) {
2391cb0ef41Sopenharmony_ci  let caught = false;
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  if ((typeof er === 'object' && er !== null) || typeof er === 'function') {
2421cb0ef41Sopenharmony_ci    ObjectDefineProperty(er, 'domain', {
2431cb0ef41Sopenharmony_ci      __proto__: null,
2441cb0ef41Sopenharmony_ci      configurable: true,
2451cb0ef41Sopenharmony_ci      enumerable: false,
2461cb0ef41Sopenharmony_ci      value: this,
2471cb0ef41Sopenharmony_ci      writable: true,
2481cb0ef41Sopenharmony_ci    });
2491cb0ef41Sopenharmony_ci    er.domainThrown = true;
2501cb0ef41Sopenharmony_ci  }
2511cb0ef41Sopenharmony_ci  // Pop all adjacent duplicates of the currently active domain from the stack.
2521cb0ef41Sopenharmony_ci  // This is done to prevent a domain's error handler to run within the context
2531cb0ef41Sopenharmony_ci  // of itself, and re-entering itself recursively handler as a result of an
2541cb0ef41Sopenharmony_ci  // exception thrown in its context.
2551cb0ef41Sopenharmony_ci  while (exports.active === this) {
2561cb0ef41Sopenharmony_ci    this.exit();
2571cb0ef41Sopenharmony_ci  }
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci  // The top-level domain-handler is handled separately.
2601cb0ef41Sopenharmony_ci  //
2611cb0ef41Sopenharmony_ci  // The reason is that if V8 was passed a command line option
2621cb0ef41Sopenharmony_ci  // asking it to abort on an uncaught exception (currently
2631cb0ef41Sopenharmony_ci  // "--abort-on-uncaught-exception"), we want an uncaught exception
2641cb0ef41Sopenharmony_ci  // in the top-level domain error handler to make the
2651cb0ef41Sopenharmony_ci  // process abort. Using try/catch here would always make V8 think
2661cb0ef41Sopenharmony_ci  // that these exceptions are caught, and thus would prevent it from
2671cb0ef41Sopenharmony_ci  // aborting in these cases.
2681cb0ef41Sopenharmony_ci  if (stack.length === 0) {
2691cb0ef41Sopenharmony_ci    // If there's no error handler, do not emit an 'error' event
2701cb0ef41Sopenharmony_ci    // as this would throw an error, make the process exit, and thus
2711cb0ef41Sopenharmony_ci    // prevent the process 'uncaughtException' event from being emitted
2721cb0ef41Sopenharmony_ci    // if a listener is set.
2731cb0ef41Sopenharmony_ci    if (EventEmitter.listenerCount(this, 'error') > 0) {
2741cb0ef41Sopenharmony_ci      // Clear the uncaughtExceptionCaptureCallback so that we know that, since
2751cb0ef41Sopenharmony_ci      // the top-level domain is not active anymore, it would be ok to abort on
2761cb0ef41Sopenharmony_ci      // an uncaught exception at this point
2771cb0ef41Sopenharmony_ci      setUncaughtExceptionCaptureCallback(null);
2781cb0ef41Sopenharmony_ci      try {
2791cb0ef41Sopenharmony_ci        caught = this.emit('error', er);
2801cb0ef41Sopenharmony_ci      } finally {
2811cb0ef41Sopenharmony_ci        updateExceptionCapture();
2821cb0ef41Sopenharmony_ci      }
2831cb0ef41Sopenharmony_ci    }
2841cb0ef41Sopenharmony_ci  } else {
2851cb0ef41Sopenharmony_ci    // Wrap this in a try/catch so we don't get infinite throwing
2861cb0ef41Sopenharmony_ci    try {
2871cb0ef41Sopenharmony_ci      // One of three things will happen here.
2881cb0ef41Sopenharmony_ci      //
2891cb0ef41Sopenharmony_ci      // 1. There is a handler, caught = true
2901cb0ef41Sopenharmony_ci      // 2. There is no handler, caught = false
2911cb0ef41Sopenharmony_ci      // 3. It throws, caught = false
2921cb0ef41Sopenharmony_ci      //
2931cb0ef41Sopenharmony_ci      // If caught is false after this, then there's no need to exit()
2941cb0ef41Sopenharmony_ci      // the domain, because we're going to crash the process anyway.
2951cb0ef41Sopenharmony_ci      caught = this.emit('error', er);
2961cb0ef41Sopenharmony_ci    } catch (er2) {
2971cb0ef41Sopenharmony_ci      // The domain error handler threw!  oh no!
2981cb0ef41Sopenharmony_ci      // See if another domain can catch THIS error,
2991cb0ef41Sopenharmony_ci      // or else crash on the original one.
3001cb0ef41Sopenharmony_ci      updateExceptionCapture();
3011cb0ef41Sopenharmony_ci      if (stack.length) {
3021cb0ef41Sopenharmony_ci        exports.active = process.domain = stack[stack.length - 1];
3031cb0ef41Sopenharmony_ci        caught = process.domain._errorHandler(er2);
3041cb0ef41Sopenharmony_ci      } else {
3051cb0ef41Sopenharmony_ci        // Pass on to the next exception handler.
3061cb0ef41Sopenharmony_ci        throw er2;
3071cb0ef41Sopenharmony_ci      }
3081cb0ef41Sopenharmony_ci    }
3091cb0ef41Sopenharmony_ci  }
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci  // Exit all domains on the stack.  Uncaught exceptions end the
3121cb0ef41Sopenharmony_ci  // current tick and no domains should be left on the stack
3131cb0ef41Sopenharmony_ci  // between ticks.
3141cb0ef41Sopenharmony_ci  domainUncaughtExceptionClear();
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci  return caught;
3171cb0ef41Sopenharmony_ci};
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci
3201cb0ef41Sopenharmony_ciDomain.prototype.enter = function() {
3211cb0ef41Sopenharmony_ci  // Note that this might be a no-op, but we still need
3221cb0ef41Sopenharmony_ci  // to push it onto the stack so that we can pop it later.
3231cb0ef41Sopenharmony_ci  exports.active = process.domain = this;
3241cb0ef41Sopenharmony_ci  ArrayPrototypePush(stack, this);
3251cb0ef41Sopenharmony_ci  updateExceptionCapture();
3261cb0ef41Sopenharmony_ci};
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ciDomain.prototype.exit = function() {
3301cb0ef41Sopenharmony_ci  // Don't do anything if this domain is not on the stack.
3311cb0ef41Sopenharmony_ci  const index = ArrayPrototypeLastIndexOf(stack, this);
3321cb0ef41Sopenharmony_ci  if (index === -1) return;
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci  // Exit all domains until this one.
3351cb0ef41Sopenharmony_ci  ArrayPrototypeSplice(stack, index);
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci  exports.active = stack.length === 0 ? undefined : stack[stack.length - 1];
3381cb0ef41Sopenharmony_ci  process.domain = exports.active;
3391cb0ef41Sopenharmony_ci  updateExceptionCapture();
3401cb0ef41Sopenharmony_ci};
3411cb0ef41Sopenharmony_ci
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci// note: this works for timers as well.
3441cb0ef41Sopenharmony_ciDomain.prototype.add = function(ee) {
3451cb0ef41Sopenharmony_ci  // If the domain is already added, then nothing left to do.
3461cb0ef41Sopenharmony_ci  if (ee.domain === this)
3471cb0ef41Sopenharmony_ci    return;
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci  // Has a domain already - remove it first.
3501cb0ef41Sopenharmony_ci  if (ee.domain)
3511cb0ef41Sopenharmony_ci    ee.domain.remove(ee);
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_ci  // Check for circular Domain->Domain links.
3541cb0ef41Sopenharmony_ci  // They cause big issues.
3551cb0ef41Sopenharmony_ci  //
3561cb0ef41Sopenharmony_ci  // For example:
3571cb0ef41Sopenharmony_ci  // var d = domain.create();
3581cb0ef41Sopenharmony_ci  // var e = domain.create();
3591cb0ef41Sopenharmony_ci  // d.add(e);
3601cb0ef41Sopenharmony_ci  // e.add(d);
3611cb0ef41Sopenharmony_ci  // e.emit('error', er); // RangeError, stack overflow!
3621cb0ef41Sopenharmony_ci  if (this.domain && (ee instanceof Domain)) {
3631cb0ef41Sopenharmony_ci    for (let d = this.domain; d; d = d.domain) {
3641cb0ef41Sopenharmony_ci      if (ee === d) return;
3651cb0ef41Sopenharmony_ci    }
3661cb0ef41Sopenharmony_ci  }
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci  ObjectDefineProperty(ee, 'domain', {
3691cb0ef41Sopenharmony_ci    __proto__: null,
3701cb0ef41Sopenharmony_ci    configurable: true,
3711cb0ef41Sopenharmony_ci    enumerable: false,
3721cb0ef41Sopenharmony_ci    value: this,
3731cb0ef41Sopenharmony_ci    writable: true,
3741cb0ef41Sopenharmony_ci  });
3751cb0ef41Sopenharmony_ci  ArrayPrototypePush(this.members, ee);
3761cb0ef41Sopenharmony_ci};
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ciDomain.prototype.remove = function(ee) {
3801cb0ef41Sopenharmony_ci  ee.domain = null;
3811cb0ef41Sopenharmony_ci  const index = ArrayPrototypeIndexOf(this.members, ee);
3821cb0ef41Sopenharmony_ci  if (index !== -1)
3831cb0ef41Sopenharmony_ci    ArrayPrototypeSplice(this.members, index, 1);
3841cb0ef41Sopenharmony_ci};
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ciDomain.prototype.run = function(fn) {
3881cb0ef41Sopenharmony_ci  this.enter();
3891cb0ef41Sopenharmony_ci  const ret = ReflectApply(fn, this, ArrayPrototypeSlice(arguments, 1));
3901cb0ef41Sopenharmony_ci  this.exit();
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_ci  return ret;
3931cb0ef41Sopenharmony_ci};
3941cb0ef41Sopenharmony_ci
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_cifunction intercepted(_this, self, cb, fnargs) {
3971cb0ef41Sopenharmony_ci  if (fnargs[0] && fnargs[0] instanceof Error) {
3981cb0ef41Sopenharmony_ci    const er = fnargs[0];
3991cb0ef41Sopenharmony_ci    er.domainBound = cb;
4001cb0ef41Sopenharmony_ci    er.domainThrown = false;
4011cb0ef41Sopenharmony_ci    ObjectDefineProperty(er, 'domain', {
4021cb0ef41Sopenharmony_ci      __proto__: null,
4031cb0ef41Sopenharmony_ci      configurable: true,
4041cb0ef41Sopenharmony_ci      enumerable: false,
4051cb0ef41Sopenharmony_ci      value: self,
4061cb0ef41Sopenharmony_ci      writable: true,
4071cb0ef41Sopenharmony_ci    });
4081cb0ef41Sopenharmony_ci    self.emit('error', er);
4091cb0ef41Sopenharmony_ci    return;
4101cb0ef41Sopenharmony_ci  }
4111cb0ef41Sopenharmony_ci
4121cb0ef41Sopenharmony_ci  self.enter();
4131cb0ef41Sopenharmony_ci  const ret = ReflectApply(cb, _this, ArrayPrototypeSlice(fnargs, 1));
4141cb0ef41Sopenharmony_ci  self.exit();
4151cb0ef41Sopenharmony_ci
4161cb0ef41Sopenharmony_ci  return ret;
4171cb0ef41Sopenharmony_ci}
4181cb0ef41Sopenharmony_ci
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ciDomain.prototype.intercept = function(cb) {
4211cb0ef41Sopenharmony_ci  const self = this;
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ci  function runIntercepted() {
4241cb0ef41Sopenharmony_ci    return intercepted(this, self, cb, arguments);
4251cb0ef41Sopenharmony_ci  }
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ci  return runIntercepted;
4281cb0ef41Sopenharmony_ci};
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci
4311cb0ef41Sopenharmony_cifunction bound(_this, self, cb, fnargs) {
4321cb0ef41Sopenharmony_ci  self.enter();
4331cb0ef41Sopenharmony_ci  const ret = ReflectApply(cb, _this, fnargs);
4341cb0ef41Sopenharmony_ci  self.exit();
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ci  return ret;
4371cb0ef41Sopenharmony_ci}
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ciDomain.prototype.bind = function(cb) {
4411cb0ef41Sopenharmony_ci  const self = this;
4421cb0ef41Sopenharmony_ci
4431cb0ef41Sopenharmony_ci  function runBound() {
4441cb0ef41Sopenharmony_ci    return bound(this, self, cb, arguments);
4451cb0ef41Sopenharmony_ci  }
4461cb0ef41Sopenharmony_ci
4471cb0ef41Sopenharmony_ci  ObjectDefineProperty(runBound, 'domain', {
4481cb0ef41Sopenharmony_ci    __proto__: null,
4491cb0ef41Sopenharmony_ci    configurable: true,
4501cb0ef41Sopenharmony_ci    enumerable: false,
4511cb0ef41Sopenharmony_ci    value: this,
4521cb0ef41Sopenharmony_ci    writable: true,
4531cb0ef41Sopenharmony_ci  });
4541cb0ef41Sopenharmony_ci
4551cb0ef41Sopenharmony_ci  return runBound;
4561cb0ef41Sopenharmony_ci};
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci// Override EventEmitter methods to make it domain-aware.
4591cb0ef41Sopenharmony_ciEventEmitter.usingDomains = true;
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_ciconst eventInit = EventEmitter.init;
4621cb0ef41Sopenharmony_ciEventEmitter.init = function(opts) {
4631cb0ef41Sopenharmony_ci  ObjectDefineProperty(this, 'domain', {
4641cb0ef41Sopenharmony_ci    __proto__: null,
4651cb0ef41Sopenharmony_ci    configurable: true,
4661cb0ef41Sopenharmony_ci    enumerable: false,
4671cb0ef41Sopenharmony_ci    value: null,
4681cb0ef41Sopenharmony_ci    writable: true,
4691cb0ef41Sopenharmony_ci  });
4701cb0ef41Sopenharmony_ci  if (exports.active && !(this instanceof exports.Domain)) {
4711cb0ef41Sopenharmony_ci    this.domain = exports.active;
4721cb0ef41Sopenharmony_ci  }
4731cb0ef41Sopenharmony_ci
4741cb0ef41Sopenharmony_ci  return FunctionPrototypeCall(eventInit, this, opts);
4751cb0ef41Sopenharmony_ci};
4761cb0ef41Sopenharmony_ci
4771cb0ef41Sopenharmony_ciconst eventEmit = EventEmitter.prototype.emit;
4781cb0ef41Sopenharmony_ciEventEmitter.prototype.emit = function emit(...args) {
4791cb0ef41Sopenharmony_ci  const domain = this.domain;
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_ci  const type = args[0];
4821cb0ef41Sopenharmony_ci  const shouldEmitError = type === 'error' &&
4831cb0ef41Sopenharmony_ci                          this.listenerCount(type) > 0;
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_ci  // Just call original `emit` if current EE instance has `error`
4861cb0ef41Sopenharmony_ci  // handler, there's no active domain or this is process
4871cb0ef41Sopenharmony_ci  if (shouldEmitError || domain === null || domain === undefined ||
4881cb0ef41Sopenharmony_ci      this === process) {
4891cb0ef41Sopenharmony_ci    return ReflectApply(eventEmit, this, args);
4901cb0ef41Sopenharmony_ci  }
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci  if (type === 'error') {
4931cb0ef41Sopenharmony_ci    const er = args.length > 1 && args[1] ?
4941cb0ef41Sopenharmony_ci      args[1] : new ERR_UNHANDLED_ERROR();
4951cb0ef41Sopenharmony_ci
4961cb0ef41Sopenharmony_ci    if (typeof er === 'object') {
4971cb0ef41Sopenharmony_ci      er.domainEmitter = this;
4981cb0ef41Sopenharmony_ci      ObjectDefineProperty(er, 'domain', {
4991cb0ef41Sopenharmony_ci        __proto__: null,
5001cb0ef41Sopenharmony_ci        configurable: true,
5011cb0ef41Sopenharmony_ci        enumerable: false,
5021cb0ef41Sopenharmony_ci        value: domain,
5031cb0ef41Sopenharmony_ci        writable: true,
5041cb0ef41Sopenharmony_ci      });
5051cb0ef41Sopenharmony_ci      er.domainThrown = false;
5061cb0ef41Sopenharmony_ci    }
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ci    // Remove the current domain (and its duplicates) from the domains stack and
5091cb0ef41Sopenharmony_ci    // set the active domain to its parent (if any) so that the domain's error
5101cb0ef41Sopenharmony_ci    // handler doesn't run in its own context. This prevents any event emitter
5111cb0ef41Sopenharmony_ci    // created or any exception thrown in that error handler from recursively
5121cb0ef41Sopenharmony_ci    // executing that error handler.
5131cb0ef41Sopenharmony_ci    const origDomainsStack = ArrayPrototypeSlice(stack);
5141cb0ef41Sopenharmony_ci    const origActiveDomain = process.domain;
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ci    // Travel the domains stack from top to bottom to find the first domain
5171cb0ef41Sopenharmony_ci    // instance that is not a duplicate of the current active domain.
5181cb0ef41Sopenharmony_ci    let idx = stack.length - 1;
5191cb0ef41Sopenharmony_ci    while (idx > -1 && process.domain === stack[idx]) {
5201cb0ef41Sopenharmony_ci      --idx;
5211cb0ef41Sopenharmony_ci    }
5221cb0ef41Sopenharmony_ci
5231cb0ef41Sopenharmony_ci    // Change the stack to not contain the current active domain, and only the
5241cb0ef41Sopenharmony_ci    // domains above it on the stack.
5251cb0ef41Sopenharmony_ci    if (idx < 0) {
5261cb0ef41Sopenharmony_ci      stack.length = 0;
5271cb0ef41Sopenharmony_ci    } else {
5281cb0ef41Sopenharmony_ci      ArrayPrototypeSplice(stack, idx + 1);
5291cb0ef41Sopenharmony_ci    }
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_ci    // Change the current active domain
5321cb0ef41Sopenharmony_ci    if (stack.length > 0) {
5331cb0ef41Sopenharmony_ci      exports.active = process.domain = stack[stack.length - 1];
5341cb0ef41Sopenharmony_ci    } else {
5351cb0ef41Sopenharmony_ci      exports.active = process.domain = null;
5361cb0ef41Sopenharmony_ci    }
5371cb0ef41Sopenharmony_ci
5381cb0ef41Sopenharmony_ci    updateExceptionCapture();
5391cb0ef41Sopenharmony_ci
5401cb0ef41Sopenharmony_ci    domain.emit('error', er);
5411cb0ef41Sopenharmony_ci
5421cb0ef41Sopenharmony_ci    // Now that the domain's error handler has completed, restore the domains
5431cb0ef41Sopenharmony_ci    // stack and the active domain to their original values.
5441cb0ef41Sopenharmony_ci    exports._stack = stack = origDomainsStack;
5451cb0ef41Sopenharmony_ci    exports.active = process.domain = origActiveDomain;
5461cb0ef41Sopenharmony_ci    updateExceptionCapture();
5471cb0ef41Sopenharmony_ci
5481cb0ef41Sopenharmony_ci    return false;
5491cb0ef41Sopenharmony_ci  }
5501cb0ef41Sopenharmony_ci
5511cb0ef41Sopenharmony_ci  domain.enter();
5521cb0ef41Sopenharmony_ci  const ret = ReflectApply(eventEmit, this, args);
5531cb0ef41Sopenharmony_ci  domain.exit();
5541cb0ef41Sopenharmony_ci
5551cb0ef41Sopenharmony_ci  return ret;
5561cb0ef41Sopenharmony_ci};
557