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