remove WaitOnAddress backend in std.ThreadParker

master
kprotty 2019-11-07 15:46:57 -06:00
parent b535e86cc0
commit b5d84635f2
2 changed files with 24 additions and 96 deletions

View File

@ -82,8 +82,6 @@ pub extern "kernel32" stdcallcc fn GetFileAttributesW(lpFileName: [*]const WCHAR
pub extern "kernel32" stdcallcc fn GetModuleFileNameW(hModule: ?HMODULE, lpFilename: [*]u16, nSize: DWORD) DWORD;
pub extern "kernel32" stdcallcc fn GetModuleHandleA(lpModuleName: ?[*]const CHAR) ?HMODULE;
pub extern "kernel32" stdcallcc fn GetModuleHandleW(lpModuleName: ?[*]const WCHAR) HMODULE;
pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
@ -206,8 +204,6 @@ pub extern "kernel32" stdcallcc fn WriteFile(
pub extern "kernel32" stdcallcc fn WriteFileEx(hFile: HANDLE, lpBuffer: [*]const u8, nNumberOfBytesToWrite: DWORD, lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE) BOOL;
pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: [*]const u8) ?HMODULE;
pub extern "kernel32" stdcallcc fn LoadLibraryW(lpLibFileName: [*]const u16) ?HMODULE;
pub extern "kernel32" stdcallcc fn GetProcAddress(hModule: HMODULE, lpProcName: [*]const u8) ?FARPROC;

View File

@ -76,107 +76,39 @@ const WindowsParker = struct {
pub fn deinit(self: *WindowsParker) void {}
pub fn unpark(self: *WindowsParker, ptr: *const u32) void {
switch (Backend.get().*) {
.WaitAddress => |*backend| backend.unpark(ptr, &self.waiters),
.KeyedEvent => |*backend| backend.unpark(ptr, &self.waiters),
const handle = getEventHandlePtr().*;
const key = @ptrCast(*const c_void, ptr);
var waiting = @atomicLoad(u32, &self.waiters, .Monotonic);
while (waiting != 0) {
waiting = @cmpxchgWeak(u32, &self.waiters, waiting, waiting - 1, .Acquire, .Monotonic) orelse {
const rc = windows.ntdll.NtReleaseKeyedEvent(handle, key, windows.FALSE, null);
assert(rc == 0);
return;
};
}
}
pub fn park(self: *WindowsParker, ptr: *const u32, expected: u32) void {
switch (Backend.get().*) {
.WaitAddress => |*backend| backend.park(ptr, expected, &self.waiters),
.KeyedEvent => |*backend| backend.park(ptr, expected, &self.waiters),
const handle = getEventHandlePtr().*;
const key = @ptrCast(*const c_void, ptr);
while (@atomicLoad(u32, ptr, .Acquire) == expected) {
_ = @atomicRmw(u32, &self.waiters, .Add, 1, .Release);
const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, null);
assert(rc == 0);
}
}
const Backend = union(enum) {
WaitAddress: WaitAddress,
KeyedEvent: KeyedEvent,
var event_handle = std.lazyInit(windows.HANDLE);
var backend = std.lazyInit(Backend);
fn get() *const Backend {
return backend.get() orelse {
// Statically linking to the KeyedEvent functions should mean its supported.
// TODO: Maybe add a CreateSemaphore backend for systems older than Windows XP ?
backend.data = WaitAddress.init()
orelse KeyedEvent.init()
orelse unreachable;
backend.resolve();
return &backend.data;
};
}
const WaitAddress = struct {
WakeByAddressSingle: stdcallcc fn(Address: *const c_void) void,
WaitOnAddress: stdcallcc fn (
Address: *const c_void,
CompareAddress: *const c_void,
AddressSize: windows.SIZE_T,
dwMilliseconds: windows.DWORD,
) windows.BOOL,
fn init() ?Backend {
const dll_name = c"api-ms-win-core-synch-l1-2-0";
const dll = windows.kernel32.GetModuleHandleA(dll_name)
orelse windows.kernel32.LoadLibraryA(dll_name)
orelse return null;
var self: WaitAddress = undefined;
const WaitOnAddress = windows.kernel32.GetProcAddress(dll, c"WaitOnAddress") orelse return null;
self.WaitOnAddress = @intToPtr(@typeOf(self.WaitOnAddress), @ptrToInt(WaitOnAddress));
const WakeByAddressSingle = windows.kernel32.GetProcAddress(dll, c"WakeByAddressSingle") orelse return null;
self.WakeByAddressSingle = @intToPtr(@typeOf(self.WakeByAddressSingle), @ptrToInt(WakeByAddressSingle));
return Backend{ .WaitAddress = self };
}
fn unpark(self: WaitAddress, ptr: *const u32, waiters: *u32) void {
const addr = @ptrCast(*const c_void, ptr);
self.WakeByAddressSingle(addr);
}
fn park(self: WaitAddress, ptr: *const u32, expected: u32, waiters: *u32) void {
var compare = expected;
const addr = @ptrCast(*const c_void, ptr);
const cmp = @ptrCast(*const c_void, &compare);
while (@atomicLoad(u32, ptr, .Acquire) == expected)
_ = self.WaitOnAddress(addr, cmp, @sizeOf(u32), windows.INFINITE);
}
fn getEventHandlePtr() *const windows.HANDLE {
return event_handle.get() orelse {
const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE;
if (windows.ntdll.NtCreateKeyedEvent(&event_handle.data, access_mask, null, 0) != 0)
@panic("Failed to setup an NT Keyed Event handle for the process");
event_handle.resolve();
return &event_handle.data;
};
const KeyedEvent = struct {
handle: windows.HANDLE,
fn init() ?Backend {
var self: KeyedEvent = undefined;
const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE;
if (windows.ntdll.NtCreateKeyedEvent(&self.handle, access_mask, null, 0) != 0)
return null;
return Backend{ .KeyedEvent = self };
}
fn unpark(self: KeyedEvent, ptr: *const u32, waiters: *u32) void {
const key = @ptrCast(*const c_void, ptr);
var waiting = @atomicLoad(u32, waiters, .Acquire);
while (waiting != 0) {
waiting = @cmpxchgWeak(u32, waiters, waiting, waiting - 1, .Acquire, .Monotonic) orelse {
const rc = windows.ntdll.NtReleaseKeyedEvent(self.handle, key, windows.FALSE, null);
assert(rc == 0);
return;
};
}
}
fn park(self: KeyedEvent, ptr: *const u32, expected: u32, waiters: *u32) void {
const key = @ptrCast(*const c_void, ptr);
while (@atomicLoad(u32, ptr, .Acquire) == expected) {
_ = @atomicRmw(u32, waiters, .Add, 1, .Release);
const rc = windows.ntdll.NtWaitForKeyedEvent(self.handle, key, windows.FALSE, null);
assert(rc == 0);
}
}
};
};
}
};
const PosixParker = struct {