Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: base/synchronization/condition_variable_win.cc

Issue 2381893002: base: Take care of unexpected wakeups in condition_variable_win.cc. (Closed)
Patch Set: build break Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/synchronization/condition_variable.h" 5 #include "base/synchronization/condition_variable.h"
6 6
7 #include "base/synchronization/lock.h" 7 #include "base/synchronization/lock.h"
8 #include "base/threading/thread_restrictions.h" 8 #include "base/threading/thread_restrictions.h"
9 #include "base/time/time.h" 9 #include "base/time/time.h"
10 10
11 namespace base { 11 namespace base {
12 12
13 namespace {
14
15 // Infinite timeout in milliseconds.
16 static const int64_t kInfiniteTimeout =
17 TimeDelta::FromMilliseconds(INFINITE).InMilliseconds();
18
19 // Number of tries after SleepConditionVariableSRW() fails.
20 static const int kMaxNumberOfTriesAfterFailure = 10;
reveman 2016/10/03 10:58:07 do we need to limit the max number of retries? wha
prashant.n 2016/10/03 11:40:14 Hmm. Actually MSDN documentation tells for ever wh
reveman 2016/10/03 13:23:40 The situation is very similar to how we handle int
21
22 // As per MSDN documentation (https://goo.gl/tPHPkY), condition variables are
23 // subject to spurious wakeups (those not associated with an explicit wake) and
24 // stolen wakeups (another thread manages to run before the woken thread). This
25 // function checks whether it's a real timeout and if not it retries
26 // kMaxNumberOfTriesAfterFailure times after which it crashes.
27 void SleepConditionVariable(PCONDITION_VARIABLE cv,
28 PSRWLOCK srw_lock,
29 BOOL infinite_timeout,
30 DWORD timeout,
31 ULONG flags) {
32 base::Time time_start = base::Time::Now();
33 int num_tries_after_failure = 0;
34
35 while (!SleepConditionVariableSRW(cv, srw_lock, timeout, flags)) {
36 // Note: Use ERROR_TIMEOUT with GetLastError().
37 DWORD error = GetLastError();
38
39 num_tries_after_failure++;
40 CHECK_LE(num_tries_after_failure, kMaxNumberOfTriesAfterFailure)
41 << "SleepConditionVariableSRW() failed after max number of retries "
42 "with error code ("
43 << error << ").";
44
45 if (infinite_timeout) {
46 // Ideally for infinite timeout, we should not get ERROR_TIMEOUT error.
47 DCHECK_NE(error, static_cast<DWORD>(ERROR_TIMEOUT));
48 } else {
49 if (error == ERROR_TIMEOUT)
50 break;
51
52 // Compute remaining timeout.
53 int64_t time_delta = (base::Time::Now() - time_start).InMilliseconds();
54 timeout -= time_delta;
55 // Break here as if timeout has occurred, otherwise continue to wait
56 // for the remaining timeout.
57 if (timeout <= 0)
58 break;
59 }
60 }
61 }
62 }
63
13 ConditionVariable::ConditionVariable(Lock* user_lock) 64 ConditionVariable::ConditionVariable(Lock* user_lock)
14 : srwlock_(user_lock->lock_.native_handle()) 65 : srwlock_(user_lock->lock_.native_handle())
15 #if DCHECK_IS_ON() 66 #if DCHECK_IS_ON()
16 , user_lock_(user_lock) 67 , user_lock_(user_lock)
17 #endif 68 #endif
18 { 69 {
19 DCHECK(user_lock); 70 DCHECK(user_lock);
20 InitializeConditionVariable(&cv_); 71 InitializeConditionVariable(&cv_);
21 } 72 }
22 73
23 ConditionVariable::~ConditionVariable() = default; 74 ConditionVariable::~ConditionVariable() = default;
24 75
25 void ConditionVariable::Wait() { 76 void ConditionVariable::Wait() {
26 TimedWait(TimeDelta::FromMilliseconds(INFINITE));
27 }
28
29 void ConditionVariable::TimedWait(const TimeDelta& max_time) {
30 base::ThreadRestrictions::AssertWaitAllowed(); 77 base::ThreadRestrictions::AssertWaitAllowed();
31 DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
32 78
33 #if DCHECK_IS_ON() 79 #if DCHECK_IS_ON()
34 user_lock_->CheckHeldAndUnmark(); 80 user_lock_->CheckHeldAndUnmark();
35 #endif 81 #endif
36 82
37 if (!SleepConditionVariableSRW(&cv_, srwlock_, timeout, 0)) { 83 SleepConditionVariable(&cv_, srwlock_, true, kInfiniteTimeout, 0);
38 // On failure, we only expect the CV to timeout. Any other error value means
39 // that we've unexpectedly woken up.
40 // Note that WAIT_TIMEOUT != ERROR_TIMEOUT. WAIT_TIMEOUT is used with the
41 // WaitFor* family of functions as a direct return value. ERROR_TIMEOUT is
42 // used with GetLastError().
43 DCHECK_EQ(static_cast<DWORD>(ERROR_TIMEOUT), GetLastError());
44 }
45 84
46 #if DCHECK_IS_ON() 85 #if DCHECK_IS_ON()
47 user_lock_->CheckUnheldAndMark(); 86 user_lock_->CheckUnheldAndMark();
87 #endif
88 }
89
90 void ConditionVariable::TimedWait(const TimeDelta& max_time) {
91 base::ThreadRestrictions::AssertWaitAllowed();
92
93 #if DCHECK_IS_ON()
94 user_lock_->CheckHeldAndUnmark();
95 #endif
96
97 SleepConditionVariable(&cv_, srwlock_, false,
98 static_cast<DWORD>(max_time.InMilliseconds()), 0);
99
100 #if DCHECK_IS_ON()
101 user_lock_->CheckUnheldAndMark();
48 #endif 102 #endif
49 } 103 }
50 104
51 void ConditionVariable::Broadcast() { 105 void ConditionVariable::Broadcast() {
52 WakeAllConditionVariable(&cv_); 106 WakeAllConditionVariable(&cv_);
53 } 107 }
54 108
55 void ConditionVariable::Signal() { 109 void ConditionVariable::Signal() {
56 WakeConditionVariable(&cv_); 110 WakeConditionVariable(&cv_);
57 } 111 }
58 112
59 } // namespace base 113 } // namespace base
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698