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