diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 02ea48df44d16d..e3bb69f24f8961 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -675,6 +675,7 @@ equal to `['pipe', 'pipe', 'pipe']`. For convenience, `options.stdio` may be one of the following strings: * `'pipe'`: equivalent to `['pipe', 'pipe', 'pipe']` (the default) +* `'overlapped'`: equivalent to `['overlapped', 'overlapped', 'overlapped']` * `'ignore'`: equivalent to `['ignore', 'ignore', 'ignore']` * `'inherit'`: equivalent to `['inherit', 'inherit', 'inherit']` or `[0, 1, 2]` @@ -688,7 +689,13 @@ pipes between the parent and child. The value is one of the following: `child_process` object as [`subprocess.stdio[fd]`][`subprocess.stdio`]. Pipes created for fds 0, 1, and 2 are also available as [`subprocess.stdin`][], [`subprocess.stdout`][] and [`subprocess.stderr`][], respectively. -2. `'ipc'`: Create an IPC channel for passing messages/file descriptors +2. `'overlapped'`: Same as `'pipe'` except that the `FILE_FLAG_OVERLAPPED` flag + is set on the handle. This is necessary for overlapped I/O on the child + process's stdio handles. See the + [docs](https://docs.microsoft.com/en-us/windows/win32/fileio/synchronous-and-asynchronous-i-o) + for more details. This is exactly the same as `'pipe'` on non-Windows + systems. +3. `'ipc'`: Create an IPC channel for passing messages/file descriptors between parent and child. A [`ChildProcess`][] may have at most one IPC stdio file descriptor. Setting this option enables the [`subprocess.send()`][] method. If the child is a Node.js process, the @@ -699,25 +706,25 @@ pipes between the parent and child. The value is one of the following: Accessing the IPC channel fd in any way other than [`process.send()`][] or using the IPC channel with a child process that is not a Node.js instance is not supported. -3. `'ignore'`: Instructs Node.js to ignore the fd in the child. While Node.js +4. `'ignore'`: Instructs Node.js to ignore the fd in the child. While Node.js will always open fds 0, 1, and 2 for the processes it spawns, setting the fd to `'ignore'` will cause Node.js to open `/dev/null` and attach it to the child's fd. -4. `'inherit'`: Pass through the corresponding stdio stream to/from the +5. `'inherit'`: Pass through the corresponding stdio stream to/from the parent process. In the first three positions, this is equivalent to `process.stdin`, `process.stdout`, and `process.stderr`, respectively. In any other position, equivalent to `'ignore'`. -5. {Stream} object: Share a readable or writable stream that refers to a tty, +6. {Stream} object: Share a readable or writable stream that refers to a tty, file, socket, or a pipe with the child process. The stream's underlying file descriptor is duplicated in the child process to the fd that corresponds to the index in the `stdio` array. The stream must have an underlying descriptor (file streams do not until the `'open'` event has occurred). -6. Positive integer: The integer value is interpreted as a file descriptor +7. Positive integer: The integer value is interpreted as a file descriptor that is currently open in the parent process. It is shared with the child process, similar to how {Stream} objects can be shared. Passing sockets is not supported on Windows. -7. `null`, `undefined`: Use default value. For stdio fds 0, 1, and 2 (in other +8. `null`, `undefined`: Use default value. For stdio fds 0, 1, and 2 (in other words, stdin, stdout, and stderr) a pipe is created. For fd 3 and up, the default is `'ignore'`. diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index 8dd85d287fc950..8512ae342fde65 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -231,6 +231,7 @@ function stdioStringToArray(stdio, channel) { switch (stdio) { case 'ignore': + case 'overlapped': case 'pipe': ArrayPrototypePush(options, stdio, stdio, stdio); break; case 'inherit': ArrayPrototypePush(options, 0, 1, 2); break; default: @@ -976,9 +977,10 @@ function getValidStdio(stdio, sync) { if (stdio === 'ignore') { ArrayPrototypePush(acc, { type: 'ignore' }); - } else if (stdio === 'pipe' || (typeof stdio === 'number' && stdio < 0)) { + } else if (stdio === 'pipe' || stdio === 'overlapped' || + (typeof stdio === 'number' && stdio < 0)) { const a = { - type: 'pipe', + type: stdio === 'overlapped' ? 'overlapped' : 'pipe', readable: i === 0, writable: i !== 0 }; diff --git a/src/env.h b/src/env.h index a0d59ff8728deb..b090021c4c1833 100644 --- a/src/env.h +++ b/src/env.h @@ -343,6 +343,7 @@ constexpr size_t kFsStatsBufferLength = V(options_string, "options") \ V(order_string, "order") \ V(output_string, "output") \ + V(overlapped_string, "overlapped") \ V(parse_error_string, "Parse Error") \ V(password_string, "password") \ V(path_string, "path") \ diff --git a/src/process_wrap.cc b/src/process_wrap.cc index 3d1065c9922183..bbb00153f7a8a8 100644 --- a/src/process_wrap.cc +++ b/src/process_wrap.cc @@ -125,6 +125,11 @@ class ProcessWrap : public HandleWrap { options->stdio[i].flags = static_cast( UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE); options->stdio[i].data.stream = StreamForWrap(env, stdio); + } else if (type->StrictEquals(env->overlapped_string())) { + options->stdio[i].flags = static_cast( + UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE | + UV_OVERLAPPED_PIPE); + options->stdio[i].data.stream = StreamForWrap(env, stdio); } else if (type->StrictEquals(env->wrap_string())) { options->stdio[i].flags = UV_INHERIT_STREAM; options->stdio[i].data.stream = StreamForWrap(env, stdio);