11cb0ef41Sopenharmony_ci// Copyright 2013 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/base/platform/condition-variable.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <errno.h>
81cb0ef41Sopenharmony_ci#include <time.h>
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#include "src/base/platform/time.h"
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci#if V8_OS_WIN
131cb0ef41Sopenharmony_ci#include <windows.h>
141cb0ef41Sopenharmony_ci#endif
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_cinamespace v8 {
171cb0ef41Sopenharmony_cinamespace base {
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci#if V8_OS_POSIX
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ciConditionVariable::ConditionVariable() {
221cb0ef41Sopenharmony_ci#if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
231cb0ef41Sopenharmony_ci     (V8_OS_LINUX && V8_LIBC_GLIBC))
241cb0ef41Sopenharmony_ci  // On Free/Net/OpenBSD and Linux with glibc we can change the time
251cb0ef41Sopenharmony_ci  // source for pthread_cond_timedwait() to use the monotonic clock.
261cb0ef41Sopenharmony_ci  pthread_condattr_t attr;
271cb0ef41Sopenharmony_ci  int result = pthread_condattr_init(&attr);
281cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
291cb0ef41Sopenharmony_ci  result = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
301cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
311cb0ef41Sopenharmony_ci  result = pthread_cond_init(&native_handle_, &attr);
321cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
331cb0ef41Sopenharmony_ci  result = pthread_condattr_destroy(&attr);
341cb0ef41Sopenharmony_ci#else
351cb0ef41Sopenharmony_ci  int result = pthread_cond_init(&native_handle_, nullptr);
361cb0ef41Sopenharmony_ci#endif
371cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
381cb0ef41Sopenharmony_ci  USE(result);
391cb0ef41Sopenharmony_ci}
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ciConditionVariable::~ConditionVariable() {
431cb0ef41Sopenharmony_ci#if defined(V8_OS_DARWIN)
441cb0ef41Sopenharmony_ci  // This hack is necessary to avoid a fatal pthreads subsystem bug in the
451cb0ef41Sopenharmony_ci  // Darwin kernel. http://crbug.com/517681.
461cb0ef41Sopenharmony_ci  {
471cb0ef41Sopenharmony_ci    Mutex lock;
481cb0ef41Sopenharmony_ci    MutexGuard l(&lock);
491cb0ef41Sopenharmony_ci    struct timespec ts;
501cb0ef41Sopenharmony_ci    ts.tv_sec = 0;
511cb0ef41Sopenharmony_ci    ts.tv_nsec = 1;
521cb0ef41Sopenharmony_ci    pthread_cond_timedwait_relative_np(&native_handle_, &lock.native_handle(),
531cb0ef41Sopenharmony_ci                                       &ts);
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci#endif
561cb0ef41Sopenharmony_ci  int result = pthread_cond_destroy(&native_handle_);
571cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
581cb0ef41Sopenharmony_ci  USE(result);
591cb0ef41Sopenharmony_ci}
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_civoid ConditionVariable::NotifyOne() {
631cb0ef41Sopenharmony_ci  int result = pthread_cond_signal(&native_handle_);
641cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
651cb0ef41Sopenharmony_ci  USE(result);
661cb0ef41Sopenharmony_ci}
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_civoid ConditionVariable::NotifyAll() {
701cb0ef41Sopenharmony_ci  int result = pthread_cond_broadcast(&native_handle_);
711cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
721cb0ef41Sopenharmony_ci  USE(result);
731cb0ef41Sopenharmony_ci}
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_civoid ConditionVariable::Wait(Mutex* mutex) {
771cb0ef41Sopenharmony_ci  mutex->AssertHeldAndUnmark();
781cb0ef41Sopenharmony_ci  int result = pthread_cond_wait(&native_handle_, &mutex->native_handle());
791cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
801cb0ef41Sopenharmony_ci  USE(result);
811cb0ef41Sopenharmony_ci  mutex->AssertUnheldAndMark();
821cb0ef41Sopenharmony_ci}
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_cibool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
861cb0ef41Sopenharmony_ci  struct timespec ts;
871cb0ef41Sopenharmony_ci  int result;
881cb0ef41Sopenharmony_ci  mutex->AssertHeldAndUnmark();
891cb0ef41Sopenharmony_ci#if V8_OS_DARWIN
901cb0ef41Sopenharmony_ci  // Mac OS X provides pthread_cond_timedwait_relative_np(), which does
911cb0ef41Sopenharmony_ci  // not depend on the real time clock, which is what you really WANT here!
921cb0ef41Sopenharmony_ci  ts = rel_time.ToTimespec();
931cb0ef41Sopenharmony_ci  DCHECK_GE(ts.tv_sec, 0);
941cb0ef41Sopenharmony_ci  DCHECK_GE(ts.tv_nsec, 0);
951cb0ef41Sopenharmony_ci  result = pthread_cond_timedwait_relative_np(
961cb0ef41Sopenharmony_ci      &native_handle_, &mutex->native_handle(), &ts);
971cb0ef41Sopenharmony_ci#else
981cb0ef41Sopenharmony_ci#if (V8_OS_FREEBSD || V8_OS_NETBSD || V8_OS_OPENBSD || \
991cb0ef41Sopenharmony_ci     (V8_OS_LINUX && V8_LIBC_GLIBC))
1001cb0ef41Sopenharmony_ci  // On Free/Net/OpenBSD and Linux with glibc we can change the time
1011cb0ef41Sopenharmony_ci  // source for pthread_cond_timedwait() to use the monotonic clock.
1021cb0ef41Sopenharmony_ci  result = clock_gettime(CLOCK_MONOTONIC, &ts);
1031cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
1041cb0ef41Sopenharmony_ci  Time now = Time::FromTimespec(ts);
1051cb0ef41Sopenharmony_ci#else
1061cb0ef41Sopenharmony_ci  // The timeout argument to pthread_cond_timedwait() is in absolute time.
1071cb0ef41Sopenharmony_ci  Time now = Time::NowFromSystemTime();
1081cb0ef41Sopenharmony_ci#endif
1091cb0ef41Sopenharmony_ci  Time end_time = now + rel_time;
1101cb0ef41Sopenharmony_ci  DCHECK_GE(end_time, now);
1111cb0ef41Sopenharmony_ci  ts = end_time.ToTimespec();
1121cb0ef41Sopenharmony_ci  result = pthread_cond_timedwait(
1131cb0ef41Sopenharmony_ci      &native_handle_, &mutex->native_handle(), &ts);
1141cb0ef41Sopenharmony_ci#endif  // V8_OS_DARWIN
1151cb0ef41Sopenharmony_ci  mutex->AssertUnheldAndMark();
1161cb0ef41Sopenharmony_ci  if (result == ETIMEDOUT) {
1171cb0ef41Sopenharmony_ci    return false;
1181cb0ef41Sopenharmony_ci  }
1191cb0ef41Sopenharmony_ci  DCHECK_EQ(0, result);
1201cb0ef41Sopenharmony_ci  return true;
1211cb0ef41Sopenharmony_ci}
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci#elif V8_OS_WIN
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ciConditionVariable::ConditionVariable() {
1261cb0ef41Sopenharmony_ci  InitializeConditionVariable(V8ToWindowsType(&native_handle_));
1271cb0ef41Sopenharmony_ci}
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ciConditionVariable::~ConditionVariable() {}
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_civoid ConditionVariable::NotifyOne() {
1331cb0ef41Sopenharmony_ci  WakeConditionVariable(V8ToWindowsType(&native_handle_));
1341cb0ef41Sopenharmony_ci}
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_civoid ConditionVariable::NotifyAll() {
1371cb0ef41Sopenharmony_ci  WakeAllConditionVariable(V8ToWindowsType(&native_handle_));
1381cb0ef41Sopenharmony_ci}
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_civoid ConditionVariable::Wait(Mutex* mutex) {
1421cb0ef41Sopenharmony_ci  mutex->AssertHeldAndUnmark();
1431cb0ef41Sopenharmony_ci  SleepConditionVariableSRW(V8ToWindowsType(&native_handle_),
1441cb0ef41Sopenharmony_ci                            V8ToWindowsType(&mutex->native_handle()), INFINITE,
1451cb0ef41Sopenharmony_ci                            0);
1461cb0ef41Sopenharmony_ci  mutex->AssertUnheldAndMark();
1471cb0ef41Sopenharmony_ci}
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_cibool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
1511cb0ef41Sopenharmony_ci  int64_t msec = rel_time.InMilliseconds();
1521cb0ef41Sopenharmony_ci  mutex->AssertHeldAndUnmark();
1531cb0ef41Sopenharmony_ci  BOOL result = SleepConditionVariableSRW(
1541cb0ef41Sopenharmony_ci      V8ToWindowsType(&native_handle_),
1551cb0ef41Sopenharmony_ci      V8ToWindowsType(&mutex->native_handle()), static_cast<DWORD>(msec), 0);
1561cb0ef41Sopenharmony_ci#ifdef DEBUG
1571cb0ef41Sopenharmony_ci  if (!result) {
1581cb0ef41Sopenharmony_ci    // On failure, we only expect the CV to timeout. Any other error value means
1591cb0ef41Sopenharmony_ci    // that we've unexpectedly woken up.
1601cb0ef41Sopenharmony_ci    // Note that WAIT_TIMEOUT != ERROR_TIMEOUT. WAIT_TIMEOUT is used with the
1611cb0ef41Sopenharmony_ci    // WaitFor* family of functions as a direct return value. ERROR_TIMEOUT is
1621cb0ef41Sopenharmony_ci    // used with GetLastError().
1631cb0ef41Sopenharmony_ci    DCHECK_EQ(static_cast<DWORD>(ERROR_TIMEOUT), GetLastError());
1641cb0ef41Sopenharmony_ci  }
1651cb0ef41Sopenharmony_ci#endif
1661cb0ef41Sopenharmony_ci  mutex->AssertUnheldAndMark();
1671cb0ef41Sopenharmony_ci  return result != 0;
1681cb0ef41Sopenharmony_ci}
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci#elif V8_OS_STARBOARD
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ciConditionVariable::ConditionVariable() {
1731cb0ef41Sopenharmony_ci  SbConditionVariableCreate(&native_handle_, nullptr);
1741cb0ef41Sopenharmony_ci}
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ciConditionVariable::~ConditionVariable() {
1771cb0ef41Sopenharmony_ci  SbConditionVariableDestroy(&native_handle_);
1781cb0ef41Sopenharmony_ci}
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_civoid ConditionVariable::NotifyOne() {
1811cb0ef41Sopenharmony_ci  SbConditionVariableSignal(&native_handle_);
1821cb0ef41Sopenharmony_ci}
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_civoid ConditionVariable::NotifyAll() {
1851cb0ef41Sopenharmony_ci  SbConditionVariableBroadcast(&native_handle_);
1861cb0ef41Sopenharmony_ci}
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_civoid ConditionVariable::Wait(Mutex* mutex) {
1891cb0ef41Sopenharmony_ci  SbConditionVariableWait(&native_handle_, &mutex->native_handle());
1901cb0ef41Sopenharmony_ci}
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_cibool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) {
1931cb0ef41Sopenharmony_ci  SbTime microseconds = static_cast<SbTime>(rel_time.InMicroseconds());
1941cb0ef41Sopenharmony_ci  SbConditionVariableResult result = SbConditionVariableWaitTimed(
1951cb0ef41Sopenharmony_ci      &native_handle_, &mutex->native_handle(), microseconds);
1961cb0ef41Sopenharmony_ci  DCHECK(result != kSbConditionVariableFailed);
1971cb0ef41Sopenharmony_ci  return result == kSbConditionVariableSignaled;
1981cb0ef41Sopenharmony_ci}
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci#endif  // V8_OS_STARBOARD
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci}  // namespace base
2031cb0ef41Sopenharmony_ci}  // namespace v8
204