tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ConditionVariable_windows.cpp (3394B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/Assertions.h"
      8 
      9 #include <float.h>
     10 #include <intrin.h>
     11 #include <windows.h>
     12 
     13 #include "mozilla/PlatformConditionVariable.h"
     14 #include "mozilla/PlatformMutex.h"
     15 #include "MutexPlatformData_windows.h"
     16 
     17 // Some versions of the Windows SDK have a bug where some interlocked functions
     18 // are not redefined as compiler intrinsics. Fix that for the interlocked
     19 // functions that are used in this file.
     20 #if defined(_MSC_VER) && !defined(InterlockedExchangeAdd)
     21 #  define InterlockedExchangeAdd(addend, value) \
     22    _InterlockedExchangeAdd((volatile long*)(addend), (long)(value))
     23 #endif
     24 
     25 #if defined(_MSC_VER) && !defined(InterlockedIncrement)
     26 #  define InterlockedIncrement(addend) \
     27    _InterlockedIncrement((volatile long*)(addend))
     28 #endif
     29 
     30 // Wrapper for native condition variable APIs.
     31 struct mozilla::detail::ConditionVariableImpl::PlatformData {
     32  CONDITION_VARIABLE cv_;
     33 };
     34 
     35 mozilla::detail::ConditionVariableImpl::ConditionVariableImpl() {
     36  InitializeConditionVariable(&platformData()->cv_);
     37 }
     38 
     39 void mozilla::detail::ConditionVariableImpl::notify_one() {
     40  WakeConditionVariable(&platformData()->cv_);
     41 }
     42 
     43 void mozilla::detail::ConditionVariableImpl::notify_all() {
     44  WakeAllConditionVariable(&platformData()->cv_);
     45 }
     46 
     47 void mozilla::detail::ConditionVariableImpl::wait(MutexImpl& lock) {
     48  SRWLOCK* srwlock = &lock.platformData()->lock;
     49  bool r =
     50      SleepConditionVariableSRW(&platformData()->cv_, srwlock, INFINITE, 0);
     51  MOZ_RELEASE_ASSERT(r);
     52 }
     53 
     54 mozilla::CVStatus mozilla::detail::ConditionVariableImpl::wait_for(
     55    MutexImpl& lock, const mozilla::TimeDuration& rel_time) {
     56  if (rel_time == mozilla::TimeDuration::Forever()) {
     57    wait(lock);
     58    return CVStatus::NoTimeout;
     59  }
     60 
     61  SRWLOCK* srwlock = &lock.platformData()->lock;
     62 
     63  // Note that DWORD is unsigned, so we have to be careful to clamp at 0. If
     64  // rel_time is Forever, then ToMilliseconds is +inf, which evaluates as
     65  // greater than UINT32_MAX, resulting in the correct INFINITE wait. We also
     66  // don't want to round sub-millisecond waits to 0, as that wastes energy (see
     67  // bug 1437167 comment 6), so we instead round submillisecond waits to 1ms.
     68  double msecd = rel_time.ToMilliseconds();
     69  DWORD msec;
     70  if (msecd < 0.0) {
     71    msec = 0;
     72  } else if (msecd > UINT32_MAX) {
     73    msec = INFINITE;
     74  } else {
     75    msec = static_cast<DWORD>(msecd);
     76    // Round submillisecond waits to 1ms.
     77    if (msec == 0 && !rel_time.IsZero()) {
     78      msec = 1;
     79    }
     80  }
     81 
     82  BOOL r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, msec, 0);
     83  if (r) return CVStatus::NoTimeout;
     84  MOZ_RELEASE_ASSERT(GetLastError() == ERROR_TIMEOUT);
     85  return CVStatus::Timeout;
     86 }
     87 
     88 mozilla::detail::ConditionVariableImpl::~ConditionVariableImpl() {
     89  // Native condition variables don't require cleanup.
     90 }
     91 
     92 inline mozilla::detail::ConditionVariableImpl::PlatformData*
     93 mozilla::detail::ConditionVariableImpl::platformData() {
     94  static_assert(sizeof platformData_ >= sizeof(PlatformData),
     95                "platformData_ is too small");
     96  return reinterpret_cast<PlatformData*>(platformData_);
     97 }