1 // Copyright 2011 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/synchronization/condition_variable.h" 6 7 #include <windows.h> 8 9 #include <optional> 10 11 #include "base/numerics/safe_conversions.h" 12 #include "base/synchronization/lock.h" 13 #include "base/threading/scoped_blocking_call.h" 14 #include "base/threading/thread_restrictions.h" 15 #include "base/time/time.h" 16 17 namespace base { 18 ConditionVariable(Lock * user_lock)19ConditionVariable::ConditionVariable(Lock* user_lock) 20 : srwlock_(user_lock->lock_.native_handle()) 21 #if DCHECK_IS_ON() 22 , user_lock_(user_lock) 23 #endif 24 { 25 DCHECK(user_lock); 26 InitializeConditionVariable(reinterpret_cast<PCONDITION_VARIABLE>(&cv_)); 27 } 28 29 ConditionVariable::~ConditionVariable() = default; 30 Wait()31void ConditionVariable::Wait() { 32 TimedWait(TimeDelta::Max()); 33 } 34 TimedWait(const TimeDelta & max_time)35void ConditionVariable::TimedWait(const TimeDelta& max_time) { 36 std::optional<internal::ScopedBlockingCallWithBaseSyncPrimitives> 37 scoped_blocking_call; 38 if (waiting_is_blocking_) 39 scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK); 40 41 // Limit timeout to INFINITE. 42 DWORD timeout = saturated_cast<DWORD>(max_time.InMilliseconds()); 43 44 #if DCHECK_IS_ON() 45 user_lock_->CheckHeldAndUnmark(); 46 #endif 47 48 if (!SleepConditionVariableSRW(reinterpret_cast<PCONDITION_VARIABLE>(&cv_), 49 reinterpret_cast<PSRWLOCK>(srwlock_.get()), 50 timeout, 0)) { 51 // On failure, we only expect the CV to timeout. Any other error value means 52 // that we've unexpectedly woken up. 53 // Note that WAIT_TIMEOUT != ERROR_TIMEOUT. WAIT_TIMEOUT is used with the 54 // WaitFor* family of functions as a direct return value. ERROR_TIMEOUT is 55 // used with GetLastError(). 56 DCHECK_EQ(static_cast<DWORD>(ERROR_TIMEOUT), GetLastError()); 57 } 58 59 #if DCHECK_IS_ON() 60 user_lock_->CheckUnheldAndMark(); 61 #endif 62 } 63 Broadcast()64void ConditionVariable::Broadcast() { 65 WakeAllConditionVariable(reinterpret_cast<PCONDITION_VARIABLE>(&cv_)); 66 } 67 Signal()68void ConditionVariable::Signal() { 69 WakeConditionVariable(reinterpret_cast<PCONDITION_VARIABLE>(&cv_)); 70 } 71 72 } // namespace base 73