1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use sync::atomic::{AtomicUsize, Ordering};
13 use sync::{mutex, MutexGuard, PoisonError};
14 use sys_common::condvar as sys;
15 use sys_common::mutex as sys_mutex;
16 use sys_common::poison::{self, LockResult};
17 use time::{Duration, Instant};
19 /// A type indicating whether a timed wait on a condition variable returned
20 /// due to a time out or not.
22 /// It is returned by the [`wait_timeout`] method.
24 /// [`wait_timeout`]: struct.Condvar.html#method.wait_timeout
25 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
26 #[stable(feature = "wait_timeout", since = "1.5.0")]
27 pub struct WaitTimeoutResult(bool);
29 impl WaitTimeoutResult {
30 /// Returns whether the wait was known to have timed out.
34 /// This example spawns a thread which will update the boolean value and
35 /// then wait 100 milliseconds before notifying the condvar.
37 /// The main thread will wait with a timeout on the condvar and then leave
38 /// once the boolean has been updated and notified.
41 /// use std::sync::{Arc, Mutex, Condvar};
43 /// use std::time::Duration;
45 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
46 /// let pair2 = pair.clone();
48 /// thread::spawn(move|| {
49 /// let &(ref lock, ref cvar) = &*pair2;
51 /// // Let's wait 20 milliseconds before notifying the condvar.
52 /// thread::sleep(Duration::from_millis(20));
54 /// let mut started = lock.lock().unwrap();
55 /// // We update the boolean value.
57 /// cvar.notify_one();
60 /// // Wait for the thread to start up.
61 /// let &(ref lock, ref cvar) = &*pair;
62 /// let mut started = lock.lock().unwrap();
64 /// // Let's put a timeout on the condvar's wait.
65 /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
66 /// // 10 milliseconds have passed, or maybe the value changed!
67 /// started = result.0;
68 /// if *started == true {
69 /// // We received the notification and the value has been updated, we can leave.
74 #[stable(feature = "wait_timeout", since = "1.5.0")]
75 pub fn timed_out(&self) -> bool {
80 /// A Condition Variable
82 /// Condition variables represent the ability to block a thread such that it
83 /// consumes no CPU time while waiting for an event to occur. Condition
84 /// variables are typically associated with a boolean predicate (a condition)
85 /// and a mutex. The predicate is always verified inside of the mutex before
86 /// determining that a thread must block.
88 /// Functions in this module will block the current **thread** of execution and
89 /// are bindings to system-provided condition variables where possible. Note
90 /// that this module places one additional restriction over the system condition
91 /// variables: each condvar can be used with precisely one mutex at runtime. Any
92 /// attempt to use multiple mutexes on the same condition variable will result
93 /// in a runtime panic. If this is not desired, then the unsafe primitives in
94 /// `sys` do not have this restriction but may result in undefined behavior.
99 /// use std::sync::{Arc, Mutex, Condvar};
102 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
103 /// let pair2 = pair.clone();
105 /// // Inside of our lock, spawn a new thread, and then wait for it to start.
106 /// thread::spawn(move|| {
107 /// let &(ref lock, ref cvar) = &*pair2;
108 /// let mut started = lock.lock().unwrap();
110 /// // We notify the condvar that the value has changed.
111 /// cvar.notify_one();
114 /// // Wait for the thread to start up.
115 /// let &(ref lock, ref cvar) = &*pair;
116 /// let mut started = lock.lock().unwrap();
117 /// while !*started {
118 /// started = cvar.wait(started).unwrap();
121 #[stable(feature = "rust1", since = "1.0.0")]
123 inner: Box<sys::Condvar>,
128 /// Creates a new condition variable which is ready to be waited on and
134 /// use std::sync::Condvar;
136 /// let condvar = Condvar::new();
138 #[stable(feature = "rust1", since = "1.0.0")]
139 pub fn new() -> Condvar {
140 let mut c = Condvar {
141 inner: box sys::Condvar::new(),
142 mutex: AtomicUsize::new(0),
150 /// Blocks the current thread until this condition variable receives a
153 /// This function will atomically unlock the mutex specified (represented by
154 /// `guard`) and block the current thread. This means that any calls
155 /// to [`notify_one`] or [`notify_all`] which happen logically after the
156 /// mutex is unlocked are candidates to wake this thread up. When this
157 /// function call returns, the lock specified will have been re-acquired.
159 /// Note that this function is susceptible to spurious wakeups. Condition
160 /// variables normally have a boolean predicate associated with them, and
161 /// the predicate must always be checked each time this function returns to
162 /// protect against spurious wakeups.
166 /// This function will return an error if the mutex being waited on is
167 /// poisoned when this thread re-acquires the lock. For more information,
168 /// see information about [poisoning] on the [`Mutex`] type.
172 /// This function will [`panic!`] if it is used with more than one mutex
173 /// over time. Each condition variable is dynamically bound to exactly one
174 /// mutex to ensure defined behavior across platforms. If this functionality
175 /// is not desired, then unsafe primitives in `sys` are provided.
177 /// [`notify_one`]: #method.notify_one
178 /// [`notify_all`]: #method.notify_all
179 /// [poisoning]: ../sync/struct.Mutex.html#poisoning
180 /// [`Mutex`]: ../sync/struct.Mutex.html
181 /// [`panic!`]: ../../std/macro.panic.html
186 /// use std::sync::{Arc, Mutex, Condvar};
189 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
190 /// let pair2 = pair.clone();
192 /// thread::spawn(move|| {
193 /// let &(ref lock, ref cvar) = &*pair2;
194 /// let mut started = lock.lock().unwrap();
196 /// // We notify the condvar that the value has changed.
197 /// cvar.notify_one();
200 /// // Wait for the thread to start up.
201 /// let &(ref lock, ref cvar) = &*pair;
202 /// let mut started = lock.lock().unwrap();
203 /// // As long as the value inside the `Mutex` is false, we wait.
204 /// while !*started {
205 /// started = cvar.wait(started).unwrap();
208 #[stable(feature = "rust1", since = "1.0.0")]
209 pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
210 -> LockResult<MutexGuard<'a, T>> {
211 let poisoned = unsafe {
212 let lock = mutex::guard_lock(&guard);
214 self.inner.wait(lock);
215 mutex::guard_poison(&guard).get()
218 Err(PoisonError::new(guard))
224 /// Blocks the current thread until this condition variable receives a
225 /// notification and the required condition is met. Spurious wakeups are
226 /// ignored and this function will only return once the condition has been
229 /// This function will atomically unlock the mutex specified (represented by
230 /// `guard`) and block the current thread. This means that any calls
231 /// to [`notify_one`] or [`notify_all`] which happen logically after the
232 /// mutex is unlocked are candidates to wake this thread up. When this
233 /// function call returns, the lock specified will have been re-acquired.
237 /// This function will return an error if the mutex being waited on is
238 /// poisoned when this thread re-acquires the lock. For more information,
239 /// see information about [poisoning] on the [`Mutex`] type.
241 /// [`notify_one`]: #method.notify_one
242 /// [`notify_all`]: #method.notify_all
243 /// [poisoning]: ../sync/struct.Mutex.html#poisoning
244 /// [`Mutex`]: ../sync/struct.Mutex.html
249 /// #![feature(wait_until)]
251 /// use std::sync::{Arc, Mutex, Condvar};
254 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
255 /// let pair2 = pair.clone();
257 /// thread::spawn(move|| {
258 /// let &(ref lock, ref cvar) = &*pair2;
259 /// let mut started = lock.lock().unwrap();
261 /// // We notify the condvar that the value has changed.
262 /// cvar.notify_one();
265 /// // Wait for the thread to start up.
266 /// let &(ref lock, ref cvar) = &*pair;
267 /// // As long as the value inside the `Mutex` is false, we wait.
268 /// let _guard = cvar.wait_until(lock.lock().unwrap(), |started| { *started }).unwrap();
270 #[unstable(feature = "wait_until", issue = "47960")]
271 pub fn wait_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
273 -> LockResult<MutexGuard<'a, T>>
274 where F: FnMut(&mut T) -> bool {
275 while !condition(&mut *guard) {
276 guard = self.wait(guard)?;
282 /// Waits on this condition variable for a notification, timing out after a
283 /// specified duration.
285 /// The semantics of this function are equivalent to [`wait`]
286 /// except that the thread will be blocked for roughly no longer
287 /// than `ms` milliseconds. This method should not be used for
288 /// precise timing due to anomalies such as preemption or platform
289 /// differences that may not cause the maximum amount of time
290 /// waited to be precisely `ms`.
292 /// Note that the best effort is made to ensure that the time waited is
293 /// measured with a monotonic clock, and not affected by the changes made to
296 /// The returned boolean is `false` only if the timeout is known
299 /// Like [`wait`], the lock specified will be re-acquired when this function
300 /// returns, regardless of whether the timeout elapsed or not.
302 /// [`wait`]: #method.wait
307 /// use std::sync::{Arc, Mutex, Condvar};
310 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
311 /// let pair2 = pair.clone();
313 /// thread::spawn(move|| {
314 /// let &(ref lock, ref cvar) = &*pair2;
315 /// let mut started = lock.lock().unwrap();
317 /// // We notify the condvar that the value has changed.
318 /// cvar.notify_one();
321 /// // Wait for the thread to start up.
322 /// let &(ref lock, ref cvar) = &*pair;
323 /// let mut started = lock.lock().unwrap();
324 /// // As long as the value inside the `Mutex` is false, we wait.
326 /// let result = cvar.wait_timeout_ms(started, 10).unwrap();
327 /// // 10 milliseconds have passed, or maybe the value changed!
328 /// started = result.0;
329 /// if *started == true {
330 /// // We received the notification and the value has been updated, we can leave.
335 #[stable(feature = "rust1", since = "1.0.0")]
336 #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
337 pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
338 -> LockResult<(MutexGuard<'a, T>, bool)> {
339 let res = self.wait_timeout(guard, Duration::from_millis(ms as u64));
340 poison::map_result(res, |(a, b)| {
345 /// Waits on this condition variable for a notification, timing out after a
346 /// specified duration.
348 /// The semantics of this function are equivalent to [`wait`] except that
349 /// the thread will be blocked for roughly no longer than `dur`. This
350 /// method should not be used for precise timing due to anomalies such as
351 /// preemption or platform differences that may not cause the maximum
352 /// amount of time waited to be precisely `dur`.
354 /// Note that the best effort is made to ensure that the time waited is
355 /// measured with a monotonic clock, and not affected by the changes made to
356 /// the system time. This function is susceptible to spurious wakeups.
357 /// Condition variables normally have a boolean predicate associated with
358 /// them, and the predicate must always be checked each time this function
359 /// returns to protect against spurious wakeups. Additionally, it is
360 /// typically desirable for the time-out to not exceed some duration in
361 /// spite of spurious wakes, thus the sleep-duration is decremented by the
362 /// amount slept. Alternatively, use the `wait_timeout_until` method
363 /// to wait until a condition is met with a total time-out regardless
364 /// of spurious wakes.
366 /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
367 /// known to have elapsed.
369 /// Like [`wait`], the lock specified will be re-acquired when this function
370 /// returns, regardless of whether the timeout elapsed or not.
372 /// [`wait`]: #method.wait
373 /// [`wait_timeout_until`]: #method.wait_timeout_until
374 /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
379 /// use std::sync::{Arc, Mutex, Condvar};
381 /// use std::time::Duration;
383 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
384 /// let pair2 = pair.clone();
386 /// thread::spawn(move|| {
387 /// let &(ref lock, ref cvar) = &*pair2;
388 /// let mut started = lock.lock().unwrap();
390 /// // We notify the condvar that the value has changed.
391 /// cvar.notify_one();
394 /// // wait for the thread to start up
395 /// let &(ref lock, ref cvar) = &*pair;
396 /// let mut started = lock.lock().unwrap();
397 /// // as long as the value inside the `Mutex` is false, we wait
399 /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
400 /// // 10 milliseconds have passed, or maybe the value changed!
401 /// started = result.0;
402 /// if *started == true {
403 /// // We received the notification and the value has been updated, we can leave.
408 #[stable(feature = "wait_timeout", since = "1.5.0")]
409 pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
411 -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
412 let (poisoned, result) = unsafe {
413 let lock = mutex::guard_lock(&guard);
415 let success = self.inner.wait_timeout(lock, dur);
416 (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
419 Err(PoisonError::new((guard, result)))
425 /// Waits on this condition variable for a notification, timing out after a
426 /// specified duration. Spurious wakes will not cause this function to
429 /// The semantics of this function are equivalent to [`wait_until`] except
430 /// that the thread will be blocked for roughly no longer than `dur`. This
431 /// method should not be used for precise timing due to anomalies such as
432 /// preemption or platform differences that may not cause the maximum
433 /// amount of time waited to be precisely `dur`.
435 /// Note that the best effort is made to ensure that the time waited is
436 /// measured with a monotonic clock, and not affected by the changes made to
439 /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
440 /// known to have elapsed without the condition being met.
442 /// Like [`wait_until`], the lock specified will be re-acquired when this
443 /// function returns, regardless of whether the timeout elapsed or not.
445 /// [`wait_until`]: #method.wait_until
446 /// [`wait_timeout`]: #method.wait_timeout
447 /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
452 /// #![feature(wait_timeout_until)]
454 /// use std::sync::{Arc, Mutex, Condvar};
456 /// use std::time::Duration;
458 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
459 /// let pair2 = pair.clone();
461 /// thread::spawn(move|| {
462 /// let &(ref lock, ref cvar) = &*pair2;
463 /// let mut started = lock.lock().unwrap();
465 /// // We notify the condvar that the value has changed.
466 /// cvar.notify_one();
469 /// // wait for the thread to start up
470 /// let &(ref lock, ref cvar) = &*pair;
471 /// let result = cvar.wait_timeout_until(
472 /// lock.lock().unwrap(),
473 /// Duration::from_millis(100),
474 /// |&mut started| started,
476 /// if result.1.timed_out() {
477 /// // timed-out without the condition ever evaluating to true.
479 /// // access the locked mutex via result.0
481 #[unstable(feature = "wait_timeout_until", issue = "47960")]
482 pub fn wait_timeout_until<'a, T, F>(&self, mut guard: MutexGuard<'a, T>,
483 dur: Duration, mut condition: F)
484 -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
485 where F: FnMut(&mut T) -> bool {
486 let start = Instant::now();
488 if condition(&mut *guard) {
489 return Ok((guard, WaitTimeoutResult(false)));
491 let timeout = match dur.checked_sub(start.elapsed()) {
492 Some(timeout) => timeout,
493 None => return Ok((guard, WaitTimeoutResult(true))),
495 guard = self.wait_timeout(guard, timeout)?.0;
499 /// Wakes up one blocked thread on this condvar.
501 /// If there is a blocked thread on this condition variable, then it will
502 /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
503 /// `notify_one` are not buffered in any way.
505 /// To wake up all threads, see [`notify_all`].
507 /// [`wait`]: #method.wait
508 /// [`wait_timeout`]: #method.wait_timeout
509 /// [`notify_all`]: #method.notify_all
514 /// use std::sync::{Arc, Mutex, Condvar};
517 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
518 /// let pair2 = pair.clone();
520 /// thread::spawn(move|| {
521 /// let &(ref lock, ref cvar) = &*pair2;
522 /// let mut started = lock.lock().unwrap();
524 /// // We notify the condvar that the value has changed.
525 /// cvar.notify_one();
528 /// // Wait for the thread to start up.
529 /// let &(ref lock, ref cvar) = &*pair;
530 /// let mut started = lock.lock().unwrap();
531 /// // As long as the value inside the `Mutex` is false, we wait.
532 /// while !*started {
533 /// started = cvar.wait(started).unwrap();
536 #[stable(feature = "rust1", since = "1.0.0")]
537 pub fn notify_one(&self) {
538 unsafe { self.inner.notify_one() }
541 /// Wakes up all blocked threads on this condvar.
543 /// This method will ensure that any current waiters on the condition
544 /// variable are awoken. Calls to `notify_all()` are not buffered in any
547 /// To wake up only one thread, see [`notify_one`].
549 /// [`notify_one`]: #method.notify_one
554 /// use std::sync::{Arc, Mutex, Condvar};
557 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
558 /// let pair2 = pair.clone();
560 /// thread::spawn(move|| {
561 /// let &(ref lock, ref cvar) = &*pair2;
562 /// let mut started = lock.lock().unwrap();
564 /// // We notify the condvar that the value has changed.
565 /// cvar.notify_all();
568 /// // Wait for the thread to start up.
569 /// let &(ref lock, ref cvar) = &*pair;
570 /// let mut started = lock.lock().unwrap();
571 /// // As long as the value inside the `Mutex` is false, we wait.
572 /// while !*started {
573 /// started = cvar.wait(started).unwrap();
576 #[stable(feature = "rust1", since = "1.0.0")]
577 pub fn notify_all(&self) {
578 unsafe { self.inner.notify_all() }
581 fn verify(&self, mutex: &sys_mutex::Mutex) {
582 let addr = mutex as *const _ as usize;
583 match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
584 // If we got out 0, then we have successfully bound the mutex to
588 // If we get out a value that's the same as `addr`, then someone
589 // already beat us to the punch.
592 // Anything else and we're using more than one mutex on this cvar,
593 // which is currently disallowed.
594 _ => panic!("attempted to use a condition variable with two \
600 #[stable(feature = "std_debug", since = "1.16.0")]
601 impl fmt::Debug for Condvar {
602 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
603 f.pad("Condvar { .. }")
607 #[stable(feature = "condvar_default", since = "1.10.0")]
608 impl Default for Condvar {
609 /// Creates a `Condvar` which is ready to be waited on and notified.
610 fn default() -> Condvar {
615 #[stable(feature = "rust1", since = "1.0.0")]
616 impl Drop for Condvar {
618 unsafe { self.inner.destroy() }
624 /// #![feature(wait_until)]
625 use sync::mpsc::channel;
626 use sync::{Condvar, Mutex, Arc};
627 use sync::atomic::{AtomicBool, Ordering};
634 let c = Condvar::new();
640 #[cfg_attr(target_os = "emscripten", ignore)]
642 let m = Arc::new(Mutex::new(()));
644 let c = Arc::new(Condvar::new());
647 let g = m.lock().unwrap();
648 let _t = thread::spawn(move|| {
649 let _g = m2.lock().unwrap();
652 let g = c.wait(g).unwrap();
657 #[cfg_attr(target_os = "emscripten", ignore)]
661 let data = Arc::new((Mutex::new(0), Condvar::new()));
662 let (tx, rx) = channel();
664 let data = data.clone();
666 thread::spawn(move|| {
667 let &(ref lock, ref cond) = &*data;
668 let mut cnt = lock.lock().unwrap();
671 tx.send(()).unwrap();
674 cnt = cond.wait(cnt).unwrap();
676 tx.send(()).unwrap();
681 let &(ref lock, ref cond) = &*data;
683 let mut cnt = lock.lock().unwrap();
694 #[cfg_attr(target_os = "emscripten", ignore)]
696 let pair = Arc::new((Mutex::new(false), Condvar::new()));
697 let pair2 = pair.clone();
699 // Inside of our lock, spawn a new thread, and then wait for it to start.
700 thread::spawn(move|| {
701 let &(ref lock, ref cvar) = &*pair2;
702 let mut started = lock.lock().unwrap();
704 // We notify the condvar that the value has changed.
708 // Wait for the thread to start up.
709 let &(ref lock, ref cvar) = &*pair;
710 let guard = cvar.wait_until(lock.lock().unwrap(), |started| {
713 assert!(*guard.unwrap());
717 #[cfg_attr(target_os = "emscripten", ignore)]
718 fn wait_timeout_wait() {
719 let m = Arc::new(Mutex::new(()));
720 let c = Arc::new(Condvar::new());
723 let g = m.lock().unwrap();
724 let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
725 // spurious wakeups mean this isn't necessarily true
726 // so execute test again, if not timeout
727 if !no_timeout.timed_out() {
736 #[cfg_attr(target_os = "emscripten", ignore)]
737 fn wait_timeout_until_wait() {
738 let m = Arc::new(Mutex::new(()));
739 let c = Arc::new(Condvar::new());
741 let g = m.lock().unwrap();
742 let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(1), |_| { false }).unwrap();
743 // no spurious wakeups. ensure it timed-out
744 assert!(wait.timed_out());
748 #[cfg_attr(target_os = "emscripten", ignore)]
749 fn wait_timeout_until_instant_satisfy() {
750 let m = Arc::new(Mutex::new(()));
751 let c = Arc::new(Condvar::new());
753 let g = m.lock().unwrap();
754 let (_g, wait) = c.wait_timeout_until(g, Duration::from_millis(0), |_| { true }).unwrap();
755 // ensure it didn't time-out even if we were not given any time.
756 assert!(!wait.timed_out());
760 #[cfg_attr(target_os = "emscripten", ignore)]
761 fn wait_timeout_until_wake() {
762 let pair = Arc::new((Mutex::new(false), Condvar::new()));
763 let pair_copy = pair.clone();
765 let &(ref m, ref c) = &*pair;
766 let g = m.lock().unwrap();
767 let _t = thread::spawn(move || {
768 let &(ref lock, ref cvar) = &*pair_copy;
769 let mut started = lock.lock().unwrap();
770 thread::sleep(Duration::from_millis(1));
774 let (g2, wait) = c.wait_timeout_until(g, Duration::from_millis(u64::MAX), |&mut notified| {
777 // ensure it didn't time-out even if we were not given any time.
778 assert!(!wait.timed_out());
783 #[cfg_attr(target_os = "emscripten", ignore)]
784 fn wait_timeout_wake() {
785 let m = Arc::new(Mutex::new(()));
786 let c = Arc::new(Condvar::new());
789 let g = m.lock().unwrap();
794 let notified = Arc::new(AtomicBool::new(false));
795 let notified_copy = notified.clone();
797 let t = thread::spawn(move || {
798 let _g = m2.lock().unwrap();
799 thread::sleep(Duration::from_millis(1));
800 notified_copy.store(true, Ordering::SeqCst);
803 let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap();
804 assert!(!timeout_res.timed_out());
805 // spurious wakeups mean this isn't necessarily true
806 // so execute test again, if not notified
807 if !notified.load(Ordering::SeqCst) {
821 #[cfg_attr(target_os = "emscripten", ignore)]
823 let m = Arc::new(Mutex::new(()));
825 let c = Arc::new(Condvar::new());
828 let mut g = m.lock().unwrap();
829 let _t = thread::spawn(move|| {
830 let _g = m2.lock().unwrap();
833 g = c.wait(g).unwrap();
836 let m = Mutex::new(());
837 let _ = c.wait(m.lock().unwrap()).unwrap();