]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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. | |
4 | // | |
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. | |
10 | ||
32a655c1 | 11 | use fmt; |
62682a34 | 12 | use sync::atomic::{AtomicUsize, Ordering}; |
9346a6ac | 13 | use sync::{mutex, MutexGuard, PoisonError}; |
1a4d82fc JJ |
14 | use sys_common::condvar as sys; |
15 | use sys_common::mutex as sys_mutex; | |
9346a6ac | 16 | use sys_common::poison::{self, LockResult}; |
5bcae85e | 17 | use time::Duration; |
1a4d82fc | 18 | |
e9174d1e SL |
19 | /// A type indicating whether a timed wait on a condition variable returned |
20 | /// due to a time out or not. | |
8bb4bdeb XL |
21 | /// |
22 | /// It is returned by the [`wait_timeout`] method. | |
23 | /// | |
24 | /// [`wait_timeout`]: struct.Condvar.html#method.wait_timeout | |
e9174d1e | 25 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] |
b039eaaf | 26 | #[stable(feature = "wait_timeout", since = "1.5.0")] |
e9174d1e SL |
27 | pub struct WaitTimeoutResult(bool); |
28 | ||
29 | impl WaitTimeoutResult { | |
30 | /// Returns whether the wait was known to have timed out. | |
8bb4bdeb XL |
31 | /// |
32 | /// # Examples | |
33 | /// | |
34 | /// This example spawns a thread which will update the boolean value and | |
35 | /// then wait 100 milliseconds before notifying the condvar. | |
36 | /// | |
37 | /// The main thread will wait with a timeout on the condvar and then leave | |
38 | /// once the boolean has been updated and notified. | |
39 | /// | |
40 | /// ``` | |
41 | /// use std::sync::{Arc, Mutex, Condvar}; | |
42 | /// use std::thread; | |
43 | /// use std::time::Duration; | |
44 | /// | |
45 | /// let pair = Arc::new((Mutex::new(false), Condvar::new())); | |
46 | /// let pair2 = pair.clone(); | |
47 | /// | |
48 | /// thread::spawn(move|| { | |
49 | /// let &(ref lock, ref cvar) = &*pair2; | |
50 | /// let mut started = lock.lock().unwrap(); | |
51 | /// // We update the boolean value. | |
52 | /// *started = true; | |
53 | /// // Let's wait 20 milliseconds before notifying the condvar. | |
54 | /// thread::sleep(Duration::from_millis(20)); | |
55 | /// cvar.notify_one(); | |
56 | /// }); | |
57 | /// | |
58 | /// // Wait for the thread to start up. | |
59 | /// let &(ref lock, ref cvar) = &*pair; | |
60 | /// let mut started = lock.lock().unwrap(); | |
61 | /// loop { | |
62 | /// // Let's put a timeout on the condvar's wait. | |
63 | /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap(); | |
64 | /// // 10 milliseconds have passed, or maybe the value changed! | |
65 | /// started = result.0; | |
66 | /// if *started == true { | |
67 | /// // We received the notification and the value has been updated, we can leave. | |
68 | /// break | |
69 | /// } | |
70 | /// } | |
71 | /// ``` | |
b039eaaf | 72 | #[stable(feature = "wait_timeout", since = "1.5.0")] |
e9174d1e SL |
73 | pub fn timed_out(&self) -> bool { |
74 | self.0 | |
75 | } | |
76 | } | |
77 | ||
1a4d82fc JJ |
78 | /// A Condition Variable |
79 | /// | |
80 | /// Condition variables represent the ability to block a thread such that it | |
81 | /// consumes no CPU time while waiting for an event to occur. Condition | |
82 | /// variables are typically associated with a boolean predicate (a condition) | |
83 | /// and a mutex. The predicate is always verified inside of the mutex before | |
8bb4bdeb | 84 | /// determining that a thread must block. |
1a4d82fc JJ |
85 | /// |
86 | /// Functions in this module will block the current **thread** of execution and | |
87 | /// are bindings to system-provided condition variables where possible. Note | |
88 | /// that this module places one additional restriction over the system condition | |
89 | /// variables: each condvar can be used with precisely one mutex at runtime. Any | |
90 | /// attempt to use multiple mutexes on the same condition variable will result | |
91 | /// in a runtime panic. If this is not desired, then the unsafe primitives in | |
92 | /// `sys` do not have this restriction but may result in undefined behavior. | |
93 | /// | |
c34b1796 | 94 | /// # Examples |
1a4d82fc JJ |
95 | /// |
96 | /// ``` | |
97 | /// use std::sync::{Arc, Mutex, Condvar}; | |
85aaf69f | 98 | /// use std::thread; |
1a4d82fc JJ |
99 | /// |
100 | /// let pair = Arc::new((Mutex::new(false), Condvar::new())); | |
101 | /// let pair2 = pair.clone(); | |
102 | /// | |
8bb4bdeb | 103 | /// // Inside of our lock, spawn a new thread, and then wait for it to start. |
85aaf69f | 104 | /// thread::spawn(move|| { |
1a4d82fc JJ |
105 | /// let &(ref lock, ref cvar) = &*pair2; |
106 | /// let mut started = lock.lock().unwrap(); | |
107 | /// *started = true; | |
8bb4bdeb | 108 | /// // We notify the condvar that the value has changed. |
1a4d82fc JJ |
109 | /// cvar.notify_one(); |
110 | /// }); | |
111 | /// | |
8bb4bdeb | 112 | /// // Wait for the thread to start up. |
1a4d82fc JJ |
113 | /// let &(ref lock, ref cvar) = &*pair; |
114 | /// let mut started = lock.lock().unwrap(); | |
115 | /// while !*started { | |
116 | /// started = cvar.wait(started).unwrap(); | |
117 | /// } | |
118 | /// ``` | |
85aaf69f | 119 | #[stable(feature = "rust1", since = "1.0.0")] |
5bcae85e SL |
120 | pub struct Condvar { |
121 | inner: Box<sys::Condvar>, | |
85aaf69f | 122 | mutex: AtomicUsize, |
1a4d82fc JJ |
123 | } |
124 | ||
1a4d82fc JJ |
125 | impl Condvar { |
126 | /// Creates a new condition variable which is ready to be waited on and | |
127 | /// notified. | |
8bb4bdeb XL |
128 | /// |
129 | /// # Examples | |
130 | /// | |
131 | /// ``` | |
132 | /// use std::sync::Condvar; | |
133 | /// | |
134 | /// let condvar = Condvar::new(); | |
135 | /// ``` | |
85aaf69f | 136 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 137 | pub fn new() -> Condvar { |
9e0c209e | 138 | let mut c = Condvar { |
5bcae85e SL |
139 | inner: box sys::Condvar::new(), |
140 | mutex: AtomicUsize::new(0), | |
9e0c209e SL |
141 | }; |
142 | unsafe { | |
143 | c.inner.init(); | |
1a4d82fc | 144 | } |
9e0c209e | 145 | c |
1a4d82fc JJ |
146 | } |
147 | ||
9346a6ac | 148 | /// Blocks the current thread until this condition variable receives a |
1a4d82fc JJ |
149 | /// notification. |
150 | /// | |
151 | /// This function will atomically unlock the mutex specified (represented by | |
8bb4bdeb | 152 | /// `guard`) and block the current thread. This means that any calls |
cc61c64b | 153 | /// to [`notify_one`] or [`notify_all`] which happen logically after the |
8bb4bdeb XL |
154 | /// mutex is unlocked are candidates to wake this thread up. When this |
155 | /// function call returns, the lock specified will have been re-acquired. | |
1a4d82fc JJ |
156 | /// |
157 | /// Note that this function is susceptible to spurious wakeups. Condition | |
158 | /// variables normally have a boolean predicate associated with them, and | |
159 | /// the predicate must always be checked each time this function returns to | |
160 | /// protect against spurious wakeups. | |
161 | /// | |
7453a54e | 162 | /// # Errors |
1a4d82fc JJ |
163 | /// |
164 | /// This function will return an error if the mutex being waited on is | |
165 | /// poisoned when this thread re-acquires the lock. For more information, | |
8bb4bdeb | 166 | /// see information about [poisoning] on the [`Mutex`] type. |
1a4d82fc JJ |
167 | /// |
168 | /// # Panics | |
169 | /// | |
cc61c64b | 170 | /// This function will [`panic!`] if it is used with more than one mutex |
1a4d82fc JJ |
171 | /// over time. Each condition variable is dynamically bound to exactly one |
172 | /// mutex to ensure defined behavior across platforms. If this functionality | |
173 | /// is not desired, then unsafe primitives in `sys` are provided. | |
8bb4bdeb | 174 | /// |
cc61c64b XL |
175 | /// [`notify_one`]: #method.notify_one |
176 | /// [`notify_all`]: #method.notify_all | |
8bb4bdeb XL |
177 | /// [poisoning]: ../sync/struct.Mutex.html#poisoning |
178 | /// [`Mutex`]: ../sync/struct.Mutex.html | |
cc61c64b | 179 | /// [`panic!`]: ../../std/macro.panic.html |
8bb4bdeb XL |
180 | /// |
181 | /// # Examples | |
182 | /// | |
183 | /// ``` | |
184 | /// use std::sync::{Arc, Mutex, Condvar}; | |
185 | /// use std::thread; | |
186 | /// | |
187 | /// let pair = Arc::new((Mutex::new(false), Condvar::new())); | |
188 | /// let pair2 = pair.clone(); | |
189 | /// | |
190 | /// thread::spawn(move|| { | |
191 | /// let &(ref lock, ref cvar) = &*pair2; | |
192 | /// let mut started = lock.lock().unwrap(); | |
193 | /// *started = true; | |
194 | /// // We notify the condvar that the value has changed. | |
195 | /// cvar.notify_one(); | |
196 | /// }); | |
197 | /// | |
198 | /// // Wait for the thread to start up. | |
199 | /// let &(ref lock, ref cvar) = &*pair; | |
200 | /// let mut started = lock.lock().unwrap(); | |
201 | /// // As long as the value inside the `Mutex` is false, we wait. | |
202 | /// while !*started { | |
203 | /// started = cvar.wait(started).unwrap(); | |
204 | /// } | |
205 | /// ``` | |
85aaf69f | 206 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
207 | pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) |
208 | -> LockResult<MutexGuard<'a, T>> { | |
5bcae85e SL |
209 | let poisoned = unsafe { |
210 | let lock = mutex::guard_lock(&guard); | |
211 | self.verify(lock); | |
212 | self.inner.wait(lock); | |
213 | mutex::guard_poison(&guard).get() | |
214 | }; | |
215 | if poisoned { | |
216 | Err(PoisonError::new(guard)) | |
217 | } else { | |
218 | Ok(guard) | |
1a4d82fc JJ |
219 | } |
220 | } | |
221 | ||
9346a6ac | 222 | /// Waits on this condition variable for a notification, timing out after a |
1a4d82fc JJ |
223 | /// specified duration. |
224 | /// | |
8bb4bdeb | 225 | /// The semantics of this function are equivalent to [`wait`] |
c34b1796 AL |
226 | /// except that the thread will be blocked for roughly no longer |
227 | /// than `ms` milliseconds. This method should not be used for | |
228 | /// precise timing due to anomalies such as preemption or platform | |
229 | /// differences that may not cause the maximum amount of time | |
230 | /// waited to be precisely `ms`. | |
1a4d82fc | 231 | /// |
9e0c209e SL |
232 | /// Note that the best effort is made to ensure that the time waited is |
233 | /// measured with a monotonic clock, and not affected by the changes made to | |
234 | /// the system time. | |
235 | /// | |
c34b1796 AL |
236 | /// The returned boolean is `false` only if the timeout is known |
237 | /// to have elapsed. | |
1a4d82fc | 238 | /// |
8bb4bdeb | 239 | /// Like [`wait`], the lock specified will be re-acquired when this function |
1a4d82fc | 240 | /// returns, regardless of whether the timeout elapsed or not. |
8bb4bdeb XL |
241 | /// |
242 | /// [`wait`]: #method.wait | |
243 | /// | |
244 | /// # Examples | |
245 | /// | |
246 | /// ``` | |
247 | /// use std::sync::{Arc, Mutex, Condvar}; | |
248 | /// use std::thread; | |
249 | /// | |
250 | /// let pair = Arc::new((Mutex::new(false), Condvar::new())); | |
251 | /// let pair2 = pair.clone(); | |
252 | /// | |
253 | /// thread::spawn(move|| { | |
254 | /// let &(ref lock, ref cvar) = &*pair2; | |
255 | /// let mut started = lock.lock().unwrap(); | |
256 | /// *started = true; | |
257 | /// // We notify the condvar that the value has changed. | |
258 | /// cvar.notify_one(); | |
259 | /// }); | |
260 | /// | |
261 | /// // Wait for the thread to start up. | |
262 | /// let &(ref lock, ref cvar) = &*pair; | |
263 | /// let mut started = lock.lock().unwrap(); | |
264 | /// // As long as the value inside the `Mutex` is false, we wait. | |
265 | /// loop { | |
266 | /// let result = cvar.wait_timeout_ms(started, 10).unwrap(); | |
267 | /// // 10 milliseconds have passed, or maybe the value changed! | |
268 | /// started = result.0; | |
269 | /// if *started == true { | |
270 | /// // We received the notification and the value has been updated, we can leave. | |
271 | /// break | |
272 | /// } | |
273 | /// } | |
274 | /// ``` | |
c34b1796 | 275 | #[stable(feature = "rust1", since = "1.0.0")] |
92a42be0 | 276 | #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")] |
c34b1796 AL |
277 | pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32) |
278 | -> LockResult<(MutexGuard<'a, T>, bool)> { | |
54a0048b SL |
279 | let res = self.wait_timeout(guard, Duration::from_millis(ms as u64)); |
280 | poison::map_result(res, |(a, b)| { | |
281 | (a, !b.timed_out()) | |
282 | }) | |
1a4d82fc JJ |
283 | } |
284 | ||
d9579d0f AL |
285 | /// Waits on this condition variable for a notification, timing out after a |
286 | /// specified duration. | |
287 | /// | |
8bb4bdeb | 288 | /// The semantics of this function are equivalent to [`wait`] except that |
d9579d0f AL |
289 | /// the thread will be blocked for roughly no longer than `dur`. This |
290 | /// method should not be used for precise timing due to anomalies such as | |
291 | /// preemption or platform differences that may not cause the maximum | |
292 | /// amount of time waited to be precisely `dur`. | |
293 | /// | |
9e0c209e SL |
294 | /// Note that the best effort is made to ensure that the time waited is |
295 | /// measured with a monotonic clock, and not affected by the changes made to | |
296 | /// the system time. | |
297 | /// | |
8bb4bdeb | 298 | /// The returned [`WaitTimeoutResult`] value indicates if the timeout is |
e9174d1e | 299 | /// known to have elapsed. |
d9579d0f | 300 | /// |
8bb4bdeb | 301 | /// Like [`wait`], the lock specified will be re-acquired when this function |
d9579d0f | 302 | /// returns, regardless of whether the timeout elapsed or not. |
8bb4bdeb XL |
303 | /// |
304 | /// [`wait`]: #method.wait | |
305 | /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html | |
306 | /// | |
307 | /// # Examples | |
308 | /// | |
309 | /// ``` | |
310 | /// use std::sync::{Arc, Mutex, Condvar}; | |
311 | /// use std::thread; | |
312 | /// use std::time::Duration; | |
313 | /// | |
314 | /// let pair = Arc::new((Mutex::new(false), Condvar::new())); | |
315 | /// let pair2 = pair.clone(); | |
316 | /// | |
317 | /// thread::spawn(move|| { | |
318 | /// let &(ref lock, ref cvar) = &*pair2; | |
319 | /// let mut started = lock.lock().unwrap(); | |
320 | /// *started = true; | |
321 | /// // We notify the condvar that the value has changed. | |
322 | /// cvar.notify_one(); | |
323 | /// }); | |
324 | /// | |
325 | /// // wait for the thread to start up | |
326 | /// let &(ref lock, ref cvar) = &*pair; | |
327 | /// let mut started = lock.lock().unwrap(); | |
328 | /// // as long as the value inside the `Mutex` is false, we wait | |
329 | /// loop { | |
330 | /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap(); | |
331 | /// // 10 milliseconds have passed, or maybe the value changed! | |
332 | /// started = result.0; | |
333 | /// if *started == true { | |
334 | /// // We received the notification and the value has been updated, we can leave. | |
335 | /// break | |
336 | /// } | |
337 | /// } | |
338 | /// ``` | |
b039eaaf | 339 | #[stable(feature = "wait_timeout", since = "1.5.0")] |
d9579d0f AL |
340 | pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, |
341 | dur: Duration) | |
e9174d1e | 342 | -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> { |
5bcae85e SL |
343 | let (poisoned, result) = unsafe { |
344 | let lock = mutex::guard_lock(&guard); | |
345 | self.verify(lock); | |
346 | let success = self.inner.wait_timeout(lock, dur); | |
347 | (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success)) | |
348 | }; | |
349 | if poisoned { | |
350 | Err(PoisonError::new((guard, result))) | |
351 | } else { | |
352 | Ok((guard, result)) | |
d9579d0f AL |
353 | } |
354 | } | |
355 | ||
9346a6ac | 356 | /// Wakes up one blocked thread on this condvar. |
1a4d82fc JJ |
357 | /// |
358 | /// If there is a blocked thread on this condition variable, then it will | |
8bb4bdeb | 359 | /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to |
1a4d82fc JJ |
360 | /// `notify_one` are not buffered in any way. |
361 | /// | |
cc61c64b | 362 | /// To wake up all threads, see [`notify_all`]. |
8bb4bdeb XL |
363 | /// |
364 | /// [`wait`]: #method.wait | |
365 | /// [`wait_timeout`]: #method.wait_timeout | |
cc61c64b | 366 | /// [`notify_all`]: #method.notify_all |
8bb4bdeb XL |
367 | /// |
368 | /// # Examples | |
369 | /// | |
370 | /// ``` | |
371 | /// use std::sync::{Arc, Mutex, Condvar}; | |
372 | /// use std::thread; | |
373 | /// | |
374 | /// let pair = Arc::new((Mutex::new(false), Condvar::new())); | |
375 | /// let pair2 = pair.clone(); | |
376 | /// | |
377 | /// thread::spawn(move|| { | |
378 | /// let &(ref lock, ref cvar) = &*pair2; | |
379 | /// let mut started = lock.lock().unwrap(); | |
380 | /// *started = true; | |
381 | /// // We notify the condvar that the value has changed. | |
382 | /// cvar.notify_one(); | |
383 | /// }); | |
384 | /// | |
385 | /// // Wait for the thread to start up. | |
386 | /// let &(ref lock, ref cvar) = &*pair; | |
387 | /// let mut started = lock.lock().unwrap(); | |
388 | /// // As long as the value inside the `Mutex` is false, we wait. | |
389 | /// while !*started { | |
390 | /// started = cvar.wait(started).unwrap(); | |
391 | /// } | |
392 | /// ``` | |
85aaf69f | 393 | #[stable(feature = "rust1", since = "1.0.0")] |
5bcae85e SL |
394 | pub fn notify_one(&self) { |
395 | unsafe { self.inner.notify_one() } | |
396 | } | |
1a4d82fc | 397 | |
9346a6ac | 398 | /// Wakes up all blocked threads on this condvar. |
1a4d82fc JJ |
399 | /// |
400 | /// This method will ensure that any current waiters on the condition | |
401 | /// variable are awoken. Calls to `notify_all()` are not buffered in any | |
402 | /// way. | |
403 | /// | |
cc61c64b | 404 | /// To wake up only one thread, see [`notify_one`]. |
8bb4bdeb | 405 | /// |
cc61c64b | 406 | /// [`notify_one`]: #method.notify_one |
8bb4bdeb XL |
407 | /// |
408 | /// # Examples | |
409 | /// | |
410 | /// ``` | |
411 | /// use std::sync::{Arc, Mutex, Condvar}; | |
412 | /// use std::thread; | |
413 | /// | |
414 | /// let pair = Arc::new((Mutex::new(false), Condvar::new())); | |
415 | /// let pair2 = pair.clone(); | |
416 | /// | |
417 | /// thread::spawn(move|| { | |
418 | /// let &(ref lock, ref cvar) = &*pair2; | |
419 | /// let mut started = lock.lock().unwrap(); | |
420 | /// *started = true; | |
421 | /// // We notify the condvar that the value has changed. | |
422 | /// cvar.notify_all(); | |
423 | /// }); | |
424 | /// | |
425 | /// // Wait for the thread to start up. | |
426 | /// let &(ref lock, ref cvar) = &*pair; | |
427 | /// let mut started = lock.lock().unwrap(); | |
428 | /// // As long as the value inside the `Mutex` is false, we wait. | |
429 | /// while !*started { | |
430 | /// started = cvar.wait(started).unwrap(); | |
431 | /// } | |
432 | /// ``` | |
85aaf69f | 433 | #[stable(feature = "rust1", since = "1.0.0")] |
5bcae85e SL |
434 | pub fn notify_all(&self) { |
435 | unsafe { self.inner.notify_all() } | |
1a4d82fc JJ |
436 | } |
437 | ||
438 | fn verify(&self, mutex: &sys_mutex::Mutex) { | |
c34b1796 | 439 | let addr = mutex as *const _ as usize; |
1a4d82fc JJ |
440 | match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) { |
441 | // If we got out 0, then we have successfully bound the mutex to | |
442 | // this cvar. | |
443 | 0 => {} | |
444 | ||
445 | // If we get out a value that's the same as `addr`, then someone | |
446 | // already beat us to the punch. | |
447 | n if n == addr => {} | |
448 | ||
449 | // Anything else and we're using more than one mutex on this cvar, | |
450 | // which is currently disallowed. | |
451 | _ => panic!("attempted to use a condition variable with two \ | |
452 | mutexes"), | |
453 | } | |
454 | } | |
455 | } | |
456 | ||
8bb4bdeb | 457 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 SL |
458 | impl fmt::Debug for Condvar { |
459 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
460 | f.pad("Condvar { .. }") | |
461 | } | |
462 | } | |
463 | ||
7cac9316 | 464 | #[stable(feature = "condvar_default", since = "1.10.0")] |
5bcae85e | 465 | impl Default for Condvar { |
9e0c209e | 466 | /// Creates a `Condvar` which is ready to be waited on and notified. |
5bcae85e SL |
467 | fn default() -> Condvar { |
468 | Condvar::new() | |
469 | } | |
470 | } | |
471 | ||
472 | #[stable(feature = "rust1", since = "1.0.0")] | |
473 | impl Drop for Condvar { | |
474 | fn drop(&mut self) { | |
475 | unsafe { self.inner.destroy() } | |
476 | } | |
477 | } | |
478 | ||
1a4d82fc JJ |
479 | #[cfg(test)] |
480 | mod tests { | |
1a4d82fc | 481 | use sync::mpsc::channel; |
5bcae85e | 482 | use sync::{Condvar, Mutex, Arc}; |
85aaf69f | 483 | use thread; |
1a4d82fc | 484 | use time::Duration; |
c34b1796 | 485 | use u32; |
1a4d82fc JJ |
486 | |
487 | #[test] | |
488 | fn smoke() { | |
489 | let c = Condvar::new(); | |
490 | c.notify_one(); | |
491 | c.notify_all(); | |
492 | } | |
493 | ||
1a4d82fc | 494 | #[test] |
c30ab7b3 | 495 | #[cfg_attr(target_os = "emscripten", ignore)] |
1a4d82fc | 496 | fn notify_one() { |
5bcae85e SL |
497 | let m = Arc::new(Mutex::new(())); |
498 | let m2 = m.clone(); | |
499 | let c = Arc::new(Condvar::new()); | |
500 | let c2 = c.clone(); | |
1a4d82fc | 501 | |
5bcae85e | 502 | let g = m.lock().unwrap(); |
85aaf69f | 503 | let _t = thread::spawn(move|| { |
5bcae85e SL |
504 | let _g = m2.lock().unwrap(); |
505 | c2.notify_one(); | |
1a4d82fc | 506 | }); |
5bcae85e | 507 | let g = c.wait(g).unwrap(); |
1a4d82fc | 508 | drop(g); |
1a4d82fc JJ |
509 | } |
510 | ||
511 | #[test] | |
c30ab7b3 | 512 | #[cfg_attr(target_os = "emscripten", ignore)] |
1a4d82fc | 513 | fn notify_all() { |
c34b1796 | 514 | const N: usize = 10; |
1a4d82fc JJ |
515 | |
516 | let data = Arc::new((Mutex::new(0), Condvar::new())); | |
517 | let (tx, rx) = channel(); | |
85aaf69f | 518 | for _ in 0..N { |
1a4d82fc JJ |
519 | let data = data.clone(); |
520 | let tx = tx.clone(); | |
85aaf69f | 521 | thread::spawn(move|| { |
1a4d82fc JJ |
522 | let &(ref lock, ref cond) = &*data; |
523 | let mut cnt = lock.lock().unwrap(); | |
524 | *cnt += 1; | |
525 | if *cnt == N { | |
526 | tx.send(()).unwrap(); | |
527 | } | |
528 | while *cnt != 0 { | |
529 | cnt = cond.wait(cnt).unwrap(); | |
530 | } | |
531 | tx.send(()).unwrap(); | |
532 | }); | |
533 | } | |
534 | drop(tx); | |
535 | ||
536 | let &(ref lock, ref cond) = &*data; | |
537 | rx.recv().unwrap(); | |
538 | let mut cnt = lock.lock().unwrap(); | |
539 | *cnt = 0; | |
540 | cond.notify_all(); | |
541 | drop(cnt); | |
542 | ||
85aaf69f | 543 | for _ in 0..N { |
1a4d82fc JJ |
544 | rx.recv().unwrap(); |
545 | } | |
546 | } | |
547 | ||
548 | #[test] | |
c30ab7b3 | 549 | #[cfg_attr(target_os = "emscripten", ignore)] |
c34b1796 | 550 | fn wait_timeout_ms() { |
5bcae85e SL |
551 | let m = Arc::new(Mutex::new(())); |
552 | let m2 = m.clone(); | |
553 | let c = Arc::new(Condvar::new()); | |
554 | let c2 = c.clone(); | |
1a4d82fc | 555 | |
5bcae85e SL |
556 | let g = m.lock().unwrap(); |
557 | let (g, _no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap(); | |
85aaf69f SL |
558 | // spurious wakeups mean this isn't necessarily true |
559 | // assert!(!no_timeout); | |
560 | let _t = thread::spawn(move || { | |
5bcae85e SL |
561 | let _g = m2.lock().unwrap(); |
562 | c2.notify_one(); | |
1a4d82fc | 563 | }); |
5bcae85e | 564 | let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u32::MAX as u64)).unwrap(); |
9cc50fc6 | 565 | assert!(!timeout_res.timed_out()); |
1a4d82fc | 566 | drop(g); |
85aaf69f SL |
567 | } |
568 | ||
1a4d82fc | 569 | #[test] |
c34b1796 | 570 | #[should_panic] |
c30ab7b3 | 571 | #[cfg_attr(target_os = "emscripten", ignore)] |
1a4d82fc | 572 | fn two_mutexes() { |
5bcae85e SL |
573 | let m = Arc::new(Mutex::new(())); |
574 | let m2 = m.clone(); | |
575 | let c = Arc::new(Condvar::new()); | |
576 | let c2 = c.clone(); | |
1a4d82fc | 577 | |
5bcae85e | 578 | let mut g = m.lock().unwrap(); |
85aaf69f | 579 | let _t = thread::spawn(move|| { |
5bcae85e SL |
580 | let _g = m2.lock().unwrap(); |
581 | c2.notify_one(); | |
1a4d82fc | 582 | }); |
5bcae85e | 583 | g = c.wait(g).unwrap(); |
1a4d82fc JJ |
584 | drop(g); |
585 | ||
5bcae85e SL |
586 | let m = Mutex::new(()); |
587 | let _ = c.wait(m.lock().unwrap()).unwrap(); | |
1a4d82fc JJ |
588 | } |
589 | } |