• 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_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