wdk_mutex::kmutex

Struct KMutex

Source
pub struct KMutex<T> { /* private fields */ }
Expand description

A thread safe mutex implemented through acquiring a KMUTEX in the Windows kernel.

The type Kmutex<T> provides mutually exclusive access to the inner type T allocated through this crate in the non-paged pool. All data required to initialise the KMutex is allocated in the non-paged pool and as such is safe to pass stack data into the type as it will not go out of scope.

KMutex holds an inner value which is a pointer to a KMutexInner type which is the actual type allocated in the non-paged pool, and this holds information relating to the mutex.

Access to the T within the KMutex can be done through calling Self::lock.

§Lifetimes

As the KMutex is designed to be used in the Windows Kernel, with the Windows wdk crate, the lifetimes of the KMutex must be considered by the caller. See examples below for usage.

The KMutex can exist in a locally scoped function with little additional configuration. To use the mutex across thread boundaries, or to use it in callback functions, you can use the Grt module found in this crate. See below for details.

§Deallocation

KMutex handles the deallocation of resources at the point the KMutex is dropped.

§Examples

§Locally scoped mutex:

{
    let mtx = KMutex::new(0u32).unwrap();
    let lock = mtx.lock().unwrap();

    // If T implements display, you do not need to dereference the lock to print.
    println!("The value is: {}", lock);
} // Mutex will become unlocked as it is managed via RAII

§Global scope via the Grt module in wdk-mutex:

// Initialise the mutex on DriverEntry
 
#[export_name = "DriverEntry"]
pub unsafe extern "system" fn driver_entry(
    driver: &mut DRIVER_OBJECT,
    registry_path: PCUNICODE_STRING,
) -> NTSTATUS {
    if let Err(e) = Grt::init() {
        println!("Error creating Grt!: {:?}", e);
        return STATUS_UNSUCCESSFUL;
    }
 
    // ...
    my_function();
}
 
 
// Register a new Mutex in the `Grt` of value 0u32:
 
pub fn my_function() {
    Grt::register_kmutex("my_test_mutex", 0u32);
}
 
unsafe extern "C" fn my_thread_fn_pointer(_: *mut c_void) {
    let my_mutex = Grt::get_kmutex::<u32>("my_test_mutex");
    if let Err(e) = my_mutex {
        println!("Error in thread: {:?}", e);
        return;
    }
 
    let mut lock = my_mutex.unwrap().lock().unwrap();
    *lock += 1;
}
 
 
// Destroy the Grt to prevent memory leak on DriverExit
 
extern "C" fn driver_exit(driver: *mut DRIVER_OBJECT) {
    unsafe {Grt::destroy()};
}

Implementations§

Source§

impl<T> KMutex<T>

Source

pub fn new(data: T) -> Result<Self, DriverMutexError>

Creates a new KMUTEX Windows Kernel Driver Mutex in a signaled (free) state.

§IRQL

This can be called at any IRQL.

§Examples
use wdk_mutex::Mutex;

let my_mutex = wdk_mutex::KMutex::new(0u32);
Source

pub fn lock(&self) -> Result<KMutexGuard<'_, T>, DriverMutexError>

Acquires a mutex in a non-alertable manner.

Once the thread has acquired the mutex, it will return a KMutexGuard which is a RAII scoped guard allowing exclusive access to the inner T.

§Errors

If the IRQL is too high, this function will return an error and will not acquire a lock. To prevent a kernel panic, the caller should match the return value rather than just unwrapping the value.

§IRQL

This function must be called at IRQL <= APC_LEVEL, if the IRQL is higher than this, the function will return an error.

It is the callers responsibility to ensure the IRQL is sufficient to call this function and it will not alter the IRQL for the caller, as this may introduce undefined behaviour elsewhere in the driver / kernel.

§Examples
let mtx = KMutex::new(0u32).unwrap();
let lock = mtx.lock().unwrap();
Source

pub unsafe fn to_owned(self) -> T

Consumes the mutex and returns an owned copy of the protected data (T).

This method performs a deep copy of the data (T) guarded by the mutex before deallocating the internal memory. Be cautious when using this method with large data types, as it may lead to inefficiencies or stack overflows.

For scenarios involving large data that you prefer not to allocate on the stack, consider using Self::to_owned_box instead.

§Safety
  • Single Ownership Guarantee: After calling Self::to_owned, ensure that no other references (especially static or global ones) attempt to access the underlying mutex. This is because the mutexes memory is deallocated once this method is invoked.
  • Exclusive Access: This function should only be called when you can guarantee that there will be no further access to the protected T. Violating this can lead to undefined behavior since the memory is freed after the call.
§Example
unsafe {
    let owned_data: T = mutex.to_owned();
    // Use `owned_data` safely here
}
Source

pub unsafe fn to_owned_box(self) -> Box<T>

Consumes the mutex and returns an owned Box<T> containing the protected data (T).

This method is an alternative to Self::to_owned and is particularly useful when dealing with large data types. By returning a Box<T>, the data is pool-allocated, avoiding potential stack overflows associated with large stack allocations.

§Safety
  • Single Ownership Guarantee: After calling Self::to_owned_box, ensure that no other references (especially static or global ones) attempt to access the underlying mutex. This is because the mutexes memory is deallocated once this method is invoked.
  • Exclusive Access: This function should only be called when you can guarantee that there will be no further access to the protected T. Violating this can lead to undefined behavior since the memory is freed after the call.
§Example
unsafe {
    let boxed_data: Box<T> = mutex.to_owned_box();
    // Use `boxed_data` safely here
}

Trait Implementations§

Source§

impl<T> Drop for KMutex<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T> Send for KMutex<T>

Source§

impl<T> Sync for KMutex<T>

Auto Trait Implementations§

§

impl<T> Freeze for KMutex<T>

§

impl<T> RefUnwindSafe for KMutex<T>
where T: RefUnwindSafe,

§

impl<T> Unpin for KMutex<T>

§

impl<T> UnwindSafe for KMutex<T>
where T: RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.