|
9 | 9 | // except according to those terms. |
10 | 10 |
|
11 | 11 | use cell::UnsafeCell; |
12 | | -use intrinsics::{atomic_cxchg, atomic_xadd, atomic_xchg}; |
| 12 | +use intrinsics::{atomic_cxchg, atomic_load, atomic_xadd, atomic_xchg}; |
13 | 13 | use ptr; |
14 | 14 | use time::Duration; |
15 | 15 |
|
16 | 16 | use sys::mutex::{mutex_unlock, Mutex}; |
17 | | -use sys::syscall::{futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; |
| 17 | +use sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; |
18 | 18 |
|
19 | 19 | pub struct Condvar { |
20 | 20 | lock: UnsafeCell<*mut i32>, |
@@ -63,33 +63,50 @@ impl Condvar { |
63 | 63 | } |
64 | 64 |
|
65 | 65 | #[inline] |
66 | | - pub fn wait(&self, mutex: &Mutex) { |
67 | | - unsafe { |
68 | | - let lock = self.lock.get(); |
69 | | - let seq = self.seq.get(); |
70 | | - |
71 | | - if *lock != mutex.lock.get() { |
72 | | - if *lock != ptr::null_mut() { |
73 | | - panic!("Condvar used with more than one Mutex"); |
74 | | - } |
| 66 | + unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool { |
| 67 | + let lock = self.lock.get(); |
| 68 | + let seq = self.seq.get(); |
75 | 69 |
|
76 | | - atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize); |
| 70 | + if *lock != mutex.lock.get() { |
| 71 | + if *lock != ptr::null_mut() { |
| 72 | + panic!("Condvar used with more than one Mutex"); |
77 | 73 | } |
78 | 74 |
|
79 | | - mutex_unlock(*lock); |
| 75 | + atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize); |
| 76 | + } |
80 | 77 |
|
81 | | - let _ = futex(seq, FUTEX_WAIT, *seq, 0, ptr::null_mut()); |
| 78 | + mutex_unlock(*lock); |
82 | 79 |
|
83 | | - while atomic_xchg(*lock, 2) != 0 { |
84 | | - let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut()); |
85 | | - } |
| 80 | + let seq_before = atomic_load(seq); |
| 81 | + |
| 82 | + let _ = futex(seq, FUTEX_WAIT, seq_before, timeout_ptr as usize, ptr::null_mut()); |
| 83 | + |
| 84 | + let seq_after = atomic_load(seq); |
| 85 | + |
| 86 | + while atomic_xchg(*lock, 2) != 0 { |
| 87 | + let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut()); |
| 88 | + } |
| 89 | + |
| 90 | + seq_before != seq_after |
| 91 | + } |
| 92 | + |
| 93 | + #[inline] |
| 94 | + pub fn wait(&self, mutex: &Mutex) { |
| 95 | + unsafe { |
| 96 | + assert!(self.wait_inner(mutex, ptr::null())); |
86 | 97 | } |
87 | 98 | } |
88 | 99 |
|
89 | 100 | #[inline] |
90 | | - pub fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { |
91 | | - ::sys_common::util::dumb_print(format_args!("condvar wait_timeout\n")); |
92 | | - unimplemented!(); |
| 101 | + pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { |
| 102 | + unsafe { |
| 103 | + let timeout = TimeSpec { |
| 104 | + tv_sec: dur.as_secs() as i64, |
| 105 | + tv_nsec: dur.subsec_nanos() as i32 |
| 106 | + }; |
| 107 | + |
| 108 | + self.wait_inner(mutex, &timeout as *const TimeSpec) |
| 109 | + } |
93 | 110 | } |
94 | 111 |
|
95 | 112 | #[inline] |
|
0 commit comments