use alloc::{boxed::Box, collections::BTreeMap, format, string::String};
use core::{any::Any, sync::atomic::AtomicU32};
use lock_api::{Mutex, RawMutex};
use static_keys::RawStaticFalseKey;
use crate::{KernelCodeManipulator, KernelTraceOps};
#[derive(Debug)]
#[repr(C)]
pub struct TraceEntry {
pub type_: u16,
pub flags: u8,
pub preempt_count: u8,
pub pid: i32,
}
impl TraceEntry {
pub fn trace_print_lat_fmt(&self) -> String {
let irqs_off = '.';
let resched = '.';
let hardsoft_irq = '.';
let mut preempt_low = '.';
if self.preempt_count & 0xf != 0 {
preempt_low = ((b'0') + (self.preempt_count & 0xf)) as char;
}
let mut preempt_high = '.';
if self.preempt_count >> 4 != 0 {
preempt_high = ((b'0') + (self.preempt_count >> 4)) as char;
}
format!("{irqs_off}{resched}{hardsoft_irq}{preempt_low}{preempt_high}")
}
}
pub struct TracePoint<L: RawMutex + 'static, K: KernelTraceOps + 'static> {
name: &'static str,
system: &'static str,
key: &'static RawStaticFalseKey<KernelCodeManipulator<K>>,
id: AtomicU32,
callback: Mutex<L, BTreeMap<usize, TracePointFunc>>,
raw_callback: Mutex<L, BTreeMap<usize, Box<dyn TracePointCallBackFunc>>>,
trace_entry_fmt_func: fn(&[u8]) -> String,
trace_print_func: fn() -> String,
flags: u8,
}
impl<L: RawMutex + 'static, K: KernelTraceOps + 'static> core::fmt::Debug for TracePoint<L, K> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("TracePoint")
.field("name", &self.name)
.field("system", &self.system)
.field("id", &self.id())
.field("flags", &self.flags)
.finish()
}
}
#[derive(Debug)]
#[repr(C)]
pub struct CommonTracePointMeta<L: RawMutex + 'static, K: KernelTraceOps + 'static> {
pub trace_point: &'static TracePoint<L, K>,
pub print_func: fn(),
}
pub trait TracePointCallBackFunc: Send + Sync {
fn call(&self, entry: &[u8]);
}
#[derive(Debug)]
pub struct TracePointFunc {
pub func: fn(),
pub data: Box<dyn Any + Send + Sync>,
}
impl<L: RawMutex + 'static, K: KernelTraceOps + 'static> TracePoint<L, K> {
pub const fn new(
key: &'static RawStaticFalseKey<KernelCodeManipulator<K>>,
name: &'static str,
system: &'static str,
fmt_func: fn(&[u8]) -> String,
trace_print_func: fn() -> String,
) -> Self {
Self {
name,
system,
key,
id: AtomicU32::new(0),
flags: 0,
trace_entry_fmt_func: fmt_func,
trace_print_func,
callback: Mutex::new(BTreeMap::new()),
raw_callback: Mutex::new(BTreeMap::new()),
}
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn system(&self) -> &'static str {
self.system
}
pub(crate) fn set_id(&self, id: u32) {
self.id.store(id, core::sync::atomic::Ordering::Relaxed);
}
pub fn id(&self) -> u32 {
self.id.load(core::sync::atomic::Ordering::Relaxed)
}
pub fn flags(&self) -> u8 {
self.flags
}
pub(crate) fn fmt_func(&self) -> fn(&[u8]) -> String {
self.trace_entry_fmt_func
}
pub fn print_fmt(&self) -> String {
let post_str = (self.trace_print_func)();
format!("name: {}\nID: {}\n{}\n", self.name(), self.id(), post_str)
}
pub fn register(&self, func: fn(), data: Box<dyn Any + Sync + Send>) {
let trace_point_func = TracePointFunc { func, data };
let ptr = func as usize;
self.callback.lock().entry(ptr).or_insert(trace_point_func);
}
pub fn unregister(&self, func: fn()) {
let func_ptr = func as usize;
self.callback.lock().remove(&func_ptr);
}
pub fn callback_list(&self, f: &dyn Fn(&TracePointFunc)) {
let callback = self.callback.lock();
for trace_func in callback.values() {
f(trace_func);
}
}
pub fn register_raw_callback(
&self,
callback_id: usize,
callback: Box<dyn TracePointCallBackFunc>,
) {
self.raw_callback
.lock()
.entry(callback_id)
.or_insert(callback);
}
pub fn unregister_raw_callback(&self, callback_id: usize) {
self.raw_callback.lock().remove(&callback_id);
}
pub fn raw_callback_list(&self, f: &dyn Fn(&Box<dyn TracePointCallBackFunc>)) {
let raw_callback = self.raw_callback.lock();
for callback in raw_callback.values() {
f(callback);
}
}
pub fn enable(&self) {
unsafe {
self.key.enable();
}
}
pub fn disable(&self) {
unsafe {
self.key.disable();
}
}
pub fn is_enabled(&self) -> bool {
self.key.is_enabled()
}
}