// Copyright 2018 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34//! Sync primitive types whose methods panic rather than returning error in case of poison.5//!6//! The Mutex/Condvar type in this crates wraps the standard library versions and mirrors the same7//! methods, except that they panic where the standard library would return an Error. This API8//! codifies our error handling strategy around poisoned mutexes in crosvm.9//!10//! - Crosvm releases are built with panic=abort so poisoning never occurs. A panic while a mutex is11//! held (or ever) takes down the entire process. Thus we would like for code not to have to12//! consider the possibility of poison.13//!14//! - We could ask developers to always write `.lock().unwrap()` on a standard library mutex.15//! However, we would like to stigmatize the use of unwrap. It is confusing to permit unwrap but16//! only on mutex lock results. During code review it may not always be obvious whether a17//! particular unwrap is unwrapping a mutex lock result or a different error that should be18//! handled in a more principled way.19//!20//! Developers should feel free to use types defined in this crate anywhere in crosvm that they21//! would otherwise be using the corresponding types in std::sync.2223mod condvar;24mod mutex;2526use std::sync::Arc;27use std::sync::WaitTimeoutResult;28use std::time::Duration;2930pub use crate::condvar::Condvar;31pub use crate::mutex::Mutex;32pub use crate::mutex::WouldBlock;3334/// Waitable allows one thread to wait on a signal from another thread.35///36/// A Waitable is usually created with a Promise using37/// `create_promise_and_waitable`, and the Promise is used by one thread and the38/// Waitable can be used by another thread. Promise and Waitable do not use any39/// OS-level synchronization primitives.40pub struct Waitable(Arc<(Condvar, Mutex<bool>)>);4142impl Waitable {43/// Return an already-signaled Waitable.44pub fn signaled() -> Self {45Waitable(Arc::new((Condvar::new(), Mutex::new(true))))46}4748/// Perform a blocking wait on this Waitable.49pub fn wait(&self, timeout: Option<Duration>) -> WaitTimeoutResult {50let timeout = timeout.unwrap_or(Duration::MAX);51let (ref condvar, ref signaled_mutex) = *self.0;52condvar53.wait_timeout_while(signaled_mutex.lock(), timeout, |signaled| !*signaled)54.155}56}5758/// Promise allows one thread to signal a waitable that another thread can wait on.59pub struct Promise(Arc<(Condvar, Mutex<bool>)>);6061impl Promise {62/// Signal this promise, and it's associated Waitable.63pub fn signal(&self) {64let (ref condvar, ref signaled_mutex) = *self.0;65*signaled_mutex.lock() = true;66condvar.notify_all();67}68}6970/// Create a paired Promise and Waitable.71///72/// Signalling the Promise will signal the Waitable.73pub fn create_promise_and_waitable() -> (Promise, Waitable) {74let inner = Arc::new((Condvar::new(), Mutex::new(false)));75(Promise(Arc::clone(&inner)), Waitable(inner))76}777879