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}