// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_THREADING_THREAD_COLLISION_WARNER_H_ #define BASE_THREADING_THREAD_COLLISION_WARNER_H_ #include "base/atomicops.h" #include "base/base_export.h" #include "base/compiler_specific.h" #include "base/dcheck_is_on.h" #include "base/macros/uniquify.h" #include "base/memory/raw_ptr.h" // A helper class alongside macros to be used to verify assumptions about thread // safety of a class. // // Example: Queue implementation non thread-safe but still usable if clients // are synchronized somehow. // // In this case the macro DFAKE_SCOPED_LOCK has to be // used, it checks that if a thread is inside the push/pop then // noone else is still inside the pop/push // // class NonThreadSafeQueue { // public: // ... // void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... } // int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... } // ... // private: // DFAKE_MUTEX(push_pop_); // }; // // // Example: Queue implementation non thread-safe but still usable if clients // are synchronized somehow, it calls a method to "protect" from // a "protected" method // // In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK // has to be used, it checks that if a thread is inside the push/pop // then noone else is still inside the pop/push // // class NonThreadSafeQueue { // public: // void push(int) { // DFAKE_SCOPED_LOCK(push_pop_); // ... // } // int pop() { // DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); // bar(); // ... // } // void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... } // ... // private: // DFAKE_MUTEX(push_pop_); // }; // // // Example: Queue implementation not usable even if clients are synchronized, // so only one thread in the class life cycle can use the two members // push/pop. // // In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the // specified // critical section the first time a thread enters push or pop, from // that time on only that thread is allowed to execute push or pop. // // class NonThreadSafeQueue { // public: // ... // void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } // int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... } // ... // private: // DFAKE_MUTEX(push_pop_); // }; // // // Example: Class that has to be contructed/destroyed on same thread, it has // a "shareable" method (with external synchronization) and a not // shareable method (even with external synchronization). // // In this case 3 Critical sections have to be defined // // class ExoticClass { // public: // ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } // ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } // // void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... } // void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... } // ... // private: // DFAKE_MUTEX(ctor_dtor_); // DFAKE_MUTEX(shareable_section_); // }; #if DCHECK_IS_ON() // Defines a class member that acts like a mutex. It is used only as a // verification tool. #define DFAKE_MUTEX(obj) … // Asserts the call is never called simultaneously in two threads. Used at // member function scope. #define DFAKE_SCOPED_LOCK(obj) … // Asserts the call is never called simultaneously in two threads. Used at // member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks. #define DFAKE_SCOPED_RECURSIVE_LOCK(obj) … // Asserts the code is always executed in the same thread. #define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) … #else #define DFAKE_MUTEX … #define DFAKE_SCOPED_LOCK … #define DFAKE_SCOPED_RECURSIVE_LOCK … #define DFAKE_SCOPED_LOCK_THREAD_LOCKED … #endif namespace base { // The class ThreadCollisionWarner uses an Asserter to notify the collision // AsserterBase is the interfaces and DCheckAsserter is the default asserter // used. During the unit tests is used another class that doesn't "DCHECK" // in case of collision (check thread_collision_warner_unittests.cc) struct BASE_EXPORT AsserterBase { … }; struct BASE_EXPORT DCheckAsserter : public AsserterBase { … }; class BASE_EXPORT ThreadCollisionWarner { … }; } // namespace base #endif // BASE_THREADING_THREAD_COLLISION_WARNER_H_