From c0be5bd9de998a872a75fd830ecc11686b213c9d Mon Sep 17 00:00:00 2001 From: Stefan Mielke Date: Thu, 15 Oct 2026 03:18:41 +0000 Subject: [PATCH] Normalize Channel timeout deadlines lovrChannelPush/lovrChannelPop built the cnd_timedwait deadline without carrying tv_nsec overflow into tv_sec. When start.tv_nsec + fraction * 1e9 reached 1e9, cnd_timedwait failed immediately (EINVAL) while still holding the channel lock, and the loop retried until the clock rolled into the next second, blocking other threads on that channel for up to ~1 second. --- src/modules/thread/thread.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/modules/thread/thread.c b/src/modules/thread/thread.c index bc64c9191..7690c034b 100644 --- a/src/modules/thread/thread.c +++ b/src/modules/thread/thread.c @@ -263,6 +263,10 @@ bool lovrChannelPush(Channel* channel, Variant* variant, double timeout, uint64_ fraction = modf(timeout, &whole); until.tv_sec = start.tv_sec + whole; until.tv_nsec = start.tv_nsec + fraction * 1e9; + if (until.tv_nsec >= 1000000000) { + until.tv_sec++; + until.tv_nsec -= 1000000000; + } cnd_timedwait(&channel->cond, &channel->lock, &until); timespec_get(&stop, TIME_UTC); timeout -= (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / 1e9; @@ -304,6 +308,10 @@ bool lovrChannelPop(Channel* channel, Variant* variant, double timeout) { fraction = modf(timeout, &whole); until.tv_sec = start.tv_sec + whole; until.tv_nsec = start.tv_nsec + fraction * 1e9; + if (until.tv_nsec >= 1000000000) { + until.tv_sec++; + until.tv_nsec -= 1000000000; + } cnd_timedwait(&channel->cond, &channel->lock, &until); timespec_get(&stop, TIME_UTC); timeout -= (stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec) / (double) 1e9;