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 }