• 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 
37 
Signal()38 void Semaphore::Signal() {
39   kern_return_t result = semaphore_signal(native_handle_);
40   DCHECK_EQ(KERN_SUCCESS, result);
41   USE(result);
42 }
43 
44 
Wait()45 void Semaphore::Wait() {
46   while (true) {
47     kern_return_t result = semaphore_wait(native_handle_);
48     if (result == KERN_SUCCESS) return;  // Semaphore was signalled.
49     DCHECK_EQ(KERN_ABORTED, result);
50   }
51 }
52 
53 
WaitFor(const TimeDelta & rel_time)54 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
55   TimeTicks now = TimeTicks::Now();
56   TimeTicks end = now + rel_time;
57   while (true) {
58     mach_timespec_t ts;
59     if (now >= end) {
60       // Return immediately if semaphore was not signalled.
61       ts.tv_sec = 0;
62       ts.tv_nsec = 0;
63     } else {
64       ts = (end - now).ToMachTimespec();
65     }
66     kern_return_t result = semaphore_timedwait(native_handle_, ts);
67     if (result == KERN_SUCCESS) return true;  // Semaphore was signalled.
68     if (result == KERN_OPERATION_TIMED_OUT) return false;  // Timeout.
69     DCHECK_EQ(KERN_ABORTED, result);
70     now = TimeTicks::Now();
71   }
72 }
73 
74 #elif V8_OS_POSIX
75 
76 Semaphore::Semaphore(int count) {
77   DCHECK(count >= 0);
78   int result = sem_init(&native_handle_, 0, count);
79   DCHECK_EQ(0, result);
80   USE(result);
81 }
82 
83 
84 Semaphore::~Semaphore() {
85   int result = sem_destroy(&native_handle_);
86   DCHECK_EQ(0, result);
87   USE(result);
88 }
89 
90 
91 void Semaphore::Signal() {
92   int result = sem_post(&native_handle_);
93   DCHECK_EQ(0, result);
94   USE(result);
95 }
96 
97 
98 void Semaphore::Wait() {
99   while (true) {
100     int result = sem_wait(&native_handle_);
101     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 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
110 #if V8_OS_NACL
111   // PNaCL doesn't support sem_timedwait, do ugly busy waiting.
112   ElapsedTimer timer;
113   timer.Start();
114   do {
115     int result = sem_trywait(&native_handle_);
116     if (result == 0) return true;
117     DCHECK(errno == EAGAIN || errno == EINTR);
118   } while (!timer.HasExpired(rel_time));
119   return false;
120 #else
121   // Compute the time for end of timeout.
122   const Time time = Time::NowFromSystemTime() + rel_time;
123   const struct timespec ts = time.ToTimespec();
124 
125   // Wait for semaphore signalled or timeout.
126   while (true) {
127     int result = sem_timedwait(&native_handle_, &ts);
128     if (result == 0) return true;  // Semaphore was signalled.
129 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
130     if (result > 0) {
131       // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
132       errno = result;
133       result = -1;
134     }
135 #endif
136     if (result == -1 && errno == ETIMEDOUT) {
137       // Timed out while waiting for semaphore.
138       return false;
139     }
140     // Signal caused spurious wakeup.
141     DCHECK_EQ(-1, result);
142     DCHECK_EQ(EINTR, errno);
143   }
144 #endif
145 }
146 
147 #elif V8_OS_WIN
148 
149 Semaphore::Semaphore(int count) {
150   DCHECK(count >= 0);
151   native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
152   DCHECK(native_handle_ != NULL);
153 }
154 
155 
156 Semaphore::~Semaphore() {
157   BOOL result = CloseHandle(native_handle_);
158   DCHECK(result);
159   USE(result);
160 }
161 
162 
163 void Semaphore::Signal() {
164   LONG dummy;
165   BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
166   DCHECK(result);
167   USE(result);
168 }
169 
170 
171 void Semaphore::Wait() {
172   DWORD result = WaitForSingleObject(native_handle_, INFINITE);
173   DCHECK(result == WAIT_OBJECT_0);
174   USE(result);
175 }
176 
177 
178 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
179   TimeTicks now = TimeTicks::Now();
180   TimeTicks end = now + rel_time;
181   while (true) {
182     int64_t msec = (end - now).InMilliseconds();
183     if (msec >= static_cast<int64_t>(INFINITE)) {
184       DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
185       if (result == WAIT_OBJECT_0) {
186         return true;
187       }
188       DCHECK(result == WAIT_TIMEOUT);
189       now = TimeTicks::Now();
190     } else {
191       DWORD result = WaitForSingleObject(
192           native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
193       if (result == WAIT_TIMEOUT) {
194         return false;
195       }
196       DCHECK(result == WAIT_OBJECT_0);
197       return true;
198     }
199   }
200 }
201 
202 #endif  // V8_OS_MACOSX
203 
204 } }  // namespace v8::base
205