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 693144 : Semaphore::Semaphore(int count) {
76 : DCHECK(count >= 0);
77 693144 : int result = sem_init(&native_handle_, 0, count);
78 : DCHECK_EQ(0, result);
79 : USE(result);
80 693146 : }
81 :
82 :
83 546738 : Semaphore::~Semaphore() {
84 546738 : int result = sem_destroy(&native_handle_);
85 : DCHECK_EQ(0, result);
86 : USE(result);
87 546738 : }
88 :
89 2095835 : void Semaphore::Signal() {
90 2095835 : 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 2096273 : CHECK_EQ(0, result);
95 2096273 : }
96 :
97 :
98 1980377 : void Semaphore::Wait() {
99 : while (true) {
100 1980384 : int result = sem_wait(&native_handle_);
101 1975064 : 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 213 : bool Semaphore::WaitFor(const TimeDelta& rel_time) {
110 : // Compute the time for end of timeout.
111 426 : const Time time = Time::NowFromSystemTime() + rel_time;
112 213 : const struct timespec ts = time.ToTimespec();
113 :
114 : // Wait for semaphore signalled or timeout.
115 : while (true) {
116 213 : int result = sem_timedwait(&native_handle_, &ts);
117 213 : if (result == 0) return true; // Semaphore was signalled.
118 : #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
119 : if (result > 0) {
120 : // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
121 : errno = result;
122 : result = -1;
123 : }
124 : #endif
125 204 : if (result == -1 && errno == ETIMEDOUT) {
126 : // Timed out while waiting for semaphore.
127 : return false;
128 : }
129 : // Signal caused spurious wakeup.
130 : DCHECK_EQ(-1, result);
131 : DCHECK_EQ(EINTR, errno);
132 : }
133 : }
134 :
135 : #elif V8_OS_WIN
136 :
137 : Semaphore::Semaphore(int count) {
138 : DCHECK(count >= 0);
139 : native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
140 : DCHECK(native_handle_ != NULL);
141 : }
142 :
143 :
144 : Semaphore::~Semaphore() {
145 : BOOL result = CloseHandle(native_handle_);
146 : DCHECK(result);
147 : USE(result);
148 : }
149 :
150 : void Semaphore::Signal() {
151 : LONG dummy;
152 : BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
153 : DCHECK(result);
154 : USE(result);
155 : }
156 :
157 :
158 : void Semaphore::Wait() {
159 : DWORD result = WaitForSingleObject(native_handle_, INFINITE);
160 : DCHECK(result == WAIT_OBJECT_0);
161 : USE(result);
162 : }
163 :
164 :
165 : bool Semaphore::WaitFor(const TimeDelta& rel_time) {
166 : TimeTicks now = TimeTicks::Now();
167 : TimeTicks end = now + rel_time;
168 : while (true) {
169 : int64_t msec = (end - now).InMilliseconds();
170 : if (msec >= static_cast<int64_t>(INFINITE)) {
171 : DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
172 : if (result == WAIT_OBJECT_0) {
173 : return true;
174 : }
175 : DCHECK(result == WAIT_TIMEOUT);
176 : now = TimeTicks::Now();
177 : } else {
178 : DWORD result = WaitForSingleObject(
179 : native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
180 : if (result == WAIT_TIMEOUT) {
181 : return false;
182 : }
183 : DCHECK(result == WAIT_OBJECT_0);
184 : return true;
185 : }
186 : }
187 : }
188 :
189 : #endif // V8_OS_MACOSX
190 :
191 : } // namespace base
192 : } // namespace v8
|