// Copyright 2022 The ChromiumOS Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. use std::any::Any; use std::panic; use std::sync::mpsc::channel; use std::sync::mpsc::Receiver; use std::thread; use std::thread::JoinHandle; use std::time::Duration; /// Spawns a thread that can be joined with a timeout. pub fn spawn_with_timeout(f: F) -> JoinHandleWithTimeout where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static, { // Use a channel to signal completion to the join handle let (tx, rx) = channel(); let handle = thread::spawn(move || { let val = panic::catch_unwind(panic::AssertUnwindSafe(f)); tx.send(()).unwrap(); val }); JoinHandleWithTimeout { handle, rx } } pub struct JoinHandleWithTimeout { handle: JoinHandle>, rx: Receiver<()>, } #[derive(Debug)] pub enum JoinError { Panic(Box), Timeout, } impl JoinHandleWithTimeout { /// Tries to join the thread. Returns an error if the join takes more than `timeout_ms`. pub fn try_join(self, timeout: Duration) -> Result { if self.rx.recv_timeout(timeout).is_ok() { self.handle.join().unwrap().map_err(|e| JoinError::Panic(e)) } else { Err(JoinError::Timeout) } } }