• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "platform/condition-variable.h"
29 
30 #include <cerrno>
31 #include <ctime>
32 
33 #include "platform/time.h"
34 
35 namespace v8 {
36 namespace internal {
37 
38 #if V8_OS_POSIX
39 
ConditionVariable()40 ConditionVariable::ConditionVariable() {
41   // TODO(bmeurer): The test for V8_LIBRT_NOT_AVAILABLE is a temporary
42   // hack to support cross-compiling Chrome for Android in AOSP. Remove
43   // this once AOSP is fixed.
44 #if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
45      (V8_OS_LINUX && V8_LIBC_GLIBC)) && !V8_LIBRT_NOT_AVAILABLE
46   // On Free/Net/OpenBSD and Linux with glibc we can change the time
47   // source for pthread_cond_timedwait() to use the monotonic clock.
48   pthread_condattr_t attr;
49   int result = pthread_condattr_init(&attr);
50   ASSERT_EQ(0, result);
51   result = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
52   ASSERT_EQ(0, result);
53   result = pthread_cond_init(&native_handle_, &attr);
54   ASSERT_EQ(0, result);
55   result = pthread_condattr_destroy(&attr);
56 #else
57   int result = pthread_cond_init(&native_handle_, NULL);
58 #endif
59   ASSERT_EQ(0, result);
60   USE(result);
61 }
62 
63 
~ConditionVariable()64 ConditionVariable::~ConditionVariable() {
65   int result = pthread_cond_destroy(&native_handle_);
66   ASSERT_EQ(0, result);
67   USE(result);
68 }
69 
70 
NotifyOne()71 void ConditionVariable::NotifyOne() {
72   int result = pthread_cond_signal(&native_handle_);
73   ASSERT_EQ(0, result);
74   USE(result);
75 }
76 
77 
NotifyAll()78 void ConditionVariable::NotifyAll() {
79   int result = pthread_cond_broadcast(&native_handle_);
80   ASSERT_EQ(0, result);
81   USE(result);
82 }
83 
84 
Wait(Mutex * mutex)85 void ConditionVariable::Wait(Mutex* mutex) {
86   mutex->AssertHeldAndUnmark();
87   int result = pthread_cond_wait(&native_handle_, &mutex->native_handle());
88   ASSERT_EQ(0, result);
89   USE(result);
90   mutex->AssertUnheldAndMark();
91 }
92 
93 
WaitFor(Mutex * mutex,const TimeDelta & rel_time)94 bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
95   struct timespec ts;
96   int result;
97   mutex->AssertHeldAndUnmark();
98 #if V8_OS_MACOSX
99   // Mac OS X provides pthread_cond_timedwait_relative_np(), which does
100   // not depend on the real time clock, which is what you really WANT here!
101   ts = rel_time.ToTimespec();
102   ASSERT_GE(ts.tv_sec, 0);
103   ASSERT_GE(ts.tv_nsec, 0);
104   result = pthread_cond_timedwait_relative_np(
105       &native_handle_, &mutex->native_handle(), &ts);
106 #else
107   // TODO(bmeurer): The test for V8_LIBRT_NOT_AVAILABLE is a temporary
108   // hack to support cross-compiling Chrome for Android in AOSP. Remove
109   // this once AOSP is fixed.
110 #if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
111      (V8_OS_LINUX && V8_LIBC_GLIBC)) && !V8_LIBRT_NOT_AVAILABLE
112   // On Free/Net/OpenBSD and Linux with glibc we can change the time
113   // source for pthread_cond_timedwait() to use the monotonic clock.
114   result = clock_gettime(CLOCK_MONOTONIC, &ts);
115   ASSERT_EQ(0, result);
116   Time now = Time::FromTimespec(ts);
117 #else
118   // The timeout argument to pthread_cond_timedwait() is in absolute time.
119   Time now = Time::NowFromSystemTime();
120 #endif
121   Time end_time = now + rel_time;
122   ASSERT_GE(end_time, now);
123   ts = end_time.ToTimespec();
124   result = pthread_cond_timedwait(
125       &native_handle_, &mutex->native_handle(), &ts);
126 #endif  // V8_OS_MACOSX
127   mutex->AssertUnheldAndMark();
128   if (result == ETIMEDOUT) {
129     return false;
130   }
131   ASSERT_EQ(0, result);
132   return true;
133 }
134 
135 #elif V8_OS_WIN
136 
137 struct ConditionVariable::Event {
138   Event() : handle_(::CreateEventA(NULL, true, false, NULL)) {
139     ASSERT(handle_ != NULL);
140   }
141 
142   ~Event() {
143     BOOL ok = ::CloseHandle(handle_);
144     ASSERT(ok);
145     USE(ok);
146   }
147 
148   bool WaitFor(DWORD timeout_ms) {
149     DWORD result = ::WaitForSingleObject(handle_, timeout_ms);
150     if (result == WAIT_OBJECT_0) {
151       return true;
152     }
153     ASSERT(result == WAIT_TIMEOUT);
154     return false;
155   }
156 
157   HANDLE handle_;
158   Event* next_;
159   HANDLE thread_;
160   volatile bool notified_;
161 };
162 
163 
164 ConditionVariable::NativeHandle::~NativeHandle() {
165   ASSERT(waitlist_ == NULL);
166 
167   while (freelist_ != NULL) {
168     Event* event = freelist_;
169     freelist_ = event->next_;
170     delete event;
171   }
172 }
173 
174 
175 ConditionVariable::Event* ConditionVariable::NativeHandle::Pre() {
176   LockGuard<Mutex> lock_guard(&mutex_);
177 
178   // Grab an event from the free list or create a new one.
179   Event* event = freelist_;
180   if (event != NULL) {
181     freelist_ = event->next_;
182   } else {
183     event = new Event;
184   }
185   event->thread_ = GetCurrentThread();
186   event->notified_ = false;
187 
188 #ifdef DEBUG
189   // The event must not be on the wait list.
190   for (Event* we = waitlist_; we != NULL; we = we->next_) {
191     ASSERT_NE(event, we);
192   }
193 #endif
194 
195   // Prepend the event to the wait list.
196   event->next_ = waitlist_;
197   waitlist_ = event;
198 
199   return event;
200 }
201 
202 
203 void ConditionVariable::NativeHandle::Post(Event* event, bool result) {
204   LockGuard<Mutex> lock_guard(&mutex_);
205 
206   // Remove the event from the wait list.
207   for (Event** wep = &waitlist_;; wep = &(*wep)->next_) {
208     ASSERT_NE(NULL, *wep);
209     if (*wep == event) {
210       *wep = event->next_;
211       break;
212     }
213   }
214 
215 #ifdef DEBUG
216   // The event must not be on the free list.
217   for (Event* fe = freelist_; fe != NULL; fe = fe->next_) {
218     ASSERT_NE(event, fe);
219   }
220 #endif
221 
222   // Reset the event.
223   BOOL ok = ::ResetEvent(event->handle_);
224   ASSERT(ok);
225   USE(ok);
226 
227   // Insert the event into the free list.
228   event->next_ = freelist_;
229   freelist_ = event;
230 
231   // Forward signals delivered after the timeout to the next waiting event.
232   if (!result && event->notified_ && waitlist_ != NULL) {
233     ok = ::SetEvent(waitlist_->handle_);
234     ASSERT(ok);
235     USE(ok);
236     waitlist_->notified_ = true;
237   }
238 }
239 
240 
241 ConditionVariable::ConditionVariable() {}
242 
243 
244 ConditionVariable::~ConditionVariable() {}
245 
246 
247 void ConditionVariable::NotifyOne() {
248   // Notify the thread with the highest priority in the waitlist
249   // that was not already signalled.
250   LockGuard<Mutex> lock_guard(native_handle_.mutex());
251   Event* highest_event = NULL;
252   int highest_priority = std::numeric_limits<int>::min();
253   for (Event* event = native_handle().waitlist();
254        event != NULL;
255        event = event->next_) {
256     if (event->notified_) {
257       continue;
258     }
259     int priority = GetThreadPriority(event->thread_);
260     ASSERT_NE(THREAD_PRIORITY_ERROR_RETURN, priority);
261     if (priority >= highest_priority) {
262       highest_priority = priority;
263       highest_event = event;
264     }
265   }
266   if (highest_event != NULL) {
267     ASSERT(!highest_event->notified_);
268     ::SetEvent(highest_event->handle_);
269     highest_event->notified_ = true;
270   }
271 }
272 
273 
274 void ConditionVariable::NotifyAll() {
275   // Notify all threads on the waitlist.
276   LockGuard<Mutex> lock_guard(native_handle_.mutex());
277   for (Event* event = native_handle().waitlist();
278        event != NULL;
279        event = event->next_) {
280     if (!event->notified_) {
281       ::SetEvent(event->handle_);
282       event->notified_ = true;
283     }
284   }
285 }
286 
287 
288 void ConditionVariable::Wait(Mutex* mutex) {
289   // Create and setup the wait event.
290   Event* event = native_handle_.Pre();
291 
292   // Release the user mutex.
293   mutex->Unlock();
294 
295   // Wait on the wait event.
296   while (!event->WaitFor(INFINITE))
297     ;
298 
299   // Reaquire the user mutex.
300   mutex->Lock();
301 
302   // Release the wait event (we must have been notified).
303   ASSERT(event->notified_);
304   native_handle_.Post(event, true);
305 }
306 
307 
308 bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
309   // Create and setup the wait event.
310   Event* event = native_handle_.Pre();
311 
312   // Release the user mutex.
313   mutex->Unlock();
314 
315   // Wait on the wait event.
316   TimeTicks now = TimeTicks::Now();
317   TimeTicks end = now + rel_time;
318   bool result = false;
319   while (true) {
320     int64_t msec = (end - now).InMilliseconds();
321     if (msec >= static_cast<int64_t>(INFINITE)) {
322       result = event->WaitFor(INFINITE - 1);
323       if (result) {
324         break;
325       }
326       now = TimeTicks::Now();
327     } else {
328       result = event->WaitFor((msec < 0) ? 0 : static_cast<DWORD>(msec));
329       break;
330     }
331   }
332 
333   // Reaquire the user mutex.
334   mutex->Lock();
335 
336   // Release the wait event.
337   ASSERT(!result || event->notified_);
338   native_handle_.Post(event, result);
339 
340   return result;
341 }
342 
343 #endif  // V8_OS_POSIX
344 
345 } }  // namespace v8::internal
346