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