Skip to content

Commit 39fbce7

Browse files
aduh95targos
authored andcommitted
esm: propagate process.exit from the loader thread to the main thread
PR-URL: #47548 Backport-PR-URL: #50669 Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Jacob Smith <[email protected]>
1 parent 2a528b7 commit 39fbce7

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

‎lib/internal/modules/esm/hooks.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ class HooksProxy{
501501
},
502502
});
503503
this.#worker.unref();// ! Allows the process to eventually exit.
504+
this.#worker.on('exit',process.exit);
504505
}
505506

506507
#waitForWorker(){
@@ -510,6 +511,7 @@ class HooksProxy{
510511
debug('wait for signal from worker');
511512
AtomicsWait(this.#lock,WORKER_TO_MAIN_THREAD_NOTIFICATION,0);
512513
constresponse=this.#worker.receiveMessageSync();
514+
if(response.message.status==='exit'){return;}
513515
const{ preloadScripts }=this.#unwrapMessage(response);
514516
this.#executePreloadScripts(preloadScripts);
515517
}
@@ -590,6 +592,8 @@ class HooksProxy{
590592
debug('got sync response from worker',{ method, args });
591593
if(response.message.status==='never-settle'){
592594
process.exit(13);
595+
}elseif(response.message.status==='exit'){
596+
process.exit(response.message.body);
593597
}
594598
returnthis.#unwrapMessage(response);
595599
}

‎lib/internal/modules/esm/worker.js‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,19 @@ async function customizedModuleWorker(lock, syncCommPort, errorHandler){
6666
lethooks,preloadScripts,initializationError;
6767
lethasInitializationError=false;
6868

69+
{
70+
// If a custom hook is calling `process.exit`, we should wake up the main thread
71+
// so it can detect the exit event.
72+
const{ exit }=process;
73+
process.exit=function(code){
74+
syncCommPort.postMessage(wrapMessage('exit',code??process.exitCode));
75+
AtomicsAdd(lock,WORKER_TO_MAIN_THREAD_NOTIFICATION,1);
76+
AtomicsNotify(lock,WORKER_TO_MAIN_THREAD_NOTIFICATION);
77+
returnReflectApply(exit,this,arguments);
78+
};
79+
}
80+
81+
6982
try{
7083
initializeESM();
7184
constinitResult=awaitinitializeHooks();

‎test/es-module/test-esm-loader-hooks.mjs‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,52 @@ describe('Loader hooks',{concurrency: true }, () =>{
143143
assert.strictEqual(code,0);
144144
assert.strictEqual(signal,null);
145145
});
146+
147+
it('should be fine to call `process.exit` from a custom async hook',async()=>{
148+
const{ code, signal, stdout, stderr }=awaitspawnPromisified(execPath,[
149+
'--no-warnings',
150+
'--experimental-import-meta-resolve',
151+
'--experimental-loader',
152+
'data:text/javascript,export function load(a,b,next){if(a==="data:exit")process.exit(42);return next(a,b)}',
153+
'--input-type=module',
154+
'--eval',
155+
'import "data:exit"',
156+
]);
157+
158+
assert.strictEqual(stderr,'');
159+
assert.strictEqual(stdout,'');
160+
assert.strictEqual(code,42);
161+
assert.strictEqual(signal,null);
162+
});
163+
164+
it('should be fine to call `process.exit` from a custom sync hook',async()=>{
165+
const{ code, signal, stdout, stderr }=awaitspawnPromisified(execPath,[
166+
'--no-warnings',
167+
'--experimental-import-meta-resolve',
168+
'--experimental-loader',
169+
'data:text/javascript,export function resolve(a,b,next){if(a==="exit:")process.exit(42);return next(a,b)}',
170+
'--input-type=module',
171+
'--eval',
172+
'import "data:text/javascript,import.meta.resolve(%22exit:%22)"',
173+
]);
174+
175+
assert.strictEqual(stderr,'');
176+
assert.strictEqual(stdout,'');
177+
assert.strictEqual(code,42);
178+
assert.strictEqual(signal,null);
179+
});
180+
181+
it('should be fine to call `process.exit` from the loader thread top-level',async()=>{
182+
const{ code, signal, stdout, stderr }=awaitspawnPromisified(execPath,[
183+
'--no-warnings',
184+
'--experimental-loader',
185+
'data:text/javascript,process.exit(42)',
186+
fixtures.path('empty.js'),
187+
]);
188+
189+
assert.strictEqual(stderr,'');
190+
assert.strictEqual(stdout,'');
191+
assert.strictEqual(code,42);
192+
assert.strictEqual(signal,null);
193+
});
146194
});

0 commit comments

Comments
(0)