v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
condition-variable.cc
Go to the documentation of this file.
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 
29 
30 #include <errno.h>
31 #include <time.h>
32 
33 #include "platform/time.h"
34 
35 namespace v8 {
36 namespace internal {
37 
38 #if V8_OS_POSIX
39 
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 
64 ConditionVariable::~ConditionVariable() {
65  int result = pthread_cond_destroy(&native_handle_);
66  ASSERT_EQ(0, result);
67  USE(result);
68 }
69 
70 
71 void ConditionVariable::NotifyOne() {
72  int result = pthread_cond_signal(&native_handle_);
73  ASSERT_EQ(0, result);
74  USE(result);
75 }
76 
77 
78 void ConditionVariable::NotifyAll() {
79  int result = pthread_cond_broadcast(&native_handle_);
80  ASSERT_EQ(0, result);
81  USE(result);
82 }
83 
84 
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 
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
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
Definition: flags.cc:269
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths true
Definition: flags.cc:208
#define ASSERT(condition)
Definition: checks.h:329
#define ASSERT_GE(v1, v2)
Definition: checks.h:332
typedef HANDLE(__stdcall *DLL_FUNC_TYPE(CreateToolhelp32Snapshot))(DWORD dwFlags
typedef DWORD(__stdcall *DLL_FUNC_TYPE(SymGetOptions))(VOID)
typedef BOOL(__stdcall *DLL_FUNC_TYPE(SymInitialize))(IN HANDLE hProcess
#define ASSERT_EQ(v1, v2)
Definition: checks.h:330
void USE(T)
Definition: globals.h:341
#define ASSERT_NE(v1, v2)
Definition: checks.h:331