| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 1cbb74d commit da98c9f
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -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 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,52 @@ | |||
| 1 | + // Flags: --experimental-abortcontroller | ||
| 2 | + 'use strict'; | ||
| 3 | + const common = require('../common'); | ||
| 4 | + const assert = require('assert'); | ||
| 5 | + const exec = require('child_process').exec; | ||
| 6 | + const { promisify } = require('util'); | ||
| 7 | + | ||
| 8 | + let pwdcommand, dir; | ||
| 9 | + const execPromisifed = promisify(exec); | ||
| 10 | + const invalidArgTypeError = { | ||
| 11 | + code: 'ERR_INVALID_ARG_TYPE', | ||
| 12 | + name: 'TypeError' | ||
| 13 | + }; | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + if (common.isWindows) { | ||
| 17 | + pwdcommand = 'echo %cd%'; | ||
| 18 | + dir = 'c:\\windows'; | ||
| 19 | + } else { | ||
| 20 | + pwdcommand = 'pwd'; | ||
| 21 | + dir = '/dev'; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + { | ||
| 26 | + const ac = new AbortController(); | ||
| 27 | + const signal = ac.signal; | ||
| 28 | + const promise = execPromisifed(pwdcommand, { cwd: dir, signal }); | ||
| 29 | + assert.rejects(promise, /AbortError/).then(common.mustCall()); | ||
| 30 | + ac.abort(); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + { | ||
| 34 | + assert.throws(() => { | ||
| 35 | + execPromisifed(pwdcommand, { cwd: dir, signal: {} }); | ||
| 36 | + }, invalidArgTypeError); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + { | ||
| 40 | + function signal() {} | ||
| 41 | + assert.throws(() => { | ||
| 42 | + execPromisifed(pwdcommand, { cwd: dir, signal }); | ||
| 43 | + }, invalidArgTypeError); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + { | ||
| 47 | + const ac = new AbortController(); | ||
| 48 | + const signal = (ac.abort(), ac.signal); | ||
| 49 | + const promise = execPromisifed(pwdcommand, { cwd: dir, signal }); | ||
| 50 | + | ||
| 51 | + assert.rejects(promise, /AbortError/).then(common.mustCall()); | ||
| 52 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,59 @@ | |||
| 1 | + // Flags: --experimental-abortcontroller | ||
| 2 | + 'use strict'; | ||
| 3 | + | ||
| 4 | + const common = require('../common'); | ||
| 5 | + const assert = require('assert'); | ||
| 6 | + const { promisify } = require('util'); | ||
| 7 | + const execFile = require('child_process').execFile; | ||
| 8 | + const fixtures = require('../common/fixtures'); | ||
| 9 | + | ||
| 10 | + const echoFixture = fixtures.path('echo.js'); | ||
| 11 | + const promisified = promisify(execFile); | ||
| 12 | + const invalidArgTypeError = { | ||
| 13 | + code: 'ERR_INVALID_ARG_TYPE', | ||
| 14 | + name: 'TypeError' | ||
| 15 | + }; | ||
| 16 | + | ||
| 17 | + { | ||
| 18 | + // Verify that the signal option works properly | ||
| 19 | + const ac = new AbortController(); | ||
| 20 | + const signal = ac.signal; | ||
| 21 | + const promise = promisified(process.execPath, [echoFixture, 0], { signal }); | ||
| 22 | + | ||
| 23 | + ac.abort(); | ||
| 24 | + | ||
| 25 | + assert.rejects( | ||
| 26 | + promise, | ||
| 27 | + { name: 'AbortError' } | ||
| 28 | + ).then(common.mustCall()); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + { | ||
| 32 | + // Verify that the signal option works properly when already aborted | ||
| 33 | + const ac = new AbortController(); | ||
| 34 | + const { signal } = ac; | ||
| 35 | + ac.abort(); | ||
| 36 | + | ||
| 37 | + assert.rejects( | ||
| 38 | + promisified(process.execPath, [echoFixture, 0], { signal }), | ||
| 39 | + { name: 'AbortError' } | ||
| 40 | + ).then(common.mustCall()); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + { | ||
| 44 | + // Verify that if something different than Abortcontroller.signal | ||
| 45 | + // is passed, ERR_INVALID_ARG_TYPE is thrown | ||
| 46 | + const signal = {}; | ||
| 47 | + assert.throws(() => { | ||
| 48 | + promisified(process.execPath, [echoFixture, 0], { signal }); | ||
| 49 | + }, invalidArgTypeError); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + { | ||
| 53 | + // Verify that if something different than Abortcontroller.signal | ||
| 54 | + // is passed, ERR_INVALID_ARG_TYPE is thrown | ||
| 55 | + const signal = 'world!'; | ||
| 56 | + assert.throws(() => { | ||
| 57 | + promisified(process.execPath, [echoFixture, 0], { signal }); | ||
| 58 | + }, invalidArgTypeError); | ||
| 59 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -63,10 +63,23 @@ const execOpts = { encoding: 'utf8', shell: true }; | |||
| 63 | 63 | execFile(process.execPath, [echoFixture, 0], { signal }, check); | |
| 64 | 64 | }; | |
| 65 | 65 | ||
| 66 | - test(); | ||
| 67 | - ac.abort(); | ||
| 68 | 66 | // Verify that it still works the same way now that the signal is aborted. | |
| 69 | 67 | test(); | |
| 68 | + ac.abort(); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + { | ||
| 72 | + // Verify that does not spawn a child if already aborted | ||
| 73 | + const ac = new AbortController(); | ||
| 74 | + const { signal } = ac; | ||
| 75 | + ac.abort(); | ||
| 76 | + | ||
| 77 | + const check = common.mustCall((err) => { | ||
| 78 | + assert.strictEqual(err.code, 'ABORT_ERR'); | ||
| 79 | + assert.strictEqual(err.name, 'AbortError'); | ||
| 80 | + assert.strictEqual(err.signal, undefined); | ||
| 81 | + }); | ||
| 82 | + execFile(process.execPath, [echoFixture, 0], { signal }, check); | ||
| 70 | 83 | } | |
| 71 | 84 | ||
| 72 | 85 | { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments