Windows: round sleep to clock resolution to prevent sub-ms early-wake logs (#20887)
Windows: round sleep to clock resolution to prevent sub-ms early-wake logs\n\n- Round requested duration up to (1ms with timeBeginPeriod(1))\n- Use a single call; no EINTR-like loop needed on Windows\n- Avoid sub-millisecond under-sleep that caused "woke up earlier than expected" logs under MSYS2\n- Do not busy-wait; no extra now_realtime_usec() call before sleep
Costa Tsaousis committed
Aug 25, 2025 at 17:42 UTC
e48b6ac2a854af8fc3b1fdf171c468ecd2f38256
1 file changed
+16
-15
src/libnetdata/clocks/clocks.c
+16
-15
@@ -421,23 +421,24 @@ usec_t heartbeat_next(heartbeat_t *hb) {
421
}
422
423
#if defined(OS_WINDOWS)
424
-void sleep_usec_with_now(usec_t usec, usec_t started_ut) {
425
- if (!started_ut)
426
- started_ut = now_realtime_usec();
427
-
428
- usec_t end_ut = started_ut + usec;
429
- usec_t remaining_ut = usec;
430
-
431
- while (remaining_ut >= clock_realtime_resolution) {
432
- DWORD sleep_ms = (DWORD) (remaining_ut / USEC_PER_MS);
433
- Sleep(sleep_ms);
424
+void sleep_usec_with_now(usec_t usec, usec_t started_ut __maybe_unused) {
425
+ if (usec == 0)
426
+ return;
427
+
428
+ // Honor Windows timer granularity by rounding the requested duration
429
+ // up to the next multiple of the effective clock resolution.
430
+ usec_t res_ut = clock_realtime_resolution ? clock_realtime_resolution : USEC_PER_MS;
431
+ usec_t to_sleep_ut = usec;
432
+ if (res_ut) {
433
+ to_sleep_ut = ((to_sleep_ut + res_ut - 1) / res_ut) * res_ut; // round up
434
+ }
435
435
- usec_t now_ut = now_realtime_usec();
436
- if (now_ut >= end_ut)
437
- break;
436
+ // Convert microseconds to milliseconds for Sleep(), rounding up
437
+ DWORD sleep_ms = (DWORD)((to_sleep_ut + (USEC_PER_MS - 1)) / USEC_PER_MS);
438
+ if (sleep_ms == 0)
439
+ sleep_ms = 1; // safety: always sleep at least 1ms
440
439
- remaining_ut = end_ut - now_ut;
440
- }
441
+ Sleep(sleep_ms);
442
}
443
#else
444
void sleep_usec_with_now(usec_t usec, usec_t started_ut) {