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