• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 #include "src/base/platform/condition-variable.h"
6 
7 #include <errno.h>
8 #include <time.h>
9 
10 #include "src/base/platform/time.h"
11 
12 #if V8_OS_WIN
13 #include <windows.h>
14 #endif
15 
16 namespace v8 {
17 namespace base {
18 
19 #if V8_OS_POSIX
20 
ConditionVariable()21 ConditionVariable::ConditionVariable() {
22 #if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
23      (V8_OS_LINUX && V8_LIBC_GLIBC))
24   // On Free/Net/OpenBSD and Linux with glibc we can change the time
25   // source for pthread_cond_timedwait() to use the monotonic clock.
26   pthread_condattr_t attr;
27   int result = pthread_condattr_init(&attr);
28   DCHECK_EQ(0, result);
29   result = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
30   DCHECK_EQ(0, result);
31   result = pthread_cond_init(&native_handle_, &attr);
32   DCHECK_EQ(0, result);
33   result = pthread_condattr_destroy(&attr);
34 #else
35   int result = pthread_cond_init(&native_handle_, nullptr);
36 #endif
37   DCHECK_EQ(0, result);
38   USE(result);
39 }
40 
41 
~ConditionVariable()42 ConditionVariable::~ConditionVariable() {
43 #if defined(V8_OS_DARWIN)
44   // This hack is necessary to avoid a fatal pthreads subsystem bug in the
45   // Darwin kernel. http://crbug.com/517681.
46   {
47     Mutex lock;
48     MutexGuard l(&lock);
49     struct timespec ts;
50     ts.tv_sec = 0;
51     ts.tv_nsec = 1;
52     pthread_cond_timedwait_relative_np(&native_handle_, &lock.native_handle(),
53                                        &ts);
54   }
55 #endif
56   int result = pthread_cond_destroy(&native_handle_);
57   DCHECK_EQ(0, result);
58   USE(result);
59 }
60 
61 
NotifyOne()62 void ConditionVariable::NotifyOne() {
63   int result = pthread_cond_signal(&native_handle_);
64   DCHECK_EQ(0, result);
65   USE(result);
66 }
67 
68 
NotifyAll()69 void ConditionVariable::NotifyAll() {
70   int result = pthread_cond_broadcast(&native_handle_);
71   DCHECK_EQ(0, result);
72   USE(result);
73 }
74 
75 
Wait(Mutex * mutex)76 void ConditionVariable::Wait(Mutex* mutex) {
77   mutex->AssertHeldAndUnmark();
78   int result = pthread_cond_wait(&native_handle_, &mutex->native_handle());
79   DCHECK_EQ(0, result);
80   USE(result);
81   mutex->AssertUnheldAndMark();
82 }
83 
84 
WaitFor(Mutex * mutex,const TimeDelta & rel_time)85 bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
86   struct timespec ts;
87   int result;
88   mutex->AssertHeldAndUnmark();
89 #if V8_OS_DARWIN
90   // Mac OS X provides pthread_cond_timedwait_relative_np(), which does
91   // not depend on the real time clock, which is what you really WANT here!
92   ts = rel_time.ToTimespec();
93   DCHECK_GE(ts.tv_sec, 0);
94   DCHECK_GE(ts.tv_nsec, 0);
95   result = pthread_cond_timedwait_relative_np(
96       &native_handle_, &mutex->native_handle(), &ts);
97 #else
98 #if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
99      (V8_OS_LINUX && V8_LIBC_GLIBC))
100   // On Free/Net/OpenBSD and Linux with glibc we can change the time
101   // source for pthread_cond_timedwait() to use the monotonic clock.
102   result = clock_gettime(CLOCK_MONOTONIC, &ts);
103   DCHECK_EQ(0, result);
104   Time now = Time::FromTimespec(ts);
105 #else
106   // The timeout argument to pthread_cond_timedwait() is in absolute time.
107   Time now = Time::NowFromSystemTime();
108 #endif
109   Time end_time = now + rel_time;
110   DCHECK_GE(end_time, now);
111   ts = end_time.ToTimespec();
112   result = pthread_cond_timedwait(
113       &native_handle_, &mutex->native_handle(), &ts);
114 #endif  // V8_OS_DARWIN
115   mutex->AssertUnheldAndMark();
116   if (result == ETIMEDOUT) {
117     return false;
118   }
119   DCHECK_EQ(0, result);
120   return true;
121 }
122 
123 #elif V8_OS_WIN
124 
125 ConditionVariable::ConditionVariable() {
126   InitializeConditionVariable(V8ToWindowsType(&native_handle_));
127 }
128 
129 
130 ConditionVariable::~ConditionVariable() {}
131 
132 void ConditionVariable::NotifyOne() {
133   WakeConditionVariable(V8ToWindowsType(&native_handle_));
134 }
135 
136 void ConditionVariable::NotifyAll() {
137   WakeAllConditionVariable(V8ToWindowsType(&native_handle_));
138 }
139 
140 
141 void ConditionVariable::Wait(Mutex* mutex) {
142   mutex->AssertHeldAndUnmark();
143   SleepConditionVariableSRW(V8ToWindowsType(&native_handle_),
144                             V8ToWindowsType(&mutex->native_handle()), INFINITE,
145                             0);
146   mutex->AssertUnheldAndMark();
147 }
148 
149 
150 bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
151   int64_t msec = rel_time.InMilliseconds();
152   mutex->AssertHeldAndUnmark();
153   BOOL result = SleepConditionVariableSRW(
154       V8ToWindowsType(&native_handle_),
155       V8ToWindowsType(&mutex->native_handle()), static_cast<DWORD>(msec), 0);
156 #ifdef DEBUG
157   if (!result) {
158     // On failure, we only expect the CV to timeout. Any other error value means
159     // that we've unexpectedly woken up.
160     // Note that WAIT_TIMEOUT != ERROR_TIMEOUT. WAIT_TIMEOUT is used with the
161     // WaitFor* family of functions as a direct return value. ERROR_TIMEOUT is
162     // used with GetLastError().
163     DCHECK_EQ(static_cast<DWORD>(ERROR_TIMEOUT), GetLastError());
164   }
165 #endif
166   mutex->AssertUnheldAndMark();
167   return result != 0;
168 }
169 
170 #elif V8_OS_STARBOARD
171 
172 ConditionVariable::ConditionVariable() {
173   SbConditionVariableCreate(&native_handle_, nullptr);
174 }
175 
176 ConditionVariable::~ConditionVariable() {
177   SbConditionVariableDestroy(&native_handle_);
178 }
179 
180 void ConditionVariable::NotifyOne() {
181   SbConditionVariableSignal(&native_handle_);
182 }
183 
184 void ConditionVariable::NotifyAll() {
185   SbConditionVariableBroadcast(&native_handle_);
186 }
187 
188 void ConditionVariable::Wait(Mutex* mutex) {
189   SbConditionVariableWait(&native_handle_, &mutex->native_handle());
190 }
191 
192 bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
193   SbTime microseconds = static_cast<SbTime>(rel_time.InMicroseconds());
194   SbConditionVariableResult result = SbConditionVariableWaitTimed(
195       &native_handle_, &mutex->native_handle(), microseconds);
196   DCHECK(result != kSbConditionVariableFailed);
197   return result == kSbConditionVariableSignaled;
198 }
199 
200 #endif  // V8_OS_STARBOARD
201 
202 }  // namespace base
203 }  // namespace v8
204