]> git.lizzy.rs Git - rust.git/blob - library/std/src/sync/condvar.rs
4efd86aa3ede8c3e7c99c2f845f3c164a3cd57b4
[rust.git] / library / std / src / sync / condvar.rs
1 use crate::fmt;
2 use crate::sync::atomic::{AtomicUsize, Ordering};
3 use crate::sync::{mutex, MutexGuard, PoisonError};
4 use crate::sys_common::condvar as sys;
5 use crate::sys_common::mutex as sys_mutex;
6 use crate::sys_common::poison::{self, LockResult};
7 use crate::time::{Duration, Instant};
8
9 /// A type indicating whether a timed wait on a condition variable returned
10 /// due to a time out or not.
11 ///
12 /// It is returned by the [`wait_timeout`] method.
13 ///
14 /// [`wait_timeout`]: Condvar::wait_timeout
15 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
16 #[stable(feature = "wait_timeout", since = "1.5.0")]
17 pub struct WaitTimeoutResult(bool);
18
19 impl WaitTimeoutResult {
20     /// Returns `true` if the wait was known to have timed out.
21     ///
22     /// # Examples
23     ///
24     /// This example spawns a thread which will update the boolean value and
25     /// then wait 100 milliseconds before notifying the condvar.
26     ///
27     /// The main thread will wait with a timeout on the condvar and then leave
28     /// once the boolean has been updated and notified.
29     ///
30     /// ```
31     /// use std::sync::{Arc, Condvar, Mutex};
32     /// use std::thread;
33     /// use std::time::Duration;
34     ///
35     /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
36     /// let pair2 = pair.clone();
37     ///
38     /// thread::spawn(move || {
39     ///     let (lock, cvar) = &*pair2;
40     ///
41     ///     // Let's wait 20 milliseconds before notifying the condvar.
42     ///     thread::sleep(Duration::from_millis(20));
43     ///
44     ///     let mut started = lock.lock().unwrap();
45     ///     // We update the boolean value.
46     ///     *started = true;
47     ///     cvar.notify_one();
48     /// });
49     ///
50     /// // Wait for the thread to start up.
51     /// let (lock, cvar) = &*pair;
52     /// let mut started = lock.lock().unwrap();
53     /// loop {
54     ///     // Let's put a timeout on the condvar's wait.
55     ///     let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
56     ///     // 10 milliseconds have passed, or maybe the value changed!
57     ///     started = result.0;
58     ///     if *started == true {
59     ///         // We received the notification and the value has been updated, we can leave.
60     ///         break
61     ///     }
62     /// }
63     /// ```
64     #[stable(feature = "wait_timeout", since = "1.5.0")]
65     pub fn timed_out(&self) -> bool {
66         self.0
67     }
68 }
69
70 /// A Condition Variable
71 ///
72 /// Condition variables represent the ability to block a thread such that it
73 /// consumes no CPU time while waiting for an event to occur. Condition
74 /// variables are typically associated with a boolean predicate (a condition)
75 /// and a mutex. The predicate is always verified inside of the mutex before
76 /// determining that a thread must block.
77 ///
78 /// Functions in this module will block the current **thread** of execution and
79 /// are bindings to system-provided condition variables where possible. Note
80 /// that this module places one additional restriction over the system condition
81 /// variables: each condvar can be used with precisely one mutex at runtime. Any
82 /// attempt to use multiple mutexes on the same condition variable will result
83 /// in a runtime panic. If this is not desired, then the unsafe primitives in
84 /// `sys` do not have this restriction but may result in undefined behavior.
85 ///
86 /// # Examples
87 ///
88 /// ```
89 /// use std::sync::{Arc, Mutex, Condvar};
90 /// use std::thread;
91 ///
92 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
93 /// let pair2 = pair.clone();
94 ///
95 /// // Inside of our lock, spawn a new thread, and then wait for it to start.
96 /// thread::spawn(move|| {
97 ///     let (lock, cvar) = &*pair2;
98 ///     let mut started = lock.lock().unwrap();
99 ///     *started = true;
100 ///     // We notify the condvar that the value has changed.
101 ///     cvar.notify_one();
102 /// });
103 ///
104 /// // Wait for the thread to start up.
105 /// let (lock, cvar) = &*pair;
106 /// let mut started = lock.lock().unwrap();
107 /// while !*started {
108 ///     started = cvar.wait(started).unwrap();
109 /// }
110 /// ```
111 #[stable(feature = "rust1", since = "1.0.0")]
112 pub struct Condvar {
113     inner: Box<sys::Condvar>,
114     mutex: AtomicUsize,
115 }
116
117 impl Condvar {
118     /// Creates a new condition variable which is ready to be waited on and
119     /// notified.
120     ///
121     /// # Examples
122     ///
123     /// ```
124     /// use std::sync::Condvar;
125     ///
126     /// let condvar = Condvar::new();
127     /// ```
128     #[stable(feature = "rust1", since = "1.0.0")]
129     pub fn new() -> Condvar {
130         let mut c = Condvar { inner: box sys::Condvar::new(), mutex: AtomicUsize::new(0) };
131         unsafe {
132             c.inner.init();
133         }
134         c
135     }
136
137     /// Blocks the current thread until this condition variable receives a
138     /// notification.
139     ///
140     /// This function will atomically unlock the mutex specified (represented by
141     /// `guard`) and block the current thread. This means that any calls
142     /// to [`notify_one`] or [`notify_all`] which happen logically after the
143     /// mutex is unlocked are candidates to wake this thread up. When this
144     /// function call returns, the lock specified will have been re-acquired.
145     ///
146     /// Note that this function is susceptible to spurious wakeups. Condition
147     /// variables normally have a boolean predicate associated with them, and
148     /// the predicate must always be checked each time this function returns to
149     /// protect against spurious wakeups.
150     ///
151     /// # Errors
152     ///
153     /// This function will return an error if the mutex being waited on is
154     /// poisoned when this thread re-acquires the lock. For more information,
155     /// see information about [poisoning] on the [`Mutex`] type.
156     ///
157     /// # Panics
158     ///
159     /// This function will [`panic!`] if it is used with more than one mutex
160     /// over time. Each condition variable is dynamically bound to exactly one
161     /// mutex to ensure defined behavior across platforms. If this functionality
162     /// is not desired, then unsafe primitives in `sys` are provided.
163     ///
164     /// [`notify_one`]: Self::notify_one
165     /// [`notify_all`]: Self::notify_all
166     /// [poisoning]: super::Mutex#poisoning
167     /// [`Mutex`]: super::Mutex
168     ///
169     /// # Examples
170     ///
171     /// ```
172     /// use std::sync::{Arc, Mutex, Condvar};
173     /// use std::thread;
174     ///
175     /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
176     /// let pair2 = pair.clone();
177     ///
178     /// thread::spawn(move|| {
179     ///     let (lock, cvar) = &*pair2;
180     ///     let mut started = lock.lock().unwrap();
181     ///     *started = true;
182     ///     // We notify the condvar that the value has changed.
183     ///     cvar.notify_one();
184     /// });
185     ///
186     /// // Wait for the thread to start up.
187     /// let (lock, cvar) = &*pair;
188     /// let mut started = lock.lock().unwrap();
189     /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
190     /// while !*started {
191     ///     started = cvar.wait(started).unwrap();
192     /// }
193     /// ```
194     #[stable(feature = "rust1", since = "1.0.0")]
195     pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> {
196         let poisoned = unsafe {
197             let lock = mutex::guard_lock(&guard);
198             self.verify(lock);
199             self.inner.wait(lock);
200             mutex::guard_poison(&guard).get()
201         };
202         if poisoned { Err(PoisonError::new(guard)) } else { Ok(guard) }
203     }
204
205     /// Blocks the current thread until this condition variable receives a
206     /// notification and the provided condition is false.
207     ///
208     /// This function will atomically unlock the mutex specified (represented by
209     /// `guard`) and block the current thread. This means that any calls
210     /// to [`notify_one`] or [`notify_all`] which happen logically after the
211     /// mutex is unlocked are candidates to wake this thread up. When this
212     /// function call returns, the lock specified will have been re-acquired.
213     ///
214     /// # Errors
215     ///
216     /// This function will return an error if the mutex being waited on is
217     /// poisoned when this thread re-acquires the lock. For more information,
218     /// see information about [poisoning] on the [`Mutex`] type.
219     ///
220     /// [`notify_one`]: Self::notify_one
221     /// [`notify_all`]: Self::notify_all
222     /// [poisoning]: super::Mutex#poisoning
223     /// [`Mutex`]: super::Mutex
224     ///
225     /// # Examples
226     ///
227     /// ```
228     /// use std::sync::{Arc, Mutex, Condvar};
229     /// use std::thread;
230     ///
231     /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
232     /// let pair2 = pair.clone();
233     ///
234     /// thread::spawn(move|| {
235     ///     let (lock, cvar) = &*pair2;
236     ///     let mut pending = lock.lock().unwrap();
237     ///     *pending = false;
238     ///     // We notify the condvar that the value has changed.
239     ///     cvar.notify_one();
240     /// });
241     ///
242     /// // Wait for the thread to start up.
243     /// let (lock, cvar) = &*pair;
244     /// // As long as the value inside the `Mutex<bool>` is `true`, we wait.
245     /// let _guard = cvar.wait_while(lock.lock().unwrap(), |pending| { *pending }).unwrap();
246     /// ```
247     #[stable(feature = "wait_until", since = "1.42.0")]
248     pub fn wait_while<'a, T, F>(
249         &self,
250         mut guard: MutexGuard<'a, T>,
251         mut condition: F,
252     ) -> LockResult<MutexGuard<'a, T>>
253     where
254         F: FnMut(&mut T) -> bool,
255     {
256         while condition(&mut *guard) {
257             guard = self.wait(guard)?;
258         }
259         Ok(guard)
260     }
261
262     /// Waits on this condition variable for a notification, timing out after a
263     /// specified duration.
264     ///
265     /// The semantics of this function are equivalent to [`wait`]
266     /// except that the thread will be blocked for roughly no longer
267     /// than `ms` milliseconds. This method should not be used for
268     /// precise timing due to anomalies such as preemption or platform
269     /// differences that may not cause the maximum amount of time
270     /// waited to be precisely `ms`.
271     ///
272     /// Note that the best effort is made to ensure that the time waited is
273     /// measured with a monotonic clock, and not affected by the changes made to
274     /// the system time.
275     ///
276     /// The returned boolean is `false` only if the timeout is known
277     /// to have elapsed.
278     ///
279     /// Like [`wait`], the lock specified will be re-acquired when this function
280     /// returns, regardless of whether the timeout elapsed or not.
281     ///
282     /// [`wait`]: Self::wait
283     ///
284     /// # Examples
285     ///
286     /// ```
287     /// use std::sync::{Arc, Mutex, Condvar};
288     /// use std::thread;
289     ///
290     /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
291     /// let pair2 = pair.clone();
292     ///
293     /// thread::spawn(move|| {
294     ///     let (lock, cvar) = &*pair2;
295     ///     let mut started = lock.lock().unwrap();
296     ///     *started = true;
297     ///     // We notify the condvar that the value has changed.
298     ///     cvar.notify_one();
299     /// });
300     ///
301     /// // Wait for the thread to start up.
302     /// let (lock, cvar) = &*pair;
303     /// let mut started = lock.lock().unwrap();
304     /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
305     /// loop {
306     ///     let result = cvar.wait_timeout_ms(started, 10).unwrap();
307     ///     // 10 milliseconds have passed, or maybe the value changed!
308     ///     started = result.0;
309     ///     if *started == true {
310     ///         // We received the notification and the value has been updated, we can leave.
311     ///         break
312     ///     }
313     /// }
314     /// ```
315     #[stable(feature = "rust1", since = "1.0.0")]
316     #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
317     pub fn wait_timeout_ms<'a, T>(
318         &self,
319         guard: MutexGuard<'a, T>,
320         ms: u32,
321     ) -> LockResult<(MutexGuard<'a, T>, bool)> {
322         let res = self.wait_timeout(guard, Duration::from_millis(ms as u64));
323         poison::map_result(res, |(a, b)| (a, !b.timed_out()))
324     }
325
326     /// Waits on this condition variable for a notification, timing out after a
327     /// specified duration.
328     ///
329     /// The semantics of this function are equivalent to [`wait`] except that
330     /// the thread will be blocked for roughly no longer than `dur`. This
331     /// method should not be used for precise timing due to anomalies such as
332     /// preemption or platform differences that may not cause the maximum
333     /// amount of time waited to be precisely `dur`.
334     ///
335     /// Note that the best effort is made to ensure that the time waited is
336     /// measured with a monotonic clock, and not affected by the changes made to
337     /// the system time. This function is susceptible to spurious wakeups.
338     /// Condition variables normally have a boolean predicate associated with
339     /// them, and the predicate must always be checked each time this function
340     /// returns to protect against spurious wakeups. Additionally, it is
341     /// typically desirable for the timeout to not exceed some duration in
342     /// spite of spurious wakes, thus the sleep-duration is decremented by the
343     /// amount slept. Alternatively, use the `wait_timeout_while` method
344     /// to wait with a timeout while a predicate is true.
345     ///
346     /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
347     /// known to have elapsed.
348     ///
349     /// Like [`wait`], the lock specified will be re-acquired when this function
350     /// returns, regardless of whether the timeout elapsed or not.
351     ///
352     /// [`wait`]: Self::wait
353     /// [`wait_timeout_while`]: Self::wait_timeout_while
354     ///
355     /// # Examples
356     ///
357     /// ```
358     /// use std::sync::{Arc, Mutex, Condvar};
359     /// use std::thread;
360     /// use std::time::Duration;
361     ///
362     /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
363     /// let pair2 = pair.clone();
364     ///
365     /// thread::spawn(move|| {
366     ///     let (lock, cvar) = &*pair2;
367     ///     let mut started = lock.lock().unwrap();
368     ///     *started = true;
369     ///     // We notify the condvar that the value has changed.
370     ///     cvar.notify_one();
371     /// });
372     ///
373     /// // wait for the thread to start up
374     /// let (lock, cvar) = &*pair;
375     /// let mut started = lock.lock().unwrap();
376     /// // as long as the value inside the `Mutex<bool>` is `false`, we wait
377     /// loop {
378     ///     let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
379     ///     // 10 milliseconds have passed, or maybe the value changed!
380     ///     started = result.0;
381     ///     if *started == true {
382     ///         // We received the notification and the value has been updated, we can leave.
383     ///         break
384     ///     }
385     /// }
386     /// ```
387     #[stable(feature = "wait_timeout", since = "1.5.0")]
388     pub fn wait_timeout<'a, T>(
389         &self,
390         guard: MutexGuard<'a, T>,
391         dur: Duration,
392     ) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
393         let (poisoned, result) = unsafe {
394             let lock = mutex::guard_lock(&guard);
395             self.verify(lock);
396             let success = self.inner.wait_timeout(lock, dur);
397             (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
398         };
399         if poisoned { Err(PoisonError::new((guard, result))) } else { Ok((guard, result)) }
400     }
401
402     /// Waits on this condition variable for a notification, timing out after a
403     /// specified duration.
404     ///
405     /// The semantics of this function are equivalent to [`wait_while`] except
406     /// that the thread will be blocked for roughly no longer than `dur`. This
407     /// method should not be used for precise timing due to anomalies such as
408     /// preemption or platform differences that may not cause the maximum
409     /// amount of time waited to be precisely `dur`.
410     ///
411     /// Note that the best effort is made to ensure that the time waited is
412     /// measured with a monotonic clock, and not affected by the changes made to
413     /// the system time.
414     ///
415     /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
416     /// known to have elapsed without the condition being met.
417     ///
418     /// Like [`wait_while`], the lock specified will be re-acquired when this
419     /// function returns, regardless of whether the timeout elapsed or not.
420     ///
421     /// [`wait_while`]: Self::wait_while
422     /// [`wait_timeout`]: Self::wait_timeout
423     ///
424     /// # Examples
425     ///
426     /// ```
427     /// use std::sync::{Arc, Mutex, Condvar};
428     /// use std::thread;
429     /// use std::time::Duration;
430     ///
431     /// let pair = Arc::new((Mutex::new(true), Condvar::new()));
432     /// let pair2 = pair.clone();
433     ///
434     /// thread::spawn(move|| {
435     ///     let (lock, cvar) = &*pair2;
436     ///     let mut pending = lock.lock().unwrap();
437     ///     *pending = false;
438     ///     // We notify the condvar that the value has changed.
439     ///     cvar.notify_one();
440     /// });
441     ///
442     /// // wait for the thread to start up
443     /// let (lock, cvar) = &*pair;
444     /// let result = cvar.wait_timeout_while(
445     ///     lock.lock().unwrap(),
446     ///     Duration::from_millis(100),
447     ///     |&mut pending| pending,
448     /// ).unwrap();
449     /// if result.1.timed_out() {
450     ///     // timed-out without the condition ever evaluating to false.
451     /// }
452     /// // access the locked mutex via result.0
453     /// ```
454     #[stable(feature = "wait_timeout_until", since = "1.42.0")]
455     pub fn wait_timeout_while<'a, T, F>(
456         &self,
457         mut guard: MutexGuard<'a, T>,
458         dur: Duration,
459         mut condition: F,
460     ) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
461     where
462         F: FnMut(&mut T) -> bool,
463     {
464         let start = Instant::now();
465         loop {
466             if !condition(&mut *guard) {
467                 return Ok((guard, WaitTimeoutResult(false)));
468             }
469             let timeout = match dur.checked_sub(start.elapsed()) {
470                 Some(timeout) => timeout,
471                 None => return Ok((guard, WaitTimeoutResult(true))),
472             };
473             guard = self.wait_timeout(guard, timeout)?.0;
474         }
475     }
476
477     /// Wakes up one blocked thread on this condvar.
478     ///
479     /// If there is a blocked thread on this condition variable, then it will
480     /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
481     /// `notify_one` are not buffered in any way.
482     ///
483     /// To wake up all threads, see [`notify_all`].
484     ///
485     /// [`wait`]: Self::wait
486     /// [`wait_timeout`]: Self::wait_timeout
487     /// [`notify_all`]: Self::notify_all
488     ///
489     /// # Examples
490     ///
491     /// ```
492     /// use std::sync::{Arc, Mutex, Condvar};
493     /// use std::thread;
494     ///
495     /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
496     /// let pair2 = pair.clone();
497     ///
498     /// thread::spawn(move|| {
499     ///     let (lock, cvar) = &*pair2;
500     ///     let mut started = lock.lock().unwrap();
501     ///     *started = true;
502     ///     // We notify the condvar that the value has changed.
503     ///     cvar.notify_one();
504     /// });
505     ///
506     /// // Wait for the thread to start up.
507     /// let (lock, cvar) = &*pair;
508     /// let mut started = lock.lock().unwrap();
509     /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
510     /// while !*started {
511     ///     started = cvar.wait(started).unwrap();
512     /// }
513     /// ```
514     #[stable(feature = "rust1", since = "1.0.0")]
515     pub fn notify_one(&self) {
516         unsafe { self.inner.notify_one() }
517     }
518
519     /// Wakes up all blocked threads on this condvar.
520     ///
521     /// This method will ensure that any current waiters on the condition
522     /// variable are awoken. Calls to `notify_all()` are not buffered in any
523     /// way.
524     ///
525     /// To wake up only one thread, see [`notify_one`].
526     ///
527     /// [`notify_one`]: Self::notify_one
528     ///
529     /// # Examples
530     ///
531     /// ```
532     /// use std::sync::{Arc, Mutex, Condvar};
533     /// use std::thread;
534     ///
535     /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
536     /// let pair2 = pair.clone();
537     ///
538     /// thread::spawn(move|| {
539     ///     let (lock, cvar) = &*pair2;
540     ///     let mut started = lock.lock().unwrap();
541     ///     *started = true;
542     ///     // We notify the condvar that the value has changed.
543     ///     cvar.notify_all();
544     /// });
545     ///
546     /// // Wait for the thread to start up.
547     /// let (lock, cvar) = &*pair;
548     /// let mut started = lock.lock().unwrap();
549     /// // As long as the value inside the `Mutex<bool>` is `false`, we wait.
550     /// while !*started {
551     ///     started = cvar.wait(started).unwrap();
552     /// }
553     /// ```
554     #[stable(feature = "rust1", since = "1.0.0")]
555     pub fn notify_all(&self) {
556         unsafe { self.inner.notify_all() }
557     }
558
559     fn verify(&self, mutex: &sys_mutex::Mutex) {
560         let addr = mutex as *const _ as usize;
561         match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
562             // If we got out 0, then we have successfully bound the mutex to
563             // this cvar.
564             0 => {}
565
566             // If we get out a value that's the same as `addr`, then someone
567             // already beat us to the punch.
568             n if n == addr => {}
569
570             // Anything else and we're using more than one mutex on this cvar,
571             // which is currently disallowed.
572             _ => panic!(
573                 "attempted to use a condition variable with two \
574                          mutexes"
575             ),
576         }
577     }
578 }
579
580 #[stable(feature = "std_debug", since = "1.16.0")]
581 impl fmt::Debug for Condvar {
582     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583         f.pad("Condvar { .. }")
584     }
585 }
586
587 #[stable(feature = "condvar_default", since = "1.10.0")]
588 impl Default for Condvar {
589     /// Creates a `Condvar` which is ready to be waited on and notified.
590     fn default() -> Condvar {
591         Condvar::new()
592     }
593 }
594
595 #[stable(feature = "rust1", since = "1.0.0")]
596 impl Drop for Condvar {
597     fn drop(&mut self) {
598         unsafe { self.inner.destroy() }
599     }
600 }
601
602 #[cfg(test)]
603 mod tests {
604     use crate::sync::atomic::{AtomicBool, Ordering};
605     use crate::sync::mpsc::channel;
606     use crate::sync::{Arc, Condvar, Mutex};
607     use crate::thread;
608     use crate::time::Duration;
609
610     #[test]
611     fn smoke() {
612         let c = Condvar::new();
613         c.notify_one();
614         c.notify_all();
615     }
616
617     #[test]
618     #[cfg_attr(target_os = "emscripten", ignore)]
619     fn notify_one() {
620         let m = Arc::new(Mutex::new(()));
621         let m2 = m.clone();
622         let c = Arc::new(Condvar::new());
623         let c2 = c.clone();
624
625         let g = m.lock().unwrap();
626         let _t = thread::spawn(move || {
627             let _g = m2.lock().unwrap();
628             c2.notify_one();
629         });
630         let g = c.wait(g).unwrap();
631         drop(g);
632     }
633
634     #[test]
635     #[cfg_attr(target_os = "emscripten", ignore)]
636     fn notify_all() {
637         const N: usize = 10;
638
639         let data = Arc::new((Mutex::new(0), Condvar::new()));
640         let (tx, rx) = channel();
641         for _ in 0..N {
642             let data = data.clone();
643             let tx = tx.clone();
644             thread::spawn(move || {
645                 let &(ref lock, ref cond) = &*data;
646                 let mut cnt = lock.lock().unwrap();
647                 *cnt += 1;
648                 if *cnt == N {
649                     tx.send(()).unwrap();
650                 }
651                 while *cnt != 0 {
652                     cnt = cond.wait(cnt).unwrap();
653                 }
654                 tx.send(()).unwrap();
655             });
656         }
657         drop(tx);
658
659         let &(ref lock, ref cond) = &*data;
660         rx.recv().unwrap();
661         let mut cnt = lock.lock().unwrap();
662         *cnt = 0;
663         cond.notify_all();
664         drop(cnt);
665
666         for _ in 0..N {
667             rx.recv().unwrap();
668         }
669     }
670
671     #[test]
672     #[cfg_attr(target_os = "emscripten", ignore)]
673     fn wait_while() {
674         let pair = Arc::new((Mutex::new(false), Condvar::new()));
675         let pair2 = pair.clone();
676
677         // Inside of our lock, spawn a new thread, and then wait for it to start.
678         thread::spawn(move || {
679             let &(ref lock, ref cvar) = &*pair2;
680             let mut started = lock.lock().unwrap();
681             *started = true;
682             // We notify the condvar that the value has changed.
683             cvar.notify_one();
684         });
685
686         // Wait for the thread to start up.
687         let &(ref lock, ref cvar) = &*pair;
688         let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started);
689         assert!(*guard.unwrap());
690     }
691
692     #[test]
693     #[cfg_attr(target_os = "emscripten", ignore)]
694     fn wait_timeout_wait() {
695         let m = Arc::new(Mutex::new(()));
696         let c = Arc::new(Condvar::new());
697
698         loop {
699             let g = m.lock().unwrap();
700             let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
701             // spurious wakeups mean this isn't necessarily true
702             // so execute test again, if not timeout
703             if !no_timeout.timed_out() {
704                 continue;
705             }
706
707             break;
708         }
709     }
710
711     #[test]
712     #[cfg_attr(target_os = "emscripten", ignore)]
713     fn wait_timeout_while_wait() {
714         let m = Arc::new(Mutex::new(()));
715         let c = Arc::new(Condvar::new());
716
717         let g = m.lock().unwrap();
718         let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap();
719         // no spurious wakeups. ensure it timed-out
720         assert!(wait.timed_out());
721     }
722
723     #[test]
724     #[cfg_attr(target_os = "emscripten", ignore)]
725     fn wait_timeout_while_instant_satisfy() {
726         let m = Arc::new(Mutex::new(()));
727         let c = Arc::new(Condvar::new());
728
729         let g = m.lock().unwrap();
730         let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap();
731         // ensure it didn't time-out even if we were not given any time.
732         assert!(!wait.timed_out());
733     }
734
735     #[test]
736     #[cfg_attr(target_os = "emscripten", ignore)]
737     fn wait_timeout_while_wake() {
738         let pair = Arc::new((Mutex::new(false), Condvar::new()));
739         let pair_copy = pair.clone();
740
741         let &(ref m, ref c) = &*pair;
742         let g = m.lock().unwrap();
743         let _t = thread::spawn(move || {
744             let &(ref lock, ref cvar) = &*pair_copy;
745             let mut started = lock.lock().unwrap();
746             thread::sleep(Duration::from_millis(1));
747             *started = true;
748             cvar.notify_one();
749         });
750         let (g2, wait) = c
751             .wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified)
752             .unwrap();
753         // ensure it didn't time-out even if we were not given any time.
754         assert!(!wait.timed_out());
755         assert!(*g2);
756     }
757
758     #[test]
759     #[cfg_attr(target_os = "emscripten", ignore)]
760     fn wait_timeout_wake() {
761         let m = Arc::new(Mutex::new(()));
762         let c = Arc::new(Condvar::new());
763
764         loop {
765             let g = m.lock().unwrap();
766
767             let c2 = c.clone();
768             let m2 = m.clone();
769
770             let notified = Arc::new(AtomicBool::new(false));
771             let notified_copy = notified.clone();
772
773             let t = thread::spawn(move || {
774                 let _g = m2.lock().unwrap();
775                 thread::sleep(Duration::from_millis(1));
776                 notified_copy.store(true, Ordering::SeqCst);
777                 c2.notify_one();
778             });
779             let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap();
780             assert!(!timeout_res.timed_out());
781             // spurious wakeups mean this isn't necessarily true
782             // so execute test again, if not notified
783             if !notified.load(Ordering::SeqCst) {
784                 t.join().unwrap();
785                 continue;
786             }
787             drop(g);
788
789             t.join().unwrap();
790
791             break;
792         }
793     }
794
795     #[test]
796     #[should_panic]
797     #[cfg_attr(target_os = "emscripten", ignore)]
798     fn two_mutexes() {
799         let m = Arc::new(Mutex::new(()));
800         let m2 = m.clone();
801         let c = Arc::new(Condvar::new());
802         let c2 = c.clone();
803
804         let mut g = m.lock().unwrap();
805         let _t = thread::spawn(move || {
806             let _g = m2.lock().unwrap();
807             c2.notify_one();
808         });
809         g = c.wait(g).unwrap();
810         drop(g);
811
812         let m = Mutex::new(());
813         let _ = c.wait(m.lock().unwrap()).unwrap();
814     }
815 }