ipc/chromium/src/base/thread_collision_warner.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #ifndef BASE_THREAD_COLLISION_WARNER_H_
michael@0 6 #define BASE_THREAD_COLLISION_WARNER_H_
michael@0 7
michael@0 8 #include <memory.h>
michael@0 9
michael@0 10 #include "base/atomicops.h"
michael@0 11
michael@0 12 // A helper class alongside macros to be used to verify assumptions about thread
michael@0 13 // safety of a class.
michael@0 14 //
michael@0 15 // Example: Queue implementation non thread-safe but still usable if clients
michael@0 16 // are synchronized somehow.
michael@0 17 //
michael@0 18 // In this case the macro DFAKE_SCOPED_LOCK has to be
michael@0 19 // used, it checks that if a thread is inside the push/pop then
michael@0 20 // noone else is still inside the pop/push
michael@0 21 //
michael@0 22 // class NonThreadSafeQueue {
michael@0 23 // public:
michael@0 24 // ...
michael@0 25 // void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... }
michael@0 26 // int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... }
michael@0 27 // ...
michael@0 28 // private:
michael@0 29 // DFAKE_MUTEX(push_pop_);
michael@0 30 // };
michael@0 31 //
michael@0 32 //
michael@0 33 // Example: Queue implementation non thread-safe but still usable if clients
michael@0 34 // are synchronized somehow, it calls a method to "protect" from
michael@0 35 // a "protected" method
michael@0 36 //
michael@0 37 // In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK
michael@0 38 // has to be used, it checks that if a thread is inside the push/pop
michael@0 39 // then noone else is still inside the pop/push
michael@0 40 //
michael@0 41 // class NonThreadSafeQueue {
michael@0 42 // public:
michael@0 43 // void push(int) {
michael@0 44 // DFAKE_SCOPED_LOCK(push_pop_);
michael@0 45 // ...
michael@0 46 // }
michael@0 47 // int pop() {
michael@0 48 // DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
michael@0 49 // bar();
michael@0 50 // ...
michael@0 51 // }
michael@0 52 // void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... }
michael@0 53 // ...
michael@0 54 // private:
michael@0 55 // DFAKE_MUTEX(push_pop_);
michael@0 56 // };
michael@0 57 //
michael@0 58 //
michael@0 59 // Example: Queue implementation not usable even if clients are synchronized,
michael@0 60 // so only one thread in the class life cycle can use the two members
michael@0 61 // push/pop.
michael@0 62 //
michael@0 63 // In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the
michael@0 64 // specified
michael@0 65 // critical section the first time a thread enters push or pop, from
michael@0 66 // that time on only that thread is allowed to execute push or pop.
michael@0 67 //
michael@0 68 // class NonThreadSafeQueue {
michael@0 69 // public:
michael@0 70 // ...
michael@0 71 // void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
michael@0 72 // int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
michael@0 73 // ...
michael@0 74 // private:
michael@0 75 // DFAKE_MUTEX(push_pop_);
michael@0 76 // };
michael@0 77 //
michael@0 78 //
michael@0 79 // Example: Class that has to be contructed/destroyed on same thread, it has
michael@0 80 // a "shareable" method (with external syncronization) and a not
michael@0 81 // shareable method (even with external synchronization).
michael@0 82 //
michael@0 83 // In this case 3 Critical sections have to be defined
michael@0 84 //
michael@0 85 // class ExoticClass {
michael@0 86 // public:
michael@0 87 // ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
michael@0 88 // ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
michael@0 89 //
michael@0 90 // void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... }
michael@0 91 // void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
michael@0 92 // ...
michael@0 93 // private:
michael@0 94 // DFAKE_MUTEX(ctor_dtor_);
michael@0 95 // DFAKE_MUTEX(shareable_section_);
michael@0 96 // };
michael@0 97
michael@0 98
michael@0 99 #if !defined(NDEBUG)
michael@0 100
michael@0 101 // Defines a class member that acts like a mutex. It is used only as a
michael@0 102 // verification tool.
michael@0 103 #define DFAKE_MUTEX(obj) \
michael@0 104 mutable base::ThreadCollisionWarner obj;
michael@0 105 // Asserts the call is never called simultaneously in two threads. Used at
michael@0 106 // member function scope.
michael@0 107 #define DFAKE_SCOPED_LOCK(obj) \
michael@0 108 base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj)
michael@0 109 // Asserts the call is never called simultaneously in two threads. Used at
michael@0 110 // member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks.
michael@0 111 #define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \
michael@0 112 base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj)
michael@0 113 // Asserts the code is always executed in the same thread.
michael@0 114 #define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \
michael@0 115 base::ThreadCollisionWarner::Check check_##obj(&obj)
michael@0 116
michael@0 117 #else
michael@0 118
michael@0 119 #define DFAKE_MUTEX(obj)
michael@0 120 #define DFAKE_SCOPED_LOCK(obj) ((void)0)
michael@0 121 #define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0)
michael@0 122 #define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0)
michael@0 123
michael@0 124 #endif
michael@0 125
michael@0 126 namespace base {
michael@0 127
michael@0 128 // The class ThreadCollisionWarner uses an Asserter to notify the collision
michael@0 129 // AsserterBase is the interfaces and DCheckAsserter is the default asserter
michael@0 130 // used. During the unit tests is used another class that doesn't "DCHECK"
michael@0 131 // in case of collision (check thread_collision_warner_unittests.cc)
michael@0 132 struct AsserterBase {
michael@0 133 virtual ~AsserterBase() {}
michael@0 134 virtual void warn() = 0;
michael@0 135 };
michael@0 136
michael@0 137 struct DCheckAsserter : public AsserterBase {
michael@0 138 virtual ~DCheckAsserter() {}
michael@0 139 virtual void warn();
michael@0 140 };
michael@0 141
michael@0 142 class ThreadCollisionWarner {
michael@0 143 public:
michael@0 144 // The parameter asserter is there only for test purpose
michael@0 145 ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
michael@0 146 : valid_thread_id_(0),
michael@0 147 counter_(0),
michael@0 148 asserter_(asserter) {}
michael@0 149
michael@0 150 ~ThreadCollisionWarner() {
michael@0 151 delete asserter_;
michael@0 152 }
michael@0 153
michael@0 154 // This class is meant to be used through the macro
michael@0 155 // DFAKE_SCOPED_LOCK_THREAD_LOCKED
michael@0 156 // it doesn't leave the critical section, as opposed to ScopedCheck,
michael@0 157 // because the critical section being pinned is allowed to be used only
michael@0 158 // from one thread
michael@0 159 class Check {
michael@0 160 public:
michael@0 161 explicit Check(ThreadCollisionWarner* warner)
michael@0 162 : warner_(warner) {
michael@0 163 warner_->EnterSelf();
michael@0 164 }
michael@0 165
michael@0 166 ~Check() {}
michael@0 167
michael@0 168 private:
michael@0 169 ThreadCollisionWarner* warner_;
michael@0 170
michael@0 171 DISALLOW_COPY_AND_ASSIGN(Check);
michael@0 172 };
michael@0 173
michael@0 174 // This class is meant to be used through the macro
michael@0 175 // DFAKE_SCOPED_LOCK
michael@0 176 class ScopedCheck {
michael@0 177 public:
michael@0 178 explicit ScopedCheck(ThreadCollisionWarner* warner)
michael@0 179 : warner_(warner) {
michael@0 180 warner_->Enter();
michael@0 181 }
michael@0 182
michael@0 183 ~ScopedCheck() {
michael@0 184 warner_->Leave();
michael@0 185 }
michael@0 186
michael@0 187 private:
michael@0 188 ThreadCollisionWarner* warner_;
michael@0 189
michael@0 190 DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
michael@0 191 };
michael@0 192
michael@0 193 // This class is meant to be used through the macro
michael@0 194 // DFAKE_SCOPED_RECURSIVE_LOCK
michael@0 195 class ScopedRecursiveCheck {
michael@0 196 public:
michael@0 197 explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
michael@0 198 : warner_(warner) {
michael@0 199 warner_->EnterSelf();
michael@0 200 }
michael@0 201
michael@0 202 ~ScopedRecursiveCheck() {
michael@0 203 warner_->Leave();
michael@0 204 }
michael@0 205
michael@0 206 private:
michael@0 207 ThreadCollisionWarner* warner_;
michael@0 208
michael@0 209 DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
michael@0 210 };
michael@0 211
michael@0 212 private:
michael@0 213 // This method stores the current thread identifier and does a DCHECK
michael@0 214 // if a another thread has already done it, it is safe if same thread
michael@0 215 // calls this multiple time (recursion allowed).
michael@0 216 void EnterSelf();
michael@0 217
michael@0 218 // Same as EnterSelf but recursion is not allowed.
michael@0 219 void Enter();
michael@0 220
michael@0 221 // Removes the thread_id stored in order to allow other threads to
michael@0 222 // call EnterSelf or Enter.
michael@0 223 void Leave();
michael@0 224
michael@0 225 // This stores the thread id that is inside the critical section, if the
michael@0 226 // value is 0 then no thread is inside.
michael@0 227 volatile subtle::Atomic32 valid_thread_id_;
michael@0 228
michael@0 229 // Counter to trace how many time a critical section was "pinned"
michael@0 230 // (when allowed) in order to unpin it when counter_ reaches 0.
michael@0 231 volatile subtle::Atomic32 counter_;
michael@0 232
michael@0 233 // Here only for class unit tests purpose, during the test I need to not
michael@0 234 // DCHECK but notify the collision with something else.
michael@0 235 AsserterBase* asserter_;
michael@0 236
michael@0 237 DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
michael@0 238 };
michael@0 239
michael@0 240 } // namespace base
michael@0 241
michael@0 242 #endif // BASE_THREAD_COLLISION_WARNER_H_

mercurial