#[cfg(feature = "bsd_use_timerfd")]
pub mod timer_fd_bsd;
#[cfg(not(feature = "bsd_use_timerfd"))]
pub mod timer_kqueue_fd_bsd;
#[cfg(feature = "bsd_use_poll")]
pub mod timer_poll;
#[cfg(feature = "bsd_use_poll")]
pub use timer_poll::TimerEventWatch;
#[cfg(not(feature = "bsd_use_poll"))]
pub mod timer_kqueue_bsd;
#[cfg(not(feature = "bsd_use_poll"))]
pub use timer_kqueue_bsd::TimerEventWatch;
#[cfg(not(feature = "bsd_use_timerfd"))]
pub mod kqueue_itimerspecs_specific
{
use nix::{errno::Errno, sys::event::{EvFlags, EventFilter, FilterFlag, KEvent}};
use crate::{portable_err, timer_portable::{portable_error::TimerPortableErr, timer::ModeTimeType, TimerExpMode, TimerSetTimeFlags}};
#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
pub(crate) struct itimerspeckenent
{
pub it_value: KEvent,
pub it_delay_int: Option<(i64, FilterFlag)>,
}
impl itimerspeckenent
{
pub(crate)
fn is_interv_with_delay(&self) -> bool
{
return self.it_delay_int.is_some();
}
}
impl From<TimerSetTimeFlags> for FilterFlag
{
fn from(value: TimerSetTimeFlags) -> Self
{
if value.intersects(TimerSetTimeFlags::TFD_TIMER_ABSTIME) == true
{
return Self::from_bits_retain(0x00000010);
}
return Self::empty();
}
}
pub(crate)
fn from_timeout<M: ModeTimeType>(timeout: &M) -> (i64, FilterFlag)
{
let (data, fflags) =
timeout
.get_sec()
.checked_mul(1_000_000_000)
.map(|val|
{
let ret_val =
val
.checked_add(timeout.get_nsec())
.or(Some(val))
.unwrap();
(ret_val, FilterFlag::NOTE_NSECONDS)
}
)
.or(
timeout
.get_sec()
.checked_mul(1_000_000)
.map(|val|
{
let ret_val =
timeout
.get_nsec()
.checked_div(1_000_000)
.and_then(|v| val.checked_add(v))
.or(Some(val))
.unwrap();
(ret_val, FilterFlag::NOTE_USECONDS)
}
)
.or(
timeout
.get_sec()
.checked_mul(1_000)
.map(|val|
{
let ret_val =
timeout
.get_nsec()
.checked_div(1_000)
.and_then(|v| val.checked_add(v))
.or(Some(val))
.unwrap();
(ret_val, FilterFlag::NOTE_MSECONDS)
}
)
.or(Some((timeout.get_sec(), FilterFlag::NOTE_SECONDS)))
)
)
.unwrap();
return (data, fflags);
}
impl<TIMERTYPE: ModeTimeType> TryFrom<TimerExpMode<TIMERTYPE>> for itimerspeckenent
{
type Error = TimerPortableErr;
fn try_from(value: TimerExpMode<TIMERTYPE>) -> Result<Self, Self::Error>
{
return (&value).try_into();
}
}
impl<TIMERTYPE: ModeTimeType> TryFrom<&TimerExpMode<TIMERTYPE>> for itimerspeckenent
{
type Error = TimerPortableErr;
fn try_from(value: &TimerExpMode<TIMERTYPE>) -> Result<Self, Self::Error>
{
match value
{
TimerExpMode::None =>
portable_err!(Errno::EINVAL, "null timer values"),
TimerExpMode::OneShot { timeout } =>
{
let (data, fflags) = from_timeout(timeout);
let fflags = fflags | TIMERTYPE::get_flags().into();
let ev =
KEvent::new(
0,
EventFilter::EVFILT_TIMER,
EvFlags::EV_ADD | EvFlags::EV_ENABLE | EvFlags::EV_ONESHOT,
fflags,
data as isize,
0
);
return Ok(
itimerspeckenent
{
it_value: ev,
it_delay_int: None,
}
);
},
TimerExpMode::IntervalDelayed { delay_tm, interv_tm } =>
{
let (data_delay, fflags) = from_timeout(delay_tm);
let fflags = fflags | TIMERTYPE::get_flags().into();
let ev_delay =
KEvent::new(
0,
EventFilter::EVFILT_TIMER,
EvFlags::EV_ADD | EvFlags::EV_ENABLE | EvFlags::EV_ONESHOT,
fflags,
data_delay as isize,
0
);
let (data_interv, fflags) = from_timeout(interv_tm);
let fflags = fflags | TIMERTYPE::get_flags().into();
return Ok(
itimerspeckenent
{
it_value: ev_delay,
it_delay_int: Some((data_interv, fflags)),
}
);
},
TimerExpMode::Interval { interv_tm } =>
{
let (data, fflags) = from_timeout(interv_tm);
let fflags = fflags | TIMERTYPE::get_flags().into();
let ev =
KEvent::new(
0,
EventFilter::EVFILT_TIMER,
EvFlags::EV_ADD | EvFlags::EV_ENABLE,
fflags,
data as isize,
0
);
return Ok(
itimerspeckenent
{
it_value: ev,
it_delay_int: None,
}
);
},
}
}
}
#[cfg(test)]
mod tests
{
use super::*;
#[test]
fn test_itimerspeckenent_1()
{
let fflags: FilterFlag = (TimerSetTimeFlags::TFD_TIMER_ABSTIME | TimerSetTimeFlags::TFD_TIMER_CANCEL_ON_SET).into();
assert_eq!(fflags.intersects(FilterFlag::from_bits_retain(0x00000010)), true);
let fflags: FilterFlag = TimerSetTimeFlags::empty().into();
assert_eq!(fflags.is_empty(), true);
}
}
}