node/lib/internal/main/worker_thread.js
Joyee Cheung 2e4ceb5747
util: access process states lazily in debuglog
`debuglog()` depends on `process.pid` and `process.env.NODE_DEBUG`,
so it needs to be called lazily in top scopes of internal modules
that may be loaded before these run time states are allowed to
be accessed. This patch makes its implementation lazy by default,
the process states are only accessed when the returned debug
function is called for the first time.

PR-URL: https://github.com/nodejs/node/pull/27281
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com>
2019-04-20 00:30:38 +08:00

175 lines
4.5 KiB
JavaScript

'use strict';
// In worker threads, execute the script sent through the
// message port.
const { Object } = primordials;
const {
patchProcessObject,
setupCoverageHooks,
setupInspectorHooks,
setupWarningHandler,
setupDebugEnv,
initializeDeprecations,
initializeESMLoader,
initializeFrozenIntrinsics,
initializeReport,
loadPreloadModules,
setupTraceCategoryState
} = require('internal/bootstrap/pre_execution');
const {
threadId,
getEnvMessagePort
} = internalBinding('worker');
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
} = require('internal/worker/io');
const {
fatalException: originalFatalException
} = require('internal/process/execution');
const publicWorker = require('worker_threads');
const debug = require('internal/util/debuglog').debuglog('worker');
const assert = require('internal/assert');
patchProcessObject();
setupInspectorHooks();
setupDebugEnv();
setupWarningHandler();
// Since worker threads cannot switch cwd, we do not need to
// overwrite the process.env.NODE_V8_COVERAGE variable.
if (process.env.NODE_V8_COVERAGE) {
setupCoverageHooks(process.env.NODE_V8_COVERAGE);
}
debug(`[${threadId}] is setting up worker child environment`);
// 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 = require('internal/process/worker_thread_only');
Object.defineProperty(process, 'channel', {
enumerable: false,
get: workerThreadSetup.unavailable('process.channel')
});
Object.defineProperty(process, 'connected', {
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) {
const {
filename,
doEval,
workerData,
publicPort,
manifestSrc,
manifestURL,
hasStdin
} = message;
setupTraceCategoryState();
initializeReport();
if (manifestSrc) {
require('internal/process/policy').setup(manifestSrc, manifestURL);
}
initializeDeprecations();
initializeFrozenIntrinsics();
initializeESMLoader();
loadPreloadModules();
publicWorker.parentPort = publicPort;
publicWorker.workerData = workerData;
if (!hasStdin)
process.stdin.push(null);
debug(`[${threadId}] starts worker script ${filename} ` +
`(eval = ${eval}) at cwd = ${process.cwd()}`);
port.unref();
port.postMessage({ type: UP_AND_RUNNING });
if (doEval) {
const { evalScript } = require('internal/process/execution');
evalScript('[worker eval]', filename);
} else {
process.argv[1] = filename; // script filename
require('module').runMain();
}
} else if (message.type === STDIO_PAYLOAD) {
const { stream, chunk, encoding } = message;
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]();
}
});
// Overwrite fatalException
process._fatalException = (error, fromPromise) => {
debug(`[${threadId}] gets fatal exception`);
let caught = false;
try {
caught = originalFatalException.call(this, error, fromPromise);
} catch (e) {
error = e;
}
debug(`[${threadId}] fatal exception caught = ${caught}`);
if (!caught) {
let serialized;
try {
const { serializeError } = require('internal/error-serdes');
serialized = serializeError(error);
} catch {}
debug(`[${threadId}] fatal exception serialized = ${!!serialized}`);
if (serialized)
port.postMessage({
type: ERROR_MESSAGE,
error: serialized
});
else
port.postMessage({ type: COULD_NOT_SERIALIZE_ERROR });
const { clearAsyncIdStack } = require('internal/async_hooks');
clearAsyncIdStack();
process.exit();
}
};
markBootstrapComplete();
port.start();