authorgravatar for nathan@nmichaels.orgNathan Michaels <nathan@nmichaels.org> 2019-12-19 23:42:27-05:00
committergravatar for nathan@nmichaels.orgNathan Michaels <nathan@nmichaels.org> 2019-12-19 23:42:27-05:00
log33b5dbb82c3c68596ce41abcea6aea3834c0d3a7
treec032739d12a545006e530a64f00f45f3ea89b213
parent4d54e9a4fbb899a18f1d7b9e83bbb65f0973a0cb

Document std.Mutex.

Not sure what the build platform is for the generated documentation, and it's worth thinking about how best to deal with this pattern. It might be worth figuring out how to rewrite this to have a single definition of the public API with the implementation chosen at compile time.

1 files changed, 34 insertions(+), 5 deletions(-)

lib/std/mutex.zig+34-5
...@@ -5,11 +5,28 @@ const testing = std.testing;...@@ -5,11 +5,28 @@ const testing = std.testing;
5const SpinLock = std.SpinLock;5const SpinLock = std.SpinLock;
6const ResetEvent = std.ResetEvent;6const ResetEvent = std.ResetEvent;
77
8/// Lock may be held only once. If the same thread8/// Lock may be held only once. If the same thread tries to acquire
9/// tries to acquire the same mutex twice, it deadlocks.9/// the same mutex twice, it deadlocks. This type supports static
10/// This type supports static initialization and is at most `@sizeOf(usize)` in size.10/// initialization and is at most `@sizeOf(usize)` in size. When an
11/// When an application is built in single threaded release mode, all the functions are11/// application is built in single threaded release mode, all the
12/// no-ops. In single threaded debug mode, there is deadlock detection.12/// functions are no-ops. In single threaded debug mode, there is
13/// deadlock detection.
14///
15/// Example usage:
16/// var m = Mutex.init();
17/// defer m.deinit();
18///
19/// const lock = m.acquire();
20/// defer lock.release();
21/// ... critical code
22///
23/// Non-blocking:
24/// if (m.tryAcquire) |lock| {
25/// defer lock.release();
26/// // ... critical section
27/// } else {
28/// // ... lock not acquired
29/// }
13pub const Mutex = if (builtin.single_threaded)30pub const Mutex = if (builtin.single_threaded)
14 struct {31 struct {
15 lock: @TypeOf(lock_init),32 lock: @TypeOf(lock_init),
...@@ -26,14 +43,21 @@ pub const Mutex = if (builtin.single_threaded)...@@ -26,14 +43,21 @@ pub const Mutex = if (builtin.single_threaded)
26 }43 }
27 };44 };
2845
46 /// Create a new mutex in unlocked state.
29 pub fn init() Mutex {47 pub fn init() Mutex {
30 return Mutex{ .lock = lock_init };48 return Mutex{ .lock = lock_init };
31 }49 }
3250
51 /// Free a mutex created with init. Calling this while the
52 /// mutex is held may result in safety-checked undefined
53 /// behavior.
33 pub fn deinit(self: *Mutex) void {54 pub fn deinit(self: *Mutex) void {
34 self.* = undefined;55 self.* = undefined;
35 }56 }
3657
58 /// Try to acquire the mutex without blocking. Returns null if
59 /// the mutex is unavailable. Otherwise returns Held. Call
60 /// release on Held.
37 pub fn tryAcquire(self: *Mutex) ?Held {61 pub fn tryAcquire(self: *Mutex) ?Held {
38 if (std.debug.runtime_safety) {62 if (std.debug.runtime_safety) {
39 if (self.lock) return null;63 if (self.lock) return null;
...@@ -42,6 +66,8 @@ pub const Mutex = if (builtin.single_threaded)...@@ -42,6 +66,8 @@ pub const Mutex = if (builtin.single_threaded)
42 return Held{ .mutex = self };66 return Held{ .mutex = self };
43 }67 }
4468
69 /// Acquire the mutex. Will deadlock if the mutex is already
70 /// held by the calling thread.
45 pub fn acquire(self: *Mutex) Held {71 pub fn acquire(self: *Mutex) Held {
46 return self.tryAcquire() orelse @panic("deadlock detected");72 return self.tryAcquire() orelse @panic("deadlock detected");
47 }73 }
...@@ -200,9 +226,12 @@ else if (builtin.link_libc or builtin.os == .linux)...@@ -200,9 +226,12 @@ else if (builtin.link_libc or builtin.os == .linux)
200 }226 }
201 }227 }
202228
229 /// Returned when the lock is acquired. Call release to
230 /// release.
203 pub const Held = struct {231 pub const Held = struct {
204 mutex: *Mutex,232 mutex: *Mutex,
205233
234 /// Release the held lock.
206 pub fn release(self: Held) void {235 pub fn release(self: Held) void {
207 // first, remove the lock bit so another possibly parallel acquire() can succeed.236 // first, remove the lock bit so another possibly parallel acquire() can succeed.
208 // use .Sub since it can be usually compiled down more efficiency237 // use .Sub since it can be usually compiled down more efficiency