| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| | 3 | const time = std.time; |
| 3 | const testing = std.testing; | 4 | const testing = std.testing; |
| 4 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 5 | const SpinLock = std.SpinLock; | 6 | const SpinLock = std.SpinLock; |
| ... | @@ -76,12 +77,13 @@ const WindowsParker = struct { | ... | @@ -76,12 +77,13 @@ const WindowsParker = struct { |
| 76 | pub fn deinit(self: *WindowsParker) void {} | 77 | pub fn deinit(self: *WindowsParker) void {} |
| 77 | | 78 | |
| 78 | pub fn unpark(self: *WindowsParker, ptr: *const u32) void { | 79 | pub fn unpark(self: *WindowsParker, ptr: *const u32) void { |
| 79 | const handle = getEventHandlePtr().*; | | |
| 80 | const key = @ptrCast(*const c_void, ptr); | 80 | const key = @ptrCast(*const c_void, ptr); |
| | 81 | const handle_ptr = getEventHandlePtr() orelse return; |
| | 82 | |
| 81 | var waiting = @atomicLoad(u32, &self.waiters, .Monotonic); | 83 | var waiting = @atomicLoad(u32, &self.waiters, .Monotonic); |
| 82 | while (waiting != 0) { | 84 | while (waiting != 0) { |
| 83 | waiting = @cmpxchgWeak(u32, &self.waiters, waiting, waiting - 1, .Acquire, .Monotonic) orelse { | 85 | waiting = @cmpxchgWeak(u32, &self.waiters, waiting, waiting - 1, .Acquire, .Monotonic) orelse { |
| 84 | const rc = windows.ntdll.NtReleaseKeyedEvent(handle, key, windows.FALSE, null); | 86 | const rc = windows.ntdll.NtReleaseKeyedEvent(handle_ptr.*, key, windows.FALSE, null); |
| 85 | assert(rc == 0); | 87 | assert(rc == 0); |
| 86 | return; | 88 | return; |
| 87 | }; | 89 | }; |
| ... | @@ -89,22 +91,27 @@ const WindowsParker = struct { | ... | @@ -89,22 +91,27 @@ const WindowsParker = struct { |
| 89 | } | 91 | } |
| 90 | | 92 | |
| 91 | pub fn park(self: *WindowsParker, ptr: *const u32, expected: u32) void { | 93 | pub fn park(self: *WindowsParker, ptr: *const u32, expected: u32) void { |
| 92 | const handle = getEventHandlePtr().*; | 94 | var spin = SpinLock.Backoff.init(); |
| 93 | const key = @ptrCast(*const c_void, ptr); | 95 | const key = @ptrCast(*const c_void, ptr); |
| | 96 | |
| 94 | while (@atomicLoad(u32, ptr, .Acquire) == expected) { | 97 | while (@atomicLoad(u32, ptr, .Acquire) == expected) { |
| 95 | _ = @atomicRmw(u32, &self.waiters, .Add, 1, .Release); | 98 | if (getEventHandlePtr()) |handle_ptr| { |
| 96 | const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, null); | 99 | _ = @atomicRmw(u32, &self.waiters, .Add, 1, .Release); |
| 97 | assert(rc == 0); | 100 | const rc = windows.ntdll.NtWaitForKeyedEvent(handle_ptr.*, key, windows.FALSE, null); |
| | 101 | assert(rc == 0); |
| | 102 | } else { |
| | 103 | spin.yield(); |
| | 104 | } |
| 98 | } | 105 | } |
| 99 | } | 106 | } |
| 100 | | 107 | |
| 101 | var event_handle = std.lazyInit(windows.HANDLE); | 108 | var event_handle = std.lazyInit(windows.HANDLE); |
| 102 | | 109 | |
| 103 | fn getEventHandlePtr() *const windows.HANDLE { | 110 | fn getEventHandlePtr() ?*const windows.HANDLE { |
| 104 | return event_handle.get() orelse { | 111 | return event_handle.get() orelse { |
| 105 | const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE; | 112 | const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE; |
| 106 | if (windows.ntdll.NtCreateKeyedEvent(&event_handle.data, access_mask, null, 0) != 0) | 113 | if (windows.ntdll.NtCreateKeyedEvent(&event_handle.data, access_mask, null, 0) != 0) |
| 107 | @panic("Failed to setup an NT Keyed Event handle for the process"); | 114 | return null; |
| 108 | event_handle.resolve(); | 115 | event_handle.resolve(); |
| 109 | return &event_handle.data; | 116 | return &event_handle.data; |
| 110 | }; | 117 | }; |