diff options
| author | Fuwn <[email protected]> | 2022-01-03 03:20:12 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2022-01-03 03:20:12 -0800 |
| commit | 85db2b507f3f69b32811c54a89d9ac7bbbc46121 (patch) | |
| tree | 2efd66da452f8a6a2cc6c91584c925f237506ddf /crates/windows-kernel-rs/src/sync/fast_mutex.rs | |
| download | driver-85db2b507f3f69b32811c54a89d9ac7bbbc46121.tar.xz driver-85db2b507f3f69b32811c54a89d9ac7bbbc46121.zip | |
feat(driver): commit primer
Diffstat (limited to 'crates/windows-kernel-rs/src/sync/fast_mutex.rs')
| -rw-r--r-- | crates/windows-kernel-rs/src/sync/fast_mutex.rs | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/crates/windows-kernel-rs/src/sync/fast_mutex.rs b/crates/windows-kernel-rs/src/sync/fast_mutex.rs new file mode 100644 index 0000000..9a82524 --- /dev/null +++ b/crates/windows-kernel-rs/src/sync/fast_mutex.rs @@ -0,0 +1,137 @@ +use alloc::boxed::Box; +use core::{ + cell::UnsafeCell, + ops::{Deref, DerefMut}, +}; + +use windows_kernel_sys::{ + base::FAST_MUTEX, + ntoskrnl::{ + ExAcquireFastMutex, + ExInitializeFastMutex, + ExReleaseFastMutex, + ExTryToAcquireFastMutex, + }, +}; + +/// A mutual exclusion primitive useful for protecting shared data. +/// +/// This mutex will block threads waiting for the lock to become available. The +/// mutex can also be statically initialized or created via a [`new`] +/// constructor. Each mutex has a type parameter which represents the data that +/// it is protecting. The data can only be accessed through the RAII +/// guards returned from [`lock`] and [`try_lock`], which guarantees that the +/// data is only ever accessed when the mutex is locked. +/// +/// [`new`]: FastMutex::new +/// [`lock`]: FastMutex::lock +/// [`try_lock`]: FastMutex::try_lock +pub struct FastMutex<T: ?Sized> { + pub(crate) lock: Box<FAST_MUTEX>, + pub(crate) data: UnsafeCell<T>, +} + +unsafe impl<T> Send for FastMutex<T> {} +unsafe impl<T> Sync for FastMutex<T> {} + +impl<T> FastMutex<T> { + /// Creates a new mutex in an unlocked state ready for use. + pub fn new(data: T) -> Self { + let mut lock: Box<FAST_MUTEX> = Box::new(unsafe { core::mem::zeroed() }); + + unsafe { ExInitializeFastMutex(&mut *lock) }; + + Self { + lock, + data: UnsafeCell::new(data), + } + } + + /// Consumes this `FastMutex`, returning the underlying data. + #[inline] + pub fn into_inner(self) -> T { + let Self { + data, .. + } = self; + data.into_inner() + } + + /// Attempts to acquire this lock. + /// + /// If the lock could not be acquired at this time, then `None` is returned. + /// Otherwise, an RAII guard is returned. The lock will be unlocked when the + /// guard is dropped. + /// + /// This function does not block. + #[inline] + pub fn try_lock(&mut self) -> Option<FastMutexGuard<T>> { + let status = unsafe { ExTryToAcquireFastMutex(&mut *self.lock) } != 0; + + match status { + true => + Some(FastMutexGuard { + lock: &mut self.lock, + data: unsafe { &mut *self.data.get() }, + }), + _ => None, + } + } + + /// Acquires a mutex, blocking the current thread until it is able to do so. + /// + /// This function will block the local thread until it is available to acquire + /// the mutex. Upon returning, the thread is the only thread with the lock + /// held. An RAII guard is returned to allow scoped unlock of the lock. When + /// the guard goes out of scope, the mutex will be unlocked. + /// + /// The underlying function does not allow for recursion. If the thread + /// already holds the lock and tries to lock the mutex again, this function + /// will return `None` instead. + #[inline] + pub fn lock(&mut self) -> Option<FastMutexGuard<T>> { + unsafe { ExAcquireFastMutex(&mut *self.lock) }; + + Some(FastMutexGuard { + lock: &mut self.lock, + data: unsafe { &mut *self.data.get() }, + }) + } +} + +impl<T: ?Sized + Default> Default for FastMutex<T> { + fn default() -> Self { Self::new(T::default()) } +} + +impl<T> From<T> for FastMutex<T> { + fn from(data: T) -> Self { Self::new(data) } +} + +/// An RAII implementation of a "scoped lock" of a mutex. When this structure is +/// dropped (falls out of scope), the lock will be unlocked. +/// +/// The data protected by the mutex can be accessed through this guard via its +/// [`Deref`] and [`DerefMut`] implementations. +/// +/// This structure is created by the [`lock`] and [`try_lock`] methods on +/// [`FastMutex`]. +/// +/// [`lock`]: FastMutex::lock +/// [`try_lock`]: FastMutex::try_lock +pub struct FastMutexGuard<'a, T: 'a + ?Sized> { + pub(crate) lock: &'a mut FAST_MUTEX, + pub(crate) data: &'a mut T, +} + +impl<'a, T: ?Sized> Drop for FastMutexGuard<'a, T> { + fn drop(&mut self) { unsafe { ExReleaseFastMutex(&mut *self.lock) }; } +} + +impl<'a, T: ?Sized> Deref for FastMutexGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { self.data } +} + +impl<'a, T: ?Sized> DerefMut for FastMutexGuard<'a, T> { + fn deref_mut(&mut self) -> &mut T { self.data } +} |