use super::{ClockSource, Delta, Instant};
use crate::{prelude::*, types::Opaque};
use core::{marker::PhantomData, ptr::NonNull};
use pin_init::PinInit;
pub type HrTimerInstant<T> = Instant<<<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock>;
#[pin_data]
#[repr(C)]
pub struct HrTimer<T> {
#[pin]
timer: Opaque<bindings::hrtimer>,
_t: PhantomData<T>,
}
unsafe impl<T> Send for HrTimer<T> {}
unsafe impl<T> Sync for HrTimer<T> {}
impl<T> HrTimer<T> {
pub fn new() -> impl PinInit<Self>
where
T: HrTimerCallback,
T: HasHrTimer<T>,
{
pin_init!(Self {
timer <- Opaque::ffi_init(move |place: *mut bindings::hrtimer| {
unsafe {
bindings::hrtimer_setup(
place,
Some(T::Pointer::run),
<<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock::ID,
<T as HasHrTimer<T>>::TimerMode::C_MODE,
);
}
}),
_t: PhantomData,
})
}
unsafe fn raw_get(this: *const Self) -> *mut bindings::hrtimer {
unsafe { Opaque::cast_into(core::ptr::addr_of!((*this).timer)) }
}
pub(crate) unsafe fn raw_cancel(this: *const Self) -> bool {
let c_timer_ptr = unsafe { HrTimer::raw_get(this) };
unsafe { bindings::hrtimer_cancel(c_timer_ptr) != 0 }
}
#[inline]
unsafe fn raw_forward(self_ptr: *mut Self, now: HrTimerInstant<T>, interval: Delta) -> u64
where
T: HasHrTimer<T>,
{
unsafe {
bindings::hrtimer_forward(Self::raw_get(self_ptr), now.as_nanos(), interval.as_nanos())
}
}
pub fn forward(self: Pin<&mut Self>, now: HrTimerInstant<T>, interval: Delta) -> u64
where
T: HasHrTimer<T>,
{
let this = unsafe { self.get_unchecked_mut() };
unsafe { Self::raw_forward(this, now, interval) }
}
pub fn forward_now(self: Pin<&mut Self>, interval: Delta) -> u64
where
T: HasHrTimer<T>,
{
self.forward(HrTimerInstant::<T>::now(), interval)
}
pub fn expires(&self) -> HrTimerInstant<T>
where
T: HasHrTimer<T>,
{
let c_timer_ptr = unsafe { HrTimer::raw_get(self) };
unsafe {
Instant::from_ktime(
core::ptr::read_volatile(&raw const ((*c_timer_ptr).node.expires)),
)
}
}
}
pub trait HrTimerPointer: Sync + Sized {
type TimerMode: HrTimerMode;
type TimerHandle: HrTimerHandle;
fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle;
}
pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {
type TimerMode: HrTimerMode;
type TimerHandle: HrTimerHandle;
unsafe fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle;
}
pub unsafe trait ScopedHrTimerPointer {
type TimerMode: HrTimerMode;
fn start_scoped<T, F>(self, expires: <Self::TimerMode as HrTimerMode>::Expires, f: F) -> T
where
F: FnOnce() -> T;
}
unsafe impl<T> ScopedHrTimerPointer for T
where
T: UnsafeHrTimerPointer,
{
type TimerMode = T::TimerMode;
fn start_scoped<U, F>(
self,
expires: <<T as UnsafeHrTimerPointer>::TimerMode as HrTimerMode>::Expires,
f: F,
) -> U
where
F: FnOnce() -> U,
{
let handle = unsafe { UnsafeHrTimerPointer::start(self, expires) };
let t = f();
drop(handle);
t
}
}
pub trait RawHrTimerCallback {
type CallbackTarget<'a>;
unsafe extern "C" fn run(this: *mut bindings::hrtimer) -> bindings::hrtimer_restart;
}
pub trait HrTimerCallback {
type Pointer<'a>: RawHrTimerCallback;
fn run(
this: <Self::Pointer<'_> as RawHrTimerCallback>::CallbackTarget<'_>,
ctx: HrTimerCallbackContext<'_, Self>,
) -> HrTimerRestart
where
Self: Sized,
Self: HasHrTimer<Self>;
}
pub unsafe trait HrTimerHandle {
fn cancel(&mut self) -> bool;
}
pub unsafe trait HasHrTimer<T> {
type TimerMode: HrTimerMode;
unsafe fn raw_get_timer(this: *const Self) -> *const HrTimer<T>;
unsafe fn timer_container_of(ptr: *mut HrTimer<T>) -> *mut Self
where
Self: Sized;
unsafe fn c_timer_ptr(this: *const Self) -> *const bindings::hrtimer {
let timer_ptr = unsafe { Self::raw_get_timer(this) };
unsafe { HrTimer::raw_get(timer_ptr) }
}
unsafe fn start(this: *const Self, expires: <Self::TimerMode as HrTimerMode>::Expires) {
unsafe {
bindings::hrtimer_start_range_ns(
Self::c_timer_ptr(this).cast_mut(),
expires.as_nanos(),
0,
<Self::TimerMode as HrTimerMode>::C_MODE,
);
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(u32)]
pub enum HrTimerRestart {
NoRestart = bindings::hrtimer_restart_HRTIMER_NORESTART,
Restart = bindings::hrtimer_restart_HRTIMER_RESTART,
}
impl HrTimerRestart {
fn into_c(self) -> bindings::hrtimer_restart {
self as bindings::hrtimer_restart
}
}
pub trait HrTimerExpires {
fn as_nanos(&self) -> i64;
}
impl<C: ClockSource> HrTimerExpires for Instant<C> {
#[inline]
fn as_nanos(&self) -> i64 {
Instant::<C>::as_nanos(self)
}
}
impl HrTimerExpires for Delta {
#[inline]
fn as_nanos(&self) -> i64 {
Delta::as_nanos(*self)
}
}
mod private {
use crate::time::ClockSource;
pub trait Sealed {}
impl<C: ClockSource> Sealed for super::AbsoluteMode<C> {}
impl<C: ClockSource> Sealed for super::RelativeMode<C> {}
impl<C: ClockSource> Sealed for super::AbsolutePinnedMode<C> {}
impl<C: ClockSource> Sealed for super::RelativePinnedMode<C> {}
impl<C: ClockSource> Sealed for super::AbsoluteSoftMode<C> {}
impl<C: ClockSource> Sealed for super::RelativeSoftMode<C> {}
impl<C: ClockSource> Sealed for super::AbsolutePinnedSoftMode<C> {}
impl<C: ClockSource> Sealed for super::RelativePinnedSoftMode<C> {}
impl<C: ClockSource> Sealed for super::AbsoluteHardMode<C> {}
impl<C: ClockSource> Sealed for super::RelativeHardMode<C> {}
impl<C: ClockSource> Sealed for super::AbsolutePinnedHardMode<C> {}
impl<C: ClockSource> Sealed for super::RelativePinnedHardMode<C> {}
}
pub trait HrTimerMode: private::Sealed {
const C_MODE: bindings::hrtimer_mode;
type Clock: ClockSource;
type Expires: HrTimerExpires;
}
pub struct AbsoluteMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for AbsoluteMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS;
type Clock = C;
type Expires = Instant<C>;
}
pub struct RelativeMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for RelativeMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL;
type Clock = C;
type Expires = Delta;
}
pub struct AbsolutePinnedMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for AbsolutePinnedMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED;
type Clock = C;
type Expires = Instant<C>;
}
pub struct RelativePinnedMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for RelativePinnedMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED;
type Clock = C;
type Expires = Delta;
}
pub struct AbsoluteSoftMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for AbsoluteSoftMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_SOFT;
type Clock = C;
type Expires = Instant<C>;
}
pub struct RelativeSoftMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for RelativeSoftMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_SOFT;
type Clock = C;
type Expires = Delta;
}
pub struct AbsolutePinnedSoftMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for AbsolutePinnedSoftMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT;
type Clock = C;
type Expires = Instant<C>;
}
pub struct RelativePinnedSoftMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for RelativePinnedSoftMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT;
type Clock = C;
type Expires = Delta;
}
pub struct AbsoluteHardMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for AbsoluteHardMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_HARD;
type Clock = C;
type Expires = Instant<C>;
}
pub struct RelativeHardMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for RelativeHardMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_HARD;
type Clock = C;
type Expires = Delta;
}
pub struct AbsolutePinnedHardMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for AbsolutePinnedHardMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD;
type Clock = C;
type Expires = Instant<C>;
}
pub struct RelativePinnedHardMode<C: ClockSource>(PhantomData<C>);
impl<C: ClockSource> HrTimerMode for RelativePinnedHardMode<C> {
const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD;
type Clock = C;
type Expires = Delta;
}
pub struct HrTimerCallbackContext<'a, T: HasHrTimer<T>>(NonNull<HrTimer<T>>, PhantomData<&'a ()>);
impl<'a, T: HasHrTimer<T>> HrTimerCallbackContext<'a, T> {
pub(crate) unsafe fn from_raw(timer: *mut HrTimer<T>) -> Self {
Self(unsafe { NonNull::new_unchecked(timer) }, PhantomData)
}
pub fn forward(&mut self, now: HrTimerInstant<T>, interval: Delta) -> u64 {
unsafe { HrTimer::<T>::raw_forward(self.0.as_ptr(), now, interval) }
}
pub fn forward_now(&mut self, duration: Delta) -> u64 {
self.forward(HrTimerInstant::<T>::now(), duration)
}
}
#[macro_export]
macro_rules! impl_has_hr_timer {
(
impl$({$($generics:tt)*})?
HasHrTimer<$timer_type:ty>
for $self:ty
{
mode : $mode:ty,
field : self.$field:ident $(,)?
}
$($rest:tt)*
) => {
unsafe impl$(<$($generics)*>)? $crate::time::hrtimer::HasHrTimer<$timer_type> for $self {
type TimerMode = $mode;
#[inline]
unsafe fn raw_get_timer(
this: *const Self,
) -> *const $crate::time::hrtimer::HrTimer<$timer_type> {
unsafe { ::core::ptr::addr_of!((*this).$field) }
}
#[inline]
unsafe fn timer_container_of(
ptr: *mut $crate::time::hrtimer::HrTimer<$timer_type>,
) -> *mut Self {
unsafe { ::kernel::container_of!(ptr, $timer_type, $field) }
}
}
}
}
mod arc;
pub use arc::ArcHrTimerHandle;
mod pin;
pub use pin::PinHrTimerHandle;
mod pin_mut;
pub use pin_mut::PinMutHrTimerHandle;
mod tbox;
pub use tbox::BoxHrTimerHandle;