use std::sync::OnceLock;
use std::thread::Thread;
use std::time::Duration;
pub(super) struct Bell {
thread: OnceLock<Thread>,
#[cfg(windows)]
handles: Option<windows::Handles>,
}
impl Bell {
pub(super) fn new() -> Self {
Self {
thread: OnceLock::new(),
#[cfg(windows)]
handles: windows::Handles::new(),
}
}
pub(super) fn bind(&self) {
let _ = self.thread.set(std::thread::current());
}
pub(super) fn wait(&self) {
#[cfg(windows)]
if self.handles.as_ref().is_some_and(|h| h.wait(None)) {
return;
}
std::thread::park();
}
pub(super) fn wait_for(&self, left: Duration) {
#[cfg(windows)]
if self.handles.as_ref().is_some_and(|h| h.wait(Some(left))) {
return;
}
std::thread::park_timeout(left);
}
pub(super) fn ring(&self) {
#[cfg(windows)]
if let Some(handles) = &self.handles {
handles.ring();
}
if let Some(thread) = self.thread.get() {
thread.unpark();
}
}
}
#[cfg(windows)]
mod windows {
use std::time::Duration;
use crate::syscore::windows::{
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, CloseHandle, CreateEventW, CreateWaitableTimerExW,
HANDLE, INFINITE, SetEvent, SetWaitableTimer, TIMER_ALL_ACCESS, WAIT_OBJECT_0,
WaitForMultipleObjects, WaitForSingleObject,
};
pub(super) struct Handles {
event: HANDLE,
timer: HANDLE,
}
unsafe impl Send for Handles {}
unsafe impl Sync for Handles {}
impl Handles {
pub(super) fn new() -> Option<Self> {
unsafe {
let event = CreateEventW(core::ptr::null_mut(), 0, 0, core::ptr::null());
if event.is_null() {
return None;
}
let timer = CreateWaitableTimerExW(
core::ptr::null_mut(),
core::ptr::null(),
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
TIMER_ALL_ACCESS,
);
if timer.is_null() {
CloseHandle(event);
return None;
}
Some(Self { event, timer })
}
}
pub(super) fn wait(&self, left: Option<Duration>) -> bool {
unsafe {
let Some(left) = left else {
return WaitForSingleObject(self.event, INFINITE) == WAIT_OBJECT_0;
};
let due = -(i64::try_from(left.as_nanos().div_ceil(100)).unwrap_or(i64::MAX));
if SetWaitableTimer(
self.timer,
&due,
0,
core::ptr::null(),
core::ptr::null_mut(),
0,
) == 0
{
return false;
}
let both = [self.event, self.timer];
WaitForMultipleObjects(2, both.as_ptr(), 0, INFINITE) < WAIT_OBJECT_0 + 2
}
}
pub(super) fn ring(&self) {
unsafe {
SetEvent(self.event);
}
}
}
impl Drop for Handles {
fn drop(&mut self) {
unsafe {
CloseHandle(self.timer);
CloseHandle(self.event);
}
}
}
}