authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-09 18:27:12-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-09 18:31:03-07:00
log008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
tree99374a7b0f5dc0bf56fc5daff702eecb7758d4f5
parent65e518e8e8ab74b276c5a284caebfad4e5aa502c

std.Thread.Mutex: change API to lock() and unlock()

This is a breaking change. Before, usage looked like this: ```zig const held = mutex.acquire(); defer held.release(); ``` Now it looks like this: ```zig mutex.lock(); defer mutex.unlock(); ``` The `Held` type was an idea to make mutexes slightly safer by making it more difficult to forget to release an aquired lock. However, this ultimately caused more problems than it solved, when any data structures needed to store a held mutex. Simplify everything by reducing the API down to the primitives: lock() and unlock(). Closes #8051 Closes #8246 Closes #10105

18 files changed, 140 insertions(+), 179 deletions(-)

lib/std/Progress.zig+9-9
...@@ -56,7 +56,7 @@ done: bool = true,...@@ -56,7 +56,7 @@ done: bool = true,
56/// Protects the `refresh` function, as well as `node.recently_updated_child`.56/// Protects the `refresh` function, as well as `node.recently_updated_child`.
57/// Without this, callsites would call `Node.end` and then free `Node` memory57/// Without this, callsites would call `Node.end` and then free `Node` memory
58/// while it was still being accessed by the `refresh` function.58/// while it was still being accessed by the `refresh` function.
59update_lock: std.Thread.Mutex = .{},59update_mutex: std.Thread.Mutex = .{},
6060
61/// Keeps track of how many columns in the terminal have been output, so that61/// Keeps track of how many columns in the terminal have been output, so that
62/// we can move the cursor back later.62/// we can move the cursor back later.
...@@ -103,14 +103,14 @@ pub const Node = struct {...@@ -103,14 +103,14 @@ pub const Node = struct {
103 self.context.maybeRefresh();103 self.context.maybeRefresh();
104 if (self.parent) |parent| {104 if (self.parent) |parent| {
105 {105 {
106 const held = self.context.update_lock.acquire();106 self.context.update_mutex.lock();
107 defer held.release();107 defer self.context.update_mutex.unlock();
108 _ = @cmpxchgStrong(?*Node, &parent.recently_updated_child, self, null, .Monotonic, .Monotonic);108 _ = @cmpxchgStrong(?*Node, &parent.recently_updated_child, self, null, .Monotonic, .Monotonic);
109 }109 }
110 parent.completeOne();110 parent.completeOne();
111 } else {111 } else {
112 const held = self.context.update_lock.acquire();112 self.context.update_mutex.lock();
113 defer held.release();113 defer self.context.update_mutex.unlock();
114 self.context.done = true;114 self.context.done = true;
115 self.context.refreshWithHeldLock();115 self.context.refreshWithHeldLock();
116 }116 }
...@@ -170,8 +170,8 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) !*...@@ -170,8 +170,8 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) !*
170pub fn maybeRefresh(self: *Progress) void {170pub fn maybeRefresh(self: *Progress) void {
171 const now = self.timer.read();171 const now = self.timer.read();
172 if (now < self.initial_delay_ns) return;172 if (now < self.initial_delay_ns) return;
173 const held = self.update_lock.tryAcquire() orelse return;173 if (!self.update_mutex.tryLock()) return;
174 defer held.release();174 defer self.update_mutex.unlock();
175 // TODO I have observed this to happen sometimes. I think we need to follow Rust's175 // TODO I have observed this to happen sometimes. I think we need to follow Rust's
176 // lead and guarantee monotonically increasing times in the std lib itself.176 // lead and guarantee monotonically increasing times in the std lib itself.
177 if (now < self.prev_refresh_timestamp) return;177 if (now < self.prev_refresh_timestamp) return;
...@@ -181,8 +181,8 @@ pub fn maybeRefresh(self: *Progress) void {...@@ -181,8 +181,8 @@ pub fn maybeRefresh(self: *Progress) void {
181181
182/// Updates the terminal and resets `self.next_refresh_timestamp`. Thread-safe.182/// Updates the terminal and resets `self.next_refresh_timestamp`. Thread-safe.
183pub fn refresh(self: *Progress) void {183pub fn refresh(self: *Progress) void {
184 const held = self.update_lock.tryAcquire() orelse return;184 if (!self.update_mutex.tryLock()) return;
185 defer held.release();185 defer self.update_mutex.unlock();
186186
187 return self.refreshWithHeldLock();187 return self.refreshWithHeldLock();
188}188}
lib/std/Thread/Condition.zig+6-6
...@@ -145,8 +145,8 @@ pub const AtomicCondition = struct {...@@ -145,8 +145,8 @@ pub const AtomicCondition = struct {
145 var waiter = QueueList.Node{ .data = .{} };145 var waiter = QueueList.Node{ .data = .{} };
146146
147 {147 {
148 const held = cond.queue_mutex.acquire();148 cond.queue_mutex.lock();
149 defer held.release();149 defer cond.queue_mutex.unlock();
150150
151 cond.queue_list.prepend(&waiter);151 cond.queue_list.prepend(&waiter);
152 @atomicStore(bool, &cond.pending, true, .SeqCst);152 @atomicStore(bool, &cond.pending, true, .SeqCst);
...@@ -162,8 +162,8 @@ pub const AtomicCondition = struct {...@@ -162,8 +162,8 @@ pub const AtomicCondition = struct {
162 return;162 return;
163163
164 const maybe_waiter = blk: {164 const maybe_waiter = blk: {
165 const held = cond.queue_mutex.acquire();165 cond.queue_mutex.lock();
166 defer held.release();166 defer cond.queue_mutex.unlock();
167167
168 const maybe_waiter = cond.queue_list.popFirst();168 const maybe_waiter = cond.queue_list.popFirst();
169 @atomicStore(bool, &cond.pending, cond.queue_list.first != null, .SeqCst);169 @atomicStore(bool, &cond.pending, cond.queue_list.first != null, .SeqCst);
...@@ -181,8 +181,8 @@ pub const AtomicCondition = struct {...@@ -181,8 +181,8 @@ pub const AtomicCondition = struct {
181 @atomicStore(bool, &cond.pending, false, .SeqCst);181 @atomicStore(bool, &cond.pending, false, .SeqCst);
182182
183 var waiters = blk: {183 var waiters = blk: {
184 const held = cond.queue_mutex.acquire();184 cond.queue_mutex.lock();
185 defer held.release();185 defer cond.queue_mutex.unlock();
186186
187 const waiters = cond.queue_list;187 const waiters = cond.queue_list;
188 cond.queue_list = .{};188 cond.queue_list = .{};
lib/std/Thread/Mutex.zig+32-74
...@@ -8,13 +8,13 @@...@@ -8,13 +8,13 @@
8//! Example usage:8//! Example usage:
9//! var m = Mutex{};9//! var m = Mutex{};
10//!10//!
11//! const lock = m.acquire();11//! m.lock();
12//! defer lock.release();12//! defer m.release();
13//! ... critical code13//! ... critical code
14//!14//!
15//! Non-blocking:15//! Non-blocking:
16//! if (m.tryAcquire) |lock| {16//! if (m.tryLock()) {
17//! defer lock.release();17//! defer m.unlock();
18//! // ... critical section18//! // ... critical section
19//! } else {19//! } else {
20//! // ... lock not acquired20//! // ... lock not acquired
...@@ -32,30 +32,22 @@ const linux = os.linux;...@@ -32,30 +32,22 @@ const linux = os.linux;
32const testing = std.testing;32const testing = std.testing;
33const StaticResetEvent = std.thread.StaticResetEvent;33const StaticResetEvent = std.thread.StaticResetEvent;
3434
35/// Try to acquire the mutex without blocking. Returns `null` if the mutex is35/// Try to acquire the mutex without blocking. Returns `false` if the mutex is
36/// unavailable. Otherwise returns `Held`. Call `release` on `Held`, or use36/// unavailable. Otherwise returns `true`. Call `unlock` on the mutex to release.
37/// releaseDirect().37pub fn tryLock(m: *Mutex) bool {
38pub fn tryAcquire(m: *Mutex) ?Held {38 return m.impl.tryLock();
39 return m.impl.tryAcquire();
40}39}
4140
42/// Acquire the mutex. Deadlocks if the mutex is already41/// Acquire the mutex. Deadlocks if the mutex is already
43/// held by the calling thread.42/// held by the calling thread.
44pub fn acquire(m: *Mutex) Held {43pub fn lock(m: *Mutex) void {
45 return m.impl.acquire();44 m.impl.lock();
46}45}
4746
48/// Release the mutex. Prefer Held.release() if available.47pub fn unlock(m: *Mutex) void {
49pub fn releaseDirect(m: *Mutex) void {48 m.impl.unlock();
50 return m.impl.releaseDirect();
51}49}
5250
53/// A held mutex handle. Call release to allow other threads to
54/// take the mutex. Do not call release() more than once.
55/// For more complex scenarios, this handle can be discarded
56/// and Mutex.releaseDirect can be called instead.
57pub const Held = Impl.Held;
58
59const Impl = if (builtin.single_threaded)51const Impl = if (builtin.single_threaded)
60 Dummy52 Dummy
61else if (builtin.os.tag == .windows)53else if (builtin.os.tag == .windows)
...@@ -65,32 +57,6 @@ else if (std.Thread.use_pthreads)...@@ -65,32 +57,6 @@ else if (std.Thread.use_pthreads)
65else57else
66 AtomicMutex;58 AtomicMutex;
6759
68fn HeldInterface(comptime MutexType: type) type {
69 return struct {
70 const Mixin = @This();
71 pub const Held = struct {
72 mutex: *MutexType,
73
74 pub fn release(held: Mixin.Held) void {
75 held.mutex.releaseDirect();
76 }
77 };
78
79 pub fn tryAcquire(m: *MutexType) ?Mixin.Held {
80 if (m.tryAcquireDirect()) {
81 return Mixin.Held{ .mutex = m };
82 } else {
83 return null;
84 }
85 }
86
87 pub fn acquire(m: *MutexType) Mixin.Held {
88 m.acquireDirect();
89 return Mixin.Held{ .mutex = m };
90 }
91 };
92}
93
94pub const AtomicMutex = struct {60pub const AtomicMutex = struct {
95 state: State = .unlocked,61 state: State = .unlocked,
9662
...@@ -100,9 +66,7 @@ pub const AtomicMutex = struct {...@@ -100,9 +66,7 @@ pub const AtomicMutex = struct {
100 waiting,66 waiting,
101 };67 };
10268
103 pub usingnamespace HeldInterface(@This());69 pub fn tryLock(m: *AtomicMutex) bool {
104
105 fn tryAcquireDirect(m: *AtomicMutex) bool {
106 return @cmpxchgStrong(70 return @cmpxchgStrong(
107 State,71 State,
108 &m.state,72 &m.state,
...@@ -113,14 +77,14 @@ pub const AtomicMutex = struct {...@@ -113,14 +77,14 @@ pub const AtomicMutex = struct {
113 ) == null;77 ) == null;
114 }78 }
11579
116 fn acquireDirect(m: *AtomicMutex) void {80 pub fn lock(m: *AtomicMutex) void {
117 switch (@atomicRmw(State, &m.state, .Xchg, .locked, .Acquire)) {81 switch (@atomicRmw(State, &m.state, .Xchg, .locked, .Acquire)) {
118 .unlocked => {},82 .unlocked => {},
119 else => |s| m.lockSlow(s),83 else => |s| m.lockSlow(s),
120 }84 }
121 }85 }
12286
123 fn releaseDirect(m: *AtomicMutex) void {87 pub fn unlock(m: *AtomicMutex) void {
124 switch (@atomicRmw(State, &m.state, .Xchg, .unlocked, .Release)) {88 switch (@atomicRmw(State, &m.state, .Xchg, .unlocked, .Release)) {
125 .unlocked => unreachable,89 .unlocked => unreachable,
126 .locked => {},90 .locked => {},
...@@ -202,18 +166,16 @@ pub const AtomicMutex = struct {...@@ -202,18 +166,16 @@ pub const AtomicMutex = struct {
202pub const PthreadMutex = struct {166pub const PthreadMutex = struct {
203 pthread_mutex: std.c.pthread_mutex_t = .{},167 pthread_mutex: std.c.pthread_mutex_t = .{},
204168
205 pub usingnamespace HeldInterface(@This());
206
207 /// Try to acquire the mutex without blocking. Returns true if169 /// Try to acquire the mutex without blocking. Returns true if
208 /// the mutex is unavailable. Otherwise returns false. Call170 /// the mutex is unavailable. Otherwise returns false. Call
209 /// release when done.171 /// release when done.
210 fn tryAcquireDirect(m: *PthreadMutex) bool {172 pub fn tryLock(m: *PthreadMutex) bool {
211 return std.c.pthread_mutex_trylock(&m.pthread_mutex) == .SUCCESS;173 return std.c.pthread_mutex_trylock(&m.pthread_mutex) == .SUCCESS;
212 }174 }
213175
214 /// Acquire the mutex. Will deadlock if the mutex is already176 /// Acquire the mutex. Will deadlock if the mutex is already
215 /// held by the calling thread.177 /// held by the calling thread.
216 fn acquireDirect(m: *PthreadMutex) void {178 pub fn lock(m: *PthreadMutex) void {
217 switch (std.c.pthread_mutex_lock(&m.pthread_mutex)) {179 switch (std.c.pthread_mutex_lock(&m.pthread_mutex)) {
218 .SUCCESS => {},180 .SUCCESS => {},
219 .INVAL => unreachable,181 .INVAL => unreachable,
...@@ -225,7 +187,7 @@ pub const PthreadMutex = struct {...@@ -225,7 +187,7 @@ pub const PthreadMutex = struct {
225 }187 }
226 }188 }
227189
228 fn releaseDirect(m: *PthreadMutex) void {190 pub fn unlock(m: *PthreadMutex) void {
229 switch (std.c.pthread_mutex_unlock(&m.pthread_mutex)) {191 switch (std.c.pthread_mutex_unlock(&m.pthread_mutex)) {
230 .SUCCESS => return,192 .SUCCESS => return,
231 .INVAL => unreachable,193 .INVAL => unreachable,
...@@ -239,51 +201,47 @@ pub const PthreadMutex = struct {...@@ -239,51 +201,47 @@ pub const PthreadMutex = struct {
239/// This has the sematics as `Mutex`, however it does not actually do any201/// This has the sematics as `Mutex`, however it does not actually do any
240/// synchronization. Operations are safety-checked no-ops.202/// synchronization. Operations are safety-checked no-ops.
241pub const Dummy = struct {203pub const Dummy = struct {
242 lock: @TypeOf(lock_init) = lock_init,204 locked: @TypeOf(lock_init) = lock_init,
243
244 pub usingnamespace HeldInterface(@This());
245205
246 const lock_init = if (std.debug.runtime_safety) false else {};206 const lock_init = if (std.debug.runtime_safety) false else {};
247207
248 /// Try to acquire the mutex without blocking. Returns false if208 /// Try to acquire the mutex without blocking. Returns false if
249 /// the mutex is unavailable. Otherwise returns true.209 /// the mutex is unavailable. Otherwise returns true.
250 fn tryAcquireDirect(m: *Dummy) bool {210 pub fn tryLock(m: *Dummy) bool {
251 if (std.debug.runtime_safety) {211 if (std.debug.runtime_safety) {
252 if (m.lock) return false;212 if (m.locked) return false;
253 m.lock = true;213 m.locked = true;
254 }214 }
255 return true;215 return true;
256 }216 }
257217
258 /// Acquire the mutex. Will deadlock if the mutex is already218 /// Acquire the mutex. Will deadlock if the mutex is already
259 /// held by the calling thread.219 /// held by the calling thread.
260 fn acquireDirect(m: *Dummy) void {220 pub fn lock(m: *Dummy) void {
261 if (!m.tryAcquireDirect()) {221 if (!m.tryLock()) {
262 @panic("deadlock detected");222 @panic("deadlock detected");
263 }223 }
264 }224 }
265225
266 fn releaseDirect(m: *Dummy) void {226 pub fn unlock(m: *Dummy) void {
267 if (std.debug.runtime_safety) {227 if (std.debug.runtime_safety) {
268 m.lock = false;228 m.locked = false;
269 }229 }
270 }230 }
271};231};
272232
273const WindowsMutex = struct {233pub const WindowsMutex = struct {
274 srwlock: windows.SRWLOCK = windows.SRWLOCK_INIT,234 srwlock: windows.SRWLOCK = windows.SRWLOCK_INIT,
275235
276 pub usingnamespace HeldInterface(@This());236 pub fn tryLock(m: *WindowsMutex) bool {
277
278 fn tryAcquireDirect(m: *WindowsMutex) bool {
279 return windows.kernel32.TryAcquireSRWLockExclusive(&m.srwlock) != windows.FALSE;237 return windows.kernel32.TryAcquireSRWLockExclusive(&m.srwlock) != windows.FALSE;
280 }238 }
281239
282 fn acquireDirect(m: *WindowsMutex) void {240 pub fn lock(m: *WindowsMutex) void {
283 windows.kernel32.AcquireSRWLockExclusive(&m.srwlock);241 windows.kernel32.AcquireSRWLockExclusive(&m.srwlock);
284 }242 }
285243
286 fn releaseDirect(m: *WindowsMutex) void {244 pub fn unlock(m: *WindowsMutex) void {
287 windows.kernel32.ReleaseSRWLockExclusive(&m.srwlock);245 windows.kernel32.ReleaseSRWLockExclusive(&m.srwlock);
288 }246 }
289};247};
...@@ -322,8 +280,8 @@ test "basic usage" {...@@ -322,8 +280,8 @@ test "basic usage" {
322fn worker(ctx: *TestContext) void {280fn worker(ctx: *TestContext) void {
323 var i: usize = 0;281 var i: usize = 0;
324 while (i != TestContext.incr_count) : (i += 1) {282 while (i != TestContext.incr_count) : (i += 1) {
325 const held = ctx.mutex.acquire();283 ctx.mutex.lock();
326 defer held.release();284 defer ctx.mutex.unlock();
327285
328 ctx.data += 1;286 ctx.data += 1;
329 }287 }
lib/std/Thread/Semaphore.zig+4-4
...@@ -13,8 +13,8 @@ const Mutex = std.Thread.Mutex;...@@ -13,8 +13,8 @@ const Mutex = std.Thread.Mutex;
13const Condition = std.Thread.Condition;13const Condition = std.Thread.Condition;
1414
15pub fn wait(sem: *Semaphore) void {15pub fn wait(sem: *Semaphore) void {
16 const held = sem.mutex.acquire();16 sem.mutex.lock();
17 defer held.release();17 defer sem.mutex.unlock();
1818
19 while (sem.permits == 0)19 while (sem.permits == 0)
20 sem.cond.wait(&sem.mutex);20 sem.cond.wait(&sem.mutex);
...@@ -25,8 +25,8 @@ pub fn wait(sem: *Semaphore) void {...@@ -25,8 +25,8 @@ pub fn wait(sem: *Semaphore) void {
25}25}
2626
27pub fn post(sem: *Semaphore) void {27pub fn post(sem: *Semaphore) void {
28 const held = sem.mutex.acquire();28 sem.mutex.lock();
29 defer held.release();29 defer sem.mutex.unlock();
3030
31 sem.permits += 1;31 sem.permits += 1;
32 sem.cond.signal();32 sem.cond.signal();
lib/std/atomic/queue.zig+12-12
...@@ -31,8 +31,8 @@ pub fn Queue(comptime T: type) type {...@@ -31,8 +31,8 @@ pub fn Queue(comptime T: type) type {
31 pub fn put(self: *Self, node: *Node) void {31 pub fn put(self: *Self, node: *Node) void {
32 node.next = null;32 node.next = null;
3333
34 const held = self.mutex.acquire();34 self.mutex.lock();
35 defer held.release();35 defer self.mutex.unlock();
3636
37 node.prev = self.tail;37 node.prev = self.tail;
38 self.tail = node;38 self.tail = node;
...@@ -48,8 +48,8 @@ pub fn Queue(comptime T: type) type {...@@ -48,8 +48,8 @@ pub fn Queue(comptime T: type) type {
48 /// It is safe to `get()` a node from the queue while another thread tries48 /// It is safe to `get()` a node from the queue while another thread tries
49 /// to `remove()` the same node at the same time.49 /// to `remove()` the same node at the same time.
50 pub fn get(self: *Self) ?*Node {50 pub fn get(self: *Self) ?*Node {
51 const held = self.mutex.acquire();51 self.mutex.lock();
52 defer held.release();52 defer self.mutex.unlock();
5353
54 const head = self.head orelse return null;54 const head = self.head orelse return null;
55 self.head = head.next;55 self.head = head.next;
...@@ -67,8 +67,8 @@ pub fn Queue(comptime T: type) type {...@@ -67,8 +67,8 @@ pub fn Queue(comptime T: type) type {
67 pub fn unget(self: *Self, node: *Node) void {67 pub fn unget(self: *Self, node: *Node) void {
68 node.prev = null;68 node.prev = null;
6969
70 const held = self.mutex.acquire();70 self.mutex.lock();
71 defer held.release();71 defer self.mutex.unlock();
7272
73 const opt_head = self.head;73 const opt_head = self.head;
74 self.head = node;74 self.head = node;
...@@ -84,8 +84,8 @@ pub fn Queue(comptime T: type) type {...@@ -84,8 +84,8 @@ pub fn Queue(comptime T: type) type {
84 /// It is safe to `remove()` a node from the queue while another thread tries84 /// It is safe to `remove()` a node from the queue while another thread tries
85 /// to `get()` the same node at the same time.85 /// to `get()` the same node at the same time.
86 pub fn remove(self: *Self, node: *Node) bool {86 pub fn remove(self: *Self, node: *Node) bool {
87 const held = self.mutex.acquire();87 self.mutex.lock();
88 defer held.release();88 defer self.mutex.unlock();
8989
90 if (node.prev == null and node.next == null and self.head != node) {90 if (node.prev == null and node.next == null and self.head != node) {
91 return false;91 return false;
...@@ -110,8 +110,8 @@ pub fn Queue(comptime T: type) type {...@@ -110,8 +110,8 @@ pub fn Queue(comptime T: type) type {
110 /// Note that in a multi-consumer environment a return value of `false`110 /// Note that in a multi-consumer environment a return value of `false`
111 /// does not mean that `get` will yield a non-`null` value!111 /// does not mean that `get` will yield a non-`null` value!
112 pub fn isEmpty(self: *Self) bool {112 pub fn isEmpty(self: *Self) bool {
113 const held = self.mutex.acquire();113 self.mutex.lock();
114 defer held.release();114 defer self.mutex.unlock();
115 return self.head == null;115 return self.head == null;
116 }116 }
117117
...@@ -144,8 +144,8 @@ pub fn Queue(comptime T: type) type {...@@ -144,8 +144,8 @@ pub fn Queue(comptime T: type) type {
144 }144 }
145 }145 }
146 };146 };
147 const held = self.mutex.acquire();147 self.mutex.lock();
148 defer held.release();148 defer self.mutex.unlock();
149149
150 try stream.print("head: ", .{});150 try stream.print("head: ", .{});
151 try S.dumpRecursive(stream, self.head, 0, 4);151 try S.dumpRecursive(stream, self.head, 0, 4);
lib/std/debug.zig+4-4
...@@ -62,8 +62,8 @@ pub const warn = print;...@@ -62,8 +62,8 @@ pub const warn = print;
62/// Print to stderr, unbuffered, and silently returning on failure. Intended62/// Print to stderr, unbuffered, and silently returning on failure. Intended
63/// for use in "printf debugging." Use `std.log` functions for proper logging.63/// for use in "printf debugging." Use `std.log` functions for proper logging.
64pub fn print(comptime fmt: []const u8, args: anytype) void {64pub fn print(comptime fmt: []const u8, args: anytype) void {
65 const held = stderr_mutex.acquire();65 stderr_mutex.lock();
66 defer held.release();66 defer stderr_mutex.unlock();
67 const stderr = io.getStdErr().writer();67 const stderr = io.getStdErr().writer();
68 nosuspend stderr.print(fmt, args) catch return;68 nosuspend stderr.print(fmt, args) catch return;
69}69}
...@@ -286,8 +286,8 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize...@@ -286,8 +286,8 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize
286286
287 // Make sure to release the mutex when done287 // Make sure to release the mutex when done
288 {288 {
289 const held = panic_mutex.acquire();289 panic_mutex.lock();
290 defer held.release();290 defer panic_mutex.unlock();
291291
292 const stderr = io.getStdErr().writer();292 const stderr = io.getStdErr().writer();
293 if (builtin.single_threaded) {293 if (builtin.single_threaded) {
lib/std/event/lock.zig+5-5
...@@ -32,7 +32,7 @@ pub const Lock = struct {...@@ -32,7 +32,7 @@ pub const Lock = struct {
32 }32 }
3333
34 pub fn acquire(self: *Lock) Held {34 pub fn acquire(self: *Lock) Held {
35 const held = self.mutex.acquire();35 self.mutex.lock();
3636
37 // self.head transitions from multiple stages depending on the value:37 // self.head transitions from multiple stages depending on the value:
38 // UNLOCKED -> LOCKED:38 // UNLOCKED -> LOCKED:
...@@ -44,7 +44,7 @@ pub const Lock = struct {...@@ -44,7 +44,7 @@ pub const Lock = struct {
4444
45 if (self.head == UNLOCKED) {45 if (self.head == UNLOCKED) {
46 self.head = LOCKED;46 self.head = LOCKED;
47 held.release();47 self.mutex.unlock();
48 return Held{ .lock = self };48 return Held{ .lock = self };
49 }49 }
5050
...@@ -71,7 +71,7 @@ pub const Lock = struct {...@@ -71,7 +71,7 @@ pub const Lock = struct {
71 .next = undefined,71 .next = undefined,
72 .data = @frame(),72 .data = @frame(),
73 };73 };
74 held.release();74 self.mutex.unlock();
75 }75 }
7676
77 return Held{ .lock = self };77 return Held{ .lock = self };
...@@ -82,8 +82,8 @@ pub const Lock = struct {...@@ -82,8 +82,8 @@ pub const Lock = struct {
8282
83 pub fn release(self: Held) void {83 pub fn release(self: Held) void {
84 const waiter = blk: {84 const waiter = blk: {
85 const held = self.lock.mutex.acquire();85 self.lock.mutex.lock();
86 defer held.release();86 defer self.lock.mutex.unlock();
8787
88 // self.head goes through the reverse transition from acquire():88 // self.head goes through the reverse transition from acquire():
89 // <head ptr> -> <new head ptr>:89 // <head ptr> -> <new head ptr>:
lib/std/event/loop.zig+2-2
...@@ -925,8 +925,8 @@ pub const Loop = struct {...@@ -925,8 +925,8 @@ pub const Loop = struct {
925 }925 }
926926
927 fn peekExpiringEntry(self: *Waiters) ?*Entry {927 fn peekExpiringEntry(self: *Waiters) ?*Entry {
928 const held = self.entries.mutex.acquire();928 self.entries.mutex.lock();
929 defer held.release();929 defer self.entries.mutex.unlock();
930930
931 // starting from the head931 // starting from the head
932 var head = self.entries.head orelse return null;932 var head = self.entries.head orelse return null;
lib/std/heap/general_purpose_allocator.zig+4-4
...@@ -615,8 +615,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -615,8 +615,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
615 ) Error!usize {615 ) Error!usize {
616 const self = @fieldParentPtr(Self, "allocator", allocator);616 const self = @fieldParentPtr(Self, "allocator", allocator);
617617
618 const held = self.mutex.acquire();618 self.mutex.lock();
619 defer held.release();619 defer self.mutex.unlock();
620620
621 assert(old_mem.len != 0);621 assert(old_mem.len != 0);
622622
...@@ -758,8 +758,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -758,8 +758,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
758 fn alloc(allocator: *Allocator, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 {758 fn alloc(allocator: *Allocator, len: usize, ptr_align: u29, len_align: u29, ret_addr: usize) Error![]u8 {
759 const self = @fieldParentPtr(Self, "allocator", allocator);759 const self = @fieldParentPtr(Self, "allocator", allocator);
760760
761 const held = self.mutex.acquire();761 self.mutex.lock();
762 defer held.release();762 defer self.mutex.unlock();
763763
764 if (!self.isAllocationAllowed(len)) {764 if (!self.isAllocationAllowed(len)) {
765 return error.OutOfMemory;765 return error.OutOfMemory;
lib/std/json.zig+2-2
...@@ -1319,8 +1319,8 @@ pub const Value = union(enum) {...@@ -1319,8 +1319,8 @@ pub const Value = union(enum) {
1319 }1319 }
13201320
1321 pub fn dump(self: Value) void {1321 pub fn dump(self: Value) void {
1322 var held = std.debug.getStderrMutex().acquire();1322 std.debug.getStderrMutex().lock();
1323 defer held.release();1323 defer std.debug.getStderrMutex().unlock();
13241324
1325 const stderr = std.io.getStdErr().writer();1325 const stderr = std.io.getStdErr().writer();
1326 std.json.stringify(self, std.json.StringifyOptions{ .whitespace = null }, stderr) catch return;1326 std.json.stringify(self, std.json.StringifyOptions{ .whitespace = null }, stderr) catch return;
lib/std/log.zig+4-4
...@@ -41,8 +41,8 @@...@@ -41,8 +41,8 @@
41//! const prefix = "[" ++ level.asText() ++ "] " ++ scope_prefix;41//! const prefix = "[" ++ level.asText() ++ "] " ++ scope_prefix;
42//!42//!
43//! // Print the message to stderr, silently ignoring any errors43//! // Print the message to stderr, silently ignoring any errors
44//! const held = std.debug.getStderrMutex().acquire();44//! std.debug.getStderrMutex().lock();
45//! defer held.release();45//! defer std.debug.getStderrMutex().unlock();
46//! const stderr = std.io.getStdErr().writer();46//! const stderr = std.io.getStdErr().writer();
47//! nosuspend stderr.print(prefix ++ format ++ "\n", args) catch return;47//! nosuspend stderr.print(prefix ++ format ++ "\n", args) catch return;
48//! }48//! }
...@@ -165,8 +165,8 @@ pub fn defaultLog(...@@ -165,8 +165,8 @@ pub fn defaultLog(
165 const level_txt = comptime message_level.asText();165 const level_txt = comptime message_level.asText();
166 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";166 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
167 const stderr = std.io.getStdErr().writer();167 const stderr = std.io.getStdErr().writer();
168 const held = std.debug.getStderrMutex().acquire();168 std.debug.getStderrMutex().lock();
169 defer held.release();169 defer std.debug.getStderrMutex().unlock();
170 nosuspend stderr.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;170 nosuspend stderr.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
171}171}
172172
lib/std/once.zig+2-2
...@@ -26,8 +26,8 @@ pub fn Once(comptime f: fn () void) type {...@@ -26,8 +26,8 @@ pub fn Once(comptime f: fn () void) type {
26 fn callSlow(self: *@This()) void {26 fn callSlow(self: *@This()) void {
27 @setCold(true);27 @setCold(true);
2828
29 const T = self.mutex.acquire();29 self.mutex.lock();
30 defer T.release();30 defer self.mutex.unlock();
3131
32 // The first thread to acquire the mutex gets to run the initializer32 // The first thread to acquire the mutex gets to run the initializer
33 if (!self.done) {33 if (!self.done) {
lib/std/os/windows.zig+2-2
...@@ -1324,8 +1324,8 @@ pub fn WSASocketW(...@@ -1324,8 +1324,8 @@ pub fn WSASocketW(
1324 if (!first) return error.Unexpected;1324 if (!first) return error.Unexpected;
1325 first = false;1325 first = false;
13261326
1327 var held = wsa_startup_mutex.acquire();1327 wsa_startup_mutex.lock();
1328 defer held.release();1328 defer wsa_startup_mutex.unlock();
13291329
1330 // Here we could use a flag to prevent multiple threads to prevent1330 // Here we could use a flag to prevent multiple threads to prevent
1331 // multiple calls to WSAStartup, but it doesn't matter. We're globally1331 // multiple calls to WSAStartup, but it doesn't matter. We're globally
src/Compilation.zig+14-14
...@@ -339,8 +339,8 @@ pub const AllErrors = struct {...@@ -339,8 +339,8 @@ pub const AllErrors = struct {
339 },339 },
340340
341 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {341 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {
342 const held = std.debug.getStderrMutex().acquire();342 std.debug.getStderrMutex().lock();
343 defer held.release();343 defer std.debug.getStderrMutex().unlock();
344 const stderr = std.io.getStdErr();344 const stderr = std.io.getStdErr();
345 return msg.renderToStdErrInner(ttyconf, stderr, "error:", .Red, 0) catch return;345 return msg.renderToStdErrInner(ttyconf, stderr, "error:", .Red, 0) catch return;
346 }346 }
...@@ -2691,8 +2691,8 @@ fn workerAstGenFile(...@@ -2691,8 +2691,8 @@ fn workerAstGenFile(
2691 const import_path = file.zir.nullTerminatedString(item.data.name);2691 const import_path = file.zir.nullTerminatedString(item.data.name);
26922692
2693 const import_result = blk: {2693 const import_result = blk: {
2694 const lock = comp.mutex.acquire();2694 comp.mutex.lock();
2695 defer lock.release();2695 defer comp.mutex.unlock();
26962696
2697 break :blk mod.importFile(file, import_path) catch continue;2697 break :blk mod.importFile(file, import_path) catch continue;
2698 };2698 };
...@@ -2933,8 +2933,8 @@ fn reportRetryableCObjectError(...@@ -2933,8 +2933,8 @@ fn reportRetryableCObjectError(
2933 .column = 0,2933 .column = 0,
2934 };2934 };
2935 {2935 {
2936 const lock = comp.mutex.acquire();2936 comp.mutex.lock();
2937 defer lock.release();2937 defer comp.mutex.unlock();
2938 try comp.failed_c_objects.putNoClobber(comp.gpa, c_object, c_obj_err_msg);2938 try comp.failed_c_objects.putNoClobber(comp.gpa, c_object, c_obj_err_msg);
2939 }2939 }
2940}2940}
...@@ -2981,8 +2981,8 @@ fn reportRetryableAstGenError(...@@ -2981,8 +2981,8 @@ fn reportRetryableAstGenError(
2981 errdefer err_msg.destroy(gpa);2981 errdefer err_msg.destroy(gpa);
29822982
2983 {2983 {
2984 const lock = comp.mutex.acquire();2984 comp.mutex.lock();
2985 defer lock.release();2985 defer comp.mutex.unlock();
2986 try mod.failed_files.putNoClobber(gpa, file, err_msg);2986 try mod.failed_files.putNoClobber(gpa, file, err_msg);
2987 }2987 }
2988}2988}
...@@ -3011,8 +3011,8 @@ fn reportRetryableEmbedFileError(...@@ -3011,8 +3011,8 @@ fn reportRetryableEmbedFileError(
3011 errdefer err_msg.destroy(gpa);3011 errdefer err_msg.destroy(gpa);
30123012
3013 {3013 {
3014 const lock = comp.mutex.acquire();3014 comp.mutex.lock();
3015 defer lock.release();3015 defer comp.mutex.unlock();
3016 try mod.failed_embed_files.putNoClobber(gpa, embed_file, err_msg);3016 try mod.failed_embed_files.putNoClobber(gpa, embed_file, err_msg);
3017 }3017 }
3018}3018}
...@@ -3031,8 +3031,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P...@@ -3031,8 +3031,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
30313031
3032 if (c_object.clearStatus(comp.gpa)) {3032 if (c_object.clearStatus(comp.gpa)) {
3033 // There was previous failure.3033 // There was previous failure.
3034 const lock = comp.mutex.acquire();3034 comp.mutex.lock();
3035 defer lock.release();3035 defer comp.mutex.unlock();
3036 // If the failure was OOM, there will not be an entry here, so we do3036 // If the failure was OOM, there will not be an entry here, so we do
3037 // not assert discard.3037 // not assert discard.
3038 _ = comp.failed_c_objects.swapRemove(c_object);3038 _ = comp.failed_c_objects.swapRemove(c_object);
...@@ -3576,8 +3576,8 @@ fn failCObjWithOwnedErrorMsg(...@@ -3576,8 +3576,8 @@ fn failCObjWithOwnedErrorMsg(
3576) SemaError {3576) SemaError {
3577 @setCold(true);3577 @setCold(true);
3578 {3578 {
3579 const lock = comp.mutex.acquire();3579 comp.mutex.lock();
3580 defer lock.release();3580 defer comp.mutex.unlock();
3581 {3581 {
3582 errdefer err_msg.destroy(comp.gpa);3582 errdefer err_msg.destroy(comp.gpa);
3583 try comp.failed_c_objects.ensureUnusedCapacity(comp.gpa, 1);3583 try comp.failed_c_objects.ensureUnusedCapacity(comp.gpa, 1);
src/Module.zig+10-10
...@@ -2629,8 +2629,8 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -2629,8 +2629,8 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
2629 // TODO don't report compile errors until Sema @importFile2629 // TODO don't report compile errors until Sema @importFile
2630 if (file.zir.hasCompileErrors()) {2630 if (file.zir.hasCompileErrors()) {
2631 {2631 {
2632 const lock = comp.mutex.acquire();2632 comp.mutex.lock();
2633 defer lock.release();2633 defer comp.mutex.unlock();
2634 try mod.failed_files.putNoClobber(gpa, file, null);2634 try mod.failed_files.putNoClobber(gpa, file, null);
2635 }2635 }
2636 file.status = .astgen_failure;2636 file.status = .astgen_failure;
...@@ -2742,8 +2742,8 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -2742,8 +2742,8 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
2742 }2742 }
27432743
2744 {2744 {
2745 const lock = comp.mutex.acquire();2745 comp.mutex.lock();
2746 defer lock.release();2746 defer comp.mutex.unlock();
2747 try mod.failed_files.putNoClobber(gpa, file, err_msg);2747 try mod.failed_files.putNoClobber(gpa, file, err_msg);
2748 }2748 }
2749 file.status = .parse_failure;2749 file.status = .parse_failure;
...@@ -2817,8 +2817,8 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -2817,8 +2817,8 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
28172817
2818 if (file.zir.hasCompileErrors()) {2818 if (file.zir.hasCompileErrors()) {
2819 {2819 {
2820 const lock = comp.mutex.acquire();2820 comp.mutex.lock();
2821 defer lock.release();2821 defer comp.mutex.unlock();
2822 try mod.failed_files.putNoClobber(gpa, file, null);2822 try mod.failed_files.putNoClobber(gpa, file, null);
2823 }2823 }
2824 file.status = .astgen_failure;2824 file.status = .astgen_failure;
...@@ -3701,8 +3701,8 @@ pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void {...@@ -3701,8 +3701,8 @@ pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void {
3701 embed_file.stat_mtime = stat.mtime;3701 embed_file.stat_mtime = stat.mtime;
3702 embed_file.stat_inode = stat.inode;3702 embed_file.stat_inode = stat.inode;
37033703
3704 const lock = mod.comp.mutex.acquire();3704 mod.comp.mutex.lock();
3705 defer lock.release();3705 defer mod.comp.mutex.unlock();
3706 try mod.comp.work_queue.writeItem(.{ .update_embed_file = embed_file });3706 try mod.comp.work_queue.writeItem(.{ .update_embed_file = embed_file });
3707}3707}
37083708
...@@ -4459,8 +4459,8 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {...@@ -4459,8 +4459,8 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
4459 switch (file.status) {4459 switch (file.status) {
4460 .success_zir, .retryable_failure => {},4460 .success_zir, .retryable_failure => {},
4461 .never_loaded, .parse_failure, .astgen_failure => {4461 .never_loaded, .parse_failure, .astgen_failure => {
4462 const lock = mod.comp.mutex.acquire();4462 mod.comp.mutex.lock();
4463 defer lock.release();4463 defer mod.comp.mutex.unlock();
4464 if (mod.failed_files.fetchSwapRemove(file)) |kv| {4464 if (mod.failed_files.fetchSwapRemove(file)) |kv| {
4465 if (kv.value) |msg| msg.destroy(mod.gpa); // Delete previous error message.4465 if (kv.value) |msg| msg.destroy(mod.gpa); // Delete previous error message.
4466 }4466 }
src/ThreadPool.zig+17-14
...@@ -7,7 +7,7 @@ const std = @import("std");...@@ -7,7 +7,7 @@ const std = @import("std");
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const ThreadPool = @This();8const ThreadPool = @This();
99
10lock: std.Thread.Mutex = .{},10mutex: std.Thread.Mutex = .{},
11is_running: bool = true,11is_running: bool = true,
12allocator: *std.mem.Allocator,12allocator: *std.mem.Allocator,
13workers: []Worker,13workers: []Worker,
...@@ -28,26 +28,28 @@ const Worker = struct {...@@ -28,26 +28,28 @@ const Worker = struct {
28 idle_node: IdleQueue.Node,28 idle_node: IdleQueue.Node,
2929
30 fn run(worker: *Worker) void {30 fn run(worker: *Worker) void {
31 const pool = worker.pool;
32
31 while (true) {33 while (true) {
32 const held = worker.pool.lock.acquire();34 pool.mutex.lock();
3335
34 if (worker.pool.run_queue.popFirst()) |run_node| {36 if (pool.run_queue.popFirst()) |run_node| {
35 held.release();37 pool.mutex.unlock();
36 (run_node.data.runFn)(&run_node.data);38 (run_node.data.runFn)(&run_node.data);
37 continue;39 continue;
38 }40 }
3941
40 if (worker.pool.is_running) {42 if (pool.is_running) {
41 worker.idle_node.data.reset();43 worker.idle_node.data.reset();
4244
43 worker.pool.idle_queue.prepend(&worker.idle_node);45 pool.idle_queue.prepend(&worker.idle_node);
44 held.release();46 pool.mutex.unlock();
4547
46 worker.idle_node.data.wait();48 worker.idle_node.data.wait();
47 continue;49 continue;
48 }50 }
4951
50 held.release();52 pool.mutex.unlock();
51 return;53 return;
52 }54 }
53 }55 }
...@@ -88,8 +90,8 @@ fn destroyWorkers(self: *ThreadPool, spawned: usize) void {...@@ -88,8 +90,8 @@ fn destroyWorkers(self: *ThreadPool, spawned: usize) void {
8890
89pub fn deinit(self: *ThreadPool) void {91pub fn deinit(self: *ThreadPool) void {
90 {92 {
91 const held = self.lock.acquire();93 self.mutex.lock();
92 defer held.release();94 defer self.mutex.unlock();
9395
94 self.is_running = false;96 self.is_running = false;
95 while (self.idle_queue.popFirst()) |idle_node|97 while (self.idle_queue.popFirst()) |idle_node|
...@@ -117,14 +119,15 @@ pub fn spawn(self: *ThreadPool, comptime func: anytype, args: anytype) !void {...@@ -117,14 +119,15 @@ pub fn spawn(self: *ThreadPool, comptime func: anytype, args: anytype) !void {
117 const closure = @fieldParentPtr(@This(), "run_node", run_node);119 const closure = @fieldParentPtr(@This(), "run_node", run_node);
118 @call(.{}, func, closure.arguments);120 @call(.{}, func, closure.arguments);
119121
120 const held = closure.pool.lock.acquire();122 const mutex = &closure.pool.mutex;
121 defer held.release();123 mutex.lock();
124 defer mutex.unlock();
122 closure.pool.allocator.destroy(closure);125 closure.pool.allocator.destroy(closure);
123 }126 }
124 };127 };
125128
126 const held = self.lock.acquire();129 self.mutex.lock();
127 defer held.release();130 defer self.mutex.unlock();
128131
129 const closure = try self.allocator.create(Closure);132 const closure = try self.allocator.create(Closure);
130 closure.* = .{133 closure.* = .{
src/WaitGroup.zig+9-9
...@@ -6,13 +6,13 @@...@@ -6,13 +6,13 @@
6const std = @import("std");6const std = @import("std");
7const WaitGroup = @This();7const WaitGroup = @This();
88
9lock: std.Thread.Mutex = .{},9mutex: std.Thread.Mutex = .{},
10counter: usize = 0,10counter: usize = 0,
11event: std.Thread.ResetEvent,11event: std.Thread.ResetEvent,
1212
13pub fn init(self: *WaitGroup) !void {13pub fn init(self: *WaitGroup) !void {
14 self.* = .{14 self.* = .{
15 .lock = .{},15 .mutex = .{},
16 .counter = 0,16 .counter = 0,
17 .event = undefined,17 .event = undefined,
18 };18 };
...@@ -25,15 +25,15 @@ pub fn deinit(self: *WaitGroup) void {...@@ -25,15 +25,15 @@ pub fn deinit(self: *WaitGroup) void {
25}25}
2626
27pub fn start(self: *WaitGroup) void {27pub fn start(self: *WaitGroup) void {
28 const held = self.lock.acquire();28 self.mutex.lock();
29 defer held.release();29 defer self.mutex.unlock();
3030
31 self.counter += 1;31 self.counter += 1;
32}32}
3333
34pub fn finish(self: *WaitGroup) void {34pub fn finish(self: *WaitGroup) void {
35 const held = self.lock.acquire();35 self.mutex.lock();
36 defer held.release();36 defer self.mutex.unlock();
3737
38 self.counter -= 1;38 self.counter -= 1;
3939
...@@ -44,14 +44,14 @@ pub fn finish(self: *WaitGroup) void {...@@ -44,14 +44,14 @@ pub fn finish(self: *WaitGroup) void {
4444
45pub fn wait(self: *WaitGroup) void {45pub fn wait(self: *WaitGroup) void {
46 while (true) {46 while (true) {
47 const held = self.lock.acquire();47 self.mutex.lock();
4848
49 if (self.counter == 0) {49 if (self.counter == 0) {
50 held.release();50 self.mutex.unlock();
51 return;51 return;
52 }52 }
5353
54 held.release();54 self.mutex.unlock();
55 self.event.wait();55 self.event.wait();
56 }56 }
57}57}
src/crash_report.zig+2-2
...@@ -422,7 +422,7 @@ const PanicSwitch = struct {...@@ -422,7 +422,7 @@ const PanicSwitch = struct {
422422
423 state.recover_stage = .release_ref_count;423 state.recover_stage = .release_ref_count;
424424
425 _ = panic_mutex.acquire();425 panic_mutex.lock();
426426
427 state.recover_stage = .release_mutex;427 state.recover_stage = .release_mutex;
428428
...@@ -482,7 +482,7 @@ const PanicSwitch = struct {...@@ -482,7 +482,7 @@ const PanicSwitch = struct {
482 noinline fn releaseMutex(state: *volatile PanicState) noreturn {482 noinline fn releaseMutex(state: *volatile PanicState) noreturn {
483 state.recover_stage = .abort;483 state.recover_stage = .abort;
484484
485 panic_mutex.releaseDirect();485 panic_mutex.unlock();
486486
487 goTo(releaseRefCount, .{state});487 goTo(releaseRefCount, .{state});
488 }488 }