| ... | @@ -76,107 +76,39 @@ const WindowsParker = struct { | ... | @@ -76,107 +76,39 @@ const WindowsParker = struct { |
| 76 | pub fn deinit(self: *WindowsParker) void {} | 76 | pub fn deinit(self: *WindowsParker) void {} |
| 77 | | 77 | |
| 78 | pub fn unpark(self: *WindowsParker, ptr: *const u32) void { | 78 | pub fn unpark(self: *WindowsParker, ptr: *const u32) void { |
| 79 | switch (Backend.get().*) { | 79 | const handle = getEventHandlePtr().*; |
| 80 | .WaitAddress => |*backend| backend.unpark(ptr, &self.waiters), | 80 | const key = @ptrCast(*const c_void, ptr); |
| 81 | .KeyedEvent => |*backend| backend.unpark(ptr, &self.waiters), | 81 | var waiting = @atomicLoad(u32, &self.waiters, .Monotonic); |
| | 82 | while (waiting != 0) { |
| | 83 | waiting = @cmpxchgWeak(u32, &self.waiters, waiting, waiting - 1, .Acquire, .Monotonic) orelse { |
| | 84 | const rc = windows.ntdll.NtReleaseKeyedEvent(handle, key, windows.FALSE, null); |
| | 85 | assert(rc == 0); |
| | 86 | return; |
| | 87 | }; |
| 82 | } | 88 | } |
| 83 | } | 89 | } |
| 84 | | 90 | |
| 85 | pub fn park(self: *WindowsParker, ptr: *const u32, expected: u32) void { | 91 | pub fn park(self: *WindowsParker, ptr: *const u32, expected: u32) void { |
| 86 | switch (Backend.get().*) { | 92 | const handle = getEventHandlePtr().*; |
| 87 | .WaitAddress => |*backend| backend.park(ptr, expected, &self.waiters), | 93 | const key = @ptrCast(*const c_void, ptr); |
| 88 | .KeyedEvent => |*backend| backend.park(ptr, expected, &self.waiters), | 94 | while (@atomicLoad(u32, ptr, .Acquire) == expected) { |
| | 95 | _ = @atomicRmw(u32, &self.waiters, .Add, 1, .Release); |
| | 96 | const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, null); |
| | 97 | assert(rc == 0); |
| 89 | } | 98 | } |
| 90 | } | 99 | } |
| 91 | | 100 | |
| 92 | const Backend = union(enum) { | 101 | var event_handle = std.lazyInit(windows.HANDLE); |
| 93 | WaitAddress: WaitAddress, | | |
| 94 | KeyedEvent: KeyedEvent, | | |
| 95 | | | |
| 96 | var backend = std.lazyInit(Backend); | | |
| 97 | | | |
| 98 | fn get() *const Backend { | | |
| 99 | return backend.get() orelse { | | |
| 100 | // Statically linking to the KeyedEvent functions should mean its supported. | | |
| 101 | // TODO: Maybe add a CreateSemaphore backend for systems older than Windows XP ? | | |
| 102 | backend.data = WaitAddress.init() | | |
| 103 | orelse KeyedEvent.init() | | |
| 104 | orelse unreachable; | | |
| 105 | backend.resolve(); | | |
| 106 | return &backend.data; | | |
| 107 | }; | | |
| 108 | } | | |
| 109 | | | |
| 110 | const WaitAddress = struct { | | |
| 111 | WakeByAddressSingle: stdcallcc fn(Address: *const c_void) void, | | |
| 112 | WaitOnAddress: stdcallcc fn ( | | |
| 113 | Address: *const c_void, | | |
| 114 | CompareAddress: *const c_void, | | |
| 115 | AddressSize: windows.SIZE_T, | | |
| 116 | dwMilliseconds: windows.DWORD, | | |
| 117 | ) windows.BOOL, | | |
| 118 | | | |
| 119 | fn init() ?Backend { | | |
| 120 | const dll_name = c"api-ms-win-core-synch-l1-2-0"; | | |
| 121 | const dll = windows.kernel32.GetModuleHandleA(dll_name) | | |
| 122 | orelse windows.kernel32.LoadLibraryA(dll_name) | | |
| 123 | orelse return null; | | |
| 124 | | | |
| 125 | var self: WaitAddress = undefined; | | |
| 126 | const WaitOnAddress = windows.kernel32.GetProcAddress(dll, c"WaitOnAddress") orelse return null; | | |
| 127 | self.WaitOnAddress = @intToPtr(@typeOf(self.WaitOnAddress), @ptrToInt(WaitOnAddress)); | | |
| 128 | const WakeByAddressSingle = windows.kernel32.GetProcAddress(dll, c"WakeByAddressSingle") orelse return null; | | |
| 129 | self.WakeByAddressSingle = @intToPtr(@typeOf(self.WakeByAddressSingle), @ptrToInt(WakeByAddressSingle)); | | |
| 130 | return Backend{ .WaitAddress = self }; | | |
| 131 | } | | |
| 132 | | | |
| 133 | fn unpark(self: WaitAddress, ptr: *const u32, waiters: *u32) void { | | |
| 134 | const addr = @ptrCast(*const c_void, ptr); | | |
| 135 | self.WakeByAddressSingle(addr); | | |
| 136 | } | | |
| 137 | | 102 | |
| 138 | fn park(self: WaitAddress, ptr: *const u32, expected: u32, waiters: *u32) void { | 103 | fn getEventHandlePtr() *const windows.HANDLE { |
| 139 | var compare = expected; | 104 | return event_handle.get() orelse { |
| 140 | const addr = @ptrCast(*const c_void, ptr); | 105 | const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE; |
| 141 | const cmp = @ptrCast(*const c_void, &compare); | 106 | if (windows.ntdll.NtCreateKeyedEvent(&event_handle.data, access_mask, null, 0) != 0) |
| 142 | while (@atomicLoad(u32, ptr, .Acquire) == expected) | 107 | @panic("Failed to setup an NT Keyed Event handle for the process"); |
| 143 | _ = self.WaitOnAddress(addr, cmp, @sizeOf(u32), windows.INFINITE); | 108 | event_handle.resolve(); |
| 144 | } | 109 | return &event_handle.data; |
| 145 | }; | 110 | }; |
| 146 | | 111 | } |
| 147 | const KeyedEvent = struct { | | |
| 148 | handle: windows.HANDLE, | | |
| 149 | | | |
| 150 | fn init() ?Backend { | | |
| 151 | var self: KeyedEvent = undefined; | | |
| 152 | const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE; | | |
| 153 | if (windows.ntdll.NtCreateKeyedEvent(&self.handle, access_mask, null, 0) != 0) | | |
| 154 | return null; | | |
| 155 | return Backend{ .KeyedEvent = self }; | | |
| 156 | } | | |
| 157 | | | |
| 158 | fn unpark(self: KeyedEvent, ptr: *const u32, waiters: *u32) void { | | |
| 159 | const key = @ptrCast(*const c_void, ptr); | | |
| 160 | var waiting = @atomicLoad(u32, waiters, .Acquire); | | |
| 161 | while (waiting != 0) { | | |
| 162 | waiting = @cmpxchgWeak(u32, waiters, waiting, waiting - 1, .Acquire, .Monotonic) orelse { | | |
| 163 | const rc = windows.ntdll.NtReleaseKeyedEvent(self.handle, key, windows.FALSE, null); | | |
| 164 | assert(rc == 0); | | |
| 165 | return; | | |
| 166 | }; | | |
| 167 | } | | |
| 168 | } | | |
| 169 | | | |
| 170 | fn park(self: KeyedEvent, ptr: *const u32, expected: u32, waiters: *u32) void { | | |
| 171 | const key = @ptrCast(*const c_void, ptr); | | |
| 172 | while (@atomicLoad(u32, ptr, .Acquire) == expected) { | | |
| 173 | _ = @atomicRmw(u32, waiters, .Add, 1, .Release); | | |
| 174 | const rc = windows.ntdll.NtWaitForKeyedEvent(self.handle, key, windows.FALSE, null); | | |
| 175 | assert(rc == 0); | | |
| 176 | } | | |
| 177 | } | | |
| 178 | }; | | |
| 179 | }; | | |
| 180 | }; | 112 | }; |
| 181 | | 113 | |
| 182 | const PosixParker = struct { | 114 | const PosixParker = struct { |