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