mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 02:24:33 +01:00
std.Thread.Condition: use pthread_cond_t impl when OS has no futex primitive
Same principle as #30835.
This commit is contained in:
parent
5f950884a1
commit
cf48041b55
1 changed files with 59 additions and 6 deletions
|
|
@ -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{};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue