diff --git a/src/sync/condvar.rs b/src/sync/condvar.rs index a7bd7410..fdc617e5 100644 --- a/src/sync/condvar.rs +++ b/src/sync/condvar.rs @@ -38,6 +38,22 @@ impl Condvar { Ok(guard) } + /// Blocks the current thread until this condition variable receives a + /// notification and the given condition returns false. + pub fn wait_while<'a, T, F>( + &self, + mut guard: MutexGuard<'a, T>, + mut condition: F, + ) -> LockResult> + where + F: FnMut(&mut T) -> bool, + { + while condition(&mut *guard) { + guard = self.wait(guard)?; + } + Ok(guard) + } + /// Waits on this condition variable for a notification, timing out after a /// specified duration. pub fn wait_timeout<'a, T>( diff --git a/tests/condvar.rs b/tests/condvar.rs index 2bdb52a2..47a2876c 100644 --- a/tests/condvar.rs +++ b/tests/condvar.rs @@ -42,6 +42,22 @@ fn notify_all() { }); } +#[test] +fn wait_while() { + loom::model(|| { + let inc = Arc::new(Inc::new()); + + let j = { + let inc = inc.clone(); + thread::spawn(move || inc.wait_for_1()) + }; + + thread::spawn(move || inc.inc()).join().expect("inc"); + + j.join().expect("waiter") + }); +} + struct Inc { num: AtomicUsize, mutex: Mutex<()>, @@ -70,6 +86,16 @@ impl Inc { } } + fn wait_for_1(&self) { + let guard = self.mutex.lock().unwrap(); + + drop( + self.condvar + .wait_while(guard, |_| self.num.load(SeqCst) < 1) + .unwrap(), + ); + } + fn inc(&self) { self.num.store(1, SeqCst); drop(self.mutex.lock().unwrap());