Skip to content

Commit

Permalink
esm: propagate process.exit from the loader thread to the
Browse files Browse the repository at this point in the history
PR-URL: nodejs/node#47548
Backport-PR-URL: nodejs/node#50669
Reviewed-By: Geoffrey Booth <[email protected]>
Reviewed-By: Jacob Smith <[email protected]>
  • Loading branch information
sercher committed Apr 24, 2024
1 parent dbd86ae commit a41f3e8
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 0 deletions.
4 changes: 4 additions & 0 deletions graal-nodejs/lib/internal/modules/esm/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ class HooksProxy {
},
});
this.#worker.unref(); // ! Allows the process to eventually exit.
this.#worker.on('exit', process.exit);
}

#waitForWorker() {
Expand All @@ -510,6 +511,7 @@ class HooksProxy {
debug('wait for signal from worker');
AtomicsWait(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION, 0);
const response = this.#worker.receiveMessageSync();
if (response.message.status === 'exit') { return; }
const { preloadScripts } = this.#unwrapMessage(response);
this.#executePreloadScripts(preloadScripts);
}
Expand Down Expand Up @@ -590,6 +592,8 @@ class HooksProxy {
debug('got sync response from worker', { method, args });
if (response.message.status === 'never-settle') {
process.exit(13);
} else if (response.message.status === 'exit') {
process.exit(response.message.body);
}
return this.#unwrapMessage(response);
}
Expand Down
13 changes: 13 additions & 0 deletions graal-nodejs/lib/internal/modules/esm/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ async function customizedModuleWorker(lock, syncCommPort, errorHandler) {
let hooks, preloadScripts, initializationError;
let hasInitializationError = false;

{
// If a custom hook is calling `process.exit`, we should wake up the main thread
// so it can detect the exit event.
const { exit } = process;
process.exit = function(code) {
syncCommPort.postMessage(wrapMessage('exit', code ?? process.exitCode));
AtomicsAdd(lock, WORKER_TO_MAIN_THREAD_NOTIFICATION, 1);
AtomicsNotify(lock, WORKER_TO_MAIN_THREAD_NOTIFICATION);
return ReflectApply(exit, this, arguments);
};
}


try {
initializeESM();
const initResult = await initializeHooks();
Expand Down
48 changes: 48 additions & 0 deletions graal-nodejs/test/es-module/test-esm-loader-hooks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,52 @@ describe('Loader hooks', { concurrency: true }, () => {
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});

it('should be fine to call `process.exit` from a custom async hook', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-import-meta-resolve',
'--experimental-loader',
'data:text/javascript,export function load(a,b,next){if(a==="data:exit")process.exit(42);return next(a,b)}',
'--input-type=module',
'--eval',
'import "data:exit"',
]);

assert.strictEqual(stderr, '');
assert.strictEqual(stdout, '');
assert.strictEqual(code, 42);
assert.strictEqual(signal, null);
});

it('should be fine to call `process.exit` from a custom sync hook', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-import-meta-resolve',
'--experimental-loader',
'data:text/javascript,export function resolve(a,b,next){if(a==="exit:")process.exit(42);return next(a,b)}',
'--input-type=module',
'--eval',
'import "data:text/javascript,import.meta.resolve(%22exit:%22)"',
]);

assert.strictEqual(stderr, '');
assert.strictEqual(stdout, '');
assert.strictEqual(code, 42);
assert.strictEqual(signal, null);
});

it('should be fine to call `process.exit` from the loader thread top-level', async () => {
const { code, signal, stdout, stderr } = await spawnPromisified(execPath, [
'--no-warnings',
'--experimental-loader',
'data:text/javascript,process.exit(42)',
fixtures.path('empty.js'),
]);

assert.strictEqual(stderr, '');
assert.strictEqual(stdout, '');
assert.strictEqual(code, 42);
assert.strictEqual(signal, null);
});
});

0 comments on commit a41f3e8

Please sign in to comment.