Home | History | Annotate | Download | only in platform
      1 // Copyright 2013 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "platform/semaphore.h"
     29 
     30 #if V8_OS_MACOSX
     31 #include <mach/mach_init.h>
     32 #include <mach/task.h>
     33 #endif
     34 
     35 #include <cerrno>
     36 
     37 #include "checks.h"
     38 #include "platform/time.h"
     39 
     40 namespace v8 {
     41 namespace internal {
     42 
     43 #if V8_OS_MACOSX
     44 
     45 Semaphore::Semaphore(int count) {
     46   kern_return_t result = semaphore_create(
     47       mach_task_self(), &native_handle_, SYNC_POLICY_FIFO, count);
     48   ASSERT_EQ(KERN_SUCCESS, result);
     49   USE(result);
     50 }
     51 
     52 
     53 Semaphore::~Semaphore() {
     54   kern_return_t result = semaphore_destroy(mach_task_self(), native_handle_);
     55   ASSERT_EQ(KERN_SUCCESS, result);
     56   USE(result);
     57 }
     58 
     59 
     60 void Semaphore::Signal() {
     61   kern_return_t result = semaphore_signal(native_handle_);
     62   ASSERT_EQ(KERN_SUCCESS, result);
     63   USE(result);
     64 }
     65 
     66 
     67 void Semaphore::Wait() {
     68   while (true) {
     69     kern_return_t result = semaphore_wait(native_handle_);
     70     if (result == KERN_SUCCESS) return;  // Semaphore was signalled.
     71     ASSERT_EQ(KERN_ABORTED, result);
     72   }
     73 }
     74 
     75 
     76 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
     77   TimeTicks now = TimeTicks::Now();
     78   TimeTicks end = now + rel_time;
     79   while (true) {
     80     mach_timespec_t ts;
     81     if (now >= end) {
     82       // Return immediately if semaphore was not signalled.
     83       ts.tv_sec = 0;
     84       ts.tv_nsec = 0;
     85     } else {
     86       ts = (end - now).ToMachTimespec();
     87     }
     88     kern_return_t result = semaphore_timedwait(native_handle_, ts);
     89     if (result == KERN_SUCCESS) return true;  // Semaphore was signalled.
     90     if (result == KERN_OPERATION_TIMED_OUT) return false;  // Timeout.
     91     ASSERT_EQ(KERN_ABORTED, result);
     92     now = TimeTicks::Now();
     93   }
     94 }
     95 
     96 #elif V8_OS_POSIX
     97 
     98 Semaphore::Semaphore(int count) {
     99   ASSERT(count >= 0);
    100   int result = sem_init(&native_handle_, 0, count);
    101   ASSERT_EQ(0, result);
    102   USE(result);
    103 }
    104 
    105 
    106 Semaphore::~Semaphore() {
    107   int result = sem_destroy(&native_handle_);
    108   ASSERT_EQ(0, result);
    109   USE(result);
    110 }
    111 
    112 
    113 void Semaphore::Signal() {
    114   int result = sem_post(&native_handle_);
    115   ASSERT_EQ(0, result);
    116   USE(result);
    117 }
    118 
    119 
    120 void Semaphore::Wait() {
    121   while (true) {
    122     int result = sem_wait(&native_handle_);
    123     if (result == 0) return;  // Semaphore was signalled.
    124     // Signal caused spurious wakeup.
    125     ASSERT_EQ(-1, result);
    126     ASSERT_EQ(EINTR, errno);
    127   }
    128 }
    129 
    130 
    131 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
    132   // Compute the time for end of timeout.
    133   const Time time = Time::NowFromSystemTime() + rel_time;
    134   const struct timespec ts = time.ToTimespec();
    135 
    136   // Wait for semaphore signalled or timeout.
    137   while (true) {
    138     int result = sem_timedwait(&native_handle_, &ts);
    139     if (result == 0) return true;  // Semaphore was signalled.
    140 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
    141     if (result > 0) {
    142       // sem_timedwait in glibc prior to 2.3.4 returns the errno instead of -1.
    143       errno = result;
    144       result = -1;
    145     }
    146 #endif
    147     if (result == -1 && errno == ETIMEDOUT) {
    148       // Timed out while waiting for semaphore.
    149       return false;
    150     }
    151     // Signal caused spurious wakeup.
    152     ASSERT_EQ(-1, result);
    153     ASSERT_EQ(EINTR, errno);
    154   }
    155 }
    156 
    157 #elif V8_OS_WIN
    158 
    159 Semaphore::Semaphore(int count) {
    160   ASSERT(count >= 0);
    161   native_handle_ = ::CreateSemaphoreA(NULL, count, 0x7fffffff, NULL);
    162   ASSERT(native_handle_ != NULL);
    163 }
    164 
    165 
    166 Semaphore::~Semaphore() {
    167   BOOL result = CloseHandle(native_handle_);
    168   ASSERT(result);
    169   USE(result);
    170 }
    171 
    172 
    173 void Semaphore::Signal() {
    174   LONG dummy;
    175   BOOL result = ReleaseSemaphore(native_handle_, 1, &dummy);
    176   ASSERT(result);
    177   USE(result);
    178 }
    179 
    180 
    181 void Semaphore::Wait() {
    182   DWORD result = WaitForSingleObject(native_handle_, INFINITE);
    183   ASSERT(result == WAIT_OBJECT_0);
    184   USE(result);
    185 }
    186 
    187 
    188 bool Semaphore::WaitFor(const TimeDelta& rel_time) {
    189   TimeTicks now = TimeTicks::Now();
    190   TimeTicks end = now + rel_time;
    191   while (true) {
    192     int64_t msec = (end - now).InMilliseconds();
    193     if (msec >= static_cast<int64_t>(INFINITE)) {
    194       DWORD result = WaitForSingleObject(native_handle_, INFINITE - 1);
    195       if (result == WAIT_OBJECT_0) {
    196         return true;
    197       }
    198       ASSERT(result == WAIT_TIMEOUT);
    199       now = TimeTicks::Now();
    200     } else {
    201       DWORD result = WaitForSingleObject(
    202           native_handle_, (msec < 0) ? 0 : static_cast<DWORD>(msec));
    203       if (result == WAIT_TIMEOUT) {
    204         return false;
    205       }
    206       ASSERT(result == WAIT_OBJECT_0);
    207       return true;
    208     }
    209   }
    210 }
    211 
    212 #endif  // V8_OS_MACOSX
    213 
    214 } }  // namespace v8::internal
    215