xref: /aosp_15_r20/external/cronet/base/synchronization/condition_variable_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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)19 ConditionVariable::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()31 void ConditionVariable::Wait() {
32   TimedWait(TimeDelta::Max());
33 }
34 
TimedWait(const TimeDelta & max_time)35 void 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()64 void ConditionVariable::Broadcast() {
65   WakeAllConditionVariable(reinterpret_cast<PCONDITION_VARIABLE>(&cv_));
66 }
67 
Signal()68 void ConditionVariable::Signal() {
69   WakeConditionVariable(reinterpret_cast<PCONDITION_VARIABLE>(&cv_));
70 }
71 
72 }  // namespace base
73