nvml_wrapper/event.rs
1use crate::error::{nvml_sym, nvml_try, NvmlError};
2use crate::ffi::bindings::*;
3use crate::Nvml;
4
5use std::mem;
6
7use crate::struct_wrappers::event::EventData;
8
9/**
10Handle to a set of events.
11
12**Operations on a set are not thread-safe.** It does not, therefore, implement `Sync`.
13
14You can get yourself an `EventSet` via `Nvml.create_event_set`.
15
16Lifetimes are used to enforce that each `EventSet` instance cannot be used after
17the `Nvml` instance it was obtained from is dropped:
18
19```compile_fail
20use nvml_wrapper::Nvml;
21# use nvml_wrapper::error::*;
22
23# fn main() -> Result<(), NvmlError> {
24let nvml = Nvml::init()?;
25let event_set = nvml.create_event_set()?;
26
27drop(nvml);
28
29// This won't compile
30event_set.wait(5)?;
31# Ok(())
32# }
33```
34*/
35// Checked against local
36#[derive(Debug)]
37pub struct EventSet<'nvml> {
38 set: nvmlEventSet_t,
39 pub nvml: &'nvml Nvml,
40}
41
42unsafe impl<'nvml> Send for EventSet<'nvml> {}
43
44impl<'nvml> EventSet<'nvml> {
45 /**
46 Create a new `EventSet` wrapper.
47
48 You will most likely never need to call this; see the methods available to you
49 on the `Nvml` struct to get one.
50
51 # Safety
52
53 It is your responsibility to ensure that the given `nvmlEventSet_t` pointer
54 is valid.
55 */
56 // TODO: move constructor to this struct?
57 // Clippy bug, see https://github.com/rust-lang/rust-clippy/issues/5593
58 #[allow(clippy::missing_safety_doc)]
59 pub unsafe fn new(set: nvmlEventSet_t, nvml: &'nvml Nvml) -> Self {
60 Self { set, nvml }
61 }
62
63 /**
64 Use this to release the set's events if you care about handling
65 potential errors (*the `Drop` implementation ignores errors!*).
66
67 # Errors
68
69 * `Uninitialized`, if the library has not been successfully initialized
70 * `Unknown`, on any unexpected error
71 */
72 // Checked against local
73 #[doc(alias = "nvmlEventSetFree")]
74 pub fn release_events(self) -> Result<(), NvmlError> {
75 let sym = nvml_sym(self.nvml.lib.nvmlEventSetFree.as_ref())?;
76
77 unsafe {
78 nvml_try(sym(self.set))?;
79 }
80
81 mem::forget(self);
82 Ok(())
83 }
84
85 /**
86 Waits on events for the given timeout (in ms) and delivers one when it arrives.
87
88 See the `high_level::event_loop` module for an abstracted version of this.
89
90 This method returns immediately if an event is ready to be delivered when it
91 is called. If no events are ready it will sleep until an event arrives, but
92 not longer than the specified timeout. In certain conditions, this method
93 could return before the timeout passes (e.g. when an interrupt arrives).
94
95 In the case of an XID error, the function returns the most recent XID error
96 type seen by the system. If there are multiple XID errors generated before
97 this method is called, the last seen XID error type will be returned for
98 all XID error events.
99
100 # Errors
101
102 * `Uninitialized`, if the library has not been successfully initialized
103 * `Timeout`, if no event arrived in the specified timeout or an interrupt
104 arrived
105 * `GpuLost`, if a GPU has fallen off the bus or is otherwise inaccessible
106 * `Unknown`, on any unexpected error
107
108 # Device Support
109
110 Supports Fermi and newer fully supported devices.
111 */
112 // Checked against local
113 #[doc(alias = "nvmlEventSetWait_v2")]
114 pub fn wait(&self, timeout_ms: u32) -> Result<EventData<'nvml>, NvmlError> {
115 let sym = nvml_sym(self.nvml.lib.nvmlEventSetWait_v2.as_ref())?;
116
117 unsafe {
118 let mut data: nvmlEventData_t = mem::zeroed();
119 nvml_try(sym(self.set, &mut data, timeout_ms))?;
120
121 Ok(EventData::new(data, self.nvml))
122 }
123 }
124
125 /// Get the raw device handle contained in this struct
126 ///
127 /// Sometimes necessary for C interop.
128 ///
129 /// # Safety
130 ///
131 /// This is unsafe to prevent it from being used without care. In
132 /// particular, you must avoid creating a new `EventSet` from this handle
133 /// and allowing both this `EventSet` and the newly created one to drop
134 /// (which would result in a double-free).
135 pub unsafe fn handle(&self) -> nvmlEventSet_t {
136 self.set
137 }
138}
139
140/// This `Drop` implementation ignores errors! Use the `.release_events()`
141/// method on the `EventSet` struct if you care about handling them.
142impl<'nvml> Drop for EventSet<'nvml> {
143 #[doc(alias = "nvmlEventSetFree")]
144 fn drop(&mut self) {
145 unsafe {
146 self.nvml.lib.nvmlEventSetFree(self.set);
147 }
148 }
149}
150
151#[cfg(test)]
152#[cfg(target_os = "linux")]
153mod test {
154 use crate::bitmasks::event::*;
155 use crate::test_utils::*;
156
157 #[test]
158 fn release_events() {
159 let nvml = nvml();
160 test_with_device(3, &nvml, |device| {
161 let set = nvml.create_event_set()?;
162 let set = device
163 .register_events(
164 EventTypes::PSTATE_CHANGE
165 | EventTypes::CRITICAL_XID_ERROR
166 | EventTypes::CLOCK_CHANGE,
167 set,
168 )
169 .map_err(|e| e.error)?;
170
171 set.release_events()
172 })
173 }
174
175 #[cfg(feature = "test-local")]
176 #[test]
177 fn wait() {
178 use crate::error::NvmlError;
179
180 let nvml = nvml();
181 let device = device(&nvml);
182 let set = nvml.create_event_set().expect("event set");
183 let set = device
184 .register_events(
185 EventTypes::PSTATE_CHANGE
186 | EventTypes::CRITICAL_XID_ERROR
187 | EventTypes::CLOCK_CHANGE,
188 set,
189 )
190 .expect("registration");
191
192 let data = match set.wait(10_000) {
193 Err(NvmlError::Timeout) => return (),
194 Ok(d) => d,
195 _ => panic!("An error other than `Timeout` occurred"),
196 };
197
198 print!("{:?} ...", data);
199 }
200}