aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Thread
diff options
context:
space:
mode:
authorMartin Wickham <spexguy070@gmail.com>2021-09-29 18:37:12 -0500
committerAndrew Kelley <andrew@ziglang.org>2021-09-30 17:39:01 -0400
commitf87156e33c688effcf00b8fa9c2542391423ee78 (patch)
tree6b209218f51ca1a9e70bf246e364be7534cfd3fa /lib/std/Thread
parent2ed9288246821c39ae75fa21998a53b34e713cd4 (diff)
downloadzig-f87156e33c688effcf00b8fa9c2542391423ee78.tar.gz
zig-f87156e33c688effcf00b8fa9c2542391423ee78.zip
Add a panic handler to give better errors for crashes in sema
Diffstat (limited to 'lib/std/Thread')
-rw-r--r--lib/std/Thread/Mutex.zig177
1 files changed, 97 insertions, 80 deletions
diff --git a/lib/std/Thread/Mutex.zig b/lib/std/Thread/Mutex.zig
index a337809a18..7473d9ec7f 100644
--- a/lib/std/Thread/Mutex.zig
+++ b/lib/std/Thread/Mutex.zig
@@ -33,17 +33,29 @@ const testing = std.testing;
const StaticResetEvent = std.thread.StaticResetEvent;
/// Try to acquire the mutex without blocking. Returns `null` if the mutex is
-/// unavailable. Otherwise returns `Held`. Call `release` on `Held`.
-pub fn tryAcquire(m: *Mutex) ?Impl.Held {
+/// unavailable. Otherwise returns `Held`. Call `release` on `Held`, or use
+/// releaseDirect().
+pub fn tryAcquire(m: *Mutex) ?Held {
return m.impl.tryAcquire();
}
/// Acquire the mutex. Deadlocks if the mutex is already
/// held by the calling thread.
-pub fn acquire(m: *Mutex) Impl.Held {
+pub fn acquire(m: *Mutex) Held {
return m.impl.acquire();
}
+/// Release the mutex. Prefer Held.release() if available.
+pub fn releaseDirect(m: *Mutex) void {
+ return m.impl.releaseDirect();
+}
+
+/// A held mutex handle. Call release to allow other threads to
+/// take the mutex. Do not call release() more than once.
+/// For more complex scenarios, this handle can be discarded
+/// and Mutex.releaseDirect can be called instead.
+pub const Held = Impl.Held;
+
const Impl = if (builtin.single_threaded)
Dummy
else if (builtin.os.tag == .windows)
@@ -53,6 +65,32 @@ else if (std.Thread.use_pthreads)
else
AtomicMutex;
+fn HeldInterface(comptime MutexType: type) type {
+ return struct {
+ const Mixin = @This();
+ pub const Held = struct {
+ mutex: *MutexType,
+
+ pub fn release(held: Mixin.Held) void {
+ held.mutex.releaseDirect();
+ }
+ };
+
+ pub fn tryAcquire(m: *MutexType) ?Mixin.Held {
+ if (m.tryAcquireDirect()) {
+ return Mixin.Held{ .mutex = m };
+ } else {
+ return null;
+ }
+ }
+
+ pub fn acquire(m: *MutexType) Mixin.Held {
+ m.acquireDirect();
+ return Mixin.Held{ .mutex = m };
+ }
+ };
+}
+
pub const AtomicMutex = struct {
state: State = .unlocked,
@@ -62,39 +100,32 @@ pub const AtomicMutex = struct {
waiting,
};
- pub const Held = struct {
- mutex: *AtomicMutex,
+ pub usingnamespace HeldInterface(@This());
- pub fn release(held: Held) void {
- switch (@atomicRmw(State, &held.mutex.state, .Xchg, .unlocked, .Release)) {
- .unlocked => unreachable,
- .locked => {},
- .waiting => held.mutex.unlockSlow(),
- }
- }
- };
-
- pub fn tryAcquire(m: *AtomicMutex) ?Held {
- if (@cmpxchgStrong(
+ fn tryAcquireDirect(m: *AtomicMutex) bool {
+ return @cmpxchgStrong(
State,
&m.state,
.unlocked,
.locked,
.Acquire,
.Monotonic,
- ) == null) {
- return Held{ .mutex = m };
- } else {
- return null;
- }
+ ) == null;
}
- pub fn acquire(m: *AtomicMutex) Held {
+ fn acquireDirect(m: *AtomicMutex) void {
switch (@atomicRmw(State, &m.state, .Xchg, .locked, .Acquire)) {
.unlocked => {},
else => |s| m.lockSlow(s),
}
- return Held{ .mutex = m };
+ }
+
+ fn releaseDirect(m: *AtomicMutex) void {
+ switch (@atomicRmw(State, &m.state, .Xchg, .unlocked, .Release)) {
+ .unlocked => unreachable,
+ .locked => {},
+ .waiting => m.unlockSlow(),
+ }
}
fn lockSlow(m: *AtomicMutex, current_state: State) void {
@@ -171,36 +202,20 @@ pub const AtomicMutex = struct {
pub const PthreadMutex = struct {
pthread_mutex: std.c.pthread_mutex_t = .{},
- pub const Held = struct {
- mutex: *PthreadMutex,
-
- pub fn release(held: Held) void {
- switch (std.c.pthread_mutex_unlock(&held.mutex.pthread_mutex)) {
- .SUCCESS => return,
- .INVAL => unreachable,
- .AGAIN => unreachable,
- .PERM => unreachable,
- else => unreachable,
- }
- }
- };
+ pub usingnamespace HeldInterface(@This());
- /// Try to acquire the mutex without blocking. Returns null if
- /// the mutex is unavailable. Otherwise returns Held. Call
- /// release on Held.
- pub fn tryAcquire(m: *PthreadMutex) ?Held {
- if (std.c.pthread_mutex_trylock(&m.pthread_mutex) == .SUCCESS) {
- return Held{ .mutex = m };
- } else {
- return null;
- }
+ /// Try to acquire the mutex without blocking. Returns true if
+ /// the mutex is unavailable. Otherwise returns false. Call
+ /// release when done.
+ fn tryAcquireDirect(m: *PthreadMutex) bool {
+ return std.c.pthread_mutex_trylock(&m.pthread_mutex) == .SUCCESS;
}
/// Acquire the mutex. Will deadlock if the mutex is already
/// held by the calling thread.
- pub fn acquire(m: *PthreadMutex) Held {
+ fn acquireDirect(m: *PthreadMutex) void {
switch (std.c.pthread_mutex_lock(&m.pthread_mutex)) {
- .SUCCESS => return Held{ .mutex = m },
+ .SUCCESS => {},
.INVAL => unreachable,
.BUSY => unreachable,
.AGAIN => unreachable,
@@ -209,6 +224,16 @@ pub const PthreadMutex = struct {
else => unreachable,
}
}
+
+ fn releaseDirect(m: *PthreadMutex) void {
+ switch (std.c.pthread_mutex_unlock(&m.pthread_mutex)) {
+ .SUCCESS => return,
+ .INVAL => unreachable,
+ .AGAIN => unreachable,
+ .PERM => unreachable,
+ else => unreachable,
+ }
+ }
};
/// This has the sematics as `Mutex`, however it does not actually do any
@@ -216,58 +241,50 @@ pub const PthreadMutex = struct {
pub const Dummy = struct {
lock: @TypeOf(lock_init) = lock_init,
- const lock_init = if (std.debug.runtime_safety) false else {};
-
- pub const Held = struct {
- mutex: *Dummy,
+ pub usingnamespace HeldInterface(@This());
- pub fn release(held: Held) void {
- if (std.debug.runtime_safety) {
- held.mutex.lock = false;
- }
- }
- };
+ const lock_init = if (std.debug.runtime_safety) false else {};
- /// Try to acquire the mutex without blocking. Returns null if
- /// the mutex is unavailable. Otherwise returns Held. Call
- /// release on Held.
- pub fn tryAcquire(m: *Dummy) ?Held {
+ /// Try to acquire the mutex without blocking. Returns false if
+ /// the mutex is unavailable. Otherwise returns true.
+ fn tryAcquireDirect(m: *Dummy) bool {
if (std.debug.runtime_safety) {
- if (m.lock) return null;
+ if (m.lock) return false;
m.lock = true;
}
- return Held{ .mutex = m };
+ return true;
}
/// Acquire the mutex. Will deadlock if the mutex is already
/// held by the calling thread.
- pub fn acquire(m: *Dummy) Held {
- return m.tryAcquire() orelse @panic("deadlock detected");
+ fn acquireDirect(m: *Dummy) void {
+ if (!m.tryAcquireDirect()) {
+ @panic("deadlock detected");
+ }
+ }
+
+ fn releaseDirect(m: *Dummy) void {
+ if (std.debug.runtime_safety) {
+ m.lock = false;
+ }
}
};
const WindowsMutex = struct {
srwlock: windows.SRWLOCK = windows.SRWLOCK_INIT,
- pub const Held = struct {
- mutex: *WindowsMutex,
+ pub usingnamespace HeldInterface(@This());
- pub fn release(held: Held) void {
- windows.kernel32.ReleaseSRWLockExclusive(&held.mutex.srwlock);
- }
- };
-
- pub fn tryAcquire(m: *WindowsMutex) ?Held {
- if (windows.kernel32.TryAcquireSRWLockExclusive(&m.srwlock) != windows.FALSE) {
- return Held{ .mutex = m };
- } else {
- return null;
- }
+ fn tryAcquireDirect(m: *WindowsMutex) bool {
+ return windows.kernel32.TryAcquireSRWLockExclusive(&m.srwlock) != windows.FALSE;
}
- pub fn acquire(m: *WindowsMutex) Held {
+ fn acquireDirect(m: *WindowsMutex) void {
windows.kernel32.AcquireSRWLockExclusive(&m.srwlock);
- return Held{ .mutex = m };
+ }
+
+ fn releaseDirect(m: *WindowsMutex) void {
+ windows.kernel32.ReleaseSRWLockExclusive(&m.srwlock);
}
};