pmc/
error.rs

1#![allow(missing_docs)]
2
3use std::{fmt, io};
4
5#[derive(Debug)]
6pub struct Error {
7    kind: ErrorKind,
8    cause: Option<Box<dyn std::error::Error>>,
9}
10
11#[derive(Debug, PartialEq)]
12pub enum ErrorKind {
13    /// An unknown error
14    Unknown,
15
16    /// The signal handler received an unrecognised signal.
17    UnexpectedSignal,
18
19    /// Failed to initialise [`libpmc`].
20    ///
21    /// [`libpmc`]: https://www.freebsd.org/cgi/man.cgi?query=pmc
22    Init,
23
24    /// The system CPU does not support performance monitor counters.
25    Unsupported,
26
27    /// The kernel PMC interface differs from what this crate is using.
28    ///
29    /// This usually means FreeBSD/hwpmc has been updated - recompiling the
30    /// application might help.
31    VersionMismatch,
32
33    /// The provided event specification is not recognised.
34    InvalidEventSpec,
35
36    /// `AllocInit` is returned for generic `Counter` initialisation errors, and
37    /// unfortunately can be caused by other errors (such as
38    /// [`InvalidEventSpec`]) without providing any more information.
39    ///
40    /// [`InvalidEventSpec`]: #variant.InvalidEventSpec
41    AllocInit,
42
43    /// The [`hwpmc`] kernel module has been unloaded.
44    ///
45    /// In testing, this signal was not sent from the [`hwpmc`] implementation,
46    /// so this error should not be relied upon.
47    ///
48    /// [`hwpmc`]: https://www.freebsd.org/cgi/man.cgi?query=hwpmc
49    Unloaded,
50
51    /// The [`Counter`] is already attached to the requested process.
52    ///
53    /// [`Counter`]: struct.Counter.html
54    AlreadyAttached,
55
56    /// The requested [scope] is invalid for the requested event.
57    ///
58    /// [scope]: enum.Scope.html
59    BadScope,
60
61    /// The requested event requires a configured log file to write results to.
62    LogFileRequired,
63
64    /// The requested target PID is already being monitored by another process.
65    BusyTarget,
66
67    /// The requested target PID does not exist.
68    BadTarget,
69
70    /// The caller does not have the appropriate permissions.
71    Forbidden,
72}
73
74impl std::error::Error for Error {
75    fn description(&self) -> &str {
76        match self.kind {
77            ErrorKind::Init => "missing hwpmc in kernel",
78            ErrorKind::Unloaded => "hwpmc unloaded from kernel",
79            ErrorKind::Unsupported => "unsupported CPU",
80            ErrorKind::VersionMismatch => "unexpected hwpmc version",
81            ErrorKind::AllocInit => "failed to allocate counter",
82            ErrorKind::BusyTarget => "target is busy",
83            ErrorKind::BadTarget => "target PID does not exist",
84            ErrorKind::AlreadyAttached => "PMC already attached to target process",
85            ErrorKind::Forbidden => "forbidden",
86            _ => "unknown error",
87        }
88    }
89}
90
91impl fmt::Display for Error {
92    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93        write!(f, "{}", self)
94    }
95}
96
97#[doc(hidden)]
98impl PartialEq for Error {
99    fn eq(&self, other: &Error) -> bool {
100        self.kind == other.kind
101    }
102}
103
104impl Error {
105    pub fn kind(&self) -> &ErrorKind {
106        &self.kind
107    }
108
109    pub fn cause(&self) -> Option<&dyn std::error::Error> {
110        self.cause.as_deref()
111    }
112}
113
114pub(crate) fn new_os_error(kind: ErrorKind) -> Error {
115    // Get the last OS error to reference as the cause
116    Error {
117        kind,
118        cause: Some(Box::new(io::Error::last_os_error())),
119    }
120}
121
122pub(crate) fn new_error(kind: ErrorKind) -> Error {
123    Error { kind, cause: None }
124}