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