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.
13 use sync::atomic::{mod, AtomicUint};
14 use sync::{mutex, StaticMutexGuard};
15 use sys_common::condvar as sys;
16 use sys_common::mutex as sys_mutex;
19 /// A Condition Variable
21 /// Condition variables represent the ability to block a thread such that it
22 /// consumes no CPU time while waiting for an event to occur. Condition
23 /// variables are typically associated with a boolean predicate (a condition)
24 /// and a mutex. The predicate is always verified inside of the mutex before
25 /// determining that thread must block.
27 /// Functions in this module will block the current **thread** of execution and
28 /// are bindings to system-provided condition variables where possible. Note
29 /// that this module places one additional restriction over the system condition
30 /// variables: each condvar can be used with precisely one mutex at runtime. Any
31 /// attempt to use multiple mutexes on the same condition variable will result
32 /// in a runtime panic. If this is not desired, then the unsafe primitives in
33 /// `sys` do not have this restriction but may result in undefined behavior.
38 /// use std::sync::{Arc, Mutex, Condvar};
40 /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
41 /// let pair2 = pair.clone();
43 /// // Inside of our lock, spawn a new thread, and then wait for it to start
45 /// let &(ref lock, ref cvar) = &*pair2;
46 /// let mut started = lock.lock();
48 /// cvar.notify_one();
51 /// // wait for the thread to start up
52 /// let &(ref lock, ref cvar) = &*pair;
53 /// let started = lock.lock();
55 /// cvar.wait(&started);
58 pub struct Condvar { inner: Box<StaticCondvar> }
60 /// Statically allocated condition variables.
62 /// This structure is identical to `Condvar` except that it is suitable for use
63 /// in static initializers for other structures.
68 /// use std::sync::{StaticCondvar, CONDVAR_INIT};
70 /// static CVAR: StaticCondvar = CONDVAR_INIT;
72 pub struct StaticCondvar {
77 /// Constant initializer for a statically allocated condition variable.
78 pub const CONDVAR_INIT: StaticCondvar = StaticCondvar {
79 inner: sys::CONDVAR_INIT,
80 mutex: atomic::INIT_ATOMIC_UINT,
83 /// A trait for vaules which can be passed to the waiting methods of condition
84 /// variables. This is implemented by the mutex guards in this module.
86 /// Note that this trait should likely not be implemented manually unless you
87 /// really know what you're doing.
88 pub trait AsMutexGuard {
89 #[allow(missing_docs)]
90 unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard;
94 /// Creates a new condition variable which is ready to be waited on and
96 pub fn new() -> Condvar {
98 inner: box StaticCondvar {
99 inner: unsafe { sys::Condvar::new() },
100 mutex: AtomicUint::new(0),
105 /// Block the current thread until this condition variable receives a
108 /// This function will atomically unlock the mutex specified (represented by
109 /// `guard`) and block the current thread. This means that any calls to
110 /// `notify_*()` which happen logically after the mutex is unlocked are
111 /// candidates to wake this thread up. When this function call returns, the
112 /// lock specified will have been re-acquired.
114 /// Note that this function is susceptible to spurious wakeups. Condition
115 /// variables normally have a boolean predicate associated with them, and
116 /// the predicate must always be checked each time this function returns to
117 /// protect against spurious wakeups.
121 /// This function will `panic!()` if it is used with more than one mutex
122 /// over time. Each condition variable is dynamically bound to exactly one
123 /// mutex to ensure defined behavior across platforms. If this functionality
124 /// is not desired, then unsafe primitives in `sys` are provided.
125 pub fn wait<T: AsMutexGuard>(&self, mutex_guard: &T) {
127 let me: &'static Condvar = &*(self as *const _);
128 me.inner.wait(mutex_guard)
132 /// Wait on this condition variable for a notification, timing out after a
133 /// specified duration.
135 /// The semantics of this function are equivalent to `wait()` except that
136 /// the thread will be blocked for roughly no longer than `dur`. This method
137 /// should not be used for precise timing due to anomalies such as
138 /// preemption or platform differences that may not cause the maximum amount
139 /// of time waited to be precisely `dur`.
141 /// If the wait timed out, then `false` will be returned. Otherwise if a
142 /// notification was received then `true` will be returned.
144 /// Like `wait`, the lock specified will be re-acquired when this function
145 /// returns, regardless of whether the timeout elapsed or not.
146 // Note that this method is *not* public, and this is quite intentional
147 // because we're not quite sure about the semantics of relative vs absolute
148 // durations or how the timing guarantees play into what the system APIs
149 // provide. There are also additional concerns about the unix-specific
150 // implementation which may need to be addressed.
152 fn wait_timeout<T: AsMutexGuard>(&self, mutex_guard: &T,
153 dur: Duration) -> bool {
155 let me: &'static Condvar = &*(self as *const _);
156 me.inner.wait_timeout(mutex_guard, dur)
160 /// Wake up one blocked thread on this condvar.
162 /// If there is a blocked thread on this condition variable, then it will
163 /// be woken up from its call to `wait` or `wait_timeout`. Calls to
164 /// `notify_one` are not buffered in any way.
166 /// To wake up all threads, see `notify_one()`.
167 pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } }
169 /// Wake up all blocked threads on this condvar.
171 /// This method will ensure that any current waiters on the condition
172 /// variable are awoken. Calls to `notify_all()` are not buffered in any
175 /// To wake up only one thread, see `notify_one()`.
176 pub fn notify_all(&self) { unsafe { self.inner.inner.notify_all() } }
179 impl Drop for Condvar {
181 unsafe { self.inner.inner.destroy() }
186 /// Block the current thread until this condition variable receives a
189 /// See `Condvar::wait`.
190 pub fn wait<T: AsMutexGuard>(&'static self, mutex_guard: &T) {
192 let lock = mutex_guard.as_mutex_guard();
193 let sys = mutex::guard_lock(lock);
195 self.inner.wait(sys);
196 (*mutex::guard_poison(lock)).check("mutex");
200 /// Wait on this condition variable for a notification, timing out after a
201 /// specified duration.
203 /// See `Condvar::wait_timeout`.
204 #[allow(dead_code)] // may want to stabilize this later, see wait_timeout above
205 fn wait_timeout<T: AsMutexGuard>(&'static self, mutex_guard: &T,
206 dur: Duration) -> bool {
208 let lock = mutex_guard.as_mutex_guard();
209 let sys = mutex::guard_lock(lock);
211 let ret = self.inner.wait_timeout(sys, dur);
212 (*mutex::guard_poison(lock)).check("mutex");
217 /// Wake up one blocked thread on this condvar.
219 /// See `Condvar::notify_one`.
220 pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } }
222 /// Wake up all blocked threads on this condvar.
224 /// See `Condvar::notify_all`.
225 pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } }
227 /// Deallocate all resources associated with this static condvar.
229 /// This method is unsafe to call as there is no guarantee that there are no
230 /// active users of the condvar, and this also doesn't prevent any future
231 /// users of the condvar. This method is required to be called to not leak
232 /// memory on all platforms.
233 pub unsafe fn destroy(&'static self) {
237 fn verify(&self, mutex: &sys_mutex::Mutex) {
238 let addr = mutex as *const _ as uint;
239 match self.mutex.compare_and_swap(0, addr, atomic::SeqCst) {
240 // If we got out 0, then we have successfully bound the mutex to
244 // If we get out a value that's the same as `addr`, then someone
245 // already beat us to the punch.
248 // Anything else and we're using more than one mutex on this cvar,
249 // which is currently disallowed.
250 _ => panic!("attempted to use a condition variable with two \
261 use super::{StaticCondvar, CONDVAR_INIT};
262 use sync::{StaticMutex, MUTEX_INIT, Condvar, Mutex, Arc};
266 let c = Condvar::new();
273 static C: StaticCondvar = CONDVAR_INIT;
276 unsafe { C.destroy(); }
281 static C: StaticCondvar = CONDVAR_INIT;
282 static M: StaticMutex = MUTEX_INIT;
291 unsafe { C.destroy(); M.destroy(); }
298 let data = Arc::new((Mutex::new(0), Condvar::new()));
299 let (tx, rx) = channel();
300 for _ in range(0, N) {
301 let data = data.clone();
304 let &(ref lock, ref cond) = &*data;
305 let mut cnt = lock.lock();
318 let &(ref lock, ref cond) = &*data;
320 let mut cnt = lock.lock();
325 for _ in range(0, N) {
332 static C: StaticCondvar = CONDVAR_INIT;
333 static M: StaticMutex = MUTEX_INIT;
336 assert!(!C.wait_timeout(&g, Duration::nanoseconds(1000)));
341 assert!(C.wait_timeout(&g, Duration::days(1)));
343 unsafe { C.destroy(); M.destroy(); }
349 static M1: StaticMutex = MUTEX_INIT;
350 static M2: StaticMutex = MUTEX_INIT;
351 static C: StaticCondvar = CONDVAR_INIT;