use std::num::ParseIntError;
use std::path::Path;
use std::sync::atomic::{AtomicU32, Ordering};
use std::{fmt, io};
pub(in crate::events) struct CachedPmuType {
name: &'static str,
value: AtomicU32,
}
impl CachedPmuType {
pub const fn new(pmu: &'static str) -> Self {
Self {
name: pmu,
value: AtomicU32::new(0),
}
}
pub fn get(&self) -> io::Result<u32> {
match self.value.load(Ordering::Relaxed) {
0 => self.read(),
ty => Ok(ty),
}
}
#[cold]
fn read(&self) -> io::Result<u32> {
let mut path = Path::new("/sys/bus/event_source/devices").to_path_buf();
path.push(self.name);
path.push("type");
let ty = std::fs::read_to_string(&path)?
.trim_end()
.parse()
.map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
ParsePmuTypeError {
name: self.name,
error: e,
},
)
})?;
self.value.store(ty, Ordering::Relaxed);
Ok(ty)
}
}
#[derive(Debug, Clone)]
struct ParsePmuTypeError {
name: &'static str,
error: ParseIntError,
}
impl fmt::Display for ParsePmuTypeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"type file for pmu `{}` contained invalid data",
self.name
)
}
}
impl std::error::Error for ParsePmuTypeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.error)
}
}