Line data Source code
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 : namespace v8 {
13 : namespace base {
14 :
15 : #if V8_OS_POSIX
16 :
17 589551 : ConditionVariable::ConditionVariable() {
18 : #if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
19 : (V8_OS_LINUX && V8_LIBC_GLIBC))
20 : // On Free/Net/OpenBSD and Linux with glibc we can change the time
21 : // source for pthread_cond_timedwait() to use the monotonic clock.
22 : pthread_condattr_t attr;
23 589551 : int result = pthread_condattr_init(&attr);
24 : DCHECK_EQ(0, result);
25 589551 : result = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
26 : DCHECK_EQ(0, result);
27 589551 : result = pthread_cond_init(&native_handle_, &attr);
28 : DCHECK_EQ(0, result);
29 589550 : result = pthread_condattr_destroy(&attr);
30 : #else
31 : int result = pthread_cond_init(&native_handle_, nullptr);
32 : #endif
33 : DCHECK_EQ(0, result);
34 : USE(result);
35 589551 : }
36 :
37 :
38 1167841 : ConditionVariable::~ConditionVariable() {
39 : #if defined(V8_OS_MACOSX)
40 : // This hack is necessary to avoid a fatal pthreads subsystem bug in the
41 : // Darwin kernel. http://crbug.com/517681.
42 : {
43 : Mutex lock;
44 : MutexGuard l(&lock);
45 : struct timespec ts;
46 : ts.tv_sec = 0;
47 : ts.tv_nsec = 1;
48 : pthread_cond_timedwait_relative_np(&native_handle_, &lock.native_handle(),
49 : &ts);
50 : }
51 : #endif
52 583917 : int result = pthread_cond_destroy(&native_handle_);
53 : DCHECK_EQ(0, result);
54 : USE(result);
55 583924 : }
56 :
57 :
58 4617251 : void ConditionVariable::NotifyOne() {
59 4617251 : int result = pthread_cond_signal(&native_handle_);
60 : DCHECK_EQ(0, result);
61 : USE(result);
62 4619138 : }
63 :
64 :
65 1104715 : void ConditionVariable::NotifyAll() {
66 1104715 : int result = pthread_cond_broadcast(&native_handle_);
67 : DCHECK_EQ(0, result);
68 : USE(result);
69 1104715 : }
70 :
71 :
72 1873543 : void ConditionVariable::Wait(Mutex* mutex) {
73 : mutex->AssertHeldAndUnmark();
74 1873543 : int result = pthread_cond_wait(&native_handle_, &mutex->native_handle());
75 : DCHECK_EQ(0, result);
76 : USE(result);
77 : mutex->AssertUnheldAndMark();
78 1852083 : }
79 :
80 :
81 84351 : bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
82 : struct timespec ts;
83 : int result;
84 : mutex->AssertHeldAndUnmark();
85 : #if V8_OS_MACOSX
86 : // Mac OS X provides pthread_cond_timedwait_relative_np(), which does
87 : // not depend on the real time clock, which is what you really WANT here!
88 : ts = rel_time.ToTimespec();
89 : DCHECK_GE(ts.tv_sec, 0);
90 : DCHECK_GE(ts.tv_nsec, 0);
91 : result = pthread_cond_timedwait_relative_np(
92 : &native_handle_, &mutex->native_handle(), &ts);
93 : #else
94 : #if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
95 : (V8_OS_LINUX && V8_LIBC_GLIBC))
96 : // On Free/Net/OpenBSD and Linux with glibc we can change the time
97 : // source for pthread_cond_timedwait() to use the monotonic clock.
98 84351 : result = clock_gettime(CLOCK_MONOTONIC, &ts);
99 : DCHECK_EQ(0, result);
100 84351 : Time now = Time::FromTimespec(ts);
101 : #else
102 : // The timeout argument to pthread_cond_timedwait() is in absolute time.
103 : Time now = Time::NowFromSystemTime();
104 : #endif
105 84351 : Time end_time = now + rel_time;
106 : DCHECK_GE(end_time, now);
107 84351 : ts = end_time.ToTimespec();
108 84351 : result = pthread_cond_timedwait(
109 84351 : &native_handle_, &mutex->native_handle(), &ts);
110 : #endif // V8_OS_MACOSX
111 : mutex->AssertUnheldAndMark();
112 84351 : if (result == ETIMEDOUT) {
113 : return false;
114 : }
115 : DCHECK_EQ(0, result);
116 13360 : return true;
117 : }
118 :
119 : #elif V8_OS_WIN
120 :
121 : ConditionVariable::ConditionVariable() {
122 : InitializeConditionVariable(&native_handle_);
123 : }
124 :
125 :
126 : ConditionVariable::~ConditionVariable() {}
127 :
128 : void ConditionVariable::NotifyOne() { WakeConditionVariable(&native_handle_); }
129 :
130 : void ConditionVariable::NotifyAll() {
131 : WakeAllConditionVariable(&native_handle_);
132 : }
133 :
134 :
135 : void ConditionVariable::Wait(Mutex* mutex) {
136 : mutex->AssertHeldAndUnmark();
137 : SleepConditionVariableSRW(&native_handle_, &mutex->native_handle(), INFINITE,
138 : 0);
139 : mutex->AssertUnheldAndMark();
140 : }
141 :
142 :
143 : bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
144 : int64_t msec = rel_time.InMilliseconds();
145 : mutex->AssertHeldAndUnmark();
146 : BOOL result = SleepConditionVariableSRW(
147 : &native_handle_, &mutex->native_handle(), static_cast<DWORD>(msec), 0);
148 : #ifdef DEBUG
149 : if (!result) {
150 : // On failure, we only expect the CV to timeout. Any other error value means
151 : // that we've unexpectedly woken up.
152 : // Note that WAIT_TIMEOUT != ERROR_TIMEOUT. WAIT_TIMEOUT is used with the
153 : // WaitFor* family of functions as a direct return value. ERROR_TIMEOUT is
154 : // used with GetLastError().
155 : DCHECK_EQ(static_cast<DWORD>(ERROR_TIMEOUT), GetLastError());
156 : }
157 : #endif
158 : mutex->AssertUnheldAndMark();
159 : return result != 0;
160 : }
161 :
162 : #endif // V8_OS_POSIX
163 :
164 : } // namespace base
165 : } // namespace v8
|