• 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 <dispatch/dispatch.h>
9 #endif
10 
11 #include <errno.h>
12 
13 #include "src/base/logging.h"
14 #include "src/base/platform/elapsed-timer.h"
15 #include "src/base/platform/time.h"
16 
17 namespace v8 {
18 namespace base {
19 
20 #if V8_OS_MACOSX
21 
Semaphore(int count)22 Semaphore::Semaphore(int count) {
23   native_handle_ = dispatch_semaphore_create(count);
24   DCHECK(native_handle_);
25 }
26 
~Semaphore()27 Semaphore::~Semaphore() { dispatch_release(native_handle_); }
28 
Signal()29 void Semaphore::Signal() { dispatch_semaphore_signal(native_handle_); }
30 
Wait()31 void Semaphore::Wait() {
32   dispatch_semaphore_wait(native_handle_, DISPATCH_TIME_FOREVER);
33 }
34 
35 
WaitFor(const TimeDelta & rel_time)36 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
37   dispatch_time_t timeout =
38       dispatch_time(DISPATCH_TIME_NOW, rel_time.InNanoseconds());
39   return dispatch_semaphore_wait(native_handle_, timeout) == 0;
40 }
41 
42 #elif V8_OS_POSIX
43 
44 Semaphore::Semaphore(int count) {
45   DCHECK_GE(count, 0);
46   int result = sem_init(&native_handle_, 0, count);
47   DCHECK_EQ(0, result);
48   USE(result);
49 }
50 
51 
52 Semaphore::~Semaphore() {
53   int result = sem_destroy(&native_handle_);
54   DCHECK_EQ(0, result);
55   USE(result);
56 }
57 
58 void Semaphore::Signal() {
59   int result = sem_post(&native_handle_);
60   // This check may fail with <libc-2.21, which we use on the try bots, if the
61   // semaphore is destroyed while sem_post is still executed. A work around is
62   // to extend the lifetime of the semaphore.
63   if (result != 0) {
64     FATAL("Error when signaling semaphore, errno: %d", errno);
65   }
66 }
67 
68 
69 void Semaphore::Wait() {
70   while (true) {
71     int result = sem_wait(&native_handle_);
72     if (result == 0) return;  // Semaphore was signalled.
73     // Signal caused spurious wakeup.
74     DCHECK_EQ(-1, result);
75     DCHECK_EQ(EINTR, errno);
76   }
77 }
78 
79 
80 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
81   // Compute the time for end of timeout.
82   const Time time = Time::NowFromSystemTime() + rel_time;
83   const struct timespec ts = time.ToTimespec();
84 
85   // Wait for semaphore signalled or timeout.
86   while (true) {
87     int result = sem_timedwait(&native_handle_, &ts);
88     if (result == 0) return true;  // Semaphore was signalled.
89 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
90     if (result > 0) {
91       // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
92       errno = result;
93       result = -1;
94     }
95 #endif
96     if (result == -1 && errno == ETIMEDOUT) {
97       // Timed out while waiting for semaphore.
98       return false;
99     }
100     // Signal caused spurious wakeup.
101     DCHECK_EQ(-1, result);
102     DCHECK_EQ(EINTR, errno);
103   }
104 }
105 
106 #elif V8_OS_WIN
107 
108 Semaphore::Semaphore(int count) {
109   DCHECK_GE(count, 0);
110   native_handle_ = ::CreateSemaphoreA(nullptr, count, 0x7FFFFFFF, nullptr);
111   DCHECK_NOT_NULL(native_handle_);
112 }
113 
114 
115 Semaphore::~Semaphore() {
116   BOOL result = CloseHandle(native_handle_);
117   DCHECK(result);
118   USE(result);
119 }
120 
121 void Semaphore::Signal() {
122   LONG dummy;
123   BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
124   DCHECK(result);
125   USE(result);
126 }
127 
128 
129 void Semaphore::Wait() {
130   DWORD result = WaitForSingleObject(native_handle_, INFINITE);
131   DCHECK(result == WAIT_OBJECT_0);
132   USE(result);
133 }
134 
135 
136 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
137   TimeTicks now = TimeTicks::Now();
138   TimeTicks end = now + rel_time;
139   while (true) {
140     int64_t msec = (end - now).InMilliseconds();
141     if (msec >= static_cast<int64_t>(INFINITE)) {
142       DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
143       if (result == WAIT_OBJECT_0) {
144         return true;
145       }
146       DCHECK(result == WAIT_TIMEOUT);
147       now = TimeTicks::Now();
148     } else {
149       DWORD result = WaitForSingleObject(
150           native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
151       if (result == WAIT_TIMEOUT) {
152         return false;
153       }
154       DCHECK(result == WAIT_OBJECT_0);
155       return true;
156     }
157   }
158 }
159 
160 #elif V8_OS_STARBOARD
161 
162 Semaphore::Semaphore(int count) : native_handle_(count) { DCHECK_GE(count, 0); }
163 
164 Semaphore::~Semaphore() {}
165 
166 void Semaphore::Signal() { native_handle_.Put(); }
167 
168 void Semaphore::Wait() { native_handle_.Take(); }
169 
170 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
171   SbTime microseconds = rel_time.InMicroseconds();
172   return native_handle_.TakeWait(microseconds);
173 }
174 
175 #endif  // V8_OS_MACOSX
176 
177 }  // namespace base
178 }  // namespace v8
179