Line data Source code
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 :
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 :
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 : void Semaphore::Signal() {
38 : kern_return_t result = semaphore_signal(native_handle_);
39 : DCHECK_EQ(KERN_SUCCESS, result);
40 : USE(result);
41 : }
42 :
43 :
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 :
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 736581 : Semaphore::Semaphore(int count) {
76 : DCHECK_GE(count, 0);
77 736581 : int result = sem_init(&native_handle_, 0, count);
78 : DCHECK_EQ(0, result);
79 : USE(result);
80 736582 : }
81 :
82 :
83 1471959 : Semaphore::~Semaphore() {
84 735978 : int result = sem_destroy(&native_handle_);
85 : DCHECK_EQ(0, result);
86 : USE(result);
87 735981 : }
88 :
89 1233216 : void Semaphore::Signal() {
90 1233216 : 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 1232788 : if (result != 0) {
95 0 : FATAL("Error when signaling semaphore, errno: %d", errno);
96 : }
97 1232788 : }
98 :
99 :
100 1227265 : void Semaphore::Wait() {
101 : while (true) {
102 1227271 : int result = sem_wait(&native_handle_);
103 1228381 : if (result == 0) return; // Semaphore was signalled.
104 : // Signal caused spurious wakeup.
105 : DCHECK_EQ(-1, result);
106 : DCHECK_EQ(EINTR, errno);
107 : }
108 : }
109 :
110 :
111 215 : bool Semaphore::WaitFor(const TimeDelta& rel_time) {
112 : // Compute the time for end of timeout.
113 430 : const Time time = Time::NowFromSystemTime() + rel_time;
114 215 : const struct timespec ts = time.ToTimespec();
115 :
116 : // Wait for semaphore signalled or timeout.
117 : while (true) {
118 215 : int result = sem_timedwait(&native_handle_, &ts);
119 215 : if (result == 0) return true; // Semaphore was signalled.
120 : #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
121 : if (result > 0) {
122 : // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
123 : errno = result;
124 : result = -1;
125 : }
126 : #endif
127 206 : if (result == -1 && errno == ETIMEDOUT) {
128 : // Timed out while waiting for semaphore.
129 : return false;
130 : }
131 : // Signal caused spurious wakeup.
132 : DCHECK_EQ(-1, result);
133 : DCHECK_EQ(EINTR, errno);
134 : }
135 : }
136 :
137 : #elif V8_OS_WIN
138 :
139 : Semaphore::Semaphore(int count) {
140 : DCHECK_GE(count, 0);
141 : native_handle_ = ::CreateSemaphoreA(nullptr, count, 0x7FFFFFFF, nullptr);
142 : DCHECK_NOT_NULL(native_handle_);
143 : }
144 :
145 :
146 : Semaphore::~Semaphore() {
147 : BOOL result = CloseHandle(native_handle_);
148 : DCHECK(result);
149 : USE(result);
150 : }
151 :
152 : void Semaphore::Signal() {
153 : LONG dummy;
154 : BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
155 : DCHECK(result);
156 : USE(result);
157 : }
158 :
159 :
160 : void Semaphore::Wait() {
161 : DWORD result = WaitForSingleObject(native_handle_, INFINITE);
162 : DCHECK(result == WAIT_OBJECT_0);
163 : USE(result);
164 : }
165 :
166 :
167 : bool Semaphore::WaitFor(const TimeDelta& rel_time) {
168 : TimeTicks now = TimeTicks::Now();
169 : TimeTicks end = now + rel_time;
170 : while (true) {
171 : int64_t msec = (end - now).InMilliseconds();
172 : if (msec >= static_cast<int64_t>(INFINITE)) {
173 : DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
174 : if (result == WAIT_OBJECT_0) {
175 : return true;
176 : }
177 : DCHECK(result == WAIT_TIMEOUT);
178 : now = TimeTicks::Now();
179 : } else {
180 : DWORD result = WaitForSingleObject(
181 : native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
182 : if (result == WAIT_TIMEOUT) {
183 : return false;
184 : }
185 : DCHECK(result == WAIT_OBJECT_0);
186 : return true;
187 : }
188 : }
189 : }
190 :
191 : #endif // V8_OS_MACOSX
192 :
193 : } // namespace base
194 : } // namespace v8
|