From ed0aac56b26679c795f530e94339de15a4341882 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 16 Sep 2026 17:15:51 -0700 Subject: [PATCH] [test] Attempt to fix flakiness in test_poll_blocking_asyncify In `test_poll_blocking_asyncify.c`, `emscripten_set_timeout` was called before `clock_gettime(CLOCK_MONOTONIC, &begin)` in `test_unblock_poll`. Because Node.js schedules `setTimeout` relative to its internal millisecond-truncated timestamp (`binding.getLibuvNow()`), any delay or OS thread scheduling preemption between scheduling the timer and recording `begin` was subtracted from the measured duration. Record `begin` before calling `emscripten_set_timeout` (matching the pthread-based poll/select blocking tests), switch from hardcoded `1000`ms to `TIMEOUT_MS` (`300`ms, as done in #26257), normalize negative nanoseconds in `timespec_delta_ms`, and increase `TIMEOUT_MARGIN_MS` to `20`ms across all blocking poll/select tests. Fixes: #27727 --- test/core/test_poll_blocking.c | 6 +++--- test/core/test_poll_blocking_asyncify.c | 15 ++++++++------- test/core/test_ppoll_blocking.c | 6 +++--- test/core/test_pselect_blocking.c | 6 +++--- test/core/test_select_blocking.c | 6 +++--- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/test/core/test_poll_blocking.c b/test/core/test_poll_blocking.c index 86bb2284e73b2..d24ba98d4aeea 100644 --- a/test/core/test_poll_blocking.c +++ b/test/core/test_poll_blocking.c @@ -19,8 +19,8 @@ #define TIMEOUT_MS 300 // It is possible for the node timers (such as setTimeout or Atomics.wait) to wake up // slightly earlier than requested. Because we measure times accurately using -// clock_gettime, we give tests a 5 milliseconds error margin to avoid flaky timeouts. -#define TIMEOUT_MARGIN_MS 5 +// clock_gettime, we give tests a 20 milliseconds error margin to avoid flaky timeouts. +#define TIMEOUT_MARGIN_MS 20 void sleep_ms(int ms) { usleep(ms * 1000); @@ -33,7 +33,7 @@ int64_t timespec_delta_ms(struct timespec* begin, struct timespec* end) { assert(delta_sec >= 0); assert(delta_nsec > -1000000000 && delta_nsec < 1000000000); - int64_t delta_ms = (delta_sec * 1000) + (delta_nsec / 1000000); + int64_t delta_ms = (delta_sec * 1000000000LL + delta_nsec) / 1000000; assert(delta_ms >= 0); return delta_ms; } diff --git a/test/core/test_poll_blocking_asyncify.c b/test/core/test_poll_blocking_asyncify.c index a5a32bf71e7b4..ce71a65fba911 100644 --- a/test/core/test_poll_blocking_asyncify.c +++ b/test/core/test_poll_blocking_asyncify.c @@ -18,10 +18,11 @@ #include #include +#define TIMEOUT_MS 300 // It is possible for the node timers (such as setTimeout or Atomics.wait) to wake up // slightly earlier than requested. Because we measure times accurately using -// clock_gettime, we give tests a 5 milliseconds error margin to avoid flaky timeouts. -#define TIMEOUT_MARGIN_MS 5 +// clock_gettime, we give tests a 20 milliseconds error margin to avoid flaky timeouts. +#define TIMEOUT_MARGIN_MS 20 int64_t timespec_delta_ms(struct timespec* begin, struct timespec* end) { int64_t delta_sec = end->tv_sec - begin->tv_sec; @@ -30,7 +31,7 @@ int64_t timespec_delta_ms(struct timespec* begin, struct timespec* end) { assert(delta_sec >= 0); assert(delta_nsec > -1000000000 && delta_nsec < 1000000000); - int64_t delta_ms = (delta_sec * 1000) + (delta_nsec / 1000000); + int64_t delta_ms = (delta_sec * 1000000000LL + delta_nsec) / 1000000; assert(delta_ms >= 0); return delta_ms; } @@ -42,12 +43,12 @@ void test_timeout_without_fds() { struct timespec end = {0}; clock_gettime(CLOCK_MONOTONIC, &begin); - assert(poll(NULL, 0, 1000) == 0); + assert(poll(NULL, 0, TIMEOUT_MS) == 0); clock_gettime(CLOCK_MONOTONIC, &end); int64_t duration = timespec_delta_ms(&begin, &end); printf(" -> duration: %lld ms\n", duration); - assert(duration >= 1000 - TIMEOUT_MARGIN_MS); + assert(duration >= TIMEOUT_MS - TIMEOUT_MARGIN_MS); } int pipe_shared[2]; @@ -72,15 +73,15 @@ void test_unblock_poll() { {pipe_a[0], POLLIN, 0}, {pipe_shared[0], POLLIN, 0}, }; - emscripten_set_timeout(write_to_pipe, 1000, NULL); clock_gettime(CLOCK_MONOTONIC, &begin); + emscripten_set_timeout(write_to_pipe, TIMEOUT_MS, NULL); assert(poll(fds, 2, -1) == 1); clock_gettime(CLOCK_MONOTONIC, &end); assert(fds[1].revents & POLLIN); int64_t duration = timespec_delta_ms(&begin, &end); printf(" -> duration: %lld ms\n", duration); - assert(duration >= 1000 - TIMEOUT_MARGIN_MS); + assert(duration >= TIMEOUT_MS - TIMEOUT_MARGIN_MS); close(pipe_a[0]); close(pipe_a[1]); close(pipe_shared[0]); close(pipe_shared[1]); diff --git a/test/core/test_ppoll_blocking.c b/test/core/test_ppoll_blocking.c index c36077d3610ee..9e66540485477 100644 --- a/test/core/test_ppoll_blocking.c +++ b/test/core/test_ppoll_blocking.c @@ -21,8 +21,8 @@ // It is possible for the node timers (such as setTimeout or Atomics.wait) to wake up // slightly earlier than requested. Because we measure times accurately using -// clock_gettime, we give tests a 5 milliseconds error margin to avoid flaky timeouts. -#define TIMEOUT_MARGIN_MS 5 +// clock_gettime, we give tests a 20 milliseconds error margin to avoid flaky timeouts. +#define TIMEOUT_MARGIN_MS 20 void sleep_ms(int ms) { usleep(ms * 1000); @@ -35,7 +35,7 @@ int64_t timespec_delta_ms(struct timespec* begin, struct timespec* end) { assert(delta_sec >= 0); assert(delta_nsec > -1000000000 && delta_nsec < 1000000000); - int64_t delta_ms = (delta_sec * 1000) + (delta_nsec / 1000000); + int64_t delta_ms = (delta_sec * 1000000000LL + delta_nsec) / 1000000; assert(delta_ms >= 0); return delta_ms; } diff --git a/test/core/test_pselect_blocking.c b/test/core/test_pselect_blocking.c index 258547d9cd218..bc57345c19de5 100644 --- a/test/core/test_pselect_blocking.c +++ b/test/core/test_pselect_blocking.c @@ -22,8 +22,8 @@ // It is possible for the node timers (such as setTimeout or Atomics.wait) to wake up // slightly earlier than requested. Because we measure times accurately using -// clock_gettime, we give tests a 5 milliseconds error margin to avoid flaky timeouts. -#define TIMEOUT_MARGIN_MS 5 +// clock_gettime, we give tests a 20 milliseconds error margin to avoid flaky timeouts. +#define TIMEOUT_MARGIN_MS 20 void sleep_ms(int ms) { usleep(ms * 1000); @@ -36,7 +36,7 @@ int64_t timespec_delta_ms(struct timespec* begin, struct timespec* end) { assert(delta_sec >= 0); assert(delta_nsec > -1000000000 && delta_nsec < 1000000000); - int64_t delta_ms = (delta_sec * 1000) + (delta_nsec / 1000000); + int64_t delta_ms = (delta_sec * 1000000000LL + delta_nsec) / 1000000; assert(delta_ms >= 0); return delta_ms; } diff --git a/test/core/test_select_blocking.c b/test/core/test_select_blocking.c index a0593e375b471..652d982869620 100644 --- a/test/core/test_select_blocking.c +++ b/test/core/test_select_blocking.c @@ -17,8 +17,8 @@ #define TIMEOUT_MS 300 // It is possible for the node timers (such as setTimeout or Atomics.wait) to wake up // slightly earlier than requested. Because we measure times accurately using -// clock_gettime, we give tests a 5 milliseconds error margin to avoid flaky timeouts. -#define TIMEOUT_MARGIN_MS 5 +// clock_gettime, we give tests a 20 milliseconds error margin to avoid flaky timeouts. +#define TIMEOUT_MARGIN_MS 20 void sleep_ms(int ms) { usleep(ms * 1000); @@ -31,7 +31,7 @@ int64_t timespec_delta_ms(struct timespec* begin, struct timespec* end) { assert(delta_sec >= 0); assert(delta_nsec > -1000000000 && delta_nsec < 1000000000); - int64_t delta_ms = (delta_sec * 1000) + (delta_nsec / 1000000); + int64_t delta_ms = (delta_sec * 1000000000LL + delta_nsec) / 1000000; assert(delta_ms >= 0); return delta_ms; }