sync/lib.rs
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
24mod condvar;
25mod mutex;
26
27use std::sync::Arc;
28use std::sync::WaitTimeoutResult;
29use std::time::Duration;
30
31pub use crate::condvar::Condvar;
32pub use crate::mutex::Mutex;
33pub 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.
41pub struct Waitable(Arc<(Condvar, Mutex<bool>)>);
42
43impl Waitable {
44 /// Return an already-signaled Waitable.
45 pub fn signaled() -> Self {
46 Waitable(Arc::new((Condvar::new(), Mutex::new(true))))
47 }
48
49 /// Perform a blocking wait on this Waitable.
50 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.
60pub struct Promise(Arc<(Condvar, Mutex<bool>)>);
61
62impl Promise {
63 /// Signal this promise, and it's associated Waitable.
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.
74pub 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}