Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: support sync 'overlapped' stdio option #48479

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 13 additions & 8 deletions src/spawn_sync.cc
Expand Up @@ -92,14 +92,15 @@ void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) {
next_ = next;
}


SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler,
bool readable,
bool writable,
bool overlapped,
uv_buf_t input_buffer)
: process_handler_(process_handler),
readable_(readable),
writable_(writable),
overlapped_(overlapped),
input_buffer_(input_buffer),

first_output_buffer_(nullptr),
Expand All @@ -113,7 +114,6 @@ SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler,
CHECK(readable || writable);
}


SyncProcessStdioPipe::~SyncProcessStdioPipe() {
CHECK(lifecycle_ == kUninitialized || lifecycle_ == kClosed);

Expand Down Expand Up @@ -202,6 +202,9 @@ bool SyncProcessStdioPipe::writable() const {
return writable_;
}

bool SyncProcessStdioPipe::overlapped() const {
return overlapped_;
}

uv_stdio_flags SyncProcessStdioPipe::uv_flags() const {
unsigned int flags;
Expand All @@ -211,6 +214,7 @@ uv_stdio_flags SyncProcessStdioPipe::uv_flags() const {
flags |= UV_READABLE_PIPE;
if (writable())
flags |= UV_WRITABLE_PIPE;
if (overlapped()) flags |= UV_OVERLAPPED_PIPE;

return static_cast<uv_stdio_flags>(flags);
}
Expand Down Expand Up @@ -909,7 +913,8 @@ int SyncProcessRunner::ParseStdioOption(int child_fd,
if (js_type->StrictEquals(env()->ignore_string())) {
return AddStdioIgnore(child_fd);

} else if (js_type->StrictEquals(env()->pipe_string())) {
} else if (js_type->StrictEquals(env()->pipe_string()) ||
js_type->StrictEquals(env()->overlapped_string())) {
Isolate* isolate = env()->isolate();
Local<String> rs = env()->readable_string();
Local<String> ws = env()->writable_string();
Expand All @@ -936,7 +941,8 @@ int SyncProcessRunner::ParseStdioOption(int child_fd,
}
}

return AddStdioPipe(child_fd, readable, writable, buf);
bool overlapped = js_type->StrictEquals(env()->overlapped_string());
return AddStdioPipe(child_fd, readable, writable, overlapped, buf);

} else if (js_type->StrictEquals(env()->inherit_string()) ||
js_type->StrictEquals(env()->fd_string())) {
Expand All @@ -959,16 +965,16 @@ int SyncProcessRunner::AddStdioIgnore(uint32_t child_fd) {
return 0;
}


int SyncProcessRunner::AddStdioPipe(uint32_t child_fd,
bool readable,
bool writable,
bool overlapped,
uv_buf_t input_buffer) {
CHECK_LT(child_fd, stdio_count_);
CHECK(!stdio_pipes_[child_fd]);

std::unique_ptr<SyncProcessStdioPipe> h(
new SyncProcessStdioPipe(this, readable, writable, input_buffer));
std::unique_ptr<SyncProcessStdioPipe> h(new SyncProcessStdioPipe(
this, readable, writable, overlapped, input_buffer));

int r = h->Initialize(uv_loop_);
if (r < 0) {
Expand All @@ -984,7 +990,6 @@ int SyncProcessRunner::AddStdioPipe(uint32_t child_fd,
return 0;
}


int SyncProcessRunner::AddStdioInheritFD(uint32_t child_fd, int inherit_fd) {
CHECK_LT(child_fd, stdio_count_);
CHECK(!stdio_pipes_[child_fd]);
Expand Down
4 changes: 4 additions & 0 deletions src/spawn_sync.h
Expand Up @@ -75,6 +75,7 @@ class SyncProcessStdioPipe {
SyncProcessStdioPipe(SyncProcessRunner* process_handler,
bool readable,
bool writable,
bool overlapped,
uv_buf_t input_buffer);
~SyncProcessStdioPipe();

Expand All @@ -86,6 +87,7 @@ class SyncProcessStdioPipe {

inline bool readable() const;
inline bool writable() const;
inline bool overlapped() const;
inline uv_stdio_flags uv_flags() const;

inline uv_pipe_t* uv_pipe() const;
Expand Down Expand Up @@ -118,6 +120,7 @@ class SyncProcessStdioPipe {

bool readable_;
bool writable_;
bool overlapped_;
uv_buf_t input_buffer_;

SyncProcessOutputBuffer* first_output_buffer_;
Expand Down Expand Up @@ -182,6 +185,7 @@ class SyncProcessRunner {
inline int AddStdioPipe(uint32_t child_fd,
bool readable,
bool writable,
bool overlapped,
uv_buf_t input_buffer);
inline int AddStdioInheritFD(uint32_t child_fd, int inherit_fd);

Expand Down
11 changes: 11 additions & 0 deletions test/parallel/test-child-process-stdio-overlapped.js
Expand Up @@ -37,6 +37,17 @@
common.skip(exe + ' binary is not available');
}

// We can't synchronously write to the child (the 'input' and 'stdio' options
// conflict) but we can at least verify it starts up normally and is then
// terminated by the timer watchdog.
const { error } = child_process.spawnSync(exePath, [], {
stdio: ['overlapped', 'pipe', 'pipe'],
timeout: 42,
});

assert.ok(error);

Check failure on line 48 in test/parallel/test-child-process-stdio-overlapped.js

View workflow job for this annotation

GitHub Actions / test-macOS

--- stderr --- node:assert:408 throw err; ^ AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value: assert.ok(error) at Object.<anonymous> (/Users/runner/work/node/node/test/parallel/test-child-process-stdio-overlapped.js:48:8) at Module._compile (node:internal/modules/cjs/loader:1434:14) at Module._extensions..js (node:internal/modules/cjs/loader:1518:10) at Module.load (node:internal/modules/cjs/loader:1249:32) at Module._load (node:internal/modules/cjs/loader:1065:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:158:12) at node:internal/main/run_main_module:30:49 { generatedMessage: true, code: 'ERR_ASSERTION', actual: undefined, expected: true, operator: '==' } Node.js v23.0.0-pre Command: out/Release/node --test-reporter=spec --test-reporter-destination=stdout --test-reporter=./tools/github_reporter/index.js --test-reporter-destination=stdout /Users/runner/work/node/node/test/parallel/test-child-process-stdio-overlapped.js
assert.strictEqual(error.code, 'ETIMEDOUT');

const child = child_process.spawn(exePath, [], {
stdio: ['overlapped', 'pipe', 'pipe']
});
Expand Down