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