std.Thread.Condition: use pthread_cond_t impl when OS has no futex primitive

Same principle as #30835.
This commit is contained in:
Alex Rønne Petersen 2026-01-24 05:30:27 +01:00
parent 5f950884a1
commit cf48041b55

View file

@ -107,12 +107,30 @@ pub fn broadcast(self: *Condition) void {
self.impl.wake(.all);
}
const Impl = if (builtin.single_threaded)
SingleThreadedImpl
else if (builtin.os.tag == .windows)
WindowsImpl
else
FutexImpl;
const Impl = Impl: {
if (builtin.single_threaded) break :Impl SingleThreadedImpl;
if (builtin.os.tag == .windows) break :Impl WindowsImpl;
if (builtin.os.tag.isDarwin() or
builtin.target.os.tag == .linux or
builtin.target.os.tag == .freebsd or
builtin.target.os.tag == .openbsd or
builtin.target.os.tag == .dragonfly or
builtin.target.cpu.arch.isWasm())
{
// Futex is the system's synchronization primitive; use that.
break :Impl FutexImpl;
}
if (std.Thread.use_pthreads) {
// This system doesn't have a futex primitive, so `std.Thread.Futex` is using `PosixImpl`,
// which implements futex *on top of* pthread mutexes and conditions. Therefore, instead
// of going through that long inefficient path, just use pthread condition variable directly.
break :Impl PosixImpl;
}
break :Impl FutexImpl;
};
const Notify = enum {
one, // wake up only one thread
@ -291,6 +309,41 @@ const FutexImpl = struct {
}
};
const PosixImpl = struct {
cond: std.c.pthread_cond_t = .{},
fn wait(self: *Impl, mutex: *Mutex, timeout: ?u64) error{Timeout}!void {
if (builtin.mode == .Debug) {
mutex.impl.locking_thread.store(0, .unordered);
}
defer if (builtin.mode == .Debug) {
mutex.impl.locking_thread.store(std.Thread.getCurrentId(), .unordered);
};
const mtx = if (builtin.mode == .Debug) &mutex.impl.impl.mutex else &mutex.impl.mutex;
if (timeout) |t| {
switch (std.c.pthread_cond_timedwait(&self.cond, mtx, &.{
.sec = @intCast(@divFloor(t, std.time.ns_per_s)),
.nsec = @intCast(@mod(t, std.time.ns_per_s)),
})) {
.SUCCESS => return,
.TIMEDOUT => return error.Timeout,
else => unreachable,
}
}
assert(std.c.pthread_cond_wait(&self.cond, mtx) == .SUCCESS);
}
fn wake(self: *Impl, comptime notify: Notify) void {
assert(switch (notify) {
.one => std.c.pthread_cond_signal(&self.cond),
.all => std.c.pthread_cond_broadcast(&self.cond),
} == .SUCCESS);
}
};
test "smoke test" {
var mutex = Mutex{};
var cond = Condition{};