xref: /aosp_15_r20/external/crosvm/base/src/sys/windows/thread.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::any::Any;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::panic;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::mpsc::channel;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::mpsc::Receiver;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::thread;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::thread::JoinHandle;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
12*bb4ee6a4SAndroid Build Coastguard Worker 
13*bb4ee6a4SAndroid Build Coastguard Worker /// Spawns a thread that can be joined with a timeout.
spawn_with_timeout<F, T>(f: F) -> JoinHandleWithTimeout<T> where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static,14*bb4ee6a4SAndroid Build Coastguard Worker pub fn spawn_with_timeout<F, T>(f: F) -> JoinHandleWithTimeout<T>
15*bb4ee6a4SAndroid Build Coastguard Worker where
16*bb4ee6a4SAndroid Build Coastguard Worker     F: FnOnce() -> T,
17*bb4ee6a4SAndroid Build Coastguard Worker     F: Send + 'static,
18*bb4ee6a4SAndroid Build Coastguard Worker     T: Send + 'static,
19*bb4ee6a4SAndroid Build Coastguard Worker {
20*bb4ee6a4SAndroid Build Coastguard Worker     // Use a channel to signal completion to the join handle
21*bb4ee6a4SAndroid Build Coastguard Worker     let (tx, rx) = channel();
22*bb4ee6a4SAndroid Build Coastguard Worker     let handle = thread::spawn(move || {
23*bb4ee6a4SAndroid Build Coastguard Worker         let val = panic::catch_unwind(panic::AssertUnwindSafe(f));
24*bb4ee6a4SAndroid Build Coastguard Worker         tx.send(()).unwrap();
25*bb4ee6a4SAndroid Build Coastguard Worker         val
26*bb4ee6a4SAndroid Build Coastguard Worker     });
27*bb4ee6a4SAndroid Build Coastguard Worker     JoinHandleWithTimeout { handle, rx }
28*bb4ee6a4SAndroid Build Coastguard Worker }
29*bb4ee6a4SAndroid Build Coastguard Worker 
30*bb4ee6a4SAndroid Build Coastguard Worker pub struct JoinHandleWithTimeout<T> {
31*bb4ee6a4SAndroid Build Coastguard Worker     handle: JoinHandle<thread::Result<T>>,
32*bb4ee6a4SAndroid Build Coastguard Worker     rx: Receiver<()>,
33*bb4ee6a4SAndroid Build Coastguard Worker }
34*bb4ee6a4SAndroid Build Coastguard Worker 
35*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
36*bb4ee6a4SAndroid Build Coastguard Worker pub enum JoinError {
37*bb4ee6a4SAndroid Build Coastguard Worker     Panic(Box<dyn Any>),
38*bb4ee6a4SAndroid Build Coastguard Worker     Timeout,
39*bb4ee6a4SAndroid Build Coastguard Worker }
40*bb4ee6a4SAndroid Build Coastguard Worker 
41*bb4ee6a4SAndroid Build Coastguard Worker impl<T> JoinHandleWithTimeout<T> {
42*bb4ee6a4SAndroid Build Coastguard Worker     /// Tries to join the thread.  Returns an error if the join takes more than `timeout_ms`.
try_join(self, timeout: Duration) -> Result<T, JoinError>43*bb4ee6a4SAndroid Build Coastguard Worker     pub fn try_join(self, timeout: Duration) -> Result<T, JoinError> {
44*bb4ee6a4SAndroid Build Coastguard Worker         if self.rx.recv_timeout(timeout).is_ok() {
45*bb4ee6a4SAndroid Build Coastguard Worker             self.handle.join().unwrap().map_err(|e| JoinError::Panic(e))
46*bb4ee6a4SAndroid Build Coastguard Worker         } else {
47*bb4ee6a4SAndroid Build Coastguard Worker             Err(JoinError::Timeout)
48*bb4ee6a4SAndroid Build Coastguard Worker         }
49*bb4ee6a4SAndroid Build Coastguard Worker     }
50*bb4ee6a4SAndroid Build Coastguard Worker }
51