| ... | ... | @@ -45,14 +45,30 @@ const Impl = if (builtin.mode == .Debug and !builtin.single_threaded) |
| 45 | 45 | else |
| 46 | 46 | ReleaseImpl; |
| 47 | 47 | |
| 48 | | const ReleaseImpl = if (builtin.single_threaded) |
| 49 | | SingleThreadedImpl |
| 50 | | else if (builtin.os.tag == .windows) |
| 51 | | WindowsImpl |
| 52 | | else if (builtin.os.tag.isDarwin()) |
| 53 | | DarwinImpl |
| 54 | | else |
| 55 | | FutexImpl; |
| 48 | const ReleaseImpl = Impl: { |
| 49 | if (builtin.single_threaded) break :Impl SingleThreadedImpl; |
| 50 | if (builtin.os.tag == .windows) break :Impl WindowsImpl; |
| 51 | if (builtin.os.tag.isDarwin()) break :Impl DarwinImpl; |
| 52 | |
| 53 | if (builtin.target.os.tag == .linux or |
| 54 | builtin.target.os.tag == .freebsd or |
| 55 | builtin.target.os.tag == .openbsd or |
| 56 | builtin.target.os.tag == .dragonfly or |
| 57 | builtin.target.cpu.arch.isWasm()) |
| 58 | { |
| 59 | // Futex is the system's synchronization primitive; use that. |
| 60 | break :Impl FutexImpl; |
| 61 | } |
| 62 | |
| 63 | if (std.Thread.use_pthreads) { |
| 64 | // This system doesn't have a futex primitive, so `std.Thread.Futex` is using `PosixImpl`, |
| 65 | // which implements futex *on top of* pthread mutexes and conditions. Therefore, instead |
| 66 | // of going through that long inefficient path, just use pthread mutex directly. |
| 67 | break :Impl PosixImpl; |
| 68 | } |
| 69 | |
| 70 | break :Impl FutexImpl; |
| 71 | }; |
| 56 | 72 | |
| 57 | 73 | const DebugImpl = struct { |
| 58 | 74 | locking_thread: std.atomic.Value(Thread.Id) = std.atomic.Value(Thread.Id).init(0), // 0 means it's not locked. |
| ... | ... | @@ -208,6 +224,37 @@ const FutexImpl = struct { |
| 208 | 224 | } |
| 209 | 225 | }; |
| 210 | 226 | |
| 227 | const PosixImpl = struct { |
| 228 | mutex: std.c.pthread_mutex_t = .{}, |
| 229 | |
| 230 | fn tryLock(impl: *PosixImpl) bool { |
| 231 | switch (std.c.pthread_mutex_trylock(&impl.mutex)) { |
| 232 | .SUCCESS => return true, |
| 233 | .BUSY => return false, |
| 234 | .INVAL => unreachable, // mutex is initialized correctly |
| 235 | else => unreachable, |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | fn lock(impl: *PosixImpl) void { |
| 240 | switch (std.c.pthread_mutex_lock(&impl.mutex)) { |
| 241 | .SUCCESS => return, |
| 242 | .INVAL => unreachable, // mutex is initialized correctly |
| 243 | .DEADLK => unreachable, // not an error checking mutex |
| 244 | else => unreachable, |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | fn unlock(impl: *PosixImpl) void { |
| 249 | switch (std.c.pthread_mutex_unlock(&impl.mutex)) { |
| 250 | .SUCCESS => return, |
| 251 | .INVAL => unreachable, // mutex is initialized correctly |
| 252 | .PERM => unreachable, // not an error checking mutex |
| 253 | else => unreachable, |
| 254 | } |
| 255 | } |
| 256 | }; |
| 257 | |
| 211 | 258 | test "smoke test" { |
| 212 | 259 | var mutex = Mutex{}; |
| 213 | 260 | |