Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt windows-rs #311

Merged
merged 1 commit into from Jan 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 > std::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);
}
}