windows_threading/lib.rs
1#![doc = include_str!("../readme.md")]
2#![cfg(windows)]
3#![no_std]
4#![expect(non_snake_case, non_camel_case_types, clippy::upper_case_acronyms)]
5
6mod bindings;
7use bindings::*;
8
9mod pool;
10pub use pool::*;
11
12extern crate alloc;
13use alloc::boxed::Box;
14use core::ffi::c_void;
15
16/// Submit the closure to the default thread pool.
17///
18/// * The closure must have `'static` lifetime as the thread may outlive the lifetime in which `submit` is called.
19/// * The closure must be `Send` as it will be sent to another thread for execution.
20pub fn submit<F: FnOnce() + Send + 'static>(f: F) {
21 // This is safe because the closure has `'static` lifetime.
22 unsafe {
23 try_submit(core::ptr::null(), f);
24 }
25}
26
27/// Calls the closure on each element of the iterator in parallel, waiting for all closures to finish.
28///
29/// * The closure does not require `'static` lifetime since the `for_each` function bounds the lifetime of all submitted closures.
30/// * The closure must be `Sync` as multiple threads will refer to it.
31/// * The iterator items must be `Send` as they will be sent from one thread to another.
32pub fn for_each<I, F, T>(i: I, f: F)
33where
34 I: Iterator<Item = T>,
35 F: Fn(T) + Sync,
36 T: Send,
37{
38 Pool::with_scope(|pool| {
39 for item in i {
40 pool.submit(|| f(item));
41 }
42 });
43}
44
45/// The thread identifier of the calling thread.
46pub fn thread_id() -> u32 {
47 unsafe { GetCurrentThreadId() }
48}
49
50/// Suspends the execution of the current thread until the time-out interval elapses.
51pub fn sleep(milliseconds: u32) {
52 unsafe {
53 Sleep(milliseconds);
54 }
55}
56
57// When used correctly, the Windows thread pool APIs only fail when memory is exhausted. This function will cause such failures to `panic`.
58fn check<D: Default + PartialEq>(result: D) -> D {
59 if result == D::default() {
60 panic!("allocation failed");
61 }
62
63 result
64}
65
66// This function is `unsafe` as it cannot ensure that the lifetime of the closure is sufficient or
67// whether the `environment` pointer is valid.
68unsafe fn try_submit<F: FnOnce() + Send>(environment: *const TP_CALLBACK_ENVIRON_V3, f: F) {
69 unsafe extern "system" fn callback<F: FnOnce() + Send>(
70 _: PTP_CALLBACK_INSTANCE,
71 callback: *mut c_void,
72 ) {
73 unsafe {
74 Box::from_raw(callback as *mut F)();
75 }
76 }
77
78 unsafe {
79 check(TrySubmitThreadpoolCallback(
80 Some(callback::<F>),
81 Box::into_raw(Box::new(f)) as _,
82 environment,
83 ));
84 }
85}