cubecl_common/device/handle/
mod.rs1mod base;
2
3pub use base::*;
4
5use crate::device::{DeviceId, DeviceService, ServerUtilitiesHandle};
6
7#[cfg(feature = "std")]
8#[allow(dead_code)]
9mod channel;
10
11#[allow(dead_code)]
12mod mutex;
13
14#[cfg(feature = "std")]
15#[allow(dead_code)]
16mod reentrant;
17
18#[cfg(all(feature = "std", multi_threading))]
19type Inner<S> = channel::ChannelDeviceHandle<S>;
20#[cfg(all(feature = "std", not(multi_threading)))]
22type Inner<S> = reentrant::ReentrantMutexDeviceHandle<S>;
23#[cfg(all(not(feature = "std"), not(multi_threading)))]
24type Inner<S> = mutex::MutexDeviceHandle<S>;
25
26pub struct DeviceHandle<S: DeviceService> {
28 handle: Inner<S>,
29}
30
31impl<S: DeviceService> Clone for DeviceHandle<S> {
32 fn clone(&self) -> Self {
33 Self {
34 handle: self.handle.clone(),
35 }
36 }
37}
38
39#[allow(missing_docs)]
40impl<S: DeviceService> DeviceHandle<S> {
41 pub const fn is_blocking() -> bool {
42 Inner::<S>::BLOCKING
43 }
44
45 pub fn insert(device_id: super::DeviceId, service: S) -> Result<Self, ServiceCreationError> {
46 Ok(Self {
47 handle: <Inner<S> as DeviceHandleSpec<S>>::insert(device_id, service)?,
48 })
49 }
50
51 pub fn new(device_id: super::DeviceId) -> Self {
52 Self {
53 handle: <Inner<S> as DeviceHandleSpec<S>>::new(device_id),
54 }
55 }
56
57 pub fn device_id(&self) -> DeviceId {
58 self.handle.device_id()
59 }
60
61 pub fn utilities(&self) -> ServerUtilitiesHandle {
62 self.handle.utilities()
63 }
64
65 pub fn submit_blocking<'a, R: Send, T: FnOnce(&mut S) -> R + Send + 'a>(
66 &self,
67 task: T,
68 ) -> Result<R, CallError> {
69 self.handle.submit_blocking(task)
70 }
71
72 pub fn submit<T: FnOnce(&mut S) + Send + 'static>(&self, task: T) {
73 self.handle.submit(task)
74 }
75
76 pub fn flush_queue(&self) {
77 self.handle.flush_queue();
78 }
79
80 pub fn exclusive<R: Send, T: FnOnce() -> R + Send>(&self, task: T) -> Result<R, CallError> {
81 self.handle.exclusive(task)
82 }
83
84 pub fn shutdown(device_id: DeviceId) {
103 <Inner<S> as DeviceHandleSpec<S>>::shutdown(device_id)
104 }
105}
106
107#[cfg(test)]
111struct ShutdownGuard {
112 device_id: DeviceId,
113 shutdown: fn(DeviceId),
114}
115
116#[cfg(test)]
117impl Drop for ShutdownGuard {
118 fn drop(&mut self) {
119 (self.shutdown)(self.device_id);
120 }
121}
122
123#[cfg(test)]
129fn next_test_device_id() -> DeviceId {
130 use core::sync::atomic::{AtomicU16, Ordering};
131
132 static NEXT: AtomicU16 = AtomicU16::new(0);
133
134 DeviceId {
135 type_id: 0,
136 index_id: NEXT.fetch_add(1, Ordering::Relaxed),
137 }
138}
139
140#[cfg(test)]
152pub(crate) struct DeviceFixture<H> {
153 handle: H,
154 _guard: ShutdownGuard,
155 device_id: DeviceId,
156}
157
158#[cfg(test)]
159impl<H> DeviceFixture<H> {
160 pub(crate) fn new(build: fn(DeviceId) -> H, shutdown: fn(DeviceId)) -> Self {
161 let device_id = next_test_device_id();
162
163 Self {
164 handle: build(device_id),
165 _guard: ShutdownGuard {
166 device_id,
167 shutdown,
168 },
169 device_id,
170 }
171 }
172
173 pub(crate) fn device_id(&self) -> DeviceId {
174 self.device_id
175 }
176}
177
178#[cfg(test)]
179impl<H> core::ops::Deref for DeviceFixture<H> {
180 type Target = H;
181
182 fn deref(&self) -> &Self::Target {
183 &self.handle
184 }
185}
186
187#[cfg(test)]
188mod tests_channel {
189 type DeviceHandle<S> = channel::ChannelDeviceHandle<S>;
190
191 include!("./tests.rs");
192 include!("./tests_recursive.rs");
193}
194
195#[cfg(test)]
196mod tests_mutex {
197 type DeviceHandle<S> = mutex::MutexDeviceHandle<S>;
198
199 include!("./tests.rs");
200}
201
202#[cfg(test)]
203mod tests_reentrant {
204 type DeviceHandle<S> = reentrant::ReentrantMutexDeviceHandle<S>;
205
206 include!("./tests.rs");
207 include!("./tests_recursive.rs");
208}