@@ -140,7 +140,7 @@ function fork(modulePath /* , args, options */) {
140
140
options . execPath = options . execPath || process . execPath ;
141
141
options . shell = false ;
142
142
143
- return spawnWithSignal ( options . execPath , args , options ) ;
143
+ return spawn ( options . execPath , args , options ) ;
144
144
}
145
145
146
146
function _forkChild ( fd , serializationMode ) {
@@ -254,17 +254,15 @@ function execFile(file /* , args, options, callback */) {
254
254
// Validate maxBuffer, if present.
255
255
validateMaxBuffer ( options . maxBuffer ) ;
256
256
257
- // Validate signal, if present
258
- validateAbortSignal ( options . signal , 'options.signal' ) ;
259
-
260
257
options . killSignal = sanitizeKillSignal ( options . killSignal ) ;
261
258
262
259
const child = spawn ( file , args , {
263
260
cwd : options . cwd ,
264
261
env : options . env ,
265
262
gid : options . gid ,
266
- uid : options . uid ,
267
263
shell : options . shell ,
264
+ signal : options . signal ,
265
+ uid : options . uid ,
268
266
windowsHide : ! ! options . windowsHide ,
269
267
windowsVerbatimArguments : ! ! options . windowsVerbatimArguments
270
268
} ) ;
@@ -368,28 +366,12 @@ function execFile(file /* , args, options, callback */) {
368
366
}
369
367
}
370
368
371
- function abortHandler ( ) {
372
- if ( ! ex )
373
- ex = new AbortError ( ) ;
374
- process . nextTick ( ( ) => kill ( ) ) ;
375
- }
376
-
377
369
if ( options . timeout > 0 ) {
378
370
timeoutId = setTimeout ( function delayedKill ( ) {
379
371
kill ( ) ;
380
372
timeoutId = null ;
381
373
} , options . timeout ) ;
382
374
}
383
- if ( options . signal ) {
384
- if ( options . signal . aborted ) {
385
- process . nextTick ( abortHandler ) ;
386
- } else {
387
- const childController = new AbortController ( ) ;
388
- options . signal . addEventListener ( 'abort' , abortHandler ,
389
- { signal : childController . signal } ) ;
390
- child . once ( 'close' , ( ) => childController . abort ( ) ) ;
391
- }
392
- }
393
375
394
376
if ( child . stdout ) {
395
377
if ( encoding )
@@ -611,8 +593,31 @@ function normalizeSpawnArguments(file, args, options) {
611
593
612
594
function spawn ( file , args , options ) {
613
595
const child = new ChildProcess ( ) ;
614
-
615
596
options = normalizeSpawnArguments ( file , args , options ) ;
597
+
598
+ if ( options . signal ) {
599
+ const signal = options . signal ;
600
+ // Validate signal, if present
601
+ validateAbortSignal ( signal , 'options.signal' ) ;
602
+
603
+ // Do nothing and throw if already aborted
604
+ if ( signal . aborted ) {
605
+ onAbortListener ( ) ;
606
+ } else {
607
+ signal . addEventListener ( 'abort' , onAbortListener , { once : true } ) ;
608
+ child . once ( 'close' ,
609
+ ( ) => signal . removeEventListener ( 'abort' , onAbortListener ) ) ;
610
+ }
611
+
612
+ function onAbortListener ( ) {
613
+ process . nextTick ( ( ) => {
614
+ child ?. kill ?. ( options . killSignal ) ;
615
+
616
+ child . emit ( 'error' , new AbortError ( ) ) ;
617
+ } ) ;
618
+ }
619
+ }
620
+
616
621
debug ( 'spawn' , options ) ;
617
622
child . spawn ( options ) ;
618
623
@@ -752,14 +757,19 @@ function sanitizeKillSignal(killSignal) {
752
757
// This level of indirection is here because the other child_process methods
753
758
// call spawn internally but should use different cancellation logic.
754
759
function spawnWithSignal ( file , args , options ) {
755
- const child = spawn ( file , args , options ) ;
760
+ // Remove signal from options to spawn
761
+ // to avoid double emitting of AbortError
762
+ const opts = options && typeof options === 'object' && ( 'signal' in options ) ?
763
+ { ...options , signal : undefined } :
764
+ options ;
765
+ const child = spawn ( file , args , opts ) ;
756
766
757
767
if ( options && options . signal ) {
758
768
// Validate signal, if present
759
769
validateAbortSignal ( options . signal , 'options.signal' ) ;
760
770
function kill ( ) {
761
771
if ( child . _handle ) {
762
- child . kill ( 'SIGTERM' ) ;
772
+ child . _handle . kill ( options . killSignal || 'SIGTERM' ) ;
763
773
child . emit ( 'error' , new AbortError ( ) ) ;
764
774
}
765
775
}
0 commit comments