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}