thread_collision_warner.h 7.7 KB

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