diff --git a/system/lib/libc/musl/src/time/clock_nanosleep.c b/system/lib/libc/musl/src/time/clock_nanosleep.c index 434fc4939e146..7ad2aba1a0b7a 100644 --- a/system/lib/libc/musl/src/time/clock_nanosleep.c +++ b/system/lib/libc/musl/src/time/clock_nanosleep.c @@ -16,7 +16,18 @@ int __clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, stru if (!req || req->tv_nsec < 0 || req->tv_nsec > 999999999L || req->tv_sec < 0) { return EINVAL; } - emscripten_thread_sleep(req->tv_sec * 1000.0 + req->tv_nsec / 1e6); + struct timespec sleep_for = *req; + if (flags & TIMER_ABSTIME) { + struct timespec now; + clock_gettime(clk, &now); + if (now.tv_sec > req->tv_sec || (now.tv_sec == req->tv_sec && now.tv_nsec >= req->tv_nsec)) { + // The requested time has already passed + return 0; + } + sleep_for.tv_sec = req->tv_sec - now.tv_sec; + sleep_for.tv_nsec = req->tv_nsec - now.tv_nsec; + } + emscripten_thread_sleep(sleep_for.tv_sec * 1000.0 + sleep_for.tv_nsec / 1e6); return 0; #else #ifdef SYS_clock_nanosleep_time64 diff --git a/tests/other/test_clock_nanosleep.c b/tests/other/test_clock_nanosleep.c new file mode 100644 index 0000000000000..a60efbe67120e --- /dev/null +++ b/tests/other/test_clock_nanosleep.c @@ -0,0 +1,42 @@ +#include +#include +#include + +long long get_time_ms() { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return (now.tv_sec * 1000) + (now.tv_nsec / 1000 / 1000); +} + +int main(void) { + // Sleep for 10ms relative to current time (i.e. without TIMER_ABSTIME). + struct timespec sleep_for; + sleep_for.tv_sec = 0; + sleep_for.tv_nsec = 10 * 1000 * 1000; + long long before = get_time_ms(); + printf("before: %lli\n", before); + clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_for, NULL); + long long after = get_time_ms(); + printf("after: %lli\n", after); + + // Check we slept at least 10ms + assert(after > before); + assert(after - before >= 10); + assert(after - before < 10000); + + before = get_time_ms(); + printf("before: %lli\n", before); + struct timespec deadline; + clock_gettime(CLOCK_MONOTONIC, &deadline); + deadline.tv_nsec += 20 * 1000 * 1000; + clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &deadline, NULL); + after = get_time_ms(); + printf("after: %lli\n", after); + + // Check we slept at least 20ms + assert(after > before); + assert(after - before >= 20); + assert(after - before < 10000); + + return 0; +} diff --git a/tests/test_other.py b/tests/test_other.py index b39d52038ff76..f277c50d7be24 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -11806,3 +11806,6 @@ def test_wasm_worker_preprocessor_flags(self): def test_debug_opt_warning(self): err = self.expect_fail([EMCC, test_file('hello_world.c'), '-O2', '-g', '-Werror']) self.assertContained('error: running limited binaryen optimizations because DWARF info requested (or indirectly required) [-Wlimited-postlink-optimizations]', err) + + def test_clock_nanosleep(self): + self.do_runf(test_file('other/test_clock_nanosleep.c'))