xref: /aosp_15_r20/external/crosvm/base/src/worker_thread.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 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 //! Worker thread abstraction
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use std::panic;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::thread;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::thread::JoinHandle;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::thread::Thread;
11*bb4ee6a4SAndroid Build Coastguard Worker 
12*bb4ee6a4SAndroid Build Coastguard Worker use crate::Error;
13*bb4ee6a4SAndroid Build Coastguard Worker use crate::Event;
14*bb4ee6a4SAndroid Build Coastguard Worker 
15*bb4ee6a4SAndroid Build Coastguard Worker /// Wrapper object for creating a worker thread that can be stopped by signaling an event.
16*bb4ee6a4SAndroid Build Coastguard Worker pub struct WorkerThread<T: Send + 'static> {
17*bb4ee6a4SAndroid Build Coastguard Worker     worker: Option<(Event, JoinHandle<T>)>,
18*bb4ee6a4SAndroid Build Coastguard Worker }
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker impl<T: Send + 'static> WorkerThread<T> {
21*bb4ee6a4SAndroid Build Coastguard Worker     /// Starts a worker thread named `thread_name` running the `thread_func` function.
22*bb4ee6a4SAndroid Build Coastguard Worker     ///
23*bb4ee6a4SAndroid Build Coastguard Worker     /// The `thread_func` implementation must monitor the provided `Event` and return from the
24*bb4ee6a4SAndroid Build Coastguard Worker     /// thread when it is signaled.
25*bb4ee6a4SAndroid Build Coastguard Worker     ///
26*bb4ee6a4SAndroid Build Coastguard Worker     /// Call [`stop()`](Self::stop) to stop the thread.
start<F>(thread_name: impl Into<String>, thread_func: F) -> Self where F: FnOnce(Event) -> T + Send + 'static,27*bb4ee6a4SAndroid Build Coastguard Worker     pub fn start<F>(thread_name: impl Into<String>, thread_func: F) -> Self
28*bb4ee6a4SAndroid Build Coastguard Worker     where
29*bb4ee6a4SAndroid Build Coastguard Worker         F: FnOnce(Event) -> T + Send + 'static,
30*bb4ee6a4SAndroid Build Coastguard Worker     {
31*bb4ee6a4SAndroid Build Coastguard Worker         let stop_event = Event::new().expect("Event::new() failed");
32*bb4ee6a4SAndroid Build Coastguard Worker         let thread_stop_event = stop_event.try_clone().expect("Event::try_clone() failed");
33*bb4ee6a4SAndroid Build Coastguard Worker 
34*bb4ee6a4SAndroid Build Coastguard Worker         let thread_handle = thread::Builder::new()
35*bb4ee6a4SAndroid Build Coastguard Worker             .name(thread_name.into())
36*bb4ee6a4SAndroid Build Coastguard Worker             .spawn(move || thread_func(thread_stop_event))
37*bb4ee6a4SAndroid Build Coastguard Worker             .expect("thread spawn failed");
38*bb4ee6a4SAndroid Build Coastguard Worker 
39*bb4ee6a4SAndroid Build Coastguard Worker         WorkerThread {
40*bb4ee6a4SAndroid Build Coastguard Worker             worker: Some((stop_event, thread_handle)),
41*bb4ee6a4SAndroid Build Coastguard Worker         }
42*bb4ee6a4SAndroid Build Coastguard Worker     }
43*bb4ee6a4SAndroid Build Coastguard Worker 
44*bb4ee6a4SAndroid Build Coastguard Worker     /// Stops the worker thread.
45*bb4ee6a4SAndroid Build Coastguard Worker     ///
46*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the value returned by the function running in the thread.
stop(mut self) -> T47*bb4ee6a4SAndroid Build Coastguard Worker     pub fn stop(mut self) -> T {
48*bb4ee6a4SAndroid Build Coastguard Worker         // The only time the internal `Option` should be `None` is in a `drop` after `stop`, so this
49*bb4ee6a4SAndroid Build Coastguard Worker         // `expect()` should never fail.
50*bb4ee6a4SAndroid Build Coastguard Worker         self.stop_internal().expect("invalid worker state")
51*bb4ee6a4SAndroid Build Coastguard Worker     }
52*bb4ee6a4SAndroid Build Coastguard Worker 
53*bb4ee6a4SAndroid Build Coastguard Worker     // `stop_internal` accepts a reference so it can be called from `drop`.
54*bb4ee6a4SAndroid Build Coastguard Worker     #[doc(hidden)]
stop_internal(&mut self) -> Option<T>55*bb4ee6a4SAndroid Build Coastguard Worker     fn stop_internal(&mut self) -> Option<T> {
56*bb4ee6a4SAndroid Build Coastguard Worker         self.worker.take().map(|(stop_event, thread_handle)| {
57*bb4ee6a4SAndroid Build Coastguard Worker             // There is nothing the caller can do to handle `stop_event.signal()` failure, and we
58*bb4ee6a4SAndroid Build Coastguard Worker             // don't want to leave the thread running, so panic in that case.
59*bb4ee6a4SAndroid Build Coastguard Worker             stop_event
60*bb4ee6a4SAndroid Build Coastguard Worker                 .signal()
61*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("WorkerThread stop event signal failed");
62*bb4ee6a4SAndroid Build Coastguard Worker 
63*bb4ee6a4SAndroid Build Coastguard Worker             match thread_handle.join() {
64*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(v) => v,
65*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => panic::resume_unwind(e),
66*bb4ee6a4SAndroid Build Coastguard Worker             }
67*bb4ee6a4SAndroid Build Coastguard Worker         })
68*bb4ee6a4SAndroid Build Coastguard Worker     }
69*bb4ee6a4SAndroid Build Coastguard Worker 
70*bb4ee6a4SAndroid Build Coastguard Worker     /// Signal thread's stop event. Unlike stop, the function doesn't wait
71*bb4ee6a4SAndroid Build Coastguard Worker     /// on joining the thread.
72*bb4ee6a4SAndroid Build Coastguard Worker     /// The function can be called multiple times.
73*bb4ee6a4SAndroid Build Coastguard Worker     /// Calling `stop` or `drop` will internally signal the stop event again
74*bb4ee6a4SAndroid Build Coastguard Worker     /// and join the thread.
signal(&mut self) -> Result<(), Error>75*bb4ee6a4SAndroid Build Coastguard Worker     pub fn signal(&mut self) -> Result<(), Error> {
76*bb4ee6a4SAndroid Build Coastguard Worker         if let Some((event, _)) = &mut self.worker {
77*bb4ee6a4SAndroid Build Coastguard Worker             event.signal()
78*bb4ee6a4SAndroid Build Coastguard Worker         } else {
79*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
80*bb4ee6a4SAndroid Build Coastguard Worker         }
81*bb4ee6a4SAndroid Build Coastguard Worker     }
82*bb4ee6a4SAndroid Build Coastguard Worker 
83*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns a handle to the running thread.
thread(&self) -> &Thread84*bb4ee6a4SAndroid Build Coastguard Worker     pub fn thread(&self) -> &Thread {
85*bb4ee6a4SAndroid Build Coastguard Worker         // The only time the internal `Option` should be `None` is in a `drop` after `stop`, so this
86*bb4ee6a4SAndroid Build Coastguard Worker         // `unwrap()` should never fail.
87*bb4ee6a4SAndroid Build Coastguard Worker         self.worker.as_ref().unwrap().1.thread()
88*bb4ee6a4SAndroid Build Coastguard Worker     }
89*bb4ee6a4SAndroid Build Coastguard Worker }
90*bb4ee6a4SAndroid Build Coastguard Worker 
91*bb4ee6a4SAndroid Build Coastguard Worker impl<T: Send + 'static> Drop for WorkerThread<T> {
92*bb4ee6a4SAndroid Build Coastguard Worker     /// Stops the thread if the `WorkerThread` is dropped without calling [`stop()`](Self::stop).
drop(&mut self)93*bb4ee6a4SAndroid Build Coastguard Worker     fn drop(&mut self) {
94*bb4ee6a4SAndroid Build Coastguard Worker         let _ = self.stop_internal();
95*bb4ee6a4SAndroid Build Coastguard Worker     }
96*bb4ee6a4SAndroid Build Coastguard Worker }
97