• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Semaphore(int count)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 
~Semaphore()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 
Signal()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 
Wait()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 
WaitFor(const TimeDelta & rel_time)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 Semaphore::Semaphore(int count) {
76   // The sem_init() does not check for alignment of the native handle.
77   // Unaligned native handle can later cause a failure in semaphore signal.
78   // Check the alignment here to catch the failure earlier.
79   // Context: crbug.com/605349.
80 #if V8_OS_AIX
81   // On aix sem_t is of type int
82   const uintptr_t kSemaphoreAlignmentMask = sizeof(int) - 1;
83 #else
84   const uintptr_t kSemaphoreAlignmentMask = sizeof(void*) - 1;
85 #endif
86   CHECK_EQ(
87       0, reinterpret_cast<uintptr_t>(&native_handle_) &
88       kSemaphoreAlignmentMask);
89   DCHECK(count >= 0);
90   int result = sem_init(&native_handle_, 0, count);
91   DCHECK_EQ(0, result);
92   USE(result);
93 }
94 
95 
96 Semaphore::~Semaphore() {
97   int result = sem_destroy(&native_handle_);
98   DCHECK_EQ(0, result);
99   USE(result);
100 }
101 
102 void Semaphore::Signal() {
103   int result = sem_post(&native_handle_);
104   // This check may fail with <libc-2.21, which we use on the try bots, if the
105   // semaphore is destroyed while sem_post is still executed. A work around is
106   // to extend the lifetime of the semaphore.
107   CHECK_EQ(0, result);
108 }
109 
110 
111 void Semaphore::Wait() {
112   while (true) {
113     int result = sem_wait(&native_handle_);
114     if (result == 0) return;  // Semaphore was signalled.
115     // Signal caused spurious wakeup.
116     DCHECK_EQ(-1, result);
117     DCHECK_EQ(EINTR, errno);
118   }
119 }
120 
121 
122 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
123 #if V8_OS_NACL
124   // PNaCL doesn't support sem_timedwait, do ugly busy waiting.
125   ElapsedTimer timer;
126   timer.Start();
127   do {
128     int result = sem_trywait(&native_handle_);
129     if (result == 0) return true;
130     DCHECK(errno == EAGAIN || errno == EINTR);
131   } while (!timer.HasExpired(rel_time));
132   return false;
133 #else
134   // Compute the time for end of timeout.
135   const Time time = Time::NowFromSystemTime() + rel_time;
136   const struct timespec ts = time.ToTimespec();
137 
138   // Wait for semaphore signalled or timeout.
139   while (true) {
140     int result = sem_timedwait(&native_handle_, &ts);
141     if (result == 0) return true;  // Semaphore was signalled.
142 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
143     if (result > 0) {
144       // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
145       errno = result;
146       result = -1;
147     }
148 #endif
149     if (result == -1 && errno == ETIMEDOUT) {
150       // Timed out while waiting for semaphore.
151       return false;
152     }
153     // Signal caused spurious wakeup.
154     DCHECK_EQ(-1, result);
155     DCHECK_EQ(EINTR, errno);
156   }
157 #endif
158 }
159 
160 #elif V8_OS_WIN
161 
162 Semaphore::Semaphore(int count) {
163   DCHECK(count >= 0);
164   native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
165   DCHECK(native_handle_ != NULL);
166 }
167 
168 
169 Semaphore::~Semaphore() {
170   BOOL result = CloseHandle(native_handle_);
171   DCHECK(result);
172   USE(result);
173 }
174 
175 void Semaphore::Signal() {
176   LONG dummy;
177   BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
178   DCHECK(result);
179   USE(result);
180 }
181 
182 
183 void Semaphore::Wait() {
184   DWORD result = WaitForSingleObject(native_handle_, INFINITE);
185   DCHECK(result == WAIT_OBJECT_0);
186   USE(result);
187 }
188 
189 
190 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
191   TimeTicks now = TimeTicks::Now();
192   TimeTicks end = now + rel_time;
193   while (true) {
194     int64_t msec = (end - now).InMilliseconds();
195     if (msec >= static_cast<int64_t>(INFINITE)) {
196       DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
197       if (result == WAIT_OBJECT_0) {
198         return true;
199       }
200       DCHECK(result == WAIT_TIMEOUT);
201       now = TimeTicks::Now();
202     } else {
203       DWORD result = WaitForSingleObject(
204           native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
205       if (result == WAIT_TIMEOUT) {
206         return false;
207       }
208       DCHECK(result == WAIT_OBJECT_0);
209       return true;
210     }
211   }
212 }
213 
214 #endif  // V8_OS_MACOSX
215 
216 }  // namespace base
217 }  // namespace v8
218