| ... | @@ -7,14 +7,15 @@ const std = @import("std.zig"); | ... | @@ -7,14 +7,15 @@ const std = @import("std.zig"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const testing = std.testing; | 8 | const testing = std.testing; |
| 9 | const assert = std.debug.assert; | 9 | const assert = std.debug.assert; |
| | 10 | const StaticResetEvent = std.StaticResetEvent; |
| 10 | | 11 | |
| 11 | /// Similar to std.ResetEvent but on `set()` it also (atomically) does `reset()`. | 12 | /// Similar to `StaticResetEvent` but on `set()` it also (atomically) does `reset()`. |
| 12 | /// Unlike std.ResetEvent, `wait()` can only be called by one thread (MPSC-like). | 13 | /// Unlike StaticResetEvent, `wait()` can only be called by one thread (MPSC-like). |
| 13 | pub const AutoResetEvent = struct { | 14 | pub const AutoResetEvent = struct { |
| 14 | /// AutoResetEvent has 3 possible states: | 15 | /// AutoResetEvent has 3 possible states: |
| 15 | /// - UNSET: the AutoResetEvent is currently unset | 16 | /// - UNSET: the AutoResetEvent is currently unset |
| 16 | /// - SET: the AutoResetEvent was notified before a wait() was called | 17 | /// - SET: the AutoResetEvent was notified before a wait() was called |
| 17 | /// - <std.ResetEvent pointer>: there is an active waiter waiting for a notification. | 18 | /// - <StaticResetEvent pointer>: there is an active waiter waiting for a notification. |
| 18 | /// | 19 | /// |
| 19 | /// When attempting to wait: | 20 | /// When attempting to wait: |
| 20 | /// if the event is unset, it registers a ResetEvent pointer to be notified when the event is set | 21 | /// if the event is unset, it registers a ResetEvent pointer to be notified when the event is set |
| ... | @@ -25,20 +26,20 @@ pub const AutoResetEvent = struct { | ... | @@ -25,20 +26,20 @@ pub const AutoResetEvent = struct { |
| 25 | /// if theres a waiting ResetEvent, then we unset the event and notify the ResetEvent | 26 | /// if theres a waiting ResetEvent, then we unset the event and notify the ResetEvent |
| 26 | /// | 27 | /// |
| 27 | /// This ensures that the event is automatically reset after a wait() has been issued | 28 | /// This ensures that the event is automatically reset after a wait() has been issued |
| 28 | /// and avoids the race condition when using std.ResetEvent in the following scenario: | 29 | /// and avoids the race condition when using StaticResetEvent in the following scenario: |
| 29 | /// thread 1 | thread 2 | 30 | /// thread 1 | thread 2 |
| 30 | /// std.ResetEvent.wait() | | 31 | /// StaticResetEvent.wait() | |
| 31 | /// | std.ResetEvent.set() | 32 | /// | StaticResetEvent.set() |
| 32 | /// | std.ResetEvent.set() | 33 | /// | StaticResetEvent.set() |
| 33 | /// std.ResetEvent.reset() | | 34 | /// StaticResetEvent.reset() | |
| 34 | /// std.ResetEvent.wait() | (missed the second .set() notification above) | 35 | /// StaticResetEvent.wait() | (missed the second .set() notification above) |
| 35 | state: usize = UNSET, | 36 | state: usize = UNSET, |
| 36 | | 37 | |
| 37 | const UNSET = 0; | 38 | const UNSET = 0; |
| 38 | const SET = 1; | 39 | const SET = 1; |
| 39 | | 40 | |
| 40 | /// the minimum alignment for the `*std.ResetEvent` created by wait*() | 41 | /// the minimum alignment for the `*StaticResetEvent` created by wait*() |
| 41 | const event_align = std.math.max(@alignOf(std.ResetEvent), 2); | 42 | const event_align = std.math.max(@alignOf(StaticResetEvent), 2); |
| 42 | | 43 | |
| 43 | pub fn wait(self: *AutoResetEvent) void { | 44 | pub fn wait(self: *AutoResetEvent) void { |
| 44 | self.waitFor(null) catch unreachable; | 45 | self.waitFor(null) catch unreachable; |
| ... | @@ -49,12 +50,9 @@ pub const AutoResetEvent = struct { | ... | @@ -49,12 +50,9 @@ pub const AutoResetEvent = struct { |
| 49 | } | 50 | } |
| 50 | | 51 | |
| 51 | fn waitFor(self: *AutoResetEvent, timeout: ?u64) error{TimedOut}!void { | 52 | fn waitFor(self: *AutoResetEvent, timeout: ?u64) error{TimedOut}!void { |
| 52 | // lazily initialized std.ResetEvent | 53 | // lazily initialized StaticResetEvent |
| 53 | var reset_event: std.ResetEvent align(event_align) = undefined; | 54 | var reset_event: StaticResetEvent align(event_align) = undefined; |
| 54 | var has_reset_event = false; | 55 | var has_reset_event = false; |
| 55 | defer if (has_reset_event) { | | |
| 56 | reset_event.deinit(); | | |
| 57 | }; | | |
| 58 | | 56 | |
| 59 | var state = @atomicLoad(usize, &self.state, .SeqCst); | 57 | var state = @atomicLoad(usize, &self.state, .SeqCst); |
| 60 | while (true) { | 58 | while (true) { |
| ... | @@ -72,7 +70,7 @@ pub const AutoResetEvent = struct { | ... | @@ -72,7 +70,7 @@ pub const AutoResetEvent = struct { |
| 72 | // lazily initialize the ResetEvent if it hasn't been already | 70 | // lazily initialize the ResetEvent if it hasn't been already |
| 73 | if (!has_reset_event) { | 71 | if (!has_reset_event) { |
| 74 | has_reset_event = true; | 72 | has_reset_event = true; |
| 75 | reset_event = std.ResetEvent.init(); | 73 | reset_event = .{}; |
| 76 | } | 74 | } |
| 77 | | 75 | |
| 78 | // Since the AutoResetEvent currently isnt set, | 76 | // Since the AutoResetEvent currently isnt set, |
| ... | @@ -97,9 +95,10 @@ pub const AutoResetEvent = struct { | ... | @@ -97,9 +95,10 @@ pub const AutoResetEvent = struct { |
| 97 | }; | 95 | }; |
| 98 | | 96 | |
| 99 | // wait with a timeout and return if signalled via set() | 97 | // wait with a timeout and return if signalled via set() |
| 100 | if (reset_event.timedWait(timeout_ns)) |_| { | 98 | switch (reset_event.timedWait(timeout_ns)) { |
| 101 | return; | 99 | .event_set => return, |
| 102 | } else |timed_out| {} | 100 | .timed_out => {}, |
| | 101 | } |
| 103 | | 102 | |
| 104 | // If we timed out, we need to transition the AutoResetEvent back to UNSET. | 103 | // If we timed out, we need to transition the AutoResetEvent back to UNSET. |
| 105 | // If we don't, then when we return, a set() thread could observe a pointer to an invalid ResetEvent. | 104 | // If we don't, then when we return, a set() thread could observe a pointer to an invalid ResetEvent. |
| ... | @@ -164,7 +163,7 @@ pub const AutoResetEvent = struct { | ... | @@ -164,7 +163,7 @@ pub const AutoResetEvent = struct { |
| 164 | continue; | 163 | continue; |
| 165 | } | 164 | } |
| 166 | | 165 | |
| 167 | const reset_event = @intToPtr(*align(event_align) std.ResetEvent, state); | 166 | const reset_event = @intToPtr(*align(event_align) StaticResetEvent, state); |
| 168 | reset_event.set(); | 167 | reset_event.set(); |
| 169 | return; | 168 | return; |
| 170 | } | 169 | } |