summaryrefslogtreecommitdiff
path: root/crates/windows-kernel-rs/src/sync/fast_mutex.rs
blob: a45d576745aa61df0b10f642c5064b646c1a044a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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 + Send> {
  pub(crate) lock: Box<FAST_MUTEX>,
  pub(crate) data: UnsafeCell<T>,
}

unsafe impl<T: Send> Send for FastMutex<T> {}
unsafe impl<T: Send> Sync for FastMutex<T> {}

impl<T: Send> 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 + Send> Default for FastMutex<T> {
  fn default() -> Self { Self::new(T::default()) }
}

impl<T: Send> 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 }
}