pub struct Grt { /* private fields */ }
Expand description
The Global Reference Tracker (Grt) for wdk-mutex
is a module designed to improve the development ergonomics
of manually managing memory in a driver required for tracking objects passed between threads.
The Grt
abstraction makes it safe to register mutex objects and to retrieve them from callbacks and threads
at runtime in the driver, with idiomatic error handling. The Grt
makes several pool allocations which are tracked
and managed safely via RAII, so if absolute minimal speed is required for accessing mutexes, you may wish to profile this
vs a manual implementation of tracking mutexes however you see fit.
The general way to use this, is to call Self::init
during driver initialisation once, and on driver exit to call
Self::destroy
once. In between calling init
and destroy
, you may add a new T
(that will be protected by a
wdk-mutex
) to the Grt
, assigning a &str
for the key of a BTreeMap
, and the value being the T
. Note: you do
not pass a Mutex
into Self::register_kmutex
or Self::register_fast_mutex
etc; the function will automatically wrap that for you.
Self::get_kmutex
/ Self::get_fast_mutex
etc will then allow you to retrieve the Mutex
dynamically.
§Examples
// Initialise the mutex
#[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 Grt
impl Grt
Sourcepub fn init() -> Result<(), GrtError>
pub fn init() -> Result<(), GrtError>
Initialise a new instance of the Global Reference Tracker for wdk-mutex
.
This should only be called once in your driver and will initialise the Grt
to be globally available
at any point you wish to utilise it to retrieve a mutex and its wrapped T.
§Errors
This function will error if:
- You have already initialised the
Grt
§Examples
#[export_name = "DriverEntry"]
pub unsafe extern "system" fn driver_entry(
driver: &mut DRIVER_OBJECT,
registry_path: PCUNICODE_STRING,
) -> NTSTATUS {
// A good place to initialise it is early during driver initialisation
if let Err(e) = Grt::init() {
println!("Error creating Grt! {:?}", e);
return STATUS_UNSUCCESSFUL;
}
}
Sourcepub fn register_kmutex<T: Any>(
label: &'static str,
data: T,
) -> Result<(), GrtError>
pub fn register_kmutex<T: Any>( label: &'static str, data: T, ) -> Result<(), GrtError>
Register a new KMutex
for the global reference tracker to control.
The function takes a label as a static &str which is the key of a BTreeMap, and the type you wish to protect with the mutex as the data. If the key already exists, the function will indiscriminately insert a key and overwrite any existing data.
If you wish to perform this function checking for an existing key before registering the mutex object,
use Self::register_kmutex_checked
.
§Errors
This function will error if:
Grt
has not been initialised, seeGrt::init
§Examples
Grt::register_kmutex("my_test_mutex", 0u32);
Sourcepub fn register_fast_mutex<T: Any>(
label: &'static str,
data: T,
) -> Result<(), GrtError>
pub fn register_fast_mutex<T: Any>( label: &'static str, data: T, ) -> Result<(), GrtError>
Register a new FastMutex
for the global reference tracker to control.
The function takes a label as a static &str which is the key of a BTreeMap, and the type you wish to protect with the mutex as the data. If the key already exists, the function will indiscriminately insert a key and overwrite any existing data.
If you wish to perform this function checking for an existing key before registering the mutex object,
use Self::register_fast_mutex_checked
.
§Errors
This function will error if:
Grt
has not been initialised, seeGrt::init
§Examples
Grt::register_fast_mutex("my_test_mutex", 0u32);
Sourcepub fn register_kmutex_checked<T: Any>(
label: &'static str,
data: T,
) -> Result<(), GrtError>
pub fn register_kmutex_checked<T: Any>( label: &'static str, data: T, ) -> Result<(), GrtError>
Register a new KMutex
for the global reference tracker to control, throwing an error if the key already
exists.
This is a checked alternative to Self::register_kmutex
, and as such incurs a little additional overhead.
§Errors
This function will error if:
Grt
has not been initialised, seeGrt::init
- The mutex key already exists
§Examples
let result = Grt::register_kmutex_checked("my_test_mutex", 0u32);
Sourcepub fn register_fast_mutex_checked<T: Any>(
label: &'static str,
data: T,
) -> Result<(), GrtError>
pub fn register_fast_mutex_checked<T: Any>( label: &'static str, data: T, ) -> Result<(), GrtError>
Register a new FastMutex
for the global reference tracker to control, throwing an error if the key already
exists.
This is a checked alternative to Self::register_fast_mutex
, and as such incurs a little additional overhead.
§Errors
This function will error if:
Grt
has not been initialised, seeGrt::init
- The mutex key already exists
§Examples
let result = Grt::register_fast_mutex_checked("my_test_mutex", 0u32);
Sourcepub fn get_kmutex<T>(key: &'static str) -> Result<&'static KMutex<T>, GrtError>
pub fn get_kmutex<T>(key: &'static str) -> Result<&'static KMutex<T>, GrtError>
Retrieve a mutex by name from the wdk-mutex
global reference tracker.
This function takes in a static &str
to lookup your Mutex by key (where the key is the argument). When calling
this function, a turbofish specifier is required to tell the compiler what type is contained in the Mutex
. See
examples for more information.
§Errors
This function will error if:
- The
Grt
has not been initialised - The
Grt
is empty - The key does not exist
- The mutex type is anything other than a
KMutex
§Examples
{
let my_mutex = Grt::get_kmutex::<u32>("my_test_mutex");
if let Err(e) = my_mutex {
println!("An error occurred: {:?}", e);
return;
}
let mut lock = my_mutex.unwrap().lock().unwrap();
*lock += 1;
}
Sourcepub fn get_fast_mutex<T>(
key: &'static str,
) -> Result<&'static FastMutex<T>, GrtError>
pub fn get_fast_mutex<T>( key: &'static str, ) -> Result<&'static FastMutex<T>, GrtError>
Retrieve a mutex by name from the wdk-mutex
global reference tracker.
This function takes in a static &str
to lookup your Mutex by key (where the key is the argument). When calling
this function, a turbofish specifier is required to tell the compiler what type is contained in the Mutex
. See
examples for more information.
§Errors
This function will error if:
- The
Grt
has not been initialised - The
Grt
is empty - The key does not exist
- The mutex type is anything other than a
FastMutex
§Examples
{
let my_mutex = Grt::get_fast_mutex::<u32>("my_test_mutex");
if let Err(e) = my_mutex {
println!("An error occurred: {:?}", e);
return;
}
let mut lock = my_mutex.unwrap().lock().unwrap();
*lock += 1;
}
Sourcepub unsafe fn destroy() -> Result<(), GrtError>
pub unsafe fn destroy() -> Result<(), GrtError>
Destroy the global reference tracker for wdk-mutex
.
Calling Self::destroy
will destroy the ‘runtime’ provided for using globally accessible wdk-mutex
mutexes
in your driver.
§Safety
Once this function is called you will no longer be able to access any mutexes who’s lifetime is managed by the
Grt
.
Note: This function is marked unsafe
as it could lead to UB if accidentally used whilst threads / callbacks
dependant upon a mutex that it managed. Although it is unsafe
, attempting to access a mutex after the Grt
is destroyed
will not cause a null pointer dereference (they are checked), but it could lead to UB as those setter/getter functions will
return an error.
§Examples
/// Driver exit routine
extern "C" fn driver_exit(driver: *mut DRIVER_OBJECT) {
unsafe { Grt::destroy() };
}