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;
55const SpinLock = std.SpinLock;
66const ResetEvent = std.ResetEvent;
77
8/// Lock may be held only once. If the same thread
9/// tries to acquire the same mutex twice, it deadlocks.
10/// This type supports static initialization and is at most `@sizeOf(usize)` in size.
11/// When an application is built in single threaded release mode, all the functions are
12/// no-ops. In single threaded debug mode, there is deadlock detection.
8/// Lock may be held only once. If the same thread tries to acquire
9/// the same mutex twice, it deadlocks. This type supports static
10/// initialization and is at most `@sizeOf(usize)` in size. When an
11/// application is built in single threaded release mode, all the
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/// }
1330pub const Mutex = if (builtin.single_threaded)
1431 struct {
1532 lock: @TypeOf(lock_init),
......@@ -26,14 +43,21 @@ pub const Mutex = if (builtin.single_threaded)
2643 }
2744 };
2845
46 /// Create a new mutex in unlocked state.
2947 pub fn init() Mutex {
3048 return Mutex{ .lock = lock_init };
3149 }
3250
51 /// Free a mutex created with init. Calling this while the
52 /// mutex is held may result in safety-checked undefined
53 /// behavior.
3354 pub fn deinit(self: *Mutex) void {
3455 self.* = undefined;
3556 }
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.
3761 pub fn tryAcquire(self: *Mutex) ?Held {
3862 if (std.debug.runtime_safety) {
3963 if (self.lock) return null;
......@@ -42,6 +66,8 @@ pub const Mutex = if (builtin.single_threaded)
4266 return Held{ .mutex = self };
4367 }
4468
69 /// Acquire the mutex. Will deadlock if the mutex is already
70 /// held by the calling thread.
4571 pub fn acquire(self: *Mutex) Held {
4672 return self.tryAcquire() orelse @panic("deadlock detected");
4773 }
......@@ -200,9 +226,12 @@ else if (builtin.link_libc or builtin.os == .linux)
200226 }
201227 }
202228
229 /// Returned when the lock is acquired. Call release to
230 /// release.
203231 pub const Held = struct {
204232 mutex: *Mutex,
205233
234 /// Release the held lock.
206235 pub fn release(self: Held) void {
207236 // first, remove the lock bit so another possibly parallel acquire() can succeed.
208237 // use .Sub since it can be usually compiled down more efficiency