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   DCHECK(count >= 0);
     77   int result = sem_init(&native_handle_, 0, count);
     78   DCHECK_EQ(0, result);
     79   USE(result);
     80 }
     81 
     82 
     83 Semaphore::~Semaphore() {
     84   int result = sem_destroy(&native_handle_);
     85   DCHECK_EQ(0, result);
     86   USE(result);
     87 }
     88 
     89 void 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 
     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   // 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 
    137 Semaphore::Semaphore(int count) {
    138   DCHECK(count >= 0);
    139   native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
    140   DCHECK(native_handle_ != NULL);
    141 }
    142 
    143 
    144 Semaphore::~Semaphore() {
    145   BOOL result = CloseHandle(native_handle_);
    146   DCHECK(result);
    147   USE(result);
    148 }
    149 
    150 void Semaphore::Signal() {
    151   LONG dummy;
    152   BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
    153   DCHECK(result);
    154   USE(result);
    155 }
    156 
    157 
    158 void Semaphore::Wait() {
    159   DWORD result = WaitForSingleObject(native_handle_, INFINITE);
    160   DCHECK(result == WAIT_OBJECT_0);
    161   USE(result);
    162 }
    163 
    164 
    165 bool 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