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/semaphore.h"
6
7 #if V8_OS_MACOSX
8 #include <mach/mach_init.h>
9 #include <mach/task.h>
10 #endif
11
12 #include <errno.h>
13
14 #include "src/base/logging.h"
15 #include "src/base/platform/elapsed-timer.h"
16 #include "src/base/platform/time.h"
17
18 namespace v8 {
19 namespace base {
20
21 #if V8_OS_MACOSX
22
Semaphore(int count)23 Semaphore::Semaphore(int count) {
24 kern_return_t result = semaphore_create(
25 mach_task_self(), &native_handle_, SYNC_POLICY_FIFO, count);
26 DCHECK_EQ(KERN_SUCCESS, result);
27 USE(result);
28 }
29
30
~Semaphore()31 Semaphore::~Semaphore() {
32 kern_return_t result = semaphore_destroy(mach_task_self(), native_handle_);
33 DCHECK_EQ(KERN_SUCCESS, result);
34 USE(result);
35 }
36
Signal()37 void Semaphore::Signal() {
38 kern_return_t result = semaphore_signal(native_handle_);
39 DCHECK_EQ(KERN_SUCCESS, result);
40 USE(result);
41 }
42
43
Wait()44 void Semaphore::Wait() {
45 while (true) {
46 kern_return_t result = semaphore_wait(native_handle_);
47 if (result == KERN_SUCCESS) return; // Semaphore was signalled.
48 DCHECK_EQ(KERN_ABORTED, result);
49 }
50 }
51
52
WaitFor(const TimeDelta & rel_time)53 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
54 TimeTicks now = TimeTicks::Now();
55 TimeTicks end = now + rel_time;
56 while (true) {
57 mach_timespec_t ts;
58 if (now >= end) {
59 // Return immediately if semaphore was not signalled.
60 ts.tv_sec = 0;
61 ts.tv_nsec = 0;
62 } else {
63 ts = (end - now).ToMachTimespec();
64 }
65 kern_return_t result = semaphore_timedwait(native_handle_, ts);
66 if (result == KERN_SUCCESS) return true; // Semaphore was signalled.
67 if (result == KERN_OPERATION_TIMED_OUT) return false; // Timeout.
68 DCHECK_EQ(KERN_ABORTED, result);
69 now = TimeTicks::Now();
70 }
71 }
72
73 #elif V8_OS_POSIX
74
75 Semaphore::Semaphore(int count) {
76 DCHECK(count >= 0);
77 int result = sem_init(&native_handle_, 0, count);
78 DCHECK_EQ(0, result);
79 USE(result);
80 }
81
82
83 Semaphore::~Semaphore() {
84 int result = sem_destroy(&native_handle_);
85 DCHECK_EQ(0, result);
86 USE(result);
87 }
88
89 void Semaphore::Signal() {
90 int result = sem_post(&native_handle_);
91 // This check may fail with <libc-2.21, which we use on the try bots, if the
92 // semaphore is destroyed while sem_post is still executed. A work around is
93 // to extend the lifetime of the semaphore.
94 CHECK_EQ(0, result);
95 }
96
97
98 void Semaphore::Wait() {
99 while (true) {
100 int result = sem_wait(&native_handle_);
101 if (result == 0) return; // Semaphore was signalled.
102 // Signal caused spurious wakeup.
103 DCHECK_EQ(-1, result);
104 DCHECK_EQ(EINTR, errno);
105 }
106 }
107
108
109 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
110 // Compute the time for end of timeout.
111 const Time time = Time::NowFromSystemTime() + rel_time;
112 const struct timespec ts = time.ToTimespec();
113
114 // Wait for semaphore signalled or timeout.
115 while (true) {
116 int result = sem_timedwait(&native_handle_, &ts);
117 if (result == 0) return true; // Semaphore was signalled.
118 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
119 if (result > 0) {
120 // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
121 errno = result;
122 result = -1;
123 }
124 #endif
125 if (result == -1 && errno == ETIMEDOUT) {
126 // Timed out while waiting for semaphore.
127 return false;
128 }
129 // Signal caused spurious wakeup.
130 DCHECK_EQ(-1, result);
131 DCHECK_EQ(EINTR, errno);
132 }
133 }
134
135 #elif V8_OS_WIN
136
137 Semaphore::Semaphore(int count) {
138 DCHECK(count >= 0);
139 native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
140 DCHECK(native_handle_ != NULL);
141 }
142
143
144 Semaphore::~Semaphore() {
145 BOOL result = CloseHandle(native_handle_);
146 DCHECK(result);
147 USE(result);
148 }
149
150 void Semaphore::Signal() {
151 LONG dummy;
152 BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
153 DCHECK(result);
154 USE(result);
155 }
156
157
158 void Semaphore::Wait() {
159 DWORD result = WaitForSingleObject(native_handle_, INFINITE);
160 DCHECK(result == WAIT_OBJECT_0);
161 USE(result);
162 }
163
164
165 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
166 TimeTicks now = TimeTicks::Now();
167 TimeTicks end = now + rel_time;
168 while (true) {
169 int64_t msec = (end - now).InMilliseconds();
170 if (msec >= static_cast<int64_t>(INFINITE)) {
171 DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
172 if (result == WAIT_OBJECT_0) {
173 return true;
174 }
175 DCHECK(result == WAIT_TIMEOUT);
176 now = TimeTicks::Now();
177 } else {
178 DWORD result = WaitForSingleObject(
179 native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
180 if (result == WAIT_TIMEOUT) {
181 return false;
182 }
183 DCHECK(result == WAIT_OBJECT_0);
184 return true;
185 }
186 }
187 }
188
189 #endif // V8_OS_MACOSX
190
191 } // namespace base
192 } // namespace v8
193