Home | History | Annotate | Download | only in platform
      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 void Semaphore::Signal() {
     38   kern_return_t result = semaphore_signal(native_handle_);
     39   DCHECK_EQ(KERN_SUCCESS, result);
     40   USE(result);
     41 }
     42 
     43 
     44 void 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 
     53 bool 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 
     75 Semaphore::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 
     96 Semaphore::~Semaphore() {
     97   int result = sem_destroy(&native_handle_);
     98   DCHECK_EQ(0, result);
     99   USE(result);
    100 }
    101 
    102 void 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 
    111 void 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 
    122 bool 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 
    162 Semaphore::Semaphore(int count) {
    163   DCHECK(count >= 0);
    164   native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
    165   DCHECK(native_handle_ != NULL);
    166 }
    167 
    168 
    169 Semaphore::~Semaphore() {
    170   BOOL result = CloseHandle(native_handle_);
    171   DCHECK(result);
    172   USE(result);
    173 }
    174 
    175 void Semaphore::Signal() {
    176   LONG dummy;
    177   BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
    178   DCHECK(result);
    179   USE(result);
    180 }
    181 
    182 
    183 void Semaphore::Wait() {
    184   DWORD result = WaitForSingleObject(native_handle_, INFINITE);
    185   DCHECK(result == WAIT_OBJECT_0);
    186   USE(result);
    187 }
    188 
    189 
    190 bool 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