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