@@ -43,7 +43,6 @@ let debug = require('internal/util/debuglog').debuglog(
4343 debug = fn ;
4444 }
4545) ;
46- const { AbortController } = require ( 'internal/abort_controller' ) ;
4746const { Buffer } = require ( 'buffer' ) ;
4847const { Pipe, constants : PipeConstants } = internalBinding ( 'pipe_wrap' ) ;
4948
@@ -150,7 +149,7 @@ function fork(modulePath /* , args, options */) {
150149 options . execPath = options . execPath || process . execPath ;
151150 options . shell = false ;
152151
153- return spawnWithSignal ( options . execPath , args , options ) ;
152+ return spawn ( options . execPath , args , options ) ;
154153}
155154
156155function _forkChild ( fd , serializationMode ) {
@@ -311,17 +310,15 @@ function execFile(file /* , args, options, callback */) {
311310 // Validate maxBuffer, if present.
312311 validateMaxBuffer ( options . maxBuffer ) ;
313312
314- // Validate signal, if present
315- validateAbortSignal ( options . signal , 'options.signal' ) ;
316-
317313 options . killSignal = sanitizeKillSignal ( options . killSignal ) ;
318314
319315 const child = spawn ( file , args , {
320316 cwd : options . cwd ,
321317 env : options . env ,
322318 gid : options . gid ,
323- uid : options . uid ,
324319 shell : options . shell ,
320+ signal : options . signal ,
321+ uid : options . uid ,
325322 windowsHide : ! ! options . windowsHide ,
326323 windowsVerbatimArguments : ! ! options . windowsVerbatimArguments
327324 } ) ;
@@ -425,28 +422,12 @@ function execFile(file /* , args, options, callback */) {
425422 }
426423 }
427424
428- function abortHandler ( ) {
429- if ( ! ex )
430- ex = new AbortError ( ) ;
431- process . nextTick ( ( ) => kill ( ) ) ;
432- }
433-
434425 if ( options . timeout > 0 ) {
435426 timeoutId = setTimeout ( function delayedKill ( ) {
436427 kill ( ) ;
437428 timeoutId = null ;
438429 } , options . timeout ) ;
439430 }
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- }
450431
451432 if ( child . stdout ) {
452433 if ( encoding )
@@ -661,8 +642,31 @@ function normalizeSpawnArguments(file, args, options) {
661642 */
662643function spawn ( file , args , options ) {
663644 const child = new ChildProcess ( ) ;
664-
665645 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+
666670 debug ( 'spawn' , options ) ;
667671 child . spawn ( options ) ;
668672
@@ -868,14 +872,19 @@ function sanitizeKillSignal(killSignal) {
868872// This level of indirection is here because the other child_process methods
869873// call spawn internally but should use different cancellation logic.
870874function 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 ) ;
872881
873882 if ( options && options . signal ) {
874883 // Validate signal, if present
875884 validateAbortSignal ( options . signal , 'options.signal' ) ;
876885 function kill ( ) {
877886 if ( child . _handle ) {
878- child . kill ( 'SIGTERM' ) ;
887+ child . _handle . kill ( options . killSignal || 'SIGTERM' ) ;
879888 child . emit ( 'error' , new AbortError ( ) ) ;
880889 }
881890 }
0 commit comments