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

Side by Side Diff: base/lock.cc

Issue 5630: Disallow Lock class support for recursive locking (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 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 | Annotate | Revision Log
« no previous file with comments | « base/lock.h ('k') | 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) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 // Provide place to put profiling methods for the 5 // Provide place to put profiling methods for the
6 // Lock class. 6 // Lock class.
7 // The Lock class is used everywhere, and hence any changes 7 // The Lock class is used everywhere, and hence any changes
8 // to lock.h tend to require a complete rebuild. To facilitate 8 // to lock.h tend to require a complete rebuild. To facilitate
9 // profiler development, all the profiling methods are listed 9 // profiler development, all the profiling methods are listed
10 // here. Note that they are only instantiated in a debug 10 // here.
11 // build, and the header provides all the trivial implementations
12 // in a production build.
13 11
14 #include "base/lock.h" 12 #include "base/lock.h"
15 #include "base/logging.h" 13 #include "base/logging.h"
16 14
15 #ifndef NDEBUG
17 Lock::Lock() 16 Lock::Lock()
18 : lock_(), 17 : lock_(),
19 recursion_count_shadow_(0) { 18 recursion_count_shadow_(0),
20 #ifndef NDEBUG 19 recursion_used_(false),
21 recursion_used_ = false; 20 acquisition_count_(0),
22 acquisition_count_ = 0; 21 contention_count_(0) {
23 contention_count_ = 0;
24 #endif
25 } 22 }
23 #else // NDEBUG
24 Lock::Lock()
25 : lock_() {
26 }
27 #endif // NDEBUG
26 28
27 Lock::~Lock() { 29 Lock::~Lock() {
28 #ifndef NDEBUG
29 // There should be no one to contend for the lock,
30 // ...but we need the memory barrier to get a good value.
31 lock_.Lock();
32 int final_recursion_count = recursion_count_shadow_;
33 lock_.Unlock();
34 #endif
35
36 // Allow unit test exception only at end of method.
37 #ifndef NDEBUG
38 DCHECK(0 == final_recursion_count);
39 #endif
40 } 30 }
41 31
42 void Lock::Acquire() { 32 void Lock::Acquire() {
43 #ifdef NDEBUG 33 #ifdef NDEBUG
44 lock_.Lock(); 34 lock_.Lock();
45 recursion_count_shadow_++;
46 #else // NDEBUG 35 #else // NDEBUG
47 if (!lock_.Try()) { 36 if (!lock_.Try()) {
48 // We have contention. 37 // We have contention.
49 lock_.Lock(); 38 lock_.Lock();
50 contention_count_++; 39 contention_count_++;
51 } 40 }
52 // ONLY access data after locking. 41 // ONLY access data after locking.
53 recursion_count_shadow_++; 42 recursion_count_shadow_++;
54 if (1 == recursion_count_shadow_) 43 acquisition_count_++;
55 acquisition_count_++; 44 if (2 == recursion_count_shadow_ && !recursion_used_) {
56 else if (2 == recursion_count_shadow_ && !recursion_used_)
57 // Usage Note: Set a break point to debug.
58 recursion_used_ = true; 45 recursion_used_ = true;
46 // TODO(sky): Uncomment this DCHECK after fixing test cases.
47 // DCHECK(false); // Catch accidental redundant lock acquisition.
48 }
59 #endif // NDEBUG 49 #endif // NDEBUG
60 } 50 }
61 51
62 void Lock::Release() { 52 void Lock::Release() {
53 #ifndef NDEBUG
63 --recursion_count_shadow_; // ONLY access while lock is still held. 54 --recursion_count_shadow_; // ONLY access while lock is still held.
64 #ifndef NDEBUG
65 DCHECK(0 <= recursion_count_shadow_); 55 DCHECK(0 <= recursion_count_shadow_);
66 #endif 56 #endif // NDEBUG
67 lock_.Unlock(); 57 lock_.Unlock();
68 } 58 }
69 59
70 bool Lock::Try() { 60 bool Lock::Try() {
71 if (lock_.Try()) { 61 if (lock_.Try()) {
62 #ifndef NDEBUG
72 recursion_count_shadow_++; 63 recursion_count_shadow_++;
73 #ifndef NDEBUG 64 acquisition_count_++;
74 if (1 == recursion_count_shadow_) 65 if (2 == recursion_count_shadow_ && !recursion_used_) {
75 acquisition_count_++;
76 else if (2 == recursion_count_shadow_ && !recursion_used_)
77 // Usage Note: Set a break point to debug.
78 recursion_used_ = true; 66 recursion_used_ = true;
67 DCHECK(false); // Catch accidental redundant lock acquisition.
68 }
79 #endif 69 #endif
80 return true; 70 return true;
81 } else { 71 } else {
82 return false; 72 return false;
83 } 73 }
84 } 74 }
85
86 // GetCurrentThreadRecursionCount returns the number of nested Acquire() calls
87 // that have been made by the current thread holding this lock. The calling
88 // thread is ***REQUIRED*** to be *currently* holding the lock. If that
89 // calling requirement is violated, the return value is not well defined.
90 // Return results are guaranteed correct if the caller has acquired this lock.
91 // The return results might be incorrect otherwise.
92 // This method is designed to be fast in non-debug mode by co-opting
93 // synchronization using lock_ (no additional synchronization is used), but in
94 // debug mode it slowly and carefully validates the requirement (and fires a
95 // a DCHECK if it was called incorrectly).
96 int32 Lock::GetCurrentThreadRecursionCount() {
97 #ifndef NDEBUG
98 // If this DCHECK fails, then the most probable cause is:
99 // This method was called by class AutoUnlock during processing of a
100 // Wait() call made into the ConditonVariable class. That call to
101 // Wait() was made (incorrectly) without first Aquiring this Lock
102 // instance.
103 lock_.Lock();
104 int temp = recursion_count_shadow_;
105 lock_.Unlock();
106 // Unit tests catch an exception, so we need to be careful to test
107 // outside the critical section, since the Leave would be skipped!?!
108 DCHECK(temp >= 1); // Allow unit test exception only at end of method.
109 #endif // DEBUG
110
111 // We hold lock, so this *is* correct value.
112 return recursion_count_shadow_;
113 }
114
115
116 AutoUnlock::AutoUnlock(Lock& lock) : lock_(&lock), release_count_(0) {
117 // We require our caller have the lock, so we can call for recursion count.
118 // CRITICALLY: Fetch value before we release the lock.
119 int32 count = lock_->GetCurrentThreadRecursionCount();
120 DCHECK(count > 0); // Make sure we owned the lock.
121 while (count-- > 0) {
122 release_count_++;
123 lock_->Release();
124 }
125 }
126
127 AutoUnlock::~AutoUnlock() {
128 DCHECK(release_count_ >= 0);
129 while (release_count_-- > 0)
130 lock_->Acquire();
131 }
132
OLDNEW
« no previous file with comments | « base/lock.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698