UNPKG

nstdlib-nightly

Version:

Node.js standard library converted to runtime-agnostic ES modules.

256 lines (223 loc) 7.79 kB
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/main/worker_thread.js import * as __hoisted_worker_threads__ from "nstdlib/lib/worker_threads"; import * as __hoisted_internal_worker__ from "nstdlib/lib/internal/worker"; import * as __hoisted_internal_modules_esm_utils__ from "nstdlib/lib/internal/modules/esm/utils"; import * as __hoisted_internal_process_execution__ from "nstdlib/lib/internal/process/execution"; import * as __hoisted_internal_modules_cjs_loader__ from "nstdlib/lib/internal/modules/cjs/loader"; import * as __hoisted_internal_error_serdes__ from "nstdlib/lib/internal/error_serdes"; import * as __hoisted_internal_async_hooks__ from "nstdlib/lib/internal/async_hooks"; import { prepareWorkerThreadExecution, setupUserModules, markBootstrapComplete, } from "nstdlib/lib/internal/process/pre_execution"; import { threadId, getEnvMessagePort } from "nstdlib/stub/binding/worker"; import * as workerIo from "nstdlib/lib/internal/worker/io"; import { setupMainThreadPort } from "nstdlib/lib/internal/worker/messaging"; import { onGlobalUncaughtException } from "nstdlib/lib/internal/process/execution"; import * as assert from "nstdlib/lib/internal/assert"; import { exitCodes as __exitCodes__ } from "nstdlib/stub/binding/errors"; import * as __hoisted_internal_process_worker_thread_only__ from "nstdlib/lib/internal/process/worker_thread_only"; // In worker threads, execute the script sent through the // message port. const { messageTypes: { // Messages that may be received by workers LOAD_SCRIPT, // Messages that may be posted from workers UP_AND_RUNNING, ERROR_MESSAGE, COULD_NOT_SERIALIZE_ERROR, // Messages that may be either received or posted STDIO_PAYLOAD, STDIO_WANTS_MORE_DATA, }, kStdioWantsMoreDataCallback, } = workerIo; const { kGenericUserError } = __exitCodes__; prepareWorkerThreadExecution(); { /* debug */ } // Set up the message port and start listening const port = getEnvMessagePort(); // If the main thread is spawned with env NODE_CHANNEL_FD, it's probably // spawned by our child_process module. In the work threads, mark the // related IPC properties as unavailable. if (process.env.NODE_CHANNEL_FD) { const workerThreadSetup = __hoisted_internal_process_worker_thread_only__; Object.defineProperty(process, "channel", { __proto__: null, enumerable: false, get: workerThreadSetup.unavailable("process.channel"), }); Object.defineProperty(process, "connected", { __proto__: null, enumerable: false, get: workerThreadSetup.unavailable("process.connected"), }); process.send = workerThreadSetup.unavailable("process.send()"); process.disconnect = workerThreadSetup.unavailable("process.disconnect()"); } port.on("message", (message) => { if (message.type === LOAD_SCRIPT) { port.unref(); const { argv, cwdCounter, doEval, environmentData, filename, hasStdin, publicPort, workerData, mainThreadPort, } = message; if (doEval !== "internal") { if (argv !== undefined) { Array.prototype.push.apply(process.argv, argv); } const publicWorker = __hoisted_worker_threads__; publicWorker.parentPort = publicPort; publicWorker.workerData = workerData; } __hoisted_internal_worker__.assignEnvironmentData(environmentData); setupMainThreadPort(mainThreadPort); if (SharedArrayBuffer !== undefined) { // The counter is only passed to the workers created by the main thread, // not to workers created by other workers. let cachedCwd = ""; let lastCounter = -1; const originalCwd = process.cwd; process.cwd = function () { const currentCounter = AtomicsLoad(cwdCounter, 0); if (currentCounter === lastCounter) return cachedCwd; lastCounter = currentCounter; cachedCwd = originalCwd(); return cachedCwd; }; workerIo.sharedCwdCounter = cwdCounter; } const isLoaderWorker = doEval === "internal" && filename === __hoisted_internal_modules_esm_utils__.loaderWorkerId; // Disable custom loaders in loader worker. setupUserModules(isLoaderWorker); if (!hasStdin) process.stdin.push(null); { /* debug */ } port.postMessage({ type: UP_AND_RUNNING }); switch (doEval) { case "internal": { // Create this WeakMap in js-land because V8 has no C++ API for WeakMap. require("binding/module_wrap").callbackMap = new WeakMap(); require(filename)(workerData, publicPort); break; } case "classic": { const { evalScript } = __hoisted_internal_process_execution__; const name = "[worker eval]"; // This is necessary for CJS module compilation. // TODO: pass this with something really internal. Object.defineProperty(process, "_eval", { __proto__: null, configurable: true, enumerable: true, value: filename, }); Array.prototype.splice.call(process.argv, 1, 0, name); ((...args) => globalThis.evalScript(...args))(name, filename); break; } case "module": { const { evalModuleEntryPoint } = __hoisted_internal_process_execution__; Promise.prototype.then.call( ((...args) => globalThis.evalModuleEntryPoint(...args))(filename), undefined, (e) => { workerOnGlobalUncaughtException(e, true); }, ); break; } default: { // script filename // runMain here might be monkey-patched by users in --require. // XXX: the monkey-patchability here should probably be deprecated. Array.prototype.splice.call(process.argv, 1, 0, filename); const CJSLoader = __hoisted_internal_modules_cjs_loader__; CJSLoader.Module.runMain(filename); break; } } } else if (message.type === STDIO_PAYLOAD) { const { stream, chunks } = message; Array.prototype.forEach.call(chunks, ({ chunk, encoding }) => { process[stream].push(chunk, encoding); }); } else { assert( message.type === STDIO_WANTS_MORE_DATA, `Unknown worker message type ${message.type}`, ); const { stream } = message; process[stream][kStdioWantsMoreDataCallback](); } }); function workerOnGlobalUncaughtException(error, fromPromise) { { /* debug */ } let handled = false; let handlerThrew = false; try { handled = onGlobalUncaughtException(error, fromPromise); } catch (e) { error = e; handlerThrew = true; } { /* debug */ } if (handled) { return true; } if (!process._exiting) { try { process._exiting = true; process.exitCode = kGenericUserError; if (!handlerThrew) { process.emit("exit", process.exitCode); } } catch { // Continue regardless of error. } } let serialized; try { const { serializeError } = __hoisted_internal_error_serdes__; serialized = serializeError(error); } catch { // Continue regardless of error. } { /* debug */ } if (serialized) port.postMessage({ type: ERROR_MESSAGE, error: serialized, }); else port.postMessage({ type: COULD_NOT_SERIALIZE_ERROR }); const { clearAsyncIdStack } = __hoisted_internal_async_hooks__; clearAsyncIdStack(); process.exit(); } // Patch the global uncaught exception handler so it gets picked up by // node::errors::TriggerUncaughtException(). process._fatalException = workerOnGlobalUncaughtException; markBootstrapComplete(); // Necessary to reset RegExp statics before user code runs. RegExp.prototype.exec.call(/^/, ""); port.start();