relibc: fix pthread_cond_signal POSIX semantics bug

src/sync/cond.rs:signal() was calling self.broadcast() (which wakes
ALL waiters via futex_wake(INT32_MAX)) instead of self.wake(1) (which
wakes exactly one).

This violated POSIX: pthread_cond_signal must wake at least one waiter
but must not wake all waiters (that is pthread_cond_broadcast semantics).

The pre-existing code also had a commented-out self.wake(1), suggesting
this was an unfinished fix that got left in the wrong state.

Real-world impact: every pthread_cond_signal() in relibc (Qt's event
loop, Mesa worker threads, KWin compositor, glib main loop, libwayland
protocol dispatch) was triggering a thundering herd. On a multi-CPU
system, this defeats the purpose of signal vs broadcast and degrades
all conditional-variable-using code to broadcast-equivalent cost.

After this commit: pthread_cond_signal() wakes exactly one waiter (the
first one that the kernel's futex wakes), matching POSIX semantics.

Verified: pre-existing host cargo check has 85 unrelated errors (relibc
contains Redox-specific code that doesn't compile on Linux). The change
in cond.rs introduces zero new errors. Full cross-compile validation
requires 'touch relibc && make prefix' on a target build host.

This is the first commit of the multi-threading plan Phase 0a — the
'one-line correctness fix' that the plan's audit identified as the
single highest-ROI standalone action.
This commit is contained in:
2026-07-02 06:23:13 +03:00
parent a725e6ac8c
commit 6caad3a538
+8 -2
View File
@@ -61,8 +61,14 @@ impl Cond {
self.wake(i32::MAX)
}
pub fn signal(&self) -> Result<(), Errno> {
self.broadcast()
//self.wake(1)
// POSIX requires pthread_cond_signal to wake AT LEAST ONE waiter that
// is currently waiting on the condition variable, but it must not
// wake all waiters (that is pthread_cond_broadcast semantics).
// Wake exactly one via FUTEX_WAKE with count=1. Using broadcast() here
// was a thundering-herd bug: every cond_signal woke every waiter on
// every CPU. Fixed 2026-07-02 (Red Bear OS multi-threading plan,
// Phase 0a).
self.wake(1)
}
pub fn clockwait(
&self,