1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 use std::{
16 sync::{Condvar, LockResult, Mutex, MutexGuard, PoisonError, WaitTimeoutResult},
17 time::Duration,
18 };
19
20 /// A mutex with an associated condition variable.
21 #[derive(Debug)]
22 pub struct Monitor<T> {
23 pub state: Mutex<T>,
24 pub cv: Condvar,
25 }
26
27 impl<T> Monitor<T> {
28 /// Creates a new mutex wrapping the given value, and a new condition variable to go with it.
new(state: T) -> Self29 pub fn new(state: T) -> Self {
30 Self { state: Mutex::new(state), cv: Condvar::default() }
31 }
32
33 /// Waits on the condition variable while the given condition holds true on the contents of the
34 /// mutex.
35 ///
36 /// Blocks until the condition variable is notified and the function returns false.
wait_while(&self, condition: impl FnMut(&mut T) -> bool) -> LockResult<MutexGuard<T>>37 pub fn wait_while(&self, condition: impl FnMut(&mut T) -> bool) -> LockResult<MutexGuard<T>> {
38 self.cv.wait_while(self.state.lock()?, condition)
39 }
40
41 /// Waits on the condition variable while the given condition holds true on the contents of the
42 /// mutex, with a timeout.
43 ///
44 /// Blocks until the condition variable is notified and the function returns false, or the
45 /// timeout elapses.
wait_timeout_while( &self, timeout: Duration, condition: impl FnMut(&mut T) -> bool, ) -> Result<(MutexGuard<T>, WaitTimeoutResult), PoisonError<MutexGuard<T>>>46 pub fn wait_timeout_while(
47 &self,
48 timeout: Duration,
49 condition: impl FnMut(&mut T) -> bool,
50 ) -> Result<(MutexGuard<T>, WaitTimeoutResult), PoisonError<MutexGuard<T>>> {
51 self.cv
52 .wait_timeout_while(self.state.lock()?, timeout, condition)
53 .map_err(convert_poison_error)
54 }
55 }
56
convert_poison_error<T>(err: PoisonError<(T, WaitTimeoutResult)>) -> PoisonError<T>57 fn convert_poison_error<T>(err: PoisonError<(T, WaitTimeoutResult)>) -> PoisonError<T> {
58 PoisonError::new(err.into_inner().0)
59 }
60