test,win: fix race in test runner (#5066)
Port 143da93e to Windows: replace the 250 ms settle delay with a pipe-
based synchronization mechanism. The parent creates a pipe, passes the
write-end handle to the helper via UV_TEST_RUNNER_FD, then blocks on
ReadFile() until the helper calls notify_parent_process() and closes its
copy of the handle.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
40c800e5fc
commit
651f2fc161
@ -70,6 +70,20 @@ void platform_init(int argc, char **argv) {
|
||||
}
|
||||
|
||||
|
||||
void notify_parent_process(void) {
|
||||
HANDLE handle;
|
||||
char* arg;
|
||||
|
||||
arg = getenv("UV_TEST_RUNNER_FD");
|
||||
if (arg == NULL)
|
||||
return;
|
||||
|
||||
handle = (HANDLE)(uintptr_t)strtoull(arg, NULL, 10);
|
||||
SetEnvironmentVariableA("UV_TEST_RUNNER_FD", NULL);
|
||||
ASSERT_NE(CloseHandle(handle), 0);
|
||||
}
|
||||
|
||||
|
||||
int process_start(char* name, char* part, process_info_t* p, int is_helper) {
|
||||
HANDLE file = INVALID_HANDLE_VALUE;
|
||||
HANDLE nul = INVALID_HANDLE_VALUE;
|
||||
@ -79,10 +93,22 @@ int process_start(char *name, char *part, process_info_t *p, int is_helper) {
|
||||
STARTUPINFOW si;
|
||||
PROCESS_INFORMATION pi;
|
||||
DWORD result;
|
||||
HANDLE fds[2];
|
||||
char fdstr[32];
|
||||
|
||||
if (!is_helper) {
|
||||
/* Give the helpers time to settle. Race-y, fix this. */
|
||||
uv_sleep(250);
|
||||
fds[0] = fds[1] = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (is_helper) {
|
||||
/* Create a pipe so the helper can signal when it is ready. */
|
||||
if (!CreatePipe(&fds[0], &fds[1], NULL, 0))
|
||||
goto error;
|
||||
if (!SetHandleInformation(fds[0], HANDLE_FLAG_INHERIT, 0))
|
||||
goto error;
|
||||
if (!SetHandleInformation(fds[1], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
|
||||
goto error;
|
||||
snprintf(fdstr, sizeof(fdstr), "%" PRIuPTR, (uintptr_t) fds[1]);
|
||||
if (!SetEnvironmentVariableA("UV_TEST_RUNNER_FD", fdstr))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (GetTempPathW(sizeof(path) / sizeof(WCHAR), (WCHAR*)&path) == 0)
|
||||
@ -162,9 +188,41 @@ int process_start(char *name, char *part, process_info_t *p, int is_helper) {
|
||||
p->process = pi.hProcess;
|
||||
p->name = part;
|
||||
|
||||
if (!is_helper)
|
||||
return 0;
|
||||
|
||||
/* Close the write end in the parent and wait for the child to close its
|
||||
* copy, which signals that the helper has finished starting up. */
|
||||
ASSERT_NE(CloseHandle(fds[1]), 0);
|
||||
fds[1] = INVALID_HANDLE_VALUE;
|
||||
SetEnvironmentVariableA("UV_TEST_RUNNER_FD", NULL);
|
||||
|
||||
{
|
||||
char buf[1];
|
||||
DWORD bytes;
|
||||
if (ReadFile(fds[0], buf, sizeof(buf), &bytes, NULL)) {
|
||||
if (bytes > 0) {
|
||||
fprintf(stderr, "EOF expected but got data.\n");
|
||||
CloseHandle(fds[0]);
|
||||
return -1;
|
||||
}
|
||||
} else if (GetLastError() != ERROR_BROKEN_PIPE) {
|
||||
fprintf(stderr, "ReadFile: %lu\n", GetLastError());
|
||||
CloseHandle(fds[0]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_NE(CloseHandle(fds[0]), 0);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (fds[0] != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(fds[0]);
|
||||
if (fds[1] != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(fds[1]);
|
||||
SetEnvironmentVariableA("UV_TEST_RUNNER_FD", NULL);
|
||||
}
|
||||
if (file != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(file);
|
||||
if (nul != INVALID_HANDLE_VALUE)
|
||||
|
||||
@ -351,11 +351,7 @@ extern int snprintf(char*, size_t, const char*, ...);
|
||||
# define UNUSED
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define notify_parent_process() ((void) 0)
|
||||
#else
|
||||
extern void notify_parent_process(void);
|
||||
#endif
|
||||
|
||||
/* Fully close a loop */
|
||||
static void close_walk_cb(uv_handle_t* handle, void* arg) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user