Skip to content

Commit

Permalink
Adopt windows-rs
Browse files Browse the repository at this point in the history
  • Loading branch information
clemenswasser committed Jan 8, 2022
1 parent c73dd43 commit bf79b74
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 85 deletions.
8 changes: 6 additions & 2 deletions core/Cargo.toml
Expand Up @@ -23,8 +23,12 @@ libc = "0.2.95"
redox_syscall = "0.2.8"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.9", features = ["winnt", "ntstatus", "minwindef",
"winerror", "winbase", "errhandlingapi", "handleapi"] }
windows-sys = { version = "0.29", features = [
"Win32_Foundation",
"Win32_System_LibraryLoader",
"Win32_System_SystemServices",
"Win32_System_WindowsProgramming",
] }

[features]
nightly = []
Expand Down
76 changes: 30 additions & 46 deletions core/src/thread_parker/windows/keyed_event.rs
Expand Up @@ -6,24 +6,18 @@
// copied, modified, or distributed except according to those terms.

use core::{
ffi,
mem::{self, MaybeUninit},
ptr,
};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;
use winapi::{
shared::{
minwindef::{TRUE, ULONG},
ntdef::NTSTATUS,
ntstatus::{STATUS_SUCCESS, STATUS_TIMEOUT},
},
um::{
handleapi::CloseHandle,
libloaderapi::{GetModuleHandleA, GetProcAddress},
winnt::{
ACCESS_MASK, BOOLEAN, GENERIC_READ, GENERIC_WRITE, HANDLE, LARGE_INTEGER, LPCSTR,
PHANDLE, PLARGE_INTEGER, PVOID,
},

use windows_sys::Win32::{
Foundation::{CloseHandle, BOOLEAN, HANDLE, NTSTATUS, STATUS_SUCCESS, STATUS_TIMEOUT},
System::{
LibraryLoader::{GetModuleHandleA, GetProcAddress},
SystemServices::{GENERIC_READ, GENERIC_WRITE},
},
};

Expand All @@ -36,58 +30,49 @@ pub struct KeyedEvent {
handle: HANDLE,
NtReleaseKeyedEvent: extern "system" fn(
EventHandle: HANDLE,
Key: PVOID,
Key: *mut ffi::c_void,
Alertable: BOOLEAN,
Timeout: PLARGE_INTEGER,
Timeout: *mut i64,
) -> NTSTATUS,
NtWaitForKeyedEvent: extern "system" fn(
EventHandle: HANDLE,
Key: PVOID,
Key: *mut ffi::c_void,
Alertable: BOOLEAN,
Timeout: PLARGE_INTEGER,
Timeout: *mut i64,
) -> NTSTATUS,
}

impl KeyedEvent {
#[inline]
unsafe fn wait_for(&self, key: PVOID, timeout: PLARGE_INTEGER) -> NTSTATUS {
(self.NtWaitForKeyedEvent)(self.handle, key, 0, timeout)
unsafe fn wait_for(&self, key: *mut ffi::c_void, timeout: *mut i64) -> NTSTATUS {
(self.NtWaitForKeyedEvent)(self.handle, key, false.into(), timeout)
}

#[inline]
unsafe fn release(&self, key: PVOID) -> NTSTATUS {
(self.NtReleaseKeyedEvent)(self.handle, key, 0, ptr::null_mut())
unsafe fn release(&self, key: *mut ffi::c_void) -> NTSTATUS {
(self.NtReleaseKeyedEvent)(self.handle, key, false.into(), ptr::null_mut())
}

#[allow(non_snake_case)]
pub fn create() -> Option<KeyedEvent> {
unsafe {
let ntdll = GetModuleHandleA(b"ntdll.dll\0".as_ptr() as LPCSTR);
if ntdll.is_null() {
let ntdll = GetModuleHandleA(b"ntdll.dll\0".as_ptr() as *mut u8);
if ntdll == 0 {
return None;
}

let NtCreateKeyedEvent =
GetProcAddress(ntdll, b"NtCreateKeyedEvent\0".as_ptr() as LPCSTR);
if NtCreateKeyedEvent.is_null() {
return None;
}
GetProcAddress(ntdll, b"NtCreateKeyedEvent\0".as_ptr() as *mut u8)?;
let NtReleaseKeyedEvent =
GetProcAddress(ntdll, b"NtReleaseKeyedEvent\0".as_ptr() as LPCSTR);
if NtReleaseKeyedEvent.is_null() {
return None;
}
GetProcAddress(ntdll, b"NtReleaseKeyedEvent\0".as_ptr() as *mut u8)?;
let NtWaitForKeyedEvent =
GetProcAddress(ntdll, b"NtWaitForKeyedEvent\0".as_ptr() as LPCSTR);
if NtWaitForKeyedEvent.is_null() {
return None;
}
GetProcAddress(ntdll, b"NtWaitForKeyedEvent\0".as_ptr() as *mut u8)?;

let NtCreateKeyedEvent: extern "system" fn(
KeyedEventHandle: PHANDLE,
DesiredAccess: ACCESS_MASK,
ObjectAttributes: PVOID,
Flags: ULONG,
KeyedEventHandle: *mut HANDLE,
DesiredAccess: u32,
ObjectAttributes: *mut ffi::c_void,
Flags: u32,
) -> NTSTATUS = mem::transmute(NtCreateKeyedEvent);
let mut handle = MaybeUninit::uninit();
let status = NtCreateKeyedEvent(
Expand Down Expand Up @@ -120,7 +105,7 @@ impl KeyedEvent {

#[inline]
pub unsafe fn park(&'static self, key: &AtomicUsize) {
let status = self.wait_for(key as *const _ as PVOID, ptr::null_mut());
let status = self.wait_for(key as *const _ as *mut ffi::c_void, ptr::null_mut());
debug_assert_eq!(status, STATUS_SUCCESS);
}

Expand All @@ -140,22 +125,21 @@ impl KeyedEvent {

// NT uses a timeout in units of 100ns. We use a negative value to
// indicate a relative timeout based on a monotonic clock.
let mut nt_timeout: LARGE_INTEGER = mem::zeroed();
let diff = timeout - now;
let value = (diff.as_secs() as i64)
.checked_mul(-10000000)
.and_then(|x| x.checked_sub((diff.subsec_nanos() as i64 + 99) / 100));

match value {
Some(x) => *nt_timeout.QuadPart_mut() = x,
let mut nt_timeout = match value {
Some(x) => x,
None => {
// Timeout overflowed, just sleep indefinitely
self.park(key);
return true;
}
};

let status = self.wait_for(key as *const _ as PVOID, &mut nt_timeout);
let status = self.wait_for(key as *const _ as *mut ffi::c_void, &mut nt_timeout);
if status == STATUS_SUCCESS {
return true;
}
Expand Down Expand Up @@ -192,7 +176,7 @@ impl Drop for KeyedEvent {
fn drop(&mut self) {
unsafe {
let ok = CloseHandle(self.handle);
debug_assert_eq!(ok, TRUE);
debug_assert_eq!(ok, true.into());
}
}
}
Expand All @@ -211,7 +195,7 @@ impl UnparkHandle {
#[inline]
pub unsafe fn unpark(self) {
if !self.key.is_null() {
let status = self.keyed_event.release(self.key as PVOID);
let status = self.keyed_event.release(self.key as *mut ffi::c_void);
debug_assert_eq!(status, STATUS_SUCCESS);
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/thread_parker/windows/mod.rs
Expand Up @@ -177,7 +177,7 @@ pub fn thread_yield() {
// libraries, but that'll probably take a lot longer than patching this here
// and avoiding the `synchapi` feature entirely.
extern "system" {
fn Sleep(a: winapi::shared::minwindef::DWORD);
fn Sleep(a: u32);
}
unsafe {
// We don't use SwitchToThread here because it doesn't consider all
Expand Down
61 changes: 25 additions & 36 deletions core/src/thread_parker/windows/waitaddress.rs
Expand Up @@ -9,30 +9,24 @@ use core::{
mem,
sync::atomic::{AtomicUsize, Ordering},
};
use std::time::Instant;
use winapi::{
shared::{
basetsd::SIZE_T,
minwindef::{BOOL, DWORD, FALSE, TRUE},
winerror::ERROR_TIMEOUT,
},
um::{
errhandlingapi::GetLastError,
libloaderapi::{GetModuleHandleA, GetProcAddress},
winbase::INFINITE,
winnt::{LPCSTR, PVOID},
use std::{ffi, time::Instant};
use windows_sys::Win32::{
Foundation::{GetLastError, BOOL, ERROR_TIMEOUT},
System::{
LibraryLoader::{GetModuleHandleA, GetProcAddress},
WindowsProgramming::INFINITE,
},
};

#[allow(non_snake_case)]
pub struct WaitAddress {
WaitOnAddress: extern "system" fn(
Address: PVOID,
CompareAddress: PVOID,
AddressSize: SIZE_T,
dwMilliseconds: DWORD,
Address: *mut ffi::c_void,
CompareAddress: *mut ffi::c_void,
AddressSize: usize,
dwMilliseconds: u32,
) -> BOOL,
WakeByAddressSingle: extern "system" fn(Address: PVOID),
WakeByAddressSingle: extern "system" fn(Address: *mut ffi::c_void),
}

impl WaitAddress {
Expand All @@ -42,20 +36,15 @@ impl WaitAddress {
// MSDN claims that that WaitOnAddress and WakeByAddressSingle are
// located in kernel32.dll, but they are lying...
let synch_dll =
GetModuleHandleA(b"api-ms-win-core-synch-l1-2-0.dll\0".as_ptr() as LPCSTR);
if synch_dll.is_null() {
GetModuleHandleA(b"api-ms-win-core-synch-l1-2-0.dll\0".as_ptr() as *mut u8);
if synch_dll == 0 {
return None;
}

let WaitOnAddress = GetProcAddress(synch_dll, b"WaitOnAddress\0".as_ptr() as LPCSTR);
if WaitOnAddress.is_null() {
return None;
}
let WaitOnAddress = GetProcAddress(synch_dll, b"WaitOnAddress\0".as_ptr() as *mut u8)?;
let WakeByAddressSingle =
GetProcAddress(synch_dll, b"WakeByAddressSingle\0".as_ptr() as LPCSTR);
if WakeByAddressSingle.is_null() {
return None;
}
GetProcAddress(synch_dll, b"WakeByAddressSingle\0".as_ptr() as *mut u8)?;

Some(WaitAddress {
WaitOnAddress: mem::transmute(WaitOnAddress),
WakeByAddressSingle: mem::transmute(WakeByAddressSingle),
Expand All @@ -77,7 +66,7 @@ impl WaitAddress {
pub fn park(&'static self, key: &AtomicUsize) {
while key.load(Ordering::Acquire) != 0 {
let r = self.wait_on_address(key, INFINITE);
debug_assert!(r == TRUE);
debug_assert!(r == true.into());
}
}

Expand All @@ -94,14 +83,14 @@ impl WaitAddress {
.checked_mul(1000)
.and_then(|x| x.checked_add((diff.subsec_nanos() as u64 + 999999) / 1000000))
.map(|ms| {
if ms > <DWORD>::max_value() as u64 {
if ms > u32::MAX as u64 {
INFINITE
} else {
ms as DWORD
ms as u32
}
})
.unwrap_or(INFINITE);
if self.wait_on_address(key, timeout) == FALSE {
if self.wait_on_address(key, timeout) == false.into() {
debug_assert_eq!(unsafe { GetLastError() }, ERROR_TIMEOUT);
}
}
Expand All @@ -120,12 +109,12 @@ impl WaitAddress {
}

#[inline]
fn wait_on_address(&'static self, key: &AtomicUsize, timeout: DWORD) -> BOOL {
fn wait_on_address(&'static self, key: &AtomicUsize, timeout: u32) -> BOOL {
let cmp = 1usize;
(self.WaitOnAddress)(
key as *const _ as PVOID,
&cmp as *const _ as PVOID,
mem::size_of::<usize>() as SIZE_T,
key as *const _ as *mut ffi::c_void,
&cmp as *const _ as *mut ffi::c_void,
mem::size_of::<usize>(),
timeout,
)
}
Expand All @@ -144,6 +133,6 @@ impl UnparkHandle {
// released to avoid blocking the queue for too long.
#[inline]
pub fn unpark(self) {
(self.waitaddress.WakeByAddressSingle)(self.key as PVOID);
(self.waitaddress.WakeByAddressSingle)(self.key as *mut ffi::c_void);
}
}

0 comments on commit bf79b74

Please sign in to comment.