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