1120 lines · 38.5 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 //! Intrusive high resolution timers.//!//! Allows running timer callbacks without doing allocations at the time of//! starting the timer. For now, only one timer per type is allowed.//!//! # Vocabulary//!//! States://!//! - Stopped: initialized but not started, or cancelled, or not restarted.//! - Started: initialized and started or restarted.//! - Running: executing the callback.//!//! Operations://!//! * Start//! * Cancel//! * Restart//!//! Events://!//! * Expire//!//! ## State Diagram//!//! ```text//!                                                   Return NoRestart//!                       +---------------------------------------------------------------------+//!                       |                                                                     |//!                       |                                                                     |//!                       |                                                                     |//!                       |                                         Return Restart              |//!                       |                                      +------------------------+     |//!                       |                                      |                        |     |//!                       |                                      |                        |     |//!                       v                                      v                        |     |//!           +-----------------+      Start      +------------------+           +--------+-----+--+//!           |                 +---------------->|                  |           |                 |//! Init      |                 |                 |                  |  Expire   |                 |//! --------->|    Stopped      |                 |      Started     +---------->|     Running     |//!           |                 |     Cancel      |                  |           |                 |//!           |                 |<----------------+                  |           |                 |//!           +-----------------+                 +---------------+--+           +-----------------+//!                                                     ^         |//!                                                     |         |//!                                                     +---------+//!                                                      Restart//! ```//!//!//! A timer is initialized in the **stopped** state. A stopped timer can be//! **started** by the `start` operation, with an **expiry** time. After the//! `start` operation, the timer is in the **started** state. When the timer//! **expires**, the timer enters the **running** state and the handler is//! executed. After the handler has returned, the timer may enter the//! **started* or **stopped** state, depending on the return value of the//! handler. A timer in the **started** or **running** state may be **canceled**//! by the `cancel` operation. A timer that is cancelled enters the **stopped**//! state.//!//! A `cancel` or `restart` operation on a timer in the **running** state takes//! effect after the handler has returned and the timer has transitioned//! out of the **running** state.//!//! A `restart` operation on a timer in the **stopped** state is equivalent to a//! `start` operation.//!//! When a type implements both `HrTimerPointer` and `Clone`, it is possible to//! issue the `start` operation while the timer is in the **started** state. In//! this case the `start` operation is equivalent to the `restart` operation.//!//! # Examples//!//! ## Using an intrusive timer living in a [`Box`]//!//! ```//! # use kernel::{//! #     alloc::flags,//! #     impl_has_hr_timer,//! #     prelude::*,//! #     sync::{//! #         atomic::{ordering, Atomic},//! #         completion::Completion,//! #         Arc,//! #     },//! #     time::{//! #         hrtimer::{//! #             RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer,//! #             HrTimerRestart, HrTimerCallbackContext//! #         },//! #         Delta, Monotonic,//! #     },//! # };//!//! #[pin_data]//! struct Shared {//!     #[pin]//!     flag: Atomic<u64>,//!     #[pin]//!     cond: Completion,//! }//!//! impl Shared {//!     fn new() -> impl PinInit<Self> {//!         pin_init!(Self {//!             flag <- Atomic::new(0),//!             cond <- Completion::new(),//!         })//!     }//! }//!//! #[pin_data]//! struct BoxIntrusiveHrTimer {//!     #[pin]//!     timer: HrTimer<Self>,//!     shared: Arc<Shared>,//! }//!//! impl BoxIntrusiveHrTimer {//!     fn new() -> impl PinInit<Self, kernel::error::Error> {//!         try_pin_init!(Self {//!             timer <- HrTimer::new(),//!             shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,//!         })//!     }//! }//!//! impl HrTimerCallback for BoxIntrusiveHrTimer {//!     type Pointer<'a> = Pin<KBox<Self>>;//!//!     fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {//!         pr_info!("Timer called\n");//!//!         let flag = this.shared.flag.fetch_add(1, ordering::Full);//!         this.shared.cond.complete_all();//!//!         if flag == 4 {//!             HrTimerRestart::NoRestart//!         } else {//!             HrTimerRestart::Restart//!         }//!     }//! }//!//! impl_has_hr_timer! {//!     impl HasHrTimer<Self> for BoxIntrusiveHrTimer {//!         mode: RelativeMode<Monotonic>, field: self.timer//!     }//! }//!//! let has_timer = Box::pin_init(BoxIntrusiveHrTimer::new(), GFP_KERNEL)?;//! let shared = has_timer.shared.clone();//! let _handle = has_timer.start(Delta::from_micros(200));//!//! while shared.flag.load(ordering::Relaxed) != 5 {//!     shared.cond.wait_for_completion();//! }//!//! pr_info!("Counted to 5\n");//! # Ok::<(), kernel::error::Error>(())//! ```//!//! ## Using an intrusive timer in an [`Arc`]//!//! ```//! # use kernel::{//! #     alloc::flags,//! #     impl_has_hr_timer,//! #     prelude::*,//! #     sync::{//! #         atomic::{ordering, Atomic},//! #         completion::Completion,//! #         Arc, ArcBorrow,//! #     },//! #     time::{//! #         hrtimer::{//! #             RelativeMode, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,//! #             HasHrTimer, HrTimerCallbackContext//! #         },//! #         Delta, Monotonic,//! #     },//! # };//!//! #[pin_data]//! struct ArcIntrusiveHrTimer {//!     #[pin]//!     timer: HrTimer<Self>,//!     #[pin]//!     flag: Atomic<u64>,//!     #[pin]//!     cond: Completion,//! }//!//! impl ArcIntrusiveHrTimer {//!     fn new() -> impl PinInit<Self> {//!         pin_init!(Self {//!             timer <- HrTimer::new(),//!             flag <- Atomic::new(0),//!             cond <- Completion::new(),//!         })//!     }//! }//!//! impl HrTimerCallback for ArcIntrusiveHrTimer {//!     type Pointer<'a> = Arc<Self>;//!//!     fn run(//!         this: ArcBorrow<'_, Self>,//!         _ctx: HrTimerCallbackContext<'_, Self>,//!     ) -> HrTimerRestart {//!         pr_info!("Timer called\n");//!//!         let flag = this.flag.fetch_add(1, ordering::Full);//!         this.cond.complete_all();//!//!         if flag == 4 {//!             HrTimerRestart::NoRestart//!         } else {//!             HrTimerRestart::Restart//!         }//!     }//! }//!//! impl_has_hr_timer! {//!     impl HasHrTimer<Self> for ArcIntrusiveHrTimer {//!         mode: RelativeMode<Monotonic>, field: self.timer//!     }//! }//!//! let has_timer = Arc::pin_init(ArcIntrusiveHrTimer::new(), GFP_KERNEL)?;//! let _handle = has_timer.clone().start(Delta::from_micros(200));//!//! while has_timer.flag.load(ordering::Relaxed) != 5 {//!     has_timer.cond.wait_for_completion();//! }//!//! pr_info!("Counted to 5\n");//! # Ok::<(), kernel::error::Error>(())//! ```//!//! ## Using a stack-based timer//!//! ```//! # use kernel::{//! #     impl_has_hr_timer,//! #     prelude::*,//! #     sync::{//! #         atomic::{ordering, Atomic},//! #         completion::Completion,//! #     },//! #     time::{//! #         hrtimer::{//! #             ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,//! #             HasHrTimer, RelativeMode, HrTimerCallbackContext//! #         },//! #         Delta, Monotonic,//! #     },//! # };//! # use pin_init::stack_pin_init;//!//! #[pin_data]//! struct IntrusiveHrTimer {//!     #[pin]//!     timer: HrTimer<Self>,//!     #[pin]//!     flag: Atomic<u64>,//!     #[pin]//!     cond: Completion,//! }//!//! impl IntrusiveHrTimer {//!     fn new() -> impl PinInit<Self> {//!         pin_init!(Self {//!             timer <- HrTimer::new(),//!             flag <- Atomic::new(0),//!             cond <- Completion::new(),//!         })//!     }//! }//!//! impl HrTimerCallback for IntrusiveHrTimer {//!     type Pointer<'a> = Pin<&'a Self>;//!//!     fn run(this: Pin<&Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {//!         pr_info!("Timer called\n");//!//!         this.flag.store(1, ordering::Release);//!         this.cond.complete_all();//!//!         HrTimerRestart::NoRestart//!     }//! }//!//! impl_has_hr_timer! {//!     impl HasHrTimer<Self> for IntrusiveHrTimer {//!         mode: RelativeMode<Monotonic>, field: self.timer//!     }//! }//!//! stack_pin_init!( let has_timer = IntrusiveHrTimer::new() );//! has_timer.as_ref().start_scoped(Delta::from_micros(200), || {//!     while has_timer.flag.load(ordering::Relaxed) != 1 {//!         has_timer.cond.wait_for_completion();//!     }//! });//!//! pr_info!("Flag raised\n");//! # Ok::<(), kernel::error::Error>(())//! ```//!//! ## Using a mutable stack-based timer//!//! ```//! # use kernel::{//! #     alloc::flags,//! #     impl_has_hr_timer,//! #     prelude::*,//! #     sync::{//! #         atomic::{ordering, Atomic},//! #         completion::Completion,//! #         Arc,//! #     },//! #     time::{//! #         hrtimer::{//! #             ScopedHrTimerPointer, HrTimer, HrTimerCallback, HrTimerPointer, HrTimerRestart,//! #             HasHrTimer, RelativeMode, HrTimerCallbackContext//! #         },//! #         Delta, Monotonic,//! #     },//! # };//! # use pin_init::stack_try_pin_init;//!//! #[pin_data]//! struct Shared {//!     #[pin]//!     flag: Atomic<u64>,//!     #[pin]//!     cond: Completion,//! }//!//! impl Shared {//!     fn new() -> impl PinInit<Self> {//!         pin_init!(Self {//!             flag <- Atomic::new(0),//!             cond <- Completion::new(),//!         })//!     }//! }//!//! #[pin_data]//! struct IntrusiveHrTimer {//!     #[pin]//!     timer: HrTimer<Self>,//!     shared: Arc<Shared>,//! }//!//! impl IntrusiveHrTimer {//!     fn new() -> impl PinInit<Self, kernel::error::Error> {//!         try_pin_init!(Self {//!             timer <- HrTimer::new(),//!             shared: Arc::pin_init(Shared::new(), flags::GFP_KERNEL)?,//!         })//!     }//! }//!//! impl HrTimerCallback for IntrusiveHrTimer {//!     type Pointer<'a> = Pin<&'a mut Self>;//!//!     fn run(this: Pin<&mut Self>, _ctx: HrTimerCallbackContext<'_, Self>) -> HrTimerRestart {//!         pr_info!("Timer called\n");//!//!         let flag = this.shared.flag.fetch_add(1, ordering::Full);//!         this.shared.cond.complete_all();//!//!         if flag == 4 {//!             HrTimerRestart::NoRestart//!         } else {//!             HrTimerRestart::Restart//!         }//!     }//! }//!//! impl_has_hr_timer! {//!     impl HasHrTimer<Self> for IntrusiveHrTimer {//!         mode: RelativeMode<Monotonic>, field: self.timer//!     }//! }//!//! stack_try_pin_init!( let has_timer =? IntrusiveHrTimer::new() );//! let shared = has_timer.shared.clone();//!//! has_timer.as_mut().start_scoped(Delta::from_micros(200), || {//!     while shared.flag.load(ordering::Relaxed) != 5 {//!         shared.cond.wait_for_completion();//!     }//! });//!//! pr_info!("Counted to 5\n");//! # Ok::<(), kernel::error::Error>(())//! ```//!//! [`Arc`]: kernel::sync::Arc use super::{ClockSource, Delta, Instant};use crate::{prelude::*, types::Opaque};use core::{marker::PhantomData, ptr::NonNull};use pin_init::PinInit; /// A type-alias to refer to the [`Instant<C>`] for a given `T` from [`HrTimer<T>`].////// Where `C` is the [`ClockSource`] of the [`HrTimer`].pub type HrTimerInstant<T> = Instant<<<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock>; /// A timer backed by a C `struct hrtimer`.////// # Invariants////// * `self.timer` is initialized by `bindings::hrtimer_setup`.#[pin_data]#[repr(C)]pub struct HrTimer<T> {    #[pin]    timer: Opaque<bindings::hrtimer>,    _t: PhantomData<T>,} // SAFETY: Ownership of an `HrTimer` can be moved to other threads and// used/dropped from there.unsafe impl<T> Send for HrTimer<T> {} // SAFETY: Timer operations are locked on the C side, so it is safe to operate// on a timer from multiple threads.unsafe impl<T> Sync for HrTimer<T> {} impl<T> HrTimer<T> {    /// Return an initializer for a new timer instance.    pub fn new() -> impl PinInit<Self>    where        T: HrTimerCallback,        T: HasHrTimer<T>,    {        pin_init!(Self {            // INVARIANT: We initialize `timer` with `hrtimer_setup` below.            timer <- Opaque::ffi_init(move |place: *mut bindings::hrtimer| {                // SAFETY: By design of `pin_init!`, `place` is a pointer to a                // live allocation. hrtimer_setup will initialize `place` and                // does not require `place` to be initialized prior to the call.                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,        })    }     /// Get a pointer to the contained `bindings::hrtimer`.    ///    /// This function is useful to get access to the value without creating    /// intermediate references.    ///    /// # Safety    ///    /// `this` must point to a live allocation of at least the size of `Self`.    unsafe fn raw_get(this: *const Self) -> *mut bindings::hrtimer {        // SAFETY: The field projection to `timer` does not go out of bounds,        // because the caller of this function promises that `this` points to an        // allocation of at least the size of `Self`.        unsafe { Opaque::cast_into(core::ptr::addr_of!((*this).timer)) }    }     /// Cancel an initialized and potentially running timer.    ///    /// If the timer handler is running, this function will block until the    /// handler returns.    ///    /// Note that the timer might be started by a concurrent start operation. If    /// so, the timer might not be in the **stopped** state when this function    /// returns.    ///    /// Users of the `HrTimer` API would not usually call this method directly.    /// Instead they would use the safe [`HrTimerHandle::cancel`] on the handle    /// returned when the timer was started.    ///    /// This function is useful to get access to the value without creating    /// intermediate references.    ///    /// # Safety    ///    /// `this` must point to a valid `Self`.    pub(crate) unsafe fn raw_cancel(this: *const Self) -> bool {        // SAFETY: `this` points to an allocation of at least `HrTimer` size.        let c_timer_ptr = unsafe { HrTimer::raw_get(this) }; 

Lines 1–500 of 1120.