11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  ArrayPrototypePush,
51cb0ef41Sopenharmony_ci  ArrayPrototypeSlice,
61cb0ef41Sopenharmony_ci  ArrayPrototypeSome,
71cb0ef41Sopenharmony_ci  ObjectKeys,
81cb0ef41Sopenharmony_ci  ObjectValues,
91cb0ef41Sopenharmony_ci  SafeMap,
101cb0ef41Sopenharmony_ci  StringPrototypeStartsWith,
111cb0ef41Sopenharmony_ci} = primordials;
121cb0ef41Sopenharmony_ciconst {
131cb0ef41Sopenharmony_ci  codes: {
141cb0ef41Sopenharmony_ci    ERR_SOCKET_BAD_PORT,
151cb0ef41Sopenharmony_ci  },
161cb0ef41Sopenharmony_ci} = require('internal/errors');
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciconst assert = require('internal/assert');
191cb0ef41Sopenharmony_ciconst { fork } = require('child_process');
201cb0ef41Sopenharmony_ciconst path = require('path');
211cb0ef41Sopenharmony_ciconst EventEmitter = require('events');
221cb0ef41Sopenharmony_ciconst RoundRobinHandle = require('internal/cluster/round_robin_handle');
231cb0ef41Sopenharmony_ciconst SharedHandle = require('internal/cluster/shared_handle');
241cb0ef41Sopenharmony_ciconst Worker = require('internal/cluster/worker');
251cb0ef41Sopenharmony_ciconst { getInspectPort, isUsingInspector } = require('internal/util/inspector');
261cb0ef41Sopenharmony_ciconst { internal, sendHelper } = require('internal/cluster/utils');
271cb0ef41Sopenharmony_ciconst cluster = new EventEmitter();
281cb0ef41Sopenharmony_ciconst intercom = new EventEmitter();
291cb0ef41Sopenharmony_ciconst SCHED_NONE = 1;
301cb0ef41Sopenharmony_ciconst SCHED_RR = 2;
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cimodule.exports = cluster;
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ciconst handles = new SafeMap();
351cb0ef41Sopenharmony_cicluster.isWorker = false;
361cb0ef41Sopenharmony_cicluster.isMaster = true; // Deprecated alias. Must be same as isPrimary.
371cb0ef41Sopenharmony_cicluster.isPrimary = true;
381cb0ef41Sopenharmony_cicluster.Worker = Worker;
391cb0ef41Sopenharmony_cicluster.workers = {};
401cb0ef41Sopenharmony_cicluster.settings = {};
411cb0ef41Sopenharmony_cicluster.SCHED_NONE = SCHED_NONE;  // Leave it to the operating system.
421cb0ef41Sopenharmony_cicluster.SCHED_RR = SCHED_RR;      // Primary distributes connections.
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cilet ids = 0;
451cb0ef41Sopenharmony_cilet initialized = false;
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci// XXX(bnoordhuis) Fold cluster.schedulingPolicy into cluster.settings?
481cb0ef41Sopenharmony_cilet schedulingPolicy = process.env.NODE_CLUSTER_SCHED_POLICY;
491cb0ef41Sopenharmony_ciif (schedulingPolicy === 'rr')
501cb0ef41Sopenharmony_ci  schedulingPolicy = SCHED_RR;
511cb0ef41Sopenharmony_cielse if (schedulingPolicy === 'none')
521cb0ef41Sopenharmony_ci  schedulingPolicy = SCHED_NONE;
531cb0ef41Sopenharmony_cielse if (process.platform === 'win32') {
541cb0ef41Sopenharmony_ci  // Round-robin doesn't perform well on
551cb0ef41Sopenharmony_ci  // Windows due to the way IOCP is wired up.
561cb0ef41Sopenharmony_ci  schedulingPolicy = SCHED_NONE;
571cb0ef41Sopenharmony_ci} else
581cb0ef41Sopenharmony_ci  schedulingPolicy = SCHED_RR;
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_cicluster.schedulingPolicy = schedulingPolicy;
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_cicluster.setupPrimary = function(options) {
631cb0ef41Sopenharmony_ci  const settings = {
641cb0ef41Sopenharmony_ci    args: ArrayPrototypeSlice(process.argv, 2),
651cb0ef41Sopenharmony_ci    exec: process.argv[1],
661cb0ef41Sopenharmony_ci    execArgv: process.execArgv,
671cb0ef41Sopenharmony_ci    silent: false,
681cb0ef41Sopenharmony_ci    ...cluster.settings,
691cb0ef41Sopenharmony_ci    ...options,
701cb0ef41Sopenharmony_ci  };
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  // Tell V8 to write profile data for each process to a separate file.
731cb0ef41Sopenharmony_ci  // Without --logfile=v8-%p.log, everything ends up in a single, unusable
741cb0ef41Sopenharmony_ci  // file. (Unusable because what V8 logs are memory addresses and each
751cb0ef41Sopenharmony_ci  // process has its own memory mappings.)
761cb0ef41Sopenharmony_ci  if (ArrayPrototypeSome(settings.execArgv,
771cb0ef41Sopenharmony_ci                         (s) => StringPrototypeStartsWith(s, '--prof')) &&
781cb0ef41Sopenharmony_ci      !ArrayPrototypeSome(settings.execArgv,
791cb0ef41Sopenharmony_ci                          (s) => StringPrototypeStartsWith(s, '--logfile='))) {
801cb0ef41Sopenharmony_ci    settings.execArgv = [...settings.execArgv, '--logfile=v8-%p.log'];
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  cluster.settings = settings;
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci  if (initialized === true)
861cb0ef41Sopenharmony_ci    return process.nextTick(setupSettingsNT, settings);
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci  initialized = true;
891cb0ef41Sopenharmony_ci  schedulingPolicy = cluster.schedulingPolicy;  // Freeze policy.
901cb0ef41Sopenharmony_ci  assert(schedulingPolicy === SCHED_NONE || schedulingPolicy === SCHED_RR,
911cb0ef41Sopenharmony_ci         `Bad cluster.schedulingPolicy: ${schedulingPolicy}`);
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  process.nextTick(setupSettingsNT, settings);
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  process.on('internalMessage', (message) => {
961cb0ef41Sopenharmony_ci    if (message.cmd !== 'NODE_DEBUG_ENABLED')
971cb0ef41Sopenharmony_ci      return;
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci    for (const worker of ObjectValues(cluster.workers)) {
1001cb0ef41Sopenharmony_ci      if (worker.state === 'online' || worker.state === 'listening') {
1011cb0ef41Sopenharmony_ci        process._debugProcess(worker.process.pid);
1021cb0ef41Sopenharmony_ci      } else {
1031cb0ef41Sopenharmony_ci        worker.once('online', function() {
1041cb0ef41Sopenharmony_ci          process._debugProcess(this.process.pid);
1051cb0ef41Sopenharmony_ci        });
1061cb0ef41Sopenharmony_ci      }
1071cb0ef41Sopenharmony_ci    }
1081cb0ef41Sopenharmony_ci  });
1091cb0ef41Sopenharmony_ci};
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci// Deprecated alias must be same as setupPrimary
1121cb0ef41Sopenharmony_cicluster.setupMaster = cluster.setupPrimary;
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_cifunction setupSettingsNT(settings) {
1151cb0ef41Sopenharmony_ci  cluster.emit('setup', settings);
1161cb0ef41Sopenharmony_ci}
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_cifunction createWorkerProcess(id, env) {
1191cb0ef41Sopenharmony_ci  const workerEnv = { ...process.env, ...env, NODE_UNIQUE_ID: `${id}` };
1201cb0ef41Sopenharmony_ci  const execArgv = [...cluster.settings.execArgv];
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  if (cluster.settings.inspectPort === null) {
1231cb0ef41Sopenharmony_ci    throw new ERR_SOCKET_BAD_PORT('Port', null, true);
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci  if (isUsingInspector(cluster.settings.execArgv)) {
1261cb0ef41Sopenharmony_ci    ArrayPrototypePush(execArgv, `--inspect-port=${getInspectPort(cluster.settings.inspectPort)}`);
1271cb0ef41Sopenharmony_ci  }
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  return fork(cluster.settings.exec, cluster.settings.args, {
1301cb0ef41Sopenharmony_ci    cwd: cluster.settings.cwd,
1311cb0ef41Sopenharmony_ci    env: workerEnv,
1321cb0ef41Sopenharmony_ci    serialization: cluster.settings.serialization,
1331cb0ef41Sopenharmony_ci    silent: cluster.settings.silent,
1341cb0ef41Sopenharmony_ci    windowsHide: cluster.settings.windowsHide,
1351cb0ef41Sopenharmony_ci    execArgv: execArgv,
1361cb0ef41Sopenharmony_ci    stdio: cluster.settings.stdio,
1371cb0ef41Sopenharmony_ci    gid: cluster.settings.gid,
1381cb0ef41Sopenharmony_ci    uid: cluster.settings.uid,
1391cb0ef41Sopenharmony_ci  });
1401cb0ef41Sopenharmony_ci}
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_cifunction removeWorker(worker) {
1431cb0ef41Sopenharmony_ci  assert(worker);
1441cb0ef41Sopenharmony_ci  delete cluster.workers[worker.id];
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  if (ObjectKeys(cluster.workers).length === 0) {
1471cb0ef41Sopenharmony_ci    assert(handles.size === 0, 'Resource leak detected.');
1481cb0ef41Sopenharmony_ci    intercom.emit('disconnect');
1491cb0ef41Sopenharmony_ci  }
1501cb0ef41Sopenharmony_ci}
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_cifunction removeHandlesForWorker(worker) {
1531cb0ef41Sopenharmony_ci  assert(worker);
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  handles.forEach((handle, key) => {
1561cb0ef41Sopenharmony_ci    if (handle.remove(worker))
1571cb0ef41Sopenharmony_ci      handles.delete(key);
1581cb0ef41Sopenharmony_ci  });
1591cb0ef41Sopenharmony_ci}
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_cicluster.fork = function(env) {
1621cb0ef41Sopenharmony_ci  cluster.setupPrimary();
1631cb0ef41Sopenharmony_ci  const id = ++ids;
1641cb0ef41Sopenharmony_ci  const workerProcess = createWorkerProcess(id, env);
1651cb0ef41Sopenharmony_ci  const worker = new Worker({
1661cb0ef41Sopenharmony_ci    id: id,
1671cb0ef41Sopenharmony_ci    process: workerProcess,
1681cb0ef41Sopenharmony_ci  });
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci  worker.on('message', function(message, handle) {
1711cb0ef41Sopenharmony_ci    cluster.emit('message', this, message, handle);
1721cb0ef41Sopenharmony_ci  });
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  worker.process.once('exit', (exitCode, signalCode) => {
1751cb0ef41Sopenharmony_ci    /*
1761cb0ef41Sopenharmony_ci     * Remove the worker from the workers list only
1771cb0ef41Sopenharmony_ci     * if it has disconnected, otherwise we might
1781cb0ef41Sopenharmony_ci     * still want to access it.
1791cb0ef41Sopenharmony_ci     */
1801cb0ef41Sopenharmony_ci    if (!worker.isConnected()) {
1811cb0ef41Sopenharmony_ci      removeHandlesForWorker(worker);
1821cb0ef41Sopenharmony_ci      removeWorker(worker);
1831cb0ef41Sopenharmony_ci    }
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci    worker.exitedAfterDisconnect = !!worker.exitedAfterDisconnect;
1861cb0ef41Sopenharmony_ci    worker.state = 'dead';
1871cb0ef41Sopenharmony_ci    worker.emit('exit', exitCode, signalCode);
1881cb0ef41Sopenharmony_ci    cluster.emit('exit', worker, exitCode, signalCode);
1891cb0ef41Sopenharmony_ci  });
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci  worker.process.once('disconnect', () => {
1921cb0ef41Sopenharmony_ci    /*
1931cb0ef41Sopenharmony_ci     * Now is a good time to remove the handles
1941cb0ef41Sopenharmony_ci     * associated with this worker because it is
1951cb0ef41Sopenharmony_ci     * not connected to the primary anymore.
1961cb0ef41Sopenharmony_ci     */
1971cb0ef41Sopenharmony_ci    removeHandlesForWorker(worker);
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci    /*
2001cb0ef41Sopenharmony_ci     * Remove the worker from the workers list only
2011cb0ef41Sopenharmony_ci     * if its process has exited. Otherwise, we might
2021cb0ef41Sopenharmony_ci     * still want to access it.
2031cb0ef41Sopenharmony_ci     */
2041cb0ef41Sopenharmony_ci    if (worker.isDead())
2051cb0ef41Sopenharmony_ci      removeWorker(worker);
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci    worker.exitedAfterDisconnect = !!worker.exitedAfterDisconnect;
2081cb0ef41Sopenharmony_ci    worker.state = 'disconnected';
2091cb0ef41Sopenharmony_ci    worker.emit('disconnect');
2101cb0ef41Sopenharmony_ci    cluster.emit('disconnect', worker);
2111cb0ef41Sopenharmony_ci  });
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci  worker.process.on('internalMessage', internal(worker, onmessage));
2141cb0ef41Sopenharmony_ci  process.nextTick(emitForkNT, worker);
2151cb0ef41Sopenharmony_ci  cluster.workers[worker.id] = worker;
2161cb0ef41Sopenharmony_ci  return worker;
2171cb0ef41Sopenharmony_ci};
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_cifunction emitForkNT(worker) {
2201cb0ef41Sopenharmony_ci  cluster.emit('fork', worker);
2211cb0ef41Sopenharmony_ci}
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_cicluster.disconnect = function(cb) {
2241cb0ef41Sopenharmony_ci  const workers = ObjectKeys(cluster.workers);
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci  if (workers.length === 0) {
2271cb0ef41Sopenharmony_ci    process.nextTick(() => intercom.emit('disconnect'));
2281cb0ef41Sopenharmony_ci  } else {
2291cb0ef41Sopenharmony_ci    for (const worker of ObjectValues(cluster.workers)) {
2301cb0ef41Sopenharmony_ci      if (worker.isConnected()) {
2311cb0ef41Sopenharmony_ci        worker.disconnect();
2321cb0ef41Sopenharmony_ci      }
2331cb0ef41Sopenharmony_ci    }
2341cb0ef41Sopenharmony_ci  }
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci  if (typeof cb === 'function')
2371cb0ef41Sopenharmony_ci    intercom.once('disconnect', cb);
2381cb0ef41Sopenharmony_ci};
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ciconst methodMessageMapping = {
2411cb0ef41Sopenharmony_ci  close,
2421cb0ef41Sopenharmony_ci  exitedAfterDisconnect,
2431cb0ef41Sopenharmony_ci  listening,
2441cb0ef41Sopenharmony_ci  online,
2451cb0ef41Sopenharmony_ci  queryServer,
2461cb0ef41Sopenharmony_ci};
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_cifunction onmessage(message, handle) {
2491cb0ef41Sopenharmony_ci  const worker = this;
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci  const fn = methodMessageMapping[message.act];
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci  if (typeof fn === 'function')
2541cb0ef41Sopenharmony_ci    fn(worker, message);
2551cb0ef41Sopenharmony_ci}
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_cifunction online(worker) {
2581cb0ef41Sopenharmony_ci  worker.state = 'online';
2591cb0ef41Sopenharmony_ci  worker.emit('online');
2601cb0ef41Sopenharmony_ci  cluster.emit('online', worker);
2611cb0ef41Sopenharmony_ci}
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_cifunction exitedAfterDisconnect(worker, message) {
2641cb0ef41Sopenharmony_ci  worker.exitedAfterDisconnect = true;
2651cb0ef41Sopenharmony_ci  send(worker, { ack: message.seq });
2661cb0ef41Sopenharmony_ci}
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_cifunction queryServer(worker, message) {
2691cb0ef41Sopenharmony_ci  // Stop processing if worker already disconnecting
2701cb0ef41Sopenharmony_ci  if (worker.exitedAfterDisconnect)
2711cb0ef41Sopenharmony_ci    return;
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci  const key = `${message.address}:${message.port}:${message.addressType}:` +
2741cb0ef41Sopenharmony_ci              `${message.fd}:${message.index}`;
2751cb0ef41Sopenharmony_ci  let handle = handles.get(key);
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ci  if (handle === undefined) {
2781cb0ef41Sopenharmony_ci    let address = message.address;
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci    // Find shortest path for unix sockets because of the ~100 byte limit
2811cb0ef41Sopenharmony_ci    if (message.port < 0 && typeof address === 'string' &&
2821cb0ef41Sopenharmony_ci        process.platform !== 'win32') {
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci      address = path.relative(process.cwd(), address);
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci      if (message.address.length < address.length)
2871cb0ef41Sopenharmony_ci        address = message.address;
2881cb0ef41Sopenharmony_ci    }
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci    // UDP is exempt from round-robin connection balancing for what should
2911cb0ef41Sopenharmony_ci    // be obvious reasons: it's connectionless. There is nothing to send to
2921cb0ef41Sopenharmony_ci    // the workers except raw datagrams and that's pointless.
2931cb0ef41Sopenharmony_ci    if (schedulingPolicy !== SCHED_RR ||
2941cb0ef41Sopenharmony_ci        message.addressType === 'udp4' ||
2951cb0ef41Sopenharmony_ci        message.addressType === 'udp6') {
2961cb0ef41Sopenharmony_ci      handle = new SharedHandle(key, address, message);
2971cb0ef41Sopenharmony_ci    } else {
2981cb0ef41Sopenharmony_ci      handle = new RoundRobinHandle(key, address, message);
2991cb0ef41Sopenharmony_ci    }
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_ci    handles.set(key, handle);
3021cb0ef41Sopenharmony_ci  }
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_ci  if (!handle.data)
3051cb0ef41Sopenharmony_ci    handle.data = message.data;
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci  // Set custom server data
3081cb0ef41Sopenharmony_ci  handle.add(worker, (errno, reply, handle) => {
3091cb0ef41Sopenharmony_ci    const { data } = handles.get(key);
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci    if (errno)
3121cb0ef41Sopenharmony_ci      handles.delete(key);  // Gives other workers a chance to retry.
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci    send(worker, {
3151cb0ef41Sopenharmony_ci      errno,
3161cb0ef41Sopenharmony_ci      key,
3171cb0ef41Sopenharmony_ci      ack: message.seq,
3181cb0ef41Sopenharmony_ci      data,
3191cb0ef41Sopenharmony_ci      ...reply,
3201cb0ef41Sopenharmony_ci    }, handle);
3211cb0ef41Sopenharmony_ci  });
3221cb0ef41Sopenharmony_ci}
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_cifunction listening(worker, message) {
3251cb0ef41Sopenharmony_ci  const info = {
3261cb0ef41Sopenharmony_ci    addressType: message.addressType,
3271cb0ef41Sopenharmony_ci    address: message.address,
3281cb0ef41Sopenharmony_ci    port: message.port,
3291cb0ef41Sopenharmony_ci    fd: message.fd,
3301cb0ef41Sopenharmony_ci  };
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci  worker.state = 'listening';
3331cb0ef41Sopenharmony_ci  worker.emit('listening', info);
3341cb0ef41Sopenharmony_ci  cluster.emit('listening', worker, info);
3351cb0ef41Sopenharmony_ci}
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci// Server in worker is closing, remove from list. The handle may have been
3381cb0ef41Sopenharmony_ci// removed by a prior call to removeHandlesForWorker() so guard against that.
3391cb0ef41Sopenharmony_cifunction close(worker, message) {
3401cb0ef41Sopenharmony_ci  const key = message.key;
3411cb0ef41Sopenharmony_ci  const handle = handles.get(key);
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci  if (handle && handle.remove(worker))
3441cb0ef41Sopenharmony_ci    handles.delete(key);
3451cb0ef41Sopenharmony_ci}
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_cifunction send(worker, message, handle, cb) {
3481cb0ef41Sopenharmony_ci  return sendHelper(worker.process, message, handle, cb);
3491cb0ef41Sopenharmony_ci}
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ci// Extend generic Worker with methods specific to the primary process.
3521cb0ef41Sopenharmony_ciWorker.prototype.disconnect = function() {
3531cb0ef41Sopenharmony_ci  this.exitedAfterDisconnect = true;
3541cb0ef41Sopenharmony_ci  send(this, { act: 'disconnect' });
3551cb0ef41Sopenharmony_ci  removeHandlesForWorker(this);
3561cb0ef41Sopenharmony_ci  removeWorker(this);
3571cb0ef41Sopenharmony_ci  return this;
3581cb0ef41Sopenharmony_ci};
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ciWorker.prototype.destroy = function(signo) {
3611cb0ef41Sopenharmony_ci  const proc = this.process;
3621cb0ef41Sopenharmony_ci  const signal = signo || 'SIGTERM';
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci  proc.kill(signal);
3651cb0ef41Sopenharmony_ci};
366