xref: /aosp_15_r20/external/crosvm/common/sync/src/lib.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Sync primitive types whose methods panic rather than returning error in case of poison.
6 //!
7 //! The Mutex/Condvar type in this crates wraps the standard library versions and mirrors the same
8 //! methods, except that they panic where the standard library would return an Error. This API
9 //! codifies our error handling strategy around poisoned mutexes in crosvm.
10 //!
11 //! - Crosvm releases are built with panic=abort so poisoning never occurs. A panic while a mutex is
12 //!   held (or ever) takes down the entire process. Thus we would like for code not to have to
13 //!   consider the possibility of poison.
14 //!
15 //! - We could ask developers to always write `.lock().unwrap()` on a standard library mutex.
16 //!   However, we would like to stigmatize the use of unwrap. It is confusing to permit unwrap but
17 //!   only on mutex lock results. During code review it may not always be obvious whether a
18 //!   particular unwrap is unwrapping a mutex lock result or a different error that should be
19 //!   handled in a more principled way.
20 //!
21 //! Developers should feel free to use types defined in this crate anywhere in crosvm that they
22 //! would otherwise be using the corresponding types in std::sync.
23 
24 mod condvar;
25 mod mutex;
26 
27 use std::sync::Arc;
28 use std::sync::WaitTimeoutResult;
29 use std::time::Duration;
30 
31 pub use crate::condvar::Condvar;
32 pub use crate::mutex::Mutex;
33 pub use crate::mutex::WouldBlock;
34 
35 /// Waitable allows one thread to wait on a signal from another thread.
36 ///
37 /// A Waitable is usually created with a Promise using
38 /// `create_promise_and_waitable`, and the Promise is used by one thread and the
39 /// Waitable can be used by another thread. Promise and Waitable do not use any
40 /// OS-level synchronization primitives.
41 pub struct Waitable(Arc<(Condvar, Mutex<bool>)>);
42 
43 impl Waitable {
44     /// Return an already-signaled Waitable.
signaled() -> Self45     pub fn signaled() -> Self {
46         Waitable(Arc::new((Condvar::new(), Mutex::new(true))))
47     }
48 
49     /// Perform a blocking wait on this Waitable.
wait(&self, timeout: Option<Duration>) -> WaitTimeoutResult50     pub fn wait(&self, timeout: Option<Duration>) -> WaitTimeoutResult {
51         let timeout = timeout.unwrap_or(Duration::MAX);
52         let (ref condvar, ref signaled_mutex) = *self.0;
53         condvar
54             .wait_timeout_while(signaled_mutex.lock(), timeout, |signaled| !*signaled)
55             .1
56     }
57 }
58 
59 /// Promise allows one thread to signal a waitable that another thread can wait on.
60 pub struct Promise(Arc<(Condvar, Mutex<bool>)>);
61 
62 impl Promise {
63     /// Signal this promise, and it's associated Waitable.
signal(&self)64     pub fn signal(&self) {
65         let (ref condvar, ref signaled_mutex) = *self.0;
66         *signaled_mutex.lock() = true;
67         condvar.notify_all();
68     }
69 }
70 
71 /// Create a paired Promise and Waitable.
72 ///
73 /// Signalling the Promise will signal the Waitable.
create_promise_and_waitable() -> (Promise, Waitable)74 pub fn create_promise_and_waitable() -> (Promise, Waitable) {
75     let inner = Arc::new((Condvar::new(), Mutex::new(false)));
76     (Promise(Arc::clone(&inner)), Waitable(inner))
77 }
78