@@ -43,7 +43,6 @@ let debug = require('internal/util/debuglog').debuglog(
43
43
debug = fn ;
44
44
}
45
45
) ;
46
- const { AbortController } = require ( 'internal/abort_controller' ) ;
47
46
const { Buffer } = require ( 'buffer' ) ;
48
47
const { Pipe, constants : PipeConstants } = internalBinding ( 'pipe_wrap' ) ;
49
48
@@ -150,7 +149,7 @@ function fork(modulePath /* , args, options */) {
150
149
options . execPath = options . execPath || process . execPath ;
151
150
options . shell = false ;
152
151
153
- return spawnWithSignal ( options . execPath , args , options ) ;
152
+ return spawn ( options . execPath , args , options ) ;
154
153
}
155
154
156
155
function _forkChild ( fd , serializationMode ) {
@@ -311,17 +310,15 @@ function execFile(file /* , args, options, callback */) {
311
310
// Validate maxBuffer, if present.
312
311
validateMaxBuffer ( options . maxBuffer ) ;
313
312
314
- // Validate signal, if present
315
- validateAbortSignal ( options . signal , 'options.signal' ) ;
316
-
317
313
options . killSignal = sanitizeKillSignal ( options . killSignal ) ;
318
314
319
315
const child = spawn ( file , args , {
320
316
cwd : options . cwd ,
321
317
env : options . env ,
322
318
gid : options . gid ,
323
- uid : options . uid ,
324
319
shell : options . shell ,
320
+ signal : options . signal ,
321
+ uid : options . uid ,
325
322
windowsHide : ! ! options . windowsHide ,
326
323
windowsVerbatimArguments : ! ! options . windowsVerbatimArguments
327
324
} ) ;
@@ -425,28 +422,12 @@ function execFile(file /* , args, options, callback */) {
425
422
}
426
423
}
427
424
428
- function abortHandler ( ) {
429
- if ( ! ex )
430
- ex = new AbortError ( ) ;
431
- process . nextTick ( ( ) => kill ( ) ) ;
432
- }
433
-
434
425
if ( options . timeout > 0 ) {
435
426
timeoutId = setTimeout ( function delayedKill ( ) {
436
427
kill ( ) ;
437
428
timeoutId = null ;
438
429
} , options . timeout ) ;
439
430
}
440
- if ( options . signal ) {
441
- if ( options . signal . aborted ) {
442
- process . nextTick ( abortHandler ) ;
443
- } else {
444
- const childController = new AbortController ( ) ;
445
- options . signal . addEventListener ( 'abort' , abortHandler ,
446
- { signal : childController . signal } ) ;
447
- child . once ( 'close' , ( ) => childController . abort ( ) ) ;
448
- }
449
- }
450
431
451
432
if ( child . stdout ) {
452
433
if ( encoding )
@@ -661,8 +642,31 @@ function normalizeSpawnArguments(file, args, options) {
661
642
*/
662
643
function spawn ( file , args , options ) {
663
644
const child = new ChildProcess ( ) ;
664
-
665
645
options = normalizeSpawnArguments ( file , args , options ) ;
646
+
647
+ if ( options . signal ) {
648
+ const signal = options . signal ;
649
+ // Validate signal, if present
650
+ validateAbortSignal ( signal , 'options.signal' ) ;
651
+
652
+ // Do nothing and throw if already aborted
653
+ if ( signal . aborted ) {
654
+ onAbortListener ( ) ;
655
+ } else {
656
+ signal . addEventListener ( 'abort' , onAbortListener , { once : true } ) ;
657
+ child . once ( 'close' ,
658
+ ( ) => signal . removeEventListener ( 'abort' , onAbortListener ) ) ;
659
+ }
660
+
661
+ function onAbortListener ( ) {
662
+ process . nextTick ( ( ) => {
663
+ child ?. kill ?. ( options . killSignal ) ;
664
+
665
+ child . emit ( 'error' , new AbortError ( ) ) ;
666
+ } ) ;
667
+ }
668
+ }
669
+
666
670
debug ( 'spawn' , options ) ;
667
671
child . spawn ( options ) ;
668
672
@@ -868,14 +872,19 @@ function sanitizeKillSignal(killSignal) {
868
872
// This level of indirection is here because the other child_process methods
869
873
// call spawn internally but should use different cancellation logic.
870
874
function spawnWithSignal ( file , args , options ) {
871
- const child = spawn ( file , args , options ) ;
875
+ // Remove signal from options to spawn
876
+ // to avoid double emitting of AbortError
877
+ const opts = options && typeof options === 'object' && ( 'signal' in options ) ?
878
+ { ...options , signal : undefined } :
879
+ options ;
880
+ const child = spawn ( file , args , opts ) ;
872
881
873
882
if ( options && options . signal ) {
874
883
// Validate signal, if present
875
884
validateAbortSignal ( options . signal , 'options.signal' ) ;
876
885
function kill ( ) {
877
886
if ( child . _handle ) {
878
- child . kill ( 'SIGTERM' ) ;
887
+ child . _handle . kill ( options . killSignal || 'SIGTERM' ) ;
879
888
child . emit ( 'error' , new AbortError ( ) ) ;
880
889
}
881
890
}
0 commit comments