| ... | @@ -783,13 +783,13 @@ const preadv_sym = if (posix.lfs64_abi) posix.system.preadv64 else posix.system. | ... | @@ -783,13 +783,13 @@ const preadv_sym = if (posix.lfs64_abi) posix.system.preadv64 else posix.system. |
| 783 | const AsyncClosure = struct { | 783 | const AsyncClosure = struct { |
| 784 | closure: Closure, | 784 | closure: Closure, |
| 785 | func: *const fn (context: *anyopaque, result: *anyopaque) void, | 785 | func: *const fn (context: *anyopaque, result: *anyopaque) void, |
| 786 | reset_event: ResetEvent, | 786 | event: Io.Event, |
| 787 | select_condition: ?*ResetEvent, | 787 | select_condition: ?*Io.Event, |
| 788 | context_alignment: Alignment, | 788 | context_alignment: Alignment, |
| 789 | result_offset: usize, | 789 | result_offset: usize, |
| 790 | alloc_len: usize, | 790 | alloc_len: usize, |
| 791 | | 791 | |
| 792 | const done_reset_event: *ResetEvent = @ptrFromInt(@alignOf(ResetEvent)); | 792 | const done_event: *Io.Event = @ptrFromInt(@alignOf(Io.Event)); |
| 793 | | 793 | |
| 794 | fn start(closure: *Closure, t: *Threaded) void { | 794 | fn start(closure: *Closure, t: *Threaded) void { |
| 795 | const ac: *AsyncClosure = @alignCast(@fieldParentPtr("closure", closure)); | 795 | const ac: *AsyncClosure = @alignCast(@fieldParentPtr("closure", closure)); |
| ... | @@ -798,11 +798,11 @@ const AsyncClosure = struct { | ... | @@ -798,11 +798,11 @@ const AsyncClosure = struct { |
| 798 | ac.func(ac.contextPointer(), ac.resultPointer()); | 798 | ac.func(ac.contextPointer(), ac.resultPointer()); |
| 799 | current_thread.current_closure = null; | 799 | current_thread.current_closure = null; |
| 800 | | 800 | |
| 801 | if (@atomicRmw(?*ResetEvent, &ac.select_condition, .Xchg, done_reset_event, .release)) |select_reset| { | 801 | if (@atomicRmw(?*Io.Event, &ac.select_condition, .Xchg, done_event, .release)) |select_event| { |
| 802 | assert(select_reset != done_reset_event); | 802 | assert(select_event != done_event); |
| 803 | select_reset.set(); | 803 | select_event.set(ioBasic(t)); |
| 804 | } | 804 | } |
| 805 | ac.reset_event.set(); | 805 | ac.event.set(ioBasic(t)); |
| 806 | } | 806 | } |
| 807 | | 807 | |
| 808 | fn resultPointer(ac: *AsyncClosure) [*]u8 { | 808 | fn resultPointer(ac: *AsyncClosure) [*]u8 { |
| ... | @@ -844,7 +844,7 @@ const AsyncClosure = struct { | ... | @@ -844,7 +844,7 @@ const AsyncClosure = struct { |
| 844 | .context_alignment = context_alignment, | 844 | .context_alignment = context_alignment, |
| 845 | .result_offset = actual_result_offset, | 845 | .result_offset = actual_result_offset, |
| 846 | .alloc_len = alloc_len, | 846 | .alloc_len = alloc_len, |
| 847 | .reset_event = .unset, | 847 | .event = .unset, |
| 848 | .select_condition = null, | 848 | .select_condition = null, |
| 849 | }; | 849 | }; |
| 850 | @memcpy(ac.contextPointer()[0..context.len], context); | 850 | @memcpy(ac.contextPointer()[0..context.len], context); |
| ... | @@ -852,10 +852,10 @@ const AsyncClosure = struct { | ... | @@ -852,10 +852,10 @@ const AsyncClosure = struct { |
| 852 | } | 852 | } |
| 853 | | 853 | |
| 854 | fn waitAndDeinit(ac: *AsyncClosure, t: *Threaded, result: []u8) void { | 854 | fn waitAndDeinit(ac: *AsyncClosure, t: *Threaded, result: []u8) void { |
| 855 | ac.reset_event.wait(t) catch |err| switch (err) { | 855 | ac.event.wait(ioBasic(t)) catch |err| switch (err) { |
| 856 | error.Canceled => { | 856 | error.Canceled => { |
| 857 | ac.closure.requestCancel(t); | 857 | ac.closure.requestCancel(t); |
| 858 | ac.reset_event.waitUncancelable(); | 858 | ac.event.waitUncancelable(ioBasic(t)); |
| 859 | }, | 859 | }, |
| 860 | }; | 860 | }; |
| 861 | @memcpy(result, ac.resultPointer()[0..result.len]); | 861 | @memcpy(result, ac.resultPointer()[0..result.len]); |
| ... | @@ -977,14 +977,14 @@ const GroupClosure = struct { | ... | @@ -977,14 +977,14 @@ const GroupClosure = struct { |
| 977 | const current_thread = Thread.getCurrent(t); | 977 | const current_thread = Thread.getCurrent(t); |
| 978 | const group = gc.group; | 978 | const group = gc.group; |
| 979 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); | 979 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); |
| 980 | const reset_event: *ResetEvent = @ptrCast(&group.context); | 980 | const event: *Io.Event = @ptrCast(&group.context); |
| 981 | current_thread.current_closure = closure; | 981 | current_thread.current_closure = closure; |
| 982 | gc.func(group, gc.contextPointer()); | 982 | gc.func(group, gc.contextPointer()); |
| 983 | current_thread.current_closure = null; | 983 | current_thread.current_closure = null; |
| 984 | | 984 | |
| 985 | const prev_state = group_state.fetchSub(sync_one_pending, .acq_rel); | 985 | const prev_state = group_state.fetchSub(sync_one_pending, .acq_rel); |
| 986 | assert((prev_state / sync_one_pending) > 0); | 986 | assert((prev_state / sync_one_pending) > 0); |
| 987 | if (prev_state == (sync_one_pending | sync_is_waiting)) reset_event.set(); | 987 | if (prev_state == (sync_one_pending | sync_is_waiting)) event.set(ioBasic(t)); |
| 988 | } | 988 | } |
| 989 | | 989 | |
| 990 | fn contextPointer(gc: *GroupClosure) [*]u8 { | 990 | fn contextPointer(gc: *GroupClosure) [*]u8 { |
| ... | @@ -1145,10 +1145,10 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { | ... | @@ -1145,10 +1145,10 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { |
| 1145 | if (builtin.single_threaded) return; | 1145 | if (builtin.single_threaded) return; |
| 1146 | | 1146 | |
| 1147 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); | 1147 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); |
| 1148 | const reset_event: *ResetEvent = @ptrCast(&group.context); | 1148 | const event: *Io.Event = @ptrCast(&group.context); |
| 1149 | const prev_state = group_state.fetchAdd(GroupClosure.sync_is_waiting, .acquire); | 1149 | const prev_state = group_state.fetchAdd(GroupClosure.sync_is_waiting, .acquire); |
| 1150 | assert(prev_state & GroupClosure.sync_is_waiting == 0); | 1150 | assert(prev_state & GroupClosure.sync_is_waiting == 0); |
| 1151 | if ((prev_state / GroupClosure.sync_one_pending) > 0) reset_event.wait(t) catch |err| switch (err) { | 1151 | if ((prev_state / GroupClosure.sync_one_pending) > 0) event.wait(ioBasic(t)) catch |err| switch (err) { |
| 1152 | error.Canceled => { | 1152 | error.Canceled => { |
| 1153 | var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token)); | 1153 | var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token)); |
| 1154 | while (true) { | 1154 | while (true) { |
| ... | @@ -1156,7 +1156,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { | ... | @@ -1156,7 +1156,7 @@ fn groupWait(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void { |
| 1156 | gc.closure.requestCancel(t); | 1156 | gc.closure.requestCancel(t); |
| 1157 | node = node.next orelse break; | 1157 | node = node.next orelse break; |
| 1158 | } | 1158 | } |
| 1159 | reset_event.waitUncancelable(); | 1159 | event.waitUncancelable(ioBasic(t)); |
| 1160 | }, | 1160 | }, |
| 1161 | }; | 1161 | }; |
| 1162 | | 1162 | |
| ... | @@ -1185,10 +1185,10 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void | ... | @@ -1185,10 +1185,10 @@ fn groupCancel(userdata: ?*anyopaque, group: *Io.Group, token: *anyopaque) void |
| 1185 | } | 1185 | } |
| 1186 | | 1186 | |
| 1187 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); | 1187 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); |
| 1188 | const reset_event: *ResetEvent = @ptrCast(&group.context); | 1188 | const event: *Io.Event = @ptrCast(&group.context); |
| 1189 | const prev_state = group_state.fetchAdd(GroupClosure.sync_is_waiting, .acquire); | 1189 | const prev_state = group_state.fetchAdd(GroupClosure.sync_is_waiting, .acquire); |
| 1190 | assert(prev_state & GroupClosure.sync_is_waiting == 0); | 1190 | assert(prev_state & GroupClosure.sync_is_waiting == 0); |
| 1191 | if ((prev_state / GroupClosure.sync_one_pending) > 0) reset_event.waitUncancelable(); | 1191 | if ((prev_state / GroupClosure.sync_one_pending) > 0) event.waitUncancelable(ioBasic(t)); |
| 1192 | | 1192 | |
| 1193 | { | 1193 | { |
| 1194 | var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token)); | 1194 | var node: *std.SinglyLinkedList.Node = @ptrCast(@alignCast(token)); |
| ... | @@ -3684,28 +3684,28 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { | ... | @@ -3684,28 +3684,28 @@ fn sleepPosix(userdata: ?*anyopaque, timeout: Io.Timeout) Io.SleepError!void { |
| 3684 | fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) Io.Cancelable!usize { | 3684 | fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) Io.Cancelable!usize { |
| 3685 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 3685 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 3686 | | 3686 | |
| 3687 | var reset_event: ResetEvent = .unset; | 3687 | var event: Io.Event = .unset; |
| 3688 | | 3688 | |
| 3689 | for (futures, 0..) |future, i| { | 3689 | for (futures, 0..) |future, i| { |
| 3690 | const closure: *AsyncClosure = @ptrCast(@alignCast(future)); | 3690 | const closure: *AsyncClosure = @ptrCast(@alignCast(future)); |
| 3691 | if (@atomicRmw(?*ResetEvent, &closure.select_condition, .Xchg, &reset_event, .seq_cst) == AsyncClosure.done_reset_event) { | 3691 | if (@atomicRmw(?*Io.Event, &closure.select_condition, .Xchg, &event, .seq_cst) == AsyncClosure.done_event) { |
| 3692 | for (futures[0..i]) |cleanup_future| { | 3692 | for (futures[0..i]) |cleanup_future| { |
| 3693 | const cleanup_closure: *AsyncClosure = @ptrCast(@alignCast(cleanup_future)); | 3693 | const cleanup_closure: *AsyncClosure = @ptrCast(@alignCast(cleanup_future)); |
| 3694 | if (@atomicRmw(?*ResetEvent, &cleanup_closure.select_condition, .Xchg, null, .seq_cst) == AsyncClosure.done_reset_event) { | 3694 | if (@atomicRmw(?*Io.Event, &cleanup_closure.select_condition, .Xchg, null, .seq_cst) == AsyncClosure.done_event) { |
| 3695 | cleanup_closure.reset_event.waitUncancelable(); // Ensure no reference to our stack-allocated reset_event. | 3695 | cleanup_closure.event.waitUncancelable(ioBasic(t)); // Ensure no reference to our stack-allocated event. |
| 3696 | } | 3696 | } |
| 3697 | } | 3697 | } |
| 3698 | return i; | 3698 | return i; |
| 3699 | } | 3699 | } |
| 3700 | } | 3700 | } |
| 3701 | | 3701 | |
| 3702 | try reset_event.wait(t); | 3702 | try event.wait(ioBasic(t)); |
| 3703 | | 3703 | |
| 3704 | var result: ?usize = null; | 3704 | var result: ?usize = null; |
| 3705 | for (futures, 0..) |future, i| { | 3705 | for (futures, 0..) |future, i| { |
| 3706 | const closure: *AsyncClosure = @ptrCast(@alignCast(future)); | 3706 | const closure: *AsyncClosure = @ptrCast(@alignCast(future)); |
| 3707 | if (@atomicRmw(?*ResetEvent, &closure.select_condition, .Xchg, null, .seq_cst) == AsyncClosure.done_reset_event) { | 3707 | if (@atomicRmw(?*Io.Event, &closure.select_condition, .Xchg, null, .seq_cst) == AsyncClosure.done_event) { |
| 3708 | closure.reset_event.waitUncancelable(); // Ensure no reference to our stack-allocated reset_event. | 3708 | closure.event.waitUncancelable(ioBasic(t)); // Ensure no reference to our stack-allocated event. |
| 3709 | if (result == null) result = i; // In case multiple are ready, return first. | 3709 | if (result == null) result = i; // In case multiple are ready, return first. |
| 3710 | } | 3710 | } |
| 3711 | } | 3711 | } |
| ... | @@ -6666,209 +6666,6 @@ fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) Hos | ... | @@ -6666,209 +6666,6 @@ fn copyCanon(canonical_name_buffer: *[HostName.max_len]u8, name: []const u8) Hos |
| 6666 | /// ulock_wait2() uses 64-bit nano-second timeouts (with the same convention) | 6666 | /// ulock_wait2() uses 64-bit nano-second timeouts (with the same convention) |
| 6667 | const darwin_supports_ulock_wait2 = builtin.os.version_range.semver.min.major >= 11; | 6667 | const darwin_supports_ulock_wait2 = builtin.os.version_range.semver.min.major >= 11; |
| 6668 | | 6668 | |
| 6669 | /// A thread-safe logical boolean value which can be `set` and `unset`. | | |
| 6670 | /// | | |
| 6671 | /// It can also block threads until the value is set with cancelation via timed | | |
| 6672 | /// waits. Statically initializable; four bytes on all targets. | | |
| 6673 | pub const ResetEvent = switch (native_os) { | | |
| 6674 | .illumos, .netbsd, .openbsd => ResetEventPosix, | | |
| 6675 | else => ResetEventFutex, | | |
| 6676 | }; | | |
| 6677 | | | |
| 6678 | /// A `ResetEvent` implementation based on futexes. | | |
| 6679 | const ResetEventFutex = enum(u32) { | | |
| 6680 | unset = 0, | | |
| 6681 | waiting = 1, | | |
| 6682 | is_set = 2, | | |
| 6683 | | | |
| 6684 | /// Returns whether the logical boolean is `set`. | | |
| 6685 | /// | | |
| 6686 | /// Once `reset` is called, this returns false until the next `set`. | | |
| 6687 | /// | | |
| 6688 | /// The memory accesses before the `set` can be said to happen before | | |
| 6689 | /// `isSet` returns true. | | |
| 6690 | pub fn isSet(ref: *const ResetEventFutex) bool { | | |
| 6691 | if (builtin.single_threaded) return switch (ref.*) { | | |
| 6692 | .unset => false, | | |
| 6693 | .waiting => unreachable, | | |
| 6694 | .is_set => true, | | |
| 6695 | }; | | |
| 6696 | // Acquire barrier ensures memory accesses before `set` happen before | | |
| 6697 | // returning true. | | |
| 6698 | return @atomicLoad(ResetEventFutex, ref, .acquire) == .is_set; | | |
| 6699 | } | | |
| 6700 | | | |
| 6701 | /// Blocks the calling thread until `set` is called. | | |
| 6702 | /// | | |
| 6703 | /// This is effectively a more efficient version of `while (!isSet()) {}`. | | |
| 6704 | /// | | |
| 6705 | /// The memory accesses before the `set` can be said to happen before `wait` returns. | | |
| 6706 | pub fn wait(ref: *ResetEventFutex, t: *Threaded) Io.Cancelable!void { | | |
| 6707 | if (builtin.single_threaded) switch (ref.*) { | | |
| 6708 | .unset => unreachable, // Deadlock, no other threads to wake us up. | | |
| 6709 | .waiting => unreachable, // Invalid state. | | |
| 6710 | .is_set => return, | | |
| 6711 | }; | | |
| 6712 | // Try to set the state from `unset` to `waiting` to indicate to the | | |
| 6713 | // `set` thread that others are blocked on the ResetEventFutex. Avoid using | | |
| 6714 | // any strict barriers until we know the ResetEventFutex is set. | | |
| 6715 | var state = @atomicLoad(ResetEventFutex, ref, .acquire); | | |
| 6716 | if (state == .is_set) { | | |
| 6717 | @branchHint(.likely); | | |
| 6718 | return; | | |
| 6719 | } | | |
| 6720 | if (state == .unset) { | | |
| 6721 | state = @cmpxchgStrong(ResetEventFutex, ref, state, .waiting, .acquire, .acquire) orelse .waiting; | | |
| 6722 | } | | |
| 6723 | const current_thread = Thread.getCurrent(t); | | |
| 6724 | while (state == .waiting) { | | |
| 6725 | try current_thread.futexWait(@ptrCast(ref), @intFromEnum(ResetEventFutex.waiting)); | | |
| 6726 | state = @atomicLoad(ResetEventFutex, ref, .acquire); | | |
| 6727 | } | | |
| 6728 | assert(state == .is_set); | | |
| 6729 | } | | |
| 6730 | | | |
| 6731 | /// Same as `wait` except uninterruptible. | | |
| 6732 | pub fn waitUncancelable(ref: *ResetEventFutex) void { | | |
| 6733 | if (builtin.single_threaded) switch (ref.*) { | | |
| 6734 | .unset => unreachable, // Deadlock, no other threads to wake us up. | | |
| 6735 | .waiting => unreachable, // Invalid state. | | |
| 6736 | .is_set => return, | | |
| 6737 | }; | | |
| 6738 | // Try to set the state from `unset` to `waiting` to indicate to the | | |
| 6739 | // `set` thread that others are blocked on the ResetEventFutex. Avoid using | | |
| 6740 | // any strict barriers until we know the ResetEventFutex is set. | | |
| 6741 | var state = @atomicLoad(ResetEventFutex, ref, .acquire); | | |
| 6742 | if (state == .is_set) { | | |
| 6743 | @branchHint(.likely); | | |
| 6744 | return; | | |
| 6745 | } | | |
| 6746 | if (state == .unset) { | | |
| 6747 | state = @cmpxchgStrong(ResetEventFutex, ref, state, .waiting, .acquire, .acquire) orelse .waiting; | | |
| 6748 | } | | |
| 6749 | while (state == .waiting) { | | |
| 6750 | Thread.futexWaitUncancelable(@ptrCast(ref), @intFromEnum(ResetEventFutex.waiting)); | | |
| 6751 | state = @atomicLoad(ResetEventFutex, ref, .acquire); | | |
| 6752 | } | | |
| 6753 | assert(state == .is_set); | | |
| 6754 | } | | |
| 6755 | | | |
| 6756 | /// Marks the logical boolean as `set` and unblocks any threads in `wait` | | |
| 6757 | /// or `timedWait` to observe the new state. | | |
| 6758 | /// | | |
| 6759 | /// The logical boolean stays `set` until `reset` is called, making future | | |
| 6760 | /// `set` calls do nothing semantically. | | |
| 6761 | /// | | |
| 6762 | /// The memory accesses before `set` can be said to happen before `isSet` | | |
| 6763 | /// returns true or `wait`/`timedWait` return successfully. | | |
| 6764 | pub fn set(ref: *ResetEventFutex) void { | | |
| 6765 | if (builtin.single_threaded) { | | |
| 6766 | ref.* = .is_set; | | |
| 6767 | return; | | |
| 6768 | } | | |
| 6769 | if (@atomicRmw(ResetEventFutex, ref, .Xchg, .is_set, .release) == .waiting) { | | |
| 6770 | Thread.futexWake(@ptrCast(ref), std.math.maxInt(u32)); | | |
| 6771 | } | | |
| 6772 | } | | |
| 6773 | | | |
| 6774 | /// Unmarks the ResetEventFutex as if `set` was never called. | | |
| 6775 | /// | | |
| 6776 | /// Assumes no threads are blocked in `wait` or `timedWait`. Concurrent | | |
| 6777 | /// calls to `set`, `isSet` and `reset` are allowed. | | |
| 6778 | pub fn reset(ref: *ResetEventFutex) void { | | |
| 6779 | if (builtin.single_threaded) { | | |
| 6780 | ref.* = .unset; | | |
| 6781 | return; | | |
| 6782 | } | | |
| 6783 | @atomicStore(ResetEventFutex, ref, .unset, .monotonic); | | |
| 6784 | } | | |
| 6785 | }; | | |
| 6786 | | | |
| 6787 | /// A `ResetEvent` implementation based on pthreads API. | | |
| 6788 | const ResetEventPosix = struct { | | |
| 6789 | cond: std.c.pthread_cond_t, | | |
| 6790 | mutex: std.c.pthread_mutex_t, | | |
| 6791 | state: ResetEventFutex, | | |
| 6792 | | | |
| 6793 | pub const unset: ResetEventPosix = .{ | | |
| 6794 | .cond = std.c.PTHREAD_COND_INITIALIZER, | | |
| 6795 | .mutex = std.c.PTHREAD_MUTEX_INITIALIZER, | | |
| 6796 | .state = .unset, | | |
| 6797 | }; | | |
| 6798 | | | |
| 6799 | pub fn isSet(rep: *const ResetEventPosix) bool { | | |
| 6800 | if (builtin.single_threaded) return switch (rep.state) { | | |
| 6801 | .unset => false, | | |
| 6802 | .waiting => unreachable, | | |
| 6803 | .is_set => true, | | |
| 6804 | }; | | |
| 6805 | return @atomicLoad(ResetEventFutex, &rep.state, .acquire) == .is_set; | | |
| 6806 | } | | |
| 6807 | | | |
| 6808 | pub fn wait(rep: *ResetEventPosix, t: *Threaded) Io.Cancelable!void { | | |
| 6809 | if (builtin.single_threaded) switch (rep.*) { | | |
| 6810 | .unset => unreachable, // Deadlock, no other threads to wake us up. | | |
| 6811 | .waiting => unreachable, // Invalid state. | | |
| 6812 | .is_set => return, | | |
| 6813 | }; | | |
| 6814 | const current_thread = Thread.getCurrent(t); | | |
| 6815 | assert(std.c.pthread_mutex_lock(&rep.mutex) == .SUCCESS); | | |
| 6816 | defer assert(std.c.pthread_mutex_unlock(&rep.mutex) == .SUCCESS); | | |
| 6817 | sw: switch (rep.state) { | | |
| 6818 | .unset => { | | |
| 6819 | rep.state = .waiting; | | |
| 6820 | continue :sw .waiting; | | |
| 6821 | }, | | |
| 6822 | .waiting => { | | |
| 6823 | try current_thread.beginSyscall(); | | |
| 6824 | assert(std.c.pthread_cond_wait(&rep.cond, &rep.mutex) == .SUCCESS); | | |
| 6825 | current_thread.endSyscall(); | | |
| 6826 | continue :sw rep.state; | | |
| 6827 | }, | | |
| 6828 | .is_set => return, | | |
| 6829 | } | | |
| 6830 | } | | |
| 6831 | | | |
| 6832 | pub fn waitUncancelable(rep: *ResetEventPosix) void { | | |
| 6833 | if (builtin.single_threaded) switch (rep.*) { | | |
| 6834 | .unset => unreachable, // Deadlock, no other threads to wake us up. | | |
| 6835 | .waiting => unreachable, // Invalid state. | | |
| 6836 | .is_set => return, | | |
| 6837 | }; | | |
| 6838 | assert(std.c.pthread_mutex_lock(&rep.mutex) == .SUCCESS); | | |
| 6839 | defer assert(std.c.pthread_mutex_unlock(&rep.mutex) == .SUCCESS); | | |
| 6840 | sw: switch (rep.state) { | | |
| 6841 | .unset => { | | |
| 6842 | rep.state = .waiting; | | |
| 6843 | continue :sw .waiting; | | |
| 6844 | }, | | |
| 6845 | .waiting => { | | |
| 6846 | assert(std.c.pthread_cond_wait(&rep.cond, &rep.mutex) == .SUCCESS); | | |
| 6847 | continue :sw rep.state; | | |
| 6848 | }, | | |
| 6849 | .is_set => return, | | |
| 6850 | } | | |
| 6851 | } | | |
| 6852 | | | |
| 6853 | pub fn set(rep: *ResetEventPosix) void { | | |
| 6854 | if (builtin.single_threaded) { | | |
| 6855 | rep.* = .is_set; | | |
| 6856 | return; | | |
| 6857 | } | | |
| 6858 | if (@atomicRmw(ResetEventFutex, &rep.state, .Xchg, .is_set, .release) == .waiting) { | | |
| 6859 | assert(std.c.pthread_cond_broadcast(&rep.cond) == .SUCCESS); | | |
| 6860 | } | | |
| 6861 | } | | |
| 6862 | | | |
| 6863 | pub fn reset(rep: *ResetEventPosix) void { | | |
| 6864 | if (builtin.single_threaded) { | | |
| 6865 | rep.* = .unset; | | |
| 6866 | return; | | |
| 6867 | } | | |
| 6868 | @atomicStore(ResetEventFutex, &rep.state, .unset, .monotonic); | | |
| 6869 | } | | |
| 6870 | }; | | |
| 6871 | | | |
| 6872 | fn closeSocketWindows(s: ws2_32.SOCKET) void { | 6669 | fn closeSocketWindows(s: ws2_32.SOCKET) void { |
| 6873 | const rc = ws2_32.closesocket(s); | 6670 | const rc = ws2_32.closesocket(s); |
| 6874 | if (is_debug) switch (rc) { | 6671 | if (is_debug) switch (rc) { |