Commit 4e621d4260
Changed files (4)
lib/std/auto_reset_event.zig
@@ -11,33 +11,33 @@ const assert = std.debug.assert;
/// Similar to std.ResetEvent but on `set()` it also (atomically) does `reset()`.
/// Unlike std.ResetEvent, `wait()` can only be called by one thread (MPSC-like).
pub const AutoResetEvent = struct {
- // AutoResetEvent has 3 possible states:
- // - UNSET: the AutoResetEvent is currently unset
- // - SET: the AutoResetEvent was notified before a wait() was called
- // - <std.ResetEvent pointer>: there is an active waiter waiting for a notification.
- //
- // When attempting to wait:
- // if the event is unset, it registers a ResetEvent pointer to be notified when the event is set
- // if the event is already set, then it consumes the notification and resets the event.
- //
- // When attempting to notify:
- // if the event is unset, then we set the event
- // if theres a waiting ResetEvent, then we unset the event and notify the ResetEvent
- //
- // This ensures that the event is automatically reset after a wait() has been issued
- // and avoids the race condition when using std.ResetEvent in the following scenario:
- // thread 1 | thread 2
- // std.ResetEvent.wait() |
- // | std.ResetEvent.set()
- // | std.ResetEvent.set()
- // std.ResetEvent.reset() |
- // std.ResetEvent.wait() | (missed the second .set() notification above)
+ /// AutoResetEvent has 3 possible states:
+ /// - UNSET: the AutoResetEvent is currently unset
+ /// - SET: the AutoResetEvent was notified before a wait() was called
+ /// - <std.ResetEvent pointer>: there is an active waiter waiting for a notification.
+ ///
+ /// When attempting to wait:
+ /// if the event is unset, it registers a ResetEvent pointer to be notified when the event is set
+ /// if the event is already set, then it consumes the notification and resets the event.
+ ///
+ /// When attempting to notify:
+ /// if the event is unset, then we set the event
+ /// if theres a waiting ResetEvent, then we unset the event and notify the ResetEvent
+ ///
+ /// This ensures that the event is automatically reset after a wait() has been issued
+ /// and avoids the race condition when using std.ResetEvent in the following scenario:
+ /// thread 1 | thread 2
+ /// std.ResetEvent.wait() |
+ /// | std.ResetEvent.set()
+ /// | std.ResetEvent.set()
+ /// std.ResetEvent.reset() |
+ /// std.ResetEvent.wait() | (missed the second .set() notification above)
state: usize = UNSET,
const UNSET = 0;
const SET = 1;
- // the minimum alignment for the `*std.ResetEvent` created by wait*()
+ /// the minimum alignment for the `*std.ResetEvent` created by wait*()
const event_align = std.math.max(@alignOf(std.ResetEvent), 2);
pub fn wait(self: *AutoResetEvent) void {
src/Event.zig
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2020 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+const std = @import("std");
+const Event = @This();
+
+lock: std.Mutex = .{},
+event: std.ResetEvent = undefined,
+state: enum { empty, waiting, notified } = .empty,
+
+pub fn wait(self: *Event) void {
+ const held = self.lock.acquire();
+
+ switch (self.state) {
+ .empty => {
+ self.state = .waiting;
+ self.event = @TypeOf(self.event).init();
+ held.release();
+ self.event.wait();
+ self.event.deinit();
+ },
+ .waiting => unreachable,
+ .notified => held.release(),
+ }
+}
+
+pub fn set(self: *Event) void {
+ const held = self.lock.acquire();
+
+ switch (self.state) {
+ .empty => {
+ self.state = .notified;
+ held.release();
+ },
+ .waiting => {
+ held.release();
+ self.event.set();
+ },
+ .notified => unreachable,
+ }
+}
src/ThreadPool.zig
@@ -1,3 +1,8 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2020 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
const std = @import("std");
const ThreadPool = @This();
src/WaitGroup.zig
@@ -1,9 +1,15 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2020 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
const std = @import("std");
const WaitGroup = @This();
+const Event = @import("Event.zig");
lock: std.Mutex = .{},
counter: usize = 0,
-event: std.AutoResetEvent = .{},
+event: Event = .{},
pub fn start(self: *WaitGroup) void {
const held = self.lock.acquire();
@@ -22,13 +28,15 @@ pub fn stop(self: *WaitGroup) void {
}
pub fn wait(self: *WaitGroup) void {
- {
- const held = self.lock.acquire();
- defer held.release();
+ while (true) {
+ {
+ const held = self.lock.acquire();
+ defer held.release();
- if (self.counter == 0)
- return;
- }
+ if (self.counter == 0)
+ return;
+ }
- self.event.wait();
+ self.event.wait();
+ }
}