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