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,7 +70,21 @@ void platform_init(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int process_start(char *name, char *part, process_info_t *p, int is_helper) {
|
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 file = INVALID_HANDLE_VALUE;
|
||||||
HANDLE nul = INVALID_HANDLE_VALUE;
|
HANDLE nul = INVALID_HANDLE_VALUE;
|
||||||
WCHAR path[MAX_PATH], filename[MAX_PATH];
|
WCHAR path[MAX_PATH], filename[MAX_PATH];
|
||||||
@ -79,10 +93,22 @@ int process_start(char *name, char *part, process_info_t *p, int is_helper) {
|
|||||||
STARTUPINFOW si;
|
STARTUPINFOW si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
DWORD result;
|
DWORD result;
|
||||||
|
HANDLE fds[2];
|
||||||
|
char fdstr[32];
|
||||||
|
|
||||||
if (!is_helper) {
|
fds[0] = fds[1] = INVALID_HANDLE_VALUE;
|
||||||
/* Give the helpers time to settle. Race-y, fix this. */
|
|
||||||
uv_sleep(250);
|
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)
|
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->process = pi.hProcess;
|
||||||
p->name = part;
|
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;
|
return 0;
|
||||||
|
|
||||||
error:
|
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)
|
if (file != INVALID_HANDLE_VALUE)
|
||||||
CloseHandle(file);
|
CloseHandle(file);
|
||||||
if (nul != INVALID_HANDLE_VALUE)
|
if (nul != INVALID_HANDLE_VALUE)
|
||||||
|
|||||||
@ -351,11 +351,7 @@ extern int snprintf(char*, size_t, const char*, ...);
|
|||||||
# define UNUSED
|
# define UNUSED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#define notify_parent_process() ((void) 0)
|
|
||||||
#else
|
|
||||||
extern void notify_parent_process(void);
|
extern void notify_parent_process(void);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Fully close a loop */
|
/* Fully close a loop */
|
||||||
static void close_walk_cb(uv_handle_t* handle, void* arg) {
|
static void close_walk_cb(uv_handle_t* handle, void* arg) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user