condition-variable.cc 5.48 KB
Newer Older
1
// Copyright 2013 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/base/platform/condition-variable.h"
6

7 8
#include <errno.h>
#include <time.h>
9

10
#include "src/base/platform/time.h"
11 12

namespace v8 {
13
namespace base {
14 15 16 17

#if V8_OS_POSIX

ConditionVariable::ConditionVariable() {
18
#if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
19
     (V8_OS_LINUX && V8_LIBC_GLIBC))
20 21 22 23
  // On Free/Net/OpenBSD and Linux with glibc we can change the time
  // source for pthread_cond_timedwait() to use the monotonic clock.
  pthread_condattr_t attr;
  int result = pthread_condattr_init(&attr);
24
  DCHECK_EQ(0, result);
25
  result = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
26
  DCHECK_EQ(0, result);
27
  result = pthread_cond_init(&native_handle_, &attr);
28
  DCHECK_EQ(0, result);
29 30
  result = pthread_condattr_destroy(&attr);
#else
31
  int result = pthread_cond_init(&native_handle_, nullptr);
32
#endif
33
  DCHECK_EQ(0, result);
34 35 36 37 38
  USE(result);
}


ConditionVariable::~ConditionVariable() {
39 40 41 42 43
#if defined(V8_OS_MACOSX)
  // This hack is necessary to avoid a fatal pthreads subsystem bug in the
  // Darwin kernel. http://crbug.com/517681.
  {
    Mutex lock;
44
    MutexGuard l(&lock);
45 46 47 48 49 50 51
    struct timespec ts;
    ts.tv_sec = 0;
    ts.tv_nsec = 1;
    pthread_cond_timedwait_relative_np(&native_handle_, &lock.native_handle(),
                                       &ts);
  }
#endif
52
  int result = pthread_cond_destroy(&native_handle_);
53
  DCHECK_EQ(0, result);
54 55 56 57 58 59
  USE(result);
}


void ConditionVariable::NotifyOne() {
  int result = pthread_cond_signal(&native_handle_);
60
  DCHECK_EQ(0, result);
61 62 63 64 65 66
  USE(result);
}


void ConditionVariable::NotifyAll() {
  int result = pthread_cond_broadcast(&native_handle_);
67
  DCHECK_EQ(0, result);
68 69 70 71 72 73 74
  USE(result);
}


void ConditionVariable::Wait(Mutex* mutex) {
  mutex->AssertHeldAndUnmark();
  int result = pthread_cond_wait(&native_handle_, &mutex->native_handle());
75
  DCHECK_EQ(0, result);
76 77 78 79 80 81 82 83 84 85 86 87 88
  USE(result);
  mutex->AssertUnheldAndMark();
}


bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
  struct timespec ts;
  int result;
  mutex->AssertHeldAndUnmark();
#if V8_OS_MACOSX
  // Mac OS X provides pthread_cond_timedwait_relative_np(), which does
  // not depend on the real time clock, which is what you really WANT here!
  ts = rel_time.ToTimespec();
89 90
  DCHECK_GE(ts.tv_sec, 0);
  DCHECK_GE(ts.tv_nsec, 0);
91 92 93
  result = pthread_cond_timedwait_relative_np(
      &native_handle_, &mutex->native_handle(), &ts);
#else
94
#if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
95
     (V8_OS_LINUX && V8_LIBC_GLIBC))
96 97 98
  // On Free/Net/OpenBSD and Linux with glibc we can change the time
  // source for pthread_cond_timedwait() to use the monotonic clock.
  result = clock_gettime(CLOCK_MONOTONIC, &ts);
99
  DCHECK_EQ(0, result);
100 101 102 103 104 105
  Time now = Time::FromTimespec(ts);
#else
  // The timeout argument to pthread_cond_timedwait() is in absolute time.
  Time now = Time::NowFromSystemTime();
#endif
  Time end_time = now + rel_time;
106
  DCHECK_GE(end_time, now);
107 108 109 110 111 112 113 114
  ts = end_time.ToTimespec();
  result = pthread_cond_timedwait(
      &native_handle_, &mutex->native_handle(), &ts);
#endif  // V8_OS_MACOSX
  mutex->AssertUnheldAndMark();
  if (result == ETIMEDOUT) {
    return false;
  }
115
  DCHECK_EQ(0, result);
116 117 118 119 120
  return true;
}

#elif V8_OS_WIN

121 122
ConditionVariable::ConditionVariable() {
  InitializeConditionVariable(&native_handle_);
123 124 125 126 127
}


ConditionVariable::~ConditionVariable() {}

128
void ConditionVariable::NotifyOne() { WakeConditionVariable(&native_handle_); }
129 130

void ConditionVariable::NotifyAll() {
131
  WakeAllConditionVariable(&native_handle_);
132 133 134 135
}


void ConditionVariable::Wait(Mutex* mutex) {
136
  mutex->AssertHeldAndUnmark();
137 138
  SleepConditionVariableSRW(&native_handle_, &mutex->native_handle(), INFINITE,
                            0);
139
  mutex->AssertUnheldAndMark();
140 141 142 143
}


bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
144 145
  int64_t msec = rel_time.InMilliseconds();
  mutex->AssertHeldAndUnmark();
146 147
  BOOL result = SleepConditionVariableSRW(
      &native_handle_, &mutex->native_handle(), static_cast<DWORD>(msec), 0);
148 149 150 151 152 153 154 155
#ifdef DEBUG
  if (!result) {
    // On failure, we only expect the CV to timeout. Any other error value means
    // that we've unexpectedly woken up.
    // Note that WAIT_TIMEOUT != ERROR_TIMEOUT. WAIT_TIMEOUT is used with the
    // WaitFor* family of functions as a direct return value. ERROR_TIMEOUT is
    // used with GetLastError().
    DCHECK_EQ(static_cast<DWORD>(ERROR_TIMEOUT), GetLastError());
156
  }
157 158 159
#endif
  mutex->AssertUnheldAndMark();
  return result != 0;
160 161
}

johnx's avatar
johnx committed
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
#elif V8_OS_STARBOARD

ConditionVariable::ConditionVariable() {
  SbConditionVariableCreate(&native_handle_, nullptr);
}

ConditionVariable::~ConditionVariable() {
  SbConditionVariableDestroy(&native_handle_);
}

void ConditionVariable::NotifyOne() {
  SbConditionVariableSignal(&native_handle_);
}

void ConditionVariable::NotifyAll() {
  SbConditionVariableBroadcast(&native_handle_);
}

void ConditionVariable::Wait(Mutex* mutex) {
  SbConditionVariableWait(&native_handle_, &mutex->native_handle());
}

bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
  SbTime microseconds = static_cast<SbTime>(rel_time.InMicroseconds());
  SbConditionVariableResult result = SbConditionVariableWaitTimed(
      &native_handle_, &mutex->native_handle(), microseconds);
  DCHECK(result != kSbConditionVariableFailed);
  return result == kSbConditionVariableSignaled;
}

#endif  // V8_OS_STARBOARD
193

194 195
}  // namespace base
}  // namespace v8