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 18namespace v8 { 19namespace base { 20 21#if V8_OS_MACOSX 22 23Semaphore::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 31Semaphore::~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 38void Semaphore::Signal() { 39 kern_return_t result = semaphore_signal(native_handle_); 40 DCHECK_EQ(KERN_SUCCESS, result); 41 USE(result); 42} 43 44 45void 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 54bool 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 76Semaphore::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 84Semaphore::~Semaphore() { 85 int result = sem_destroy(&native_handle_); 86 DCHECK_EQ(0, result); 87 USE(result); 88} 89 90 91void Semaphore::Signal() { 92 int result = sem_post(&native_handle_); 93 DCHECK_EQ(0, result); 94 USE(result); 95} 96 97 98void 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 109bool 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 149Semaphore::Semaphore(int count) { 150 DCHECK(count >= 0); 151 native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL); 152 DCHECK(native_handle_ != NULL); 153} 154 155 156Semaphore::~Semaphore() { 157 BOOL result = CloseHandle(native_handle_); 158 DCHECK(result); 159 USE(result); 160} 161 162 163void Semaphore::Signal() { 164 LONG dummy; 165 BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy); 166 DCHECK(result); 167 USE(result); 168} 169 170 171void Semaphore::Wait() { 172 DWORD result = WaitForSingleObject(native_handle_, INFINITE); 173 DCHECK(result == WAIT_OBJECT_0); 174 USE(result); 175} 176 177 178bool 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