use std::{borrow::Cow, fmt, os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, OwnedHandle, RawHandle}, ptr::{self, null}, task::Poll};
use crossbeam_utils::atomic::AtomicCell;
use windows::
{
Win32::
{
Foundation::{HANDLE, WAIT_OBJECT_0, WAIT_TIMEOUT}, Security::SECURITY_ATTRIBUTES, System::Threading::
{
CancelWaitableTimer,
CreateWaitableTimerExW,
EVENT_ALL_ACCESS,
INFINITE,
SetWaitableTimer,
WaitForSingleObject
}
},
core::{Error, PCWSTR}
};
use crate::
{
FdTimerCom,
TimerReadRes,
map_portable_err,
portable_err,
timer_portable::
{
AsTimerId, TimerExpMode, TimerId, portable_error::TimerPortResult, timer::{FdTimerRead, ModeTimeType}, windows::{UnixFd, itimerspec}
}
};
use super::{TimerFlags, TimerType};
#[derive(Debug)]
pub struct TimerFdInternal
{
label: Cow<'static, str>,
timer_fd: OwnedHandle,
timer_flags: AtomicCell<TimerFlags>,
}
impl AsHandle for TimerFdInternal
{
fn as_handle(&self) -> BorrowedHandle<'_>
{
return self.timer_fd.as_handle();
}
}
impl AsRawHandle for TimerFdInternal
{
fn as_raw_handle(&self) -> RawHandle
{
return self.timer_fd.as_raw_handle();
}
}
impl Eq for TimerFdInternal {}
impl PartialEq for TimerFdInternal
{
fn eq(&self, other: &Self) -> bool
{
return self.timer_fd.as_raw_handle() == other.timer_fd.as_raw_handle();
}
}
impl PartialEq<str> for TimerFdInternal
{
fn eq(&self, other: &str) -> bool
{
return self.label == other;
}
}
impl AsRef<str> for TimerFdInternal
{
fn as_ref(&self) -> &str
{
return &self.label;
}
}
impl fmt::Display for TimerFdInternal
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{:p}", self.timer_fd.as_raw_handle())
}
}
impl PartialEq<RawHandle> for TimerFdInternal
{
fn eq(&self, other: &RawHandle) -> bool
{
return self.timer_fd.as_raw_handle() == *other;
}
}
impl UnixFd for TimerFdInternal
{
}
impl AsTimerId for TimerFdInternal
{
fn as_timer_id(&self) -> TimerId
{
return TimerId::from(self.timer_fd.as_raw_handle());
}
}
impl FdTimerRead for TimerFdInternal
{
#[inline]
fn read(&self) -> TimerPortResult<TimerReadRes<u64>>
{
let timeout =
if self.timer_flags.load().intersects(TimerFlags::TFD_NONBLOCK) == true
{
0
}
else
{
INFINITE
};
let res =
unsafe { WaitForSingleObject(HANDLE(self.timer_fd.as_raw_handle()), timeout) };
if res == WAIT_OBJECT_0
{
return Ok(TimerReadRes::ok());
}
else if res == WAIT_TIMEOUT
{
return Ok(TimerReadRes::WouldBlock);
}
else
{
portable_err!(Error::empty(), "read timer overflow error for timer: '{}'", self.label)
}
}
}
impl FdTimerCom for TimerFdInternal
{
fn new(label: Cow<'static, str>, _timer_type: TimerType, timer_flags: TimerFlags) -> TimerPortResult<Self>
where
Self: Sized
{
let mut label_cstr: Vec<u16> = label.as_ref().encode_utf16().collect();
label_cstr.push(0);
let timer_attr = None;
let hndl =
unsafe
{
CreateWaitableTimerExW(
timer_attr.map(|f| &f as *const _),
PCWSTR::from_raw(label_cstr.as_ptr()),
0,
EVENT_ALL_ACCESS.0
)
}
.map_err(|e|
map_portable_err!(e, "timer: '{}' create timer error", label)
)?;
return Ok(
Self
{
label:
label,
timer_fd:
unsafe { OwnedHandle::from_raw_handle(hndl.0) },
timer_flags:
AtomicCell::new(timer_flags)
}
);
}
fn set_time<TIMERTYPE: ModeTimeType>(&self, timer_exp: TimerExpMode<TIMERTYPE>) -> TimerPortResult<()>
{
let timeout: itimerspec = timer_exp.try_into()?;
return
unsafe
{
SetWaitableTimer(
HANDLE(self.timer_fd.as_raw_handle()),
&timeout.it_value as *const i64,
timeout.it_interval,
None,
None,
false
)
}
.map_err(|e|
map_portable_err!(e, "timer: '{}'set timer error", self.label)
);
}
fn unset_time(&self) -> TimerPortResult<()>
{
return
unsafe { CancelWaitableTimer(HANDLE(self.timer_fd.as_raw_handle())) }
.map_err(|e|
map_portable_err!(e, "timer: '{}' unset timer error", self.label)
);
}
fn set_nonblocking(&self, flag: bool) -> TimerPortResult<()>
{
let old_timer_flags = self.timer_flags.load();
let mut timer_flags = old_timer_flags.clone();
timer_flags.set(TimerFlags::TFD_NONBLOCK, flag);
if self.timer_flags.swap(timer_flags) != old_timer_flags
{
map_portable_err!(Error::empty(), "changed from another thread");
}
return Ok(());
}
fn is_nonblocking(&self) -> TimerPortResult<bool>
{
let old_timer_flags = self.timer_flags.load();
return Ok(old_timer_flags.intersects(TimerFlags::TFD_NONBLOCK));
}
}
impl Future for &TimerFdInternal
{
type Output = TimerPortResult<TimerReadRes<u64>>;
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output>
{
let res = self.read();
if let Ok(TimerReadRes::WouldBlock) = res
{
cx.waker().wake_by_ref();
return Poll::Pending;
}
else
{
return Poll::Ready(res);
}
}
}
impl Future for TimerFdInternal
{
type Output = TimerPortResult<TimerReadRes<u64>>;
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output>
{
let res = self.read();
if let Ok(TimerReadRes::WouldBlock) = res
{
cx.waker().wake_by_ref();
return Poll::Pending;
}
else
{
return Poll::Ready(res);
}
}
}