semaphore.cc revision 13e2dadd00298019ed862f2b2fc5068bba730bcf
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 // The sem_init() does not check for alignment of the native handle. 77 // Unaligned native handle can later cause a failure in semaphore signal. 78 // Check the alignment here to catch the failure earlier. 79 // Context: crbug.com/605349. 80#if V8_OS_AIX 81 // On aix sem_t is of type int 82 const uintptr_t kSemaphoreAlignmentMask = sizeof(int) - 1; 83#else 84 const uintptr_t kSemaphoreAlignmentMask = sizeof(void*) - 1; 85#endif 86 CHECK_EQ( 87 0, reinterpret_cast<uintptr_t>(&native_handle_) & 88 kSemaphoreAlignmentMask); 89 DCHECK(count >= 0); 90 int result = sem_init(&native_handle_, 0, count); 91 DCHECK_EQ(0, result); 92 USE(result); 93} 94 95 96Semaphore::~Semaphore() { 97 int result = sem_destroy(&native_handle_); 98 DCHECK_EQ(0, result); 99 USE(result); 100} 101 102void Semaphore::Signal() { 103 int result = sem_post(&native_handle_); 104 // This check may fail with <libc-2.21, which we use on the try bots, if the 105 // semaphore is destroyed while sem_post is still executed. A work around is 106 // to extend the lifetime of the semaphore. 107 CHECK_EQ(0, result); 108} 109 110 111void Semaphore::Wait() { 112 while (true) { 113 int result = sem_wait(&native_handle_); 114 if (result == 0) return; // Semaphore was signalled. 115 // Signal caused spurious wakeup. 116 DCHECK_EQ(-1, result); 117 DCHECK_EQ(EINTR, errno); 118 } 119} 120 121 122bool Semaphore::WaitFor(const TimeDelta& rel_time) { 123#if V8_OS_NACL 124 // PNaCL doesn't support sem_timedwait, do ugly busy waiting. 125 ElapsedTimer timer; 126 timer.Start(); 127 do { 128 int result = sem_trywait(&native_handle_); 129 if (result == 0) return true; 130 DCHECK(errno == EAGAIN || errno == EINTR); 131 } while (!timer.HasExpired(rel_time)); 132 return false; 133#else 134 // Compute the time for end of timeout. 135 const Time time = Time::NowFromSystemTime() + rel_time; 136 const struct timespec ts = time.ToTimespec(); 137 138 // Wait for semaphore signalled or timeout. 139 while (true) { 140 int result = sem_timedwait(&native_handle_, &ts); 141 if (result == 0) return true; // Semaphore was signalled. 142#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) 143 if (result > 0) { 144 // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1. 145 errno = result; 146 result = -1; 147 } 148#endif 149 if (result == -1 && errno == ETIMEDOUT) { 150 // Timed out while waiting for semaphore. 151 return false; 152 } 153 // Signal caused spurious wakeup. 154 DCHECK_EQ(-1, result); 155 DCHECK_EQ(EINTR, errno); 156 } 157#endif 158} 159 160#elif V8_OS_WIN 161 162Semaphore::Semaphore(int count) { 163 DCHECK(count >= 0); 164 native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL); 165 DCHECK(native_handle_ != NULL); 166} 167 168 169Semaphore::~Semaphore() { 170 BOOL result = CloseHandle(native_handle_); 171 DCHECK(result); 172 USE(result); 173} 174 175void Semaphore::Signal() { 176 LONG dummy; 177 BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy); 178 DCHECK(result); 179 USE(result); 180} 181 182 183void Semaphore::Wait() { 184 DWORD result = WaitForSingleObject(native_handle_, INFINITE); 185 DCHECK(result == WAIT_OBJECT_0); 186 USE(result); 187} 188 189 190bool Semaphore::WaitFor(const TimeDelta& rel_time) { 191 TimeTicks now = TimeTicks::Now(); 192 TimeTicks end = now + rel_time; 193 while (true) { 194 int64_t msec = (end - now).InMilliseconds(); 195 if (msec >= static_cast<int64_t>(INFINITE)) { 196 DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1); 197 if (result == WAIT_OBJECT_0) { 198 return true; 199 } 200 DCHECK(result == WAIT_TIMEOUT); 201 now = TimeTicks::Now(); 202 } else { 203 DWORD result = WaitForSingleObject( 204 native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec)); 205 if (result == WAIT_TIMEOUT) { 206 return false; 207 } 208 DCHECK(result == WAIT_OBJECT_0); 209 return true; 210 } 211 } 212} 213 214#endif // V8_OS_MACOSX 215 216} // namespace base 217} // namespace v8 218