V8 Project
condition-variable.cc
Go to the documentation of this file.
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <errno.h>
8 #include <time.h>
9 
10 #include "src/base/platform/time.h"
11 
12 namespace v8 {
13 namespace base {
14 
15 #if V8_OS_POSIX
16 
17 ConditionVariable::ConditionVariable() {
18  // TODO(bmeurer): The test for V8_LIBRT_NOT_AVAILABLE is a temporary
19  // hack to support cross-compiling Chrome for Android in AOSP. Remove
20  // this once AOSP is fixed.
21 #if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
22  (V8_OS_LINUX && V8_LIBC_GLIBC)) && !V8_LIBRT_NOT_AVAILABLE
23  // On Free/Net/OpenBSD and Linux with glibc we can change the time
24  // source for pthread_cond_timedwait() to use the monotonic clock.
25  pthread_condattr_t attr;
26  int result = pthread_condattr_init(&attr);
27  DCHECK_EQ(0, result);
28  result = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
29  DCHECK_EQ(0, result);
30  result = pthread_cond_init(&native_handle_, &attr);
31  DCHECK_EQ(0, result);
32  result = pthread_condattr_destroy(&attr);
33 #else
34  int result = pthread_cond_init(&native_handle_, NULL);
35 #endif
36  DCHECK_EQ(0, result);
37  USE(result);
38 }
39 
40 
41 ConditionVariable::~ConditionVariable() {
42  int result = pthread_cond_destroy(&native_handle_);
43  DCHECK_EQ(0, result);
44  USE(result);
45 }
46 
47 
48 void ConditionVariable::NotifyOne() {
49  int result = pthread_cond_signal(&native_handle_);
50  DCHECK_EQ(0, result);
51  USE(result);
52 }
53 
54 
55 void ConditionVariable::NotifyAll() {
56  int result = pthread_cond_broadcast(&native_handle_);
57  DCHECK_EQ(0, result);
58  USE(result);
59 }
60 
61 
62 void ConditionVariable::Wait(Mutex* mutex) {
63  mutex->AssertHeldAndUnmark();
64  int result = pthread_cond_wait(&native_handle_, &mutex->native_handle());
65  DCHECK_EQ(0, result);
66  USE(result);
67  mutex->AssertUnheldAndMark();
68 }
69 
70 
71 bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
72  struct timespec ts;
73  int result;
74  mutex->AssertHeldAndUnmark();
75 #if V8_OS_MACOSX
76  // Mac OS X provides pthread_cond_timedwait_relative_np(), which does
77  // not depend on the real time clock, which is what you really WANT here!
78  ts = rel_time.ToTimespec();
79  DCHECK_GE(ts.tv_sec, 0);
80  DCHECK_GE(ts.tv_nsec, 0);
81  result = pthread_cond_timedwait_relative_np(
82  &native_handle_, &mutex->native_handle(), &ts);
83 #else
84  // TODO(bmeurer): The test for V8_LIBRT_NOT_AVAILABLE is a temporary
85  // hack to support cross-compiling Chrome for Android in AOSP. Remove
86  // this once AOSP is fixed.
87 #if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
88  (V8_OS_LINUX && V8_LIBC_GLIBC)) && !V8_LIBRT_NOT_AVAILABLE
89  // On Free/Net/OpenBSD and Linux with glibc we can change the time
90  // source for pthread_cond_timedwait() to use the monotonic clock.
91  result = clock_gettime(CLOCK_MONOTONIC, &ts);
92  DCHECK_EQ(0, result);
93  Time now = Time::FromTimespec(ts);
94 #else
95  // The timeout argument to pthread_cond_timedwait() is in absolute time.
96  Time now = Time::NowFromSystemTime();
97 #endif
98  Time end_time = now + rel_time;
99  DCHECK_GE(end_time, now);
100  ts = end_time.ToTimespec();
101  result = pthread_cond_timedwait(
102  &native_handle_, &mutex->native_handle(), &ts);
103 #endif // V8_OS_MACOSX
104  mutex->AssertUnheldAndMark();
105  if (result == ETIMEDOUT) {
106  return false;
107  }
108  DCHECK_EQ(0, result);
109  return true;
110 }
111 
112 #elif V8_OS_WIN
113 
114 struct ConditionVariable::Event {
115  Event() : handle_(::CreateEventA(NULL, true, false, NULL)) {
116  DCHECK(handle_ != NULL);
117  }
118 
119  ~Event() {
120  BOOL ok = ::CloseHandle(handle_);
121  DCHECK(ok);
122  USE(ok);
123  }
124 
125  bool WaitFor(DWORD timeout_ms) {
126  DWORD result = ::WaitForSingleObject(handle_, timeout_ms);
127  if (result == WAIT_OBJECT_0) {
128  return true;
129  }
130  DCHECK(result == WAIT_TIMEOUT);
131  return false;
132  }
133 
134  HANDLE handle_;
135  Event* next_;
136  HANDLE thread_;
137  volatile bool notified_;
138 };
139 
140 
141 ConditionVariable::NativeHandle::~NativeHandle() {
142  DCHECK(waitlist_ == NULL);
143 
144  while (freelist_ != NULL) {
145  Event* event = freelist_;
146  freelist_ = event->next_;
147  delete event;
148  }
149 }
150 
151 
152 ConditionVariable::Event* ConditionVariable::NativeHandle::Pre() {
153  LockGuard<Mutex> lock_guard(&mutex_);
154 
155  // Grab an event from the free list or create a new one.
156  Event* event = freelist_;
157  if (event != NULL) {
158  freelist_ = event->next_;
159  } else {
160  event = new Event;
161  }
162  event->thread_ = GetCurrentThread();
163  event->notified_ = false;
164 
165 #ifdef DEBUG
166  // The event must not be on the wait list.
167  for (Event* we = waitlist_; we != NULL; we = we->next_) {
168  DCHECK_NE(event, we);
169  }
170 #endif
171 
172  // Prepend the event to the wait list.
173  event->next_ = waitlist_;
174  waitlist_ = event;
175 
176  return event;
177 }
178 
179 
180 void ConditionVariable::NativeHandle::Post(Event* event, bool result) {
181  LockGuard<Mutex> lock_guard(&mutex_);
182 
183  // Remove the event from the wait list.
184  for (Event** wep = &waitlist_;; wep = &(*wep)->next_) {
185  DCHECK_NE(NULL, *wep);
186  if (*wep == event) {
187  *wep = event->next_;
188  break;
189  }
190  }
191 
192 #ifdef DEBUG
193  // The event must not be on the free list.
194  for (Event* fe = freelist_; fe != NULL; fe = fe->next_) {
195  DCHECK_NE(event, fe);
196  }
197 #endif
198 
199  // Reset the event.
200  BOOL ok = ::ResetEvent(event->handle_);
201  DCHECK(ok);
202  USE(ok);
203 
204  // Insert the event into the free list.
205  event->next_ = freelist_;
206  freelist_ = event;
207 
208  // Forward signals delivered after the timeout to the next waiting event.
209  if (!result && event->notified_ && waitlist_ != NULL) {
210  ok = ::SetEvent(waitlist_->handle_);
211  DCHECK(ok);
212  USE(ok);
213  waitlist_->notified_ = true;
214  }
215 }
216 
217 
218 ConditionVariable::ConditionVariable() {}
219 
220 
221 ConditionVariable::~ConditionVariable() {}
222 
223 
224 void ConditionVariable::NotifyOne() {
225  // Notify the thread with the highest priority in the waitlist
226  // that was not already signalled.
227  LockGuard<Mutex> lock_guard(native_handle_.mutex());
228  Event* highest_event = NULL;
229  int highest_priority = std::numeric_limits<int>::min();
230  for (Event* event = native_handle().waitlist();
231  event != NULL;
232  event = event->next_) {
233  if (event->notified_) {
234  continue;
235  }
236  int priority = GetThreadPriority(event->thread_);
237  DCHECK_NE(THREAD_PRIORITY_ERROR_RETURN, priority);
238  if (priority >= highest_priority) {
239  highest_priority = priority;
240  highest_event = event;
241  }
242  }
243  if (highest_event != NULL) {
244  DCHECK(!highest_event->notified_);
245  ::SetEvent(highest_event->handle_);
246  highest_event->notified_ = true;
247  }
248 }
249 
250 
251 void ConditionVariable::NotifyAll() {
252  // Notify all threads on the waitlist.
253  LockGuard<Mutex> lock_guard(native_handle_.mutex());
254  for (Event* event = native_handle().waitlist();
255  event != NULL;
256  event = event->next_) {
257  if (!event->notified_) {
258  ::SetEvent(event->handle_);
259  event->notified_ = true;
260  }
261  }
262 }
263 
264 
265 void ConditionVariable::Wait(Mutex* mutex) {
266  // Create and setup the wait event.
267  Event* event = native_handle_.Pre();
268 
269  // Release the user mutex.
270  mutex->Unlock();
271 
272  // Wait on the wait event.
273  while (!event->WaitFor(INFINITE))
274  ;
275 
276  // Reaquire the user mutex.
277  mutex->Lock();
278 
279  // Release the wait event (we must have been notified).
280  DCHECK(event->notified_);
281  native_handle_.Post(event, true);
282 }
283 
284 
285 bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
286  // Create and setup the wait event.
287  Event* event = native_handle_.Pre();
288 
289  // Release the user mutex.
290  mutex->Unlock();
291 
292  // Wait on the wait event.
293  TimeTicks now = TimeTicks::Now();
294  TimeTicks end = now + rel_time;
295  bool result = false;
296  while (true) {
297  int64_t msec = (end - now).InMilliseconds();
298  if (msec >= static_cast<int64_t>(INFINITE)) {
299  result = event->WaitFor(INFINITE - 1);
300  if (result) {
301  break;
302  }
303  now = TimeTicks::Now();
304  } else {
305  result = event->WaitFor((msec < 0) ? 0 : static_cast<DWORD>(msec));
306  break;
307  }
308  }
309 
310  // Reaquire the user mutex.
311  mutex->Lock();
312 
313  // Release the wait event.
314  DCHECK(!result || event->notified_);
315  native_handle_.Post(event, result);
316 
317  return result;
318 }
319 
320 #endif // V8_OS_POSIX
321 
322 } } // namespace v8::base
enable harmony numeric enable harmony object literal extensions true
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define DCHECK_NE(v1, v2)
Definition: logging.h:207
#define DCHECK_GE(v1, v2)
Definition: logging.h:208
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
void USE(T)
Definition: macros.h:322
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
static int min(int a, int b)
Definition: liveedit.cc:273
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20