]>
Commit | Line | Data |
---|---|---|
32a655c1 | 1 | use fmt; |
62682a34 | 2 | use sync::atomic::{AtomicUsize, Ordering}; |
9346a6ac | 3 | use sync::{mutex, MutexGuard, PoisonError}; |
1a4d82fc JJ |
4 | use sys_common::condvar as sys; |
5 | use sys_common::mutex as sys_mutex; | |
9346a6ac | 6 | use sys_common::poison::{self, LockResult}; |
0531ce1d | 7 | use 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 |
17 | pub struct WaitTimeoutResult(bool); |
18 | ||
19 | impl 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 |
112 | pub struct Condvar { |
113 | inner: Box<sys::Condvar>, | |
85aaf69f | 114 | mutex: AtomicUsize, |
1a4d82fc JJ |
115 | } |
116 | ||
1a4d82fc JJ |
117 | impl 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 |
591 | impl 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 | 598 | impl 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")] | |
606 | impl Drop for Condvar { | |
607 | fn drop(&mut self) { | |
608 | unsafe { self.inner.destroy() } | |
609 | } | |
610 | } | |
611 | ||
1a4d82fc JJ |
612 | #[cfg(test)] |
613 | mod 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 | } |