diff options
-rw-r--r-- | rust/kernel/perf_event.rs | 76 |
1 files changed, 37 insertions, 39 deletions
diff --git a/rust/kernel/perf_event.rs b/rust/kernel/perf_event.rs index 25bf29843940..81fba3408503 100644 --- a/rust/kernel/perf_event.rs +++ b/rust/kernel/perf_event.rs @@ -5,6 +5,7 @@ //! //! C header: [`include/linux/perf_event.h`](srctree/include/linux/perf_event.h) +use crate::alloc::AllocError; use crate::error::from_err_ptr; use crate::prelude::*; use crate::types::ARef; @@ -127,20 +128,6 @@ impl PerfEventAttr { } } -/// Overflow handler for perf events -#[repr(transparent)] -pub struct PerfOverflowHandler { - inner: Opaque<bindings::perf_overflow_handler_t>, -} - -impl Default for PerfOverflowHandler { - fn default() -> Self { - Self { - inner: Opaque::new(None), - } - } -} - /// Wrapper for sample data pub struct SampleData { inner: Opaque<bindings::perf_sample_data>, @@ -174,8 +161,6 @@ impl Registers { } /// Handler function for overflow events -pub type OverflowHandler = - KBox<dyn Fn(&PerfEventRef, &mut SampleData, &mut Registers) + Send + Sync>; /// Perf Event wrapper #[repr(transparent)] @@ -226,9 +211,10 @@ impl PerfEvent { impl Drop for PerfEvent { fn drop(&mut self) { if !self.inner.is_null() { - let context_ptr = unsafe { *self.inner }.overflow_handler_context as *mut DynFn; + let context_ptr = + unsafe { *self.inner }.overflow_handler_context as *mut OverflowHandler; if !context_ptr.is_null() { - let DynFn { closure, dyn_fn } = unsafe { context_ptr.read() }; + let OverflowHandler { closure, dyn_fn } = unsafe { context_ptr.read() }; let _ = dyn_fn; unsafe { KBox::from_raw(closure) }; } @@ -255,7 +241,7 @@ pub struct EventBuilder { exclude_idle: bool, cpu: Option<i32>, task: Option<ARef<Task>>, - overflow_handler: Option<DynFn>, + overflow_handler: Option<OverflowHandler>, } /// Error type for performance event operations @@ -267,6 +253,14 @@ pub enum Error { InvalidCpu, /// Invalid task specified InvalidTask, + /// MemoryAllocation Error + Alloc(AllocError), +} + +impl From<AllocError> for Error { + fn from(value: AllocError) -> Self { + Self::Alloc(value) + } } // Implementation of From traits for event types @@ -405,20 +399,8 @@ impl EventBuilder { } /// Set handler for overflow events - /// - /// # Safety - /// - Handler must be interrupt-safe - /// - Handler must not block - /// - Handler must not alloc - /// - Handler must not panic - pub unsafe fn on_overflow( - mut self, - handler: impl for<'a, 'b, 'c> Fn(&'a PerfEventRef, &'b mut SampleData, &'c mut Registers) - + Send - + Sync - + 'static, - ) -> Self { - self.overflow_handler = into_dyn(handler).ok(); + pub fn on_overflow(mut self, handler: OverflowHandler) -> Self { + self.overflow_handler = Some(handler); self } @@ -486,7 +468,7 @@ pub fn perf_event_create_kernel_counter( perf_event_attr: PerfEventAttr, cpu: i32, task: Option<ARef<Task>>, - overflow: Option<DynFn>, + overflow: Option<OverflowHandler>, ) -> Result<PerfEvent, Error> { // Convert handler to C callback if provided // Create the perf event using kernel functions @@ -527,7 +509,7 @@ unsafe extern "C" fn overflow_trampoline( if perf_event.is_null() { return; } - let context_ptr = unsafe { *perf_event }.overflow_handler_context as *mut DynFn; + let context_ptr = unsafe { *perf_event }.overflow_handler_context as *mut OverflowHandler; if context_ptr.is_null() { return; } @@ -555,8 +537,8 @@ fn overflow_wrapper( } fn into_dyn( handler: impl Fn(&PerfEventRef, &mut SampleData, &mut Registers) + Send + Sync + 'static, -) -> Result<DynFn, Error> { - let b = KBox::new(handler, crate::alloc::flags::GFP_KERNEL).unwrap(); +) -> Result<OverflowHandler, Error> { + let b = KBox::new(handler, crate::alloc::flags::GFP_KERNEL)?; let b = Box::leak(b); let b_ptr = (b as *mut _) as *mut crate::ffi::c_void; let c = b as &'static mut (dyn FnMut(&PerfEventRef, &mut SampleData, &mut Registers) @@ -564,16 +546,32 @@ fn into_dyn( + Sync + 'static); - Ok(DynFn { + Ok(OverflowHandler { closure: b_ptr, dyn_fn: c, }) } /// Workaround for the missing support of using KBox as a fat pointer -pub struct DynFn { +pub struct OverflowHandler { closure: *mut crate::ffi::c_void, dyn_fn: &'static mut (dyn FnMut(&PerfEventRef, &mut SampleData, &mut Registers) + Send + Sync + 'static), } + +impl OverflowHandler { + /// Constructs a new overflow handler callback which is run when a performance counter overflows. + /// + /// # Safety + /// The callback function is run in an NMI context: + /// - Handler must be interrupt-safe + /// - Handler must not block + /// - Handler must not alloc + /// - Handler must not panic + pub unsafe fn new( + handler: impl Fn(&PerfEventRef, &mut SampleData, &mut Registers) + Send + Sync + 'static, + ) -> Result<Self, Error> { + into_dyn(handler) + } +} |