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