windows_threading/
lib.rs

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