1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_THREADING_THREAD_CHECKER_H_ 6 #define BASE_THREADING_THREAD_CHECKER_H_ 7 8 #include <string_view> 9 10 #include "base/base_export.h" 11 #include "base/dcheck_is_on.h" 12 #include "base/macros/uniquify.h" 13 #include "base/thread_annotations.h" 14 #include "base/threading/thread_checker_impl.h" 15 16 // ThreadChecker is a helper class used to help verify that some methods of a 17 // class are called from the same thread (for thread-affinity). It supports 18 // thread safety annotations (see base/thread_annotations.h). 19 // 20 // Use the macros below instead of the ThreadChecker directly so that the unused 21 // member doesn't result in an extra byte (four when padded) per instance in 22 // production. 23 // 24 // Usage of this class should be *rare* as most classes require thread-safety 25 // but not thread-affinity. Prefer base::SequenceChecker to verify thread-safe 26 // access. 27 // 28 // Thread-affinity checks should only be required in classes that use thread- 29 // local-storage or a third-party API that does. 30 // 31 // Prefer to encode the minimum requirements of each class instead of the 32 // environment it happens to run in today. e.g. if a class requires thread- 33 // safety but not thread-affinity, use a SequenceChecker even if it happens to 34 // run on a SingleThreadTaskRunner today. That makes it easier to understand 35 // what would need to change to turn that SingleThreadTaskRunner into a 36 // SequencedTaskRunner for ease of scheduling as well as minimizes side-effects 37 // if that change is made. 38 // 39 // Debugging: 40 // If ThreadChecker::EnableStackLogging() is called beforehand, then when 41 // ThreadChecker fails, in addition to crashing with a stack trace of where 42 // the violation occurred, it will also dump a stack trace of where the 43 // checker was bound to a thread. 44 // 45 // Usage: 46 // class MyClass { 47 // public: 48 // MyClass() { 49 // // It's sometimes useful to detach on construction for objects that are 50 // // constructed in one place and forever after used from another 51 // // thread. 52 // DETACH_FROM_THREAD(thread_checker_); 53 // } 54 // 55 // ~MyClass() { 56 // // ThreadChecker doesn't automatically check it's destroyed on origin 57 // // thread for the same reason it's sometimes detached in the 58 // // constructor. It's okay to destroy off thread if the owner otherwise 59 // // knows usage on the associated thread is done. If you're not 60 // // detaching in the constructor, you probably want to explicitly check 61 // // in the destructor. 62 // DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 63 // } 64 // 65 // void MyMethod() { 66 // DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 67 // ... (do stuff) ... 68 // } 69 // 70 // void MyOtherMethod() 71 // VALID_CONTEXT_REQUIRED(thread_checker_) { 72 // foo_ = 42; 73 // } 74 // 75 // private: 76 // int foo_ GUARDED_BY_CONTEXT(thread_checker_); 77 // 78 // THREAD_CHECKER(thread_checker_); 79 // } 80 81 #if DCHECK_IS_ON() 82 #define THREAD_CHECKER(name) base::ThreadChecker name 83 #define DCHECK_CALLED_ON_VALID_THREAD(name, ...) \ 84 base::ScopedValidateThreadChecker BASE_UNIQUIFY( \ 85 scoped_validate_thread_checker_)(name, ##__VA_ARGS__); 86 #define DETACH_FROM_THREAD(name) (name).DetachFromThread() 87 #else // DCHECK_IS_ON() 88 #define THREAD_CHECKER(name) static_assert(true, "") 89 #define DCHECK_CALLED_ON_VALID_THREAD(name, ...) EAT_CHECK_STREAM_PARAMS() 90 #define DETACH_FROM_THREAD(name) 91 #endif // DCHECK_IS_ON() 92 93 namespace base { 94 95 // Do nothing implementation, for use in release mode. 96 // 97 // Note: You should almost always use the ThreadChecker class (through the above 98 // macros) to get the right version for your build configuration. 99 // Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in 100 // order to support thread_annotations.h. 101 class LOCKABLE ThreadCheckerDoNothing { 102 public: EnableStackLogging()103 static void EnableStackLogging() {} 104 105 ThreadCheckerDoNothing() = default; 106 107 ThreadCheckerDoNothing(const ThreadCheckerDoNothing&) = delete; 108 ThreadCheckerDoNothing& operator=(const ThreadCheckerDoNothing&) = delete; 109 110 // Moving between matching threads is allowed to help classes with 111 // ThreadCheckers that want a default move-construct/assign. 112 ThreadCheckerDoNothing(ThreadCheckerDoNothing&& other) = default; 113 ThreadCheckerDoNothing& operator=(ThreadCheckerDoNothing&& other) = default; 114 115 [[nodiscard]] bool CalledOnValidThread( 116 std::unique_ptr<void*> = nullptr) const { 117 return true; 118 } DetachFromThread()119 void DetachFromThread() {} 120 }; 121 122 // Note that ThreadCheckerImpl::CalledOnValidThread() returns false when called 123 // from tasks posted to SingleThreadTaskRunners bound to different sequences, 124 // even if the tasks happen to run on the same thread (e.g. two independent 125 // SingleThreadTaskRunners on the ThreadPool that happen to share a thread). 126 #if DCHECK_IS_ON() 127 class ThreadChecker : public ThreadCheckerImpl { 128 }; 129 #else 130 class ThreadChecker : public ThreadCheckerDoNothing { 131 }; 132 #endif // DCHECK_IS_ON() 133 134 #if DCHECK_IS_ON() 135 class BASE_EXPORT SCOPED_LOCKABLE ScopedValidateThreadChecker { 136 public: 137 explicit ScopedValidateThreadChecker(const ThreadChecker& checker) 138 EXCLUSIVE_LOCK_FUNCTION(checker); 139 ScopedValidateThreadChecker(const ThreadChecker& checker, 140 std::string_view msg) 141 EXCLUSIVE_LOCK_FUNCTION(checker); 142 143 ScopedValidateThreadChecker(const ScopedValidateThreadChecker&) = delete; 144 ScopedValidateThreadChecker& operator=(const ScopedValidateThreadChecker&) = 145 delete; 146 147 ~ScopedValidateThreadChecker() UNLOCK_FUNCTION(); 148 }; 149 #endif 150 151 } // namespace base 152 153 #endif // BASE_THREADING_THREAD_CHECKER_H_ 154