cubecl_common/device/handle/
mod.rs1mod base;
2
3pub use base::*;
4
5use crate::device::{DeviceId, DeviceService, ServerUtilitiesHandle, ServiceId};
6use core::any::Any;
7
8#[cfg(feature = "std")]
9#[allow(dead_code)]
10mod channel;
11
12#[cfg(feature = "std")]
13mod placement;
14
15#[allow(dead_code)]
16mod mutex;
17
18#[cfg(feature = "std")]
19#[allow(dead_code)]
20mod reentrant;
21
22#[cfg(all(feature = "std", multi_threading))]
23type Inner = channel::ChannelDeviceHandle;
24#[cfg(all(feature = "std", not(multi_threading)))]
26type Inner = reentrant::ReentrantMutexDeviceHandle;
27#[cfg(all(not(feature = "std"), not(multi_threading)))]
28type Inner = mutex::MutexDeviceHandle;
29
30pub struct DeviceHandle<S: ?Sized, I: DeviceHandleSpec = Inner> {
37 handle: I,
38 service: ServiceId,
39 cast: fn(&mut dyn Any) -> &mut S,
40}
41
42impl<S: ?Sized, I: DeviceHandleSpec> Clone for DeviceHandle<S, I> {
43 fn clone(&self) -> Self {
44 Self {
45 handle: self.handle.clone(),
46 service: self.service,
47 cast: self.cast,
48 }
49 }
50}
51
52fn downcast<S: 'static>(state: &mut dyn Any) -> &mut S {
54 state
55 .downcast_mut::<S>()
56 .expect("State type mismatch in the device registry")
57}
58
59#[allow(missing_docs)]
60impl<S: DeviceService, I: DeviceHandleSpec> DeviceHandle<S, I> {
61 pub fn insert(device_id: DeviceId, service: S) -> Result<Self, ServiceCreationError> {
62 Ok(Self {
63 handle: I::insert::<S>(device_id, service)?,
64 service: ServiceId::of::<S>(device_id),
65 cast: downcast::<S>,
66 })
67 }
68
69 pub fn new(device_id: DeviceId) -> Self {
70 Self {
71 handle: I::new::<S>(device_id),
72 service: ServiceId::of::<S>(device_id),
73 cast: downcast::<S>,
74 }
75 }
76}
77
78#[allow(missing_docs)]
79impl<S: ?Sized + 'static, I: DeviceHandleSpec> DeviceHandle<S, I> {
80 pub const fn is_blocking() -> bool {
81 I::BLOCKING
82 }
83
84 pub fn seen_as<T: ?Sized>(self, cast: fn(&mut dyn Any) -> &mut T) -> DeviceHandle<T, I> {
87 DeviceHandle {
88 handle: self.handle,
89 service: self.service,
90 cast,
91 }
92 }
93
94 pub fn device_id(&self) -> DeviceId {
95 self.handle.device_id()
96 }
97
98 pub fn service_id(&self) -> ServiceId {
101 self.service
102 }
103
104 pub fn utilities(&self) -> ServerUtilitiesHandle {
105 self.handle.utilities()
106 }
107
108 pub fn submit_blocking<'a, R: Send, T: FnOnce(&mut S) -> R + Send + 'a>(
109 &self,
110 task: T,
111 ) -> Result<R, CallError> {
112 let cast = self.cast;
113 self.handle.submit_blocking(move |state| task(cast(state)))
114 }
115
116 pub fn submit<T: FnOnce(&mut S) + Send + 'static>(&self, task: T) {
117 let cast = self.cast;
118 self.handle.submit(move |state| task(cast(state)))
119 }
120
121 pub fn flush_queue(&self) {
122 self.handle.flush_queue();
123 }
124
125 pub fn exclusive<R: Send, T: FnOnce() -> R + Send>(&self, task: T) -> Result<R, CallError> {
126 self.handle.exclusive(task)
127 }
128
129 pub fn shutdown(device_id: DeviceId) {
148 I::shutdown(device_id)
149 }
150}
151
152#[cfg(test)]
156struct ShutdownGuard {
157 device_id: DeviceId,
158 shutdown: fn(DeviceId),
159}
160
161#[cfg(test)]
162impl Drop for ShutdownGuard {
163 fn drop(&mut self) {
164 (self.shutdown)(self.device_id);
165 }
166}
167
168#[cfg(test)]
174fn next_test_device_id() -> DeviceId {
175 use core::sync::atomic::{AtomicU16, Ordering};
176
177 static NEXT: AtomicU16 = AtomicU16::new(0);
178
179 DeviceId {
180 type_id: 0,
181 index_id: NEXT.fetch_add(1, Ordering::Relaxed),
182 }
183}
184
185#[cfg(test)]
197pub(crate) struct DeviceFixture<H> {
198 handle: H,
199 _guard: ShutdownGuard,
200 device_id: DeviceId,
201}
202
203#[cfg(test)]
204impl<H> DeviceFixture<H> {
205 pub(crate) fn new(build: fn(DeviceId) -> H, shutdown: fn(DeviceId)) -> Self {
206 let device_id = next_test_device_id();
207
208 Self {
209 handle: build(device_id),
210 _guard: ShutdownGuard {
211 device_id,
212 shutdown,
213 },
214 device_id,
215 }
216 }
217
218 pub(crate) fn device_id(&self) -> DeviceId {
219 self.device_id
220 }
221}
222
223#[cfg(test)]
224impl<H> core::ops::Deref for DeviceFixture<H> {
225 type Target = H;
226
227 fn deref(&self) -> &Self::Target {
228 &self.handle
229 }
230}
231
232#[cfg(test)]
233mod tests_channel {
234 type DeviceHandle<S> = super::DeviceHandle<S, channel::ChannelDeviceHandle>;
235
236 include!("./tests.rs");
237 include!("./tests_recursive.rs");
238}
239
240#[cfg(test)]
241mod tests_mutex {
242 type DeviceHandle<S> = super::DeviceHandle<S, mutex::MutexDeviceHandle>;
243
244 include!("./tests.rs");
245}
246
247#[cfg(test)]
248mod tests_reentrant {
249 type DeviceHandle<S> = super::DeviceHandle<S, reentrant::ReentrantMutexDeviceHandle>;
250
251 include!("./tests.rs");
252 include!("./tests_recursive.rs");
253}