blob: 9e7b59a1d2cc09f16c3ef5af043fec39a67d07f1 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
18namespace v8 {
19namespace base {
20
21#if V8_OS_MACOSX
22
23Semaphore::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
31Semaphore::~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
38void Semaphore::Signal() {
39 kern_return_t result = semaphore_signal(native_handle_);
40 DCHECK_EQ(KERN_SUCCESS, result);
41 USE(result);
42}
43
44
45void 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
54bool 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
76Semaphore::Semaphore(int count) {
77 DCHECK(count >= 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078#if V8_LIBC_GLIBC
79 // sem_init in glibc prior to 2.1 does not zero out semaphores.
80 memset(&native_handle_, 0, sizeof(native_handle_));
81#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082 int result = sem_init(&native_handle_, 0, count);
83 DCHECK_EQ(0, result);
84 USE(result);
85}
86
87
88Semaphore::~Semaphore() {
89 int result = sem_destroy(&native_handle_);
90 DCHECK_EQ(0, result);
91 USE(result);
92}
93
94
95void Semaphore::Signal() {
96 int result = sem_post(&native_handle_);
97 DCHECK_EQ(0, result);
98 USE(result);
99}
100
101
102void Semaphore::Wait() {
103 while (true) {
104 int result = sem_wait(&native_handle_);
105 if (result == 0) return; // Semaphore was signalled.
106 // Signal caused spurious wakeup.
107 DCHECK_EQ(-1, result);
108 DCHECK_EQ(EINTR, errno);
109 }
110}
111
112
113bool Semaphore::WaitFor(const TimeDelta& rel_time) {
114#if V8_OS_NACL
115 // PNaCL doesn't support sem_timedwait, do ugly busy waiting.
116 ElapsedTimer timer;
117 timer.Start();
118 do {
119 int result = sem_trywait(&native_handle_);
120 if (result == 0) return true;
121 DCHECK(errno == EAGAIN || errno == EINTR);
122 } while (!timer.HasExpired(rel_time));
123 return false;
124#else
125 // Compute the time for end of timeout.
126 const Time time = Time::NowFromSystemTime() + rel_time;
127 const struct timespec ts = time.ToTimespec();
128
129 // Wait for semaphore signalled or timeout.
130 while (true) {
131 int result = sem_timedwait(&native_handle_, &ts);
132 if (result == 0) return true; // Semaphore was signalled.
133#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
134 if (result > 0) {
135 // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
136 errno = result;
137 result = -1;
138 }
139#endif
140 if (result == -1 && errno == ETIMEDOUT) {
141 // Timed out while waiting for semaphore.
142 return false;
143 }
144 // Signal caused spurious wakeup.
145 DCHECK_EQ(-1, result);
146 DCHECK_EQ(EINTR, errno);
147 }
148#endif
149}
150
151#elif V8_OS_WIN
152
153Semaphore::Semaphore(int count) {
154 DCHECK(count >= 0);
155 native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
156 DCHECK(native_handle_ != NULL);
157}
158
159
160Semaphore::~Semaphore() {
161 BOOL result = CloseHandle(native_handle_);
162 DCHECK(result);
163 USE(result);
164}
165
166
167void Semaphore::Signal() {
168 LONG dummy;
169 BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
170 DCHECK(result);
171 USE(result);
172}
173
174
175void Semaphore::Wait() {
176 DWORD result = WaitForSingleObject(native_handle_, INFINITE);
177 DCHECK(result == WAIT_OBJECT_0);
178 USE(result);
179}
180
181
182bool Semaphore::WaitFor(const TimeDelta& rel_time) {
183 TimeTicks now = TimeTicks::Now();
184 TimeTicks end = now + rel_time;
185 while (true) {
186 int64_t msec = (end - now).InMilliseconds();
187 if (msec >= static_cast<int64_t>(INFINITE)) {
188 DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
189 if (result == WAIT_OBJECT_0) {
190 return true;
191 }
192 DCHECK(result == WAIT_TIMEOUT);
193 now = TimeTicks::Now();
194 } else {
195 DWORD result = WaitForSingleObject(
196 native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
197 if (result == WAIT_TIMEOUT) {
198 return false;
199 }
200 DCHECK(result == WAIT_OBJECT_0);
201 return true;
202 }
203 }
204}
205
206#endif // V8_OS_MACOSX
207
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208} // namespace base
209} // namespace v8