|
6 | 6 |
|
7 | 7 | use crate::{ |
8 | 8 | bindings, |
9 | | - types::{ARef, ForeignOwnable, Opaque}, |
| 9 | + types::{ARef, ForeignOwnable, NotThreadSafe, Opaque}, |
10 | 10 | }; |
11 | 11 | use core::{fmt, marker::PhantomData, ptr}; |
12 | 12 |
|
@@ -398,6 +398,35 @@ impl<Ctx: DeviceContext> Device<Ctx> { |
398 | 398 | // defined as a `#[repr(transparent)]` wrapper around `fwnode_handle`. |
399 | 399 | Some(unsafe { &*fwnode_handle.cast() }) |
400 | 400 | } |
| 401 | + |
| 402 | + /// Locks the [`Device`] for exclusive access. |
| 403 | + pub fn lock(&self) -> Guard<'_, Ctx> { |
| 404 | + // SAFETY: `self` is always valid by the type invariant. |
| 405 | + unsafe { bindings::device_lock(self.as_raw()) }; |
| 406 | + |
| 407 | + Guard { |
| 408 | + dev: self, |
| 409 | + _not_send: NotThreadSafe, |
| 410 | + } |
| 411 | + } |
| 412 | +} |
| 413 | + |
| 414 | +/// A lock guard. |
| 415 | +/// |
| 416 | +/// The lock is unlocked when the guard goes out of scope. |
| 417 | +#[must_use = "the lock unlocks immediately when the guard is unused"] |
| 418 | +pub struct Guard<'a, Ctx: DeviceContext = Normal> { |
| 419 | + dev: &'a Device<Ctx>, |
| 420 | + _not_send: NotThreadSafe, |
| 421 | +} |
| 422 | + |
| 423 | +impl<Ctx: DeviceContext> Drop for Guard<'_, Ctx> { |
| 424 | + fn drop(&mut self) { |
| 425 | + // SAFETY: |
| 426 | + // - `self.xa.xa` is always valid by the type invariant. |
| 427 | + // - The caller holds the lock, so it is safe to unlock it. |
| 428 | + unsafe { bindings::device_unlock(self.dev.as_raw()) }; |
| 429 | + } |
401 | 430 | } |
402 | 431 |
|
403 | 432 | // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic |
|
0 commit comments