summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rust/kernel/perf_event.rs76
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)
+ }
+}