use std::{cell::OnceCell, fmt, os::fd::{AsFd, RawFd}, sync::{Arc, Weak}};
use nix::{errno::Errno, sys::eventfd::EventFd};
use crate::
{
FdTimerCom,
TimerReadRes, error::{TimerErrorType, TimerResult}, map_timer_err, timer_portable::{TimerFd, portable_error::TimerPortableErr, timer::{FdTimerMarker, FdTimerRead}}
};
#[cfg(target_os = "linux")]
pub use super::linux::timer_poll::TimerEventWatch;
#[cfg(target_os = "linux")]
pub type DefaultEventWatch = TimerEventWatch;
#[cfg(
any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
target_os = "macos",
)
)]
pub use super::bsd::TimerEventWatch;
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
target_os = "macos",
))]
pub type DefaultEventWatch = TimerEventWatch;
#[derive(Debug, PartialEq, Eq)]
pub enum PollEventType
{
TimerRes(RawFd, TimerReadRes<u64>),
SubError(RawFd, TimerPortableErr)
}
impl fmt::Display for PollEventType
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self
{
Self::TimerRes(timer, res) =>
write!(f, "timer {}, res: {}", timer, res),
Self::SubError(timer, err) =>
write!(f, "timer {}, error: {}", timer, err)
}
}
}
impl PollEventType
{
pub
fn get_err(&self) -> Option<&TimerPortableErr>
{
let Self::SubError(_, err) = self
else { return None };
return Some(err);
}
}
#[derive(Debug)]
pub struct PolledTimerFd<T: FdTimerMarker>
{
arc_timer: OnceCell<T>,
poll_back_ref: Weak<DefaultEventWatch>
}
impl<T: FdTimerMarker> fmt::Display for PolledTimerFd<T>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "timer: {}, poll: {}",
self.arc_timer.get().unwrap(),
self.poll_back_ref.upgrade().map_or("poll instance removed".into(), |f| f.to_string())
)
}
}
impl<T: FdTimerMarker> Eq for PolledTimerFd<T> {}
impl<T: FdTimerMarker> PartialEq for PolledTimerFd<T>
{
fn eq(&self, other: &Self) -> bool
{
return self.arc_timer == other.arc_timer;
}
}
impl<T: FdTimerMarker> PartialEq<RawFd> for PolledTimerFd<T>
{
fn eq(&self, other: &RawFd) -> bool
{
return self.arc_timer.get().map_or(false, |f| f == other);
}
}
impl<T: FdTimerMarker> PartialEq<str> for PolledTimerFd<T>
{
fn eq(&self, other: &str) -> bool
{
return self.arc_timer.get().map_or(false, |f| f.as_ref() == other);
}
}
impl<T: FdTimerMarker> AsRef<str> for PolledTimerFd<T>
{
fn as_ref(&self) -> &str
{
return self.arc_timer.get().unwrap().as_ref().as_ref();
}
}
impl<T: FdTimerMarker> Ord for PolledTimerFd<T>
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering
{
return self.arc_timer.get().unwrap().as_raw_fd().cmp(&other.arc_timer.get().unwrap().as_raw_fd());
}
}
impl<T: FdTimerMarker> PartialOrd for PolledTimerFd <T>
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering>
{
return Some(self.cmp(other));
}
}
impl<T: FdTimerMarker> Drop for PolledTimerFd<T>
{
fn drop(&mut self)
{
let Some(t) = self.arc_timer.take()
else { return };
let Some(poll_ref) = self.poll_back_ref.upgrade()
else { return };
let _ = poll_ref.delete(&t);
}
}
impl<T: FdTimerMarker> PolledTimerFd<T>
{
fn attached_timer(timer: T, poll: Weak<DefaultEventWatch>) -> TimerResult<Self>
{
let once = OnceCell::new();
once.get_or_init(|| timer);
return Ok(
Self
{
arc_timer:
once,
poll_back_ref:
poll
}
);
}
pub
fn detach_timer(mut self) -> Result<T, Self>
{
if self.arc_timer.get().unwrap().get_strong_count() > 2
{
return Err(self);
}
if let Some(poll_ref) = self.poll_back_ref.upgrade()
{
let _ = poll_ref.delete(self.arc_timer.get().unwrap().as_fd());
}
let timer = self.arc_timer.take().unwrap();
return Ok(timer);
}
pub
fn is_poll_valid(&self) -> bool
{
return self.poll_back_ref.upgrade().is_some();
}
pub
fn get_inner(&self) -> &T
{
return self.arc_timer.get().unwrap();
}
pub
fn get_inner_mut(&mut self) -> &mut T
{
return self.arc_timer.get_mut().unwrap();
}
}
pub trait TimerPollOps
{
fn new() -> TimerResult<Self> where Self: Sized;
fn add(&self, timer: TimerFd) -> TimerResult<()>;
fn delete<FD: AsFd>(&self, timer: FD) -> TimerResult<()>;
fn poll(&self, timeout: Option<i32>) -> TimerResult<Option<Vec<PollEventType>>>;
fn get_count(&self) -> usize;
fn get_poll_interruptor(&self) -> PollInterrupt;
fn interrupt_poll(&self) -> bool;
}
#[derive(Debug)]
pub struct PollInterruptAq(Arc<EventFd>);
impl PollInterruptAq
{
pub
fn interrupt(&self) -> TimerResult<()>
{
return
self
.0
.write(1)
.map_err(|e|
map_timer_err!(TimerErrorType::EPoll(e), "can not interrupt POLL!")
)
.map(|_| ());
}
pub
fn interrupt_drop(self) -> TimerResult<()>
{
return
self.interrupt();
}
}
#[derive(Debug, Clone)]
pub struct PollInterrupt(Weak<EventFd>);
impl PollInterrupt
{
pub
fn new(ev_weak: Weak<EventFd>) -> Self
{
return Self(ev_weak);
}
pub
fn aquire(&self) -> TimerResult<PollInterruptAq>
{
return
self
.0
.upgrade()
.ok_or_else(||
map_timer_err!(TimerErrorType::EPoll(Errno::EINVAL), "timer poll has gone and not active!")
)
.map(|v| PollInterruptAq(v));
}
}
#[repr(transparent)]
#[derive(Debug, Clone)]
pub struct TimerPoll(Arc<DefaultEventWatch>);
impl fmt::Display for TimerPoll
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
write!(f, "{}", self.0.as_ref())
}
}
impl TimerPoll
{
#[inline]
fn get_timer(&self) -> &DefaultEventWatch
{
return &self.0;
}
pub
fn new() -> TimerResult<Self>
{
return Ok( Self( Arc::new(DefaultEventWatch::new()?) ) );
}
pub(super)
fn downgrade(&self) -> Weak<DefaultEventWatch>
{
return Arc::downgrade(&self.0);
}
pub
fn add<T: FdTimerMarker>(&self, timer: T) -> TimerResult<PolledTimerFd<T>>
{
let timer_fd: TimerFd = timer.clone_timer();
let timer_fd_status =
timer_fd
.get_timer()
.is_nonblocking()
.map_err(|e|
map_timer_err!(TimerErrorType::TimerError(e.get_errno()),
"timer: '{}', is_nonblocking error: '{}'", timer_fd, e)
)?;
if timer_fd_status == false
{
timer_fd
.get_timer()
.set_nonblocking(true)
.map_err(|e|
map_timer_err!(TimerErrorType::TimerError(e.get_errno()),
"timer: '{}', set_nonblocking error: '{}'", timer_fd, e)
)?
}
self.get_timer().add(timer.clone_timer())?;
return PolledTimerFd::attached_timer(timer, self.downgrade());
}
#[inline]
pub
fn poll(&self, timeout: Option<i32>) -> TimerResult<Option<Vec<PollEventType>>>
{
return self.get_timer().poll(timeout);
}
#[inline]
pub
fn get_poll_interruptor(&self) -> PollInterrupt
{
return self.get_timer().get_poll_interruptor();
}
#[inline]
pub
fn interrupt_poll(&self) -> bool
{
return self.get_timer().interrupt_poll();
}
}
#[cfg(test)]
mod tests
{
use std::{borrow::Cow, os::fd::AsRawFd};
use crate::{common, timer_portable::{timer::{AbsoluteTime, TimerFd}, TimerExpMode, TimerFlags, TimerType}, FdTimerCom, RelativeTime, TimerPoll};
use super::*;
#[test]
fn test_kqueue()
{
let timer1 =
TimerFd::new("test".into(), TimerType::CLOCK_REALTIME, TimerFlags::TFD_NONBLOCK)
.unwrap();
let poll = TimerPoll::new().unwrap();
let polled_timer1 = poll.add(timer1).unwrap();
let tss_set = AbsoluteTime::now().add_sec(2);
let tss_tm = TimerExpMode::<AbsoluteTime>::OneShot { timeout: tss_set };
polled_timer1.get_inner().get_timer().set_time(tss_tm).unwrap();
let res =poll.poll(None).unwrap();
assert_eq!(res.is_some(), true);
assert_eq!(res.as_ref().unwrap().len(), 1);
assert_eq!(res.unwrap()[0], PollEventType::TimerRes(polled_timer1.get_inner().as_raw_fd(), crate::TimerReadRes::Ok(1)));
}
#[test]
fn test_kqueue_1()
{
let ts = common::get_current_timestamp();
let timer1 =
TimerFd::new(Cow::Borrowed("test1"), TimerType::CLOCK_REALTIME, TimerFlags::TFD_NONBLOCK)
.unwrap();
let timer1_time =
TimerExpMode::<AbsoluteTime>::new_oneshot(AbsoluteTime::from(ts) + RelativeTime::new_time(2, 0));
let timer2 =
TimerFd::new(Cow::Borrowed("test2"), TimerType::CLOCK_REALTIME, TimerFlags::TFD_NONBLOCK)
.unwrap();
let timer2_time =
TimerExpMode::<AbsoluteTime>::new_oneshot(AbsoluteTime::from(ts) + RelativeTime::new_time(3, 0));
let poll = TimerPoll::new().unwrap();
let timer1 = poll.add(timer1).unwrap();
let timer2 = poll.add(timer2).unwrap();
timer1.get_inner().get_timer().set_time(timer1_time).unwrap();
timer2.get_inner().get_timer().set_time(timer2_time).unwrap();
let res = poll.poll(None).unwrap();
println!("{:?}", res);
for i in res.unwrap()
{
println!("{:?}", i);
}
let res = poll.poll(None);
println!("{:?}", res);
let res = poll.poll(Some(1000));
println!("{:?}", res);
drop(timer2);
}
}