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
37
Signal()38 void Semaphore::Signal() {
39 kern_return_t result = semaphore_signal(native_handle_);
40 DCHECK_EQ(KERN_SUCCESS, result);
41 USE(result);
42 }
43
44
Wait()45 void Semaphore::Wait() {
46 while (true) {
47 kern_return_t result = semaphore_wait(native_handle_);
48 if (result == KERN_SUCCESS) return; // Semaphore was signalled.
49 DCHECK_EQ(KERN_ABORTED, result);
50 }
51 }
52
53
WaitFor(const TimeDelta & rel_time)54 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
55 TimeTicks now = TimeTicks::Now();
56 TimeTicks end = now + rel_time;
57 while (true) {
58 mach_timespec_t ts;
59 if (now >= end) {
60 // Return immediately if semaphore was not signalled.
61 ts.tv_sec = 0;
62 ts.tv_nsec = 0;
63 } else {
64 ts = (end - now).ToMachTimespec();
65 }
66 kern_return_t result = semaphore_timedwait(native_handle_, ts);
67 if (result == KERN_SUCCESS) return true; // Semaphore was signalled.
68 if (result == KERN_OPERATION_TIMED_OUT) return false; // Timeout.
69 DCHECK_EQ(KERN_ABORTED, result);
70 now = TimeTicks::Now();
71 }
72 }
73
74 #elif V8_OS_POSIX
75
76 Semaphore::Semaphore(int count) {
77 DCHECK(count >= 0);
78 int result = sem_init(&native_handle_, 0, count);
79 DCHECK_EQ(0, result);
80 USE(result);
81 }
82
83
84 Semaphore::~Semaphore() {
85 int result = sem_destroy(&native_handle_);
86 DCHECK_EQ(0, result);
87 USE(result);
88 }
89
90
91 void Semaphore::Signal() {
92 int result = sem_post(&native_handle_);
93 DCHECK_EQ(0, result);
94 USE(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 #if V8_OS_NACL
111 // PNaCL doesn't support sem_timedwait, do ugly busy waiting.
112 ElapsedTimer timer;
113 timer.Start();
114 do {
115 int result = sem_trywait(&native_handle_);
116 if (result == 0) return true;
117 DCHECK(errno == EAGAIN || errno == EINTR);
118 } while (!timer.HasExpired(rel_time));
119 return false;
120 #else
121 // Compute the time for end of timeout.
122 const Time time = Time::NowFromSystemTime() + rel_time;
123 const struct timespec ts = time.ToTimespec();
124
125 // Wait for semaphore signalled or timeout.
126 while (true) {
127 int result = sem_timedwait(&native_handle_, &ts);
128 if (result == 0) return true; // Semaphore was signalled.
129 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
130 if (result > 0) {
131 // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
132 errno = result;
133 result = -1;
134 }
135 #endif
136 if (result == -1 && errno == ETIMEDOUT) {
137 // Timed out while waiting for semaphore.
138 return false;
139 }
140 // Signal caused spurious wakeup.
141 DCHECK_EQ(-1, result);
142 DCHECK_EQ(EINTR, errno);
143 }
144 #endif
145 }
146
147 #elif V8_OS_WIN
148
149 Semaphore::Semaphore(int count) {
150 DCHECK(count >= 0);
151 native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
152 DCHECK(native_handle_ != NULL);
153 }
154
155
156 Semaphore::~Semaphore() {
157 BOOL result = CloseHandle(native_handle_);
158 DCHECK(result);
159 USE(result);
160 }
161
162
163 void Semaphore::Signal() {
164 LONG dummy;
165 BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
166 DCHECK(result);
167 USE(result);
168 }
169
170
171 void Semaphore::Wait() {
172 DWORD result = WaitForSingleObject(native_handle_, INFINITE);
173 DCHECK(result == WAIT_OBJECT_0);
174 USE(result);
175 }
176
177
178 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
179 TimeTicks now = TimeTicks::Now();
180 TimeTicks end = now + rel_time;
181 while (true) {
182 int64_t msec = (end - now).InMilliseconds();
183 if (msec >= static_cast<int64_t>(INFINITE)) {
184 DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
185 if (result == WAIT_OBJECT_0) {
186 return true;
187 }
188 DCHECK(result == WAIT_TIMEOUT);
189 now = TimeTicks::Now();
190 } else {
191 DWORD result = WaitForSingleObject(
192 native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
193 if (result == WAIT_TIMEOUT) {
194 return false;
195 }
196 DCHECK(result == WAIT_OBJECT_0);
197 return true;
198 }
199 }
200 }
201
202 #endif // V8_OS_MACOSX
203
204 } } // namespace v8::base
205