1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/chromium/base/threading/thread_collision_warner.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,244 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#ifndef BASE_THREADING_THREAD_COLLISION_WARNER_H_ 1.9 +#define BASE_THREADING_THREAD_COLLISION_WARNER_H_ 1.10 + 1.11 +#include <memory> 1.12 + 1.13 +#include "base/atomicops.h" 1.14 +#include "base/base_export.h" 1.15 +#include "base/compiler_specific.h" 1.16 + 1.17 +// A helper class alongside macros to be used to verify assumptions about thread 1.18 +// safety of a class. 1.19 +// 1.20 +// Example: Queue implementation non thread-safe but still usable if clients 1.21 +// are synchronized somehow. 1.22 +// 1.23 +// In this case the macro DFAKE_SCOPED_LOCK has to be 1.24 +// used, it checks that if a thread is inside the push/pop then 1.25 +// noone else is still inside the pop/push 1.26 +// 1.27 +// class NonThreadSafeQueue { 1.28 +// public: 1.29 +// ... 1.30 +// void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... } 1.31 +// int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... } 1.32 +// ... 1.33 +// private: 1.34 +// DFAKE_MUTEX(push_pop_); 1.35 +// }; 1.36 +// 1.37 +// 1.38 +// Example: Queue implementation non thread-safe but still usable if clients 1.39 +// are synchronized somehow, it calls a method to "protect" from 1.40 +// a "protected" method 1.41 +// 1.42 +// In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK 1.43 +// has to be used, it checks that if a thread is inside the push/pop 1.44 +// then noone else is still inside the pop/push 1.45 +// 1.46 +// class NonThreadSafeQueue { 1.47 +// public: 1.48 +// void push(int) { 1.49 +// DFAKE_SCOPED_LOCK(push_pop_); 1.50 +// ... 1.51 +// } 1.52 +// int pop() { 1.53 +// DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); 1.54 +// bar(); 1.55 +// ... 1.56 +// } 1.57 +// void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... } 1.58 +// ... 1.59 +// private: 1.60 +// DFAKE_MUTEX(push_pop_); 1.61 +// }; 1.62 +// 1.63 +// 1.64 +// Example: Queue implementation not usable even if clients are synchronized, 1.65 +// so only one thread in the class life cycle can use the two members 1.66 +// push/pop. 1.67 +// 1.68 +// In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the 1.69 +// specified 1.70 +// critical section the first time a thread enters push or pop, from 1.71 +// that time on only that thread is allowed to execute push or pop. 1.72 +// 1.73 +// class NonThreadSafeQueue { 1.74 +// public: 1.75 +// ... 1.76 +// void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } 1.77 +// int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } 1.78 +// ... 1.79 +// private: 1.80 +// DFAKE_MUTEX(push_pop_); 1.81 +// }; 1.82 +// 1.83 +// 1.84 +// Example: Class that has to be contructed/destroyed on same thread, it has 1.85 +// a "shareable" method (with external synchronization) and a not 1.86 +// shareable method (even with external synchronization). 1.87 +// 1.88 +// In this case 3 Critical sections have to be defined 1.89 +// 1.90 +// class ExoticClass { 1.91 +// public: 1.92 +// ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } 1.93 +// ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } 1.94 +// 1.95 +// void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... } 1.96 +// void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } 1.97 +// ... 1.98 +// private: 1.99 +// DFAKE_MUTEX(ctor_dtor_); 1.100 +// DFAKE_MUTEX(shareable_section_); 1.101 +// }; 1.102 + 1.103 + 1.104 +#if !defined(NDEBUG) 1.105 + 1.106 +// Defines a class member that acts like a mutex. It is used only as a 1.107 +// verification tool. 1.108 +#define DFAKE_MUTEX(obj) \ 1.109 + mutable base::ThreadCollisionWarner obj 1.110 +// Asserts the call is never called simultaneously in two threads. Used at 1.111 +// member function scope. 1.112 +#define DFAKE_SCOPED_LOCK(obj) \ 1.113 + base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj) 1.114 +// Asserts the call is never called simultaneously in two threads. Used at 1.115 +// member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks. 1.116 +#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \ 1.117 + base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj) 1.118 +// Asserts the code is always executed in the same thread. 1.119 +#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \ 1.120 + base::ThreadCollisionWarner::Check check_##obj(&obj) 1.121 + 1.122 +#else 1.123 + 1.124 +#define DFAKE_MUTEX(obj) typedef void InternalFakeMutexType##obj 1.125 +#define DFAKE_SCOPED_LOCK(obj) ((void)0) 1.126 +#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0) 1.127 +#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0) 1.128 + 1.129 +#endif 1.130 + 1.131 +namespace base { 1.132 + 1.133 +// The class ThreadCollisionWarner uses an Asserter to notify the collision 1.134 +// AsserterBase is the interfaces and DCheckAsserter is the default asserter 1.135 +// used. During the unit tests is used another class that doesn't "DCHECK" 1.136 +// in case of collision (check thread_collision_warner_unittests.cc) 1.137 +struct BASE_EXPORT AsserterBase { 1.138 + virtual ~AsserterBase() {} 1.139 + virtual void warn() = 0; 1.140 +}; 1.141 + 1.142 +struct BASE_EXPORT DCheckAsserter : public AsserterBase { 1.143 + virtual ~DCheckAsserter() {} 1.144 + virtual void warn() OVERRIDE; 1.145 +}; 1.146 + 1.147 +class BASE_EXPORT ThreadCollisionWarner { 1.148 + public: 1.149 + // The parameter asserter is there only for test purpose 1.150 + explicit ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter()) 1.151 + : valid_thread_id_(0), 1.152 + counter_(0), 1.153 + asserter_(asserter) {} 1.154 + 1.155 + ~ThreadCollisionWarner() { 1.156 + delete asserter_; 1.157 + } 1.158 + 1.159 + // This class is meant to be used through the macro 1.160 + // DFAKE_SCOPED_LOCK_THREAD_LOCKED 1.161 + // it doesn't leave the critical section, as opposed to ScopedCheck, 1.162 + // because the critical section being pinned is allowed to be used only 1.163 + // from one thread 1.164 + class BASE_EXPORT Check { 1.165 + public: 1.166 + explicit Check(ThreadCollisionWarner* warner) 1.167 + : warner_(warner) { 1.168 + warner_->EnterSelf(); 1.169 + } 1.170 + 1.171 + ~Check() {} 1.172 + 1.173 + private: 1.174 + ThreadCollisionWarner* warner_; 1.175 + 1.176 + DISALLOW_COPY_AND_ASSIGN(Check); 1.177 + }; 1.178 + 1.179 + // This class is meant to be used through the macro 1.180 + // DFAKE_SCOPED_LOCK 1.181 + class BASE_EXPORT ScopedCheck { 1.182 + public: 1.183 + explicit ScopedCheck(ThreadCollisionWarner* warner) 1.184 + : warner_(warner) { 1.185 + warner_->Enter(); 1.186 + } 1.187 + 1.188 + ~ScopedCheck() { 1.189 + warner_->Leave(); 1.190 + } 1.191 + 1.192 + private: 1.193 + ThreadCollisionWarner* warner_; 1.194 + 1.195 + DISALLOW_COPY_AND_ASSIGN(ScopedCheck); 1.196 + }; 1.197 + 1.198 + // This class is meant to be used through the macro 1.199 + // DFAKE_SCOPED_RECURSIVE_LOCK 1.200 + class BASE_EXPORT ScopedRecursiveCheck { 1.201 + public: 1.202 + explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner) 1.203 + : warner_(warner) { 1.204 + warner_->EnterSelf(); 1.205 + } 1.206 + 1.207 + ~ScopedRecursiveCheck() { 1.208 + warner_->Leave(); 1.209 + } 1.210 + 1.211 + private: 1.212 + ThreadCollisionWarner* warner_; 1.213 + 1.214 + DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck); 1.215 + }; 1.216 + 1.217 + private: 1.218 + // This method stores the current thread identifier and does a DCHECK 1.219 + // if a another thread has already done it, it is safe if same thread 1.220 + // calls this multiple time (recursion allowed). 1.221 + void EnterSelf(); 1.222 + 1.223 + // Same as EnterSelf but recursion is not allowed. 1.224 + void Enter(); 1.225 + 1.226 + // Removes the thread_id stored in order to allow other threads to 1.227 + // call EnterSelf or Enter. 1.228 + void Leave(); 1.229 + 1.230 + // This stores the thread id that is inside the critical section, if the 1.231 + // value is 0 then no thread is inside. 1.232 + volatile subtle::Atomic32 valid_thread_id_; 1.233 + 1.234 + // Counter to trace how many time a critical section was "pinned" 1.235 + // (when allowed) in order to unpin it when counter_ reaches 0. 1.236 + volatile subtle::Atomic32 counter_; 1.237 + 1.238 + // Here only for class unit tests purpose, during the test I need to not 1.239 + // DCHECK but notify the collision with something else. 1.240 + AsserterBase* asserter_; 1.241 + 1.242 + DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner); 1.243 +}; 1.244 + 1.245 +} // namespace base 1.246 + 1.247 +#endif // BASE_THREADING_THREAD_COLLISION_WARNER_H_