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