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_SEQUENCE_CHECKER_H_ 6 #define BASE_SEQUENCE_CHECKER_H_ 7 8 #include "base/base_export.h" 9 #include "base/dcheck_is_on.h" 10 #include "base/macros/uniquify.h" 11 #include "base/sequence_checker_impl.h" 12 13 // SequenceChecker verifies mutual exclusion between calls to its 14 // `CalledOnValidSequence()` method. Mutual exclusion is guaranteed if all calls 15 // are made from the same thread, from the same sequence (see 16 // `SequencedTaskRunner`) or under the same lock acquired with 17 // `base::subtle::LockTracking::kEnabled`. SequenceChecker supports thread 18 // safety annotations (see base/thread_annotations.h). 19 // 20 // Use the macros below instead of the SequenceChecker directly so that the 21 // unused member doesn't result in an extra byte (four when padded) per instance 22 // in production. 23 // 24 // This class is much prefered to ThreadChecker for thread-safety checks. 25 // ThreadChecker should only be used for classes that are truly thread-affine 26 // (use thread-local-storage or a third-party API that does). 27 // 28 // Debugging: 29 // If SequenceChecker::EnableStackLogging() is called beforehand, then when 30 // SequenceChecker fails, in addition to crashing with a stack trace of where 31 // the violation occurred, it will also dump a stack trace of where the 32 // checker was bound to a sequence. 33 // 34 // Usage: 35 // class MyClass { 36 // public: 37 // MyClass() { 38 // // Detaching on construction is necessary for objects that are 39 // // constructed on one sequence and forever after used from another 40 // // sequence. 41 // DETACH_FROM_SEQUENCE(sequence_checker_); 42 // } 43 // 44 // ~MyClass() { 45 // // SequenceChecker doesn't automatically check it's destroyed on origin 46 // // sequence for the same reason it's sometimes detached in the 47 // // constructor. It's okay to destroy off sequence if the owner 48 // // otherwise knows usage on the associated sequence is done. If you're 49 // // not detaching in the constructor, you probably want to explicitly 50 // // check in the destructor. 51 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 52 // } 53 // void MyMethod() { 54 // DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); 55 // ... (do stuff) ... 56 // MyOtherMethod(); 57 // } 58 // 59 // void MyOtherMethod() VALID_CONTEXT_REQUIRED(sequence_checker_) { 60 // foo_ = 42; 61 // } 62 // 63 // private: 64 // // GUARDED_BY_CONTEXT() enforces that this member is only 65 // // accessed from a scope that invokes DCHECK_CALLED_ON_VALID_SEQUENCE() 66 // // or from a function annotated with VALID_CONTEXT_REQUIRED(). A 67 // // DCHECK build will not compile if the member is accessed and these 68 // // conditions are not met. 69 // int foo_ GUARDED_BY_CONTEXT(sequence_checker_); 70 // 71 // SEQUENCE_CHECKER(sequence_checker_); 72 // } 73 74 #if DCHECK_IS_ON() 75 #define SEQUENCE_CHECKER(name) base::SequenceChecker name 76 #define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...) \ 77 base::ScopedValidateSequenceChecker BASE_UNIQUIFY( \ 78 scoped_validate_sequence_checker_)(name, ##__VA_ARGS__) 79 #define DETACH_FROM_SEQUENCE(name) (name).DetachFromSequence() 80 #else // DCHECK_IS_ON() 81 // A no-op expansion that can be followed by a semicolon at class level. 82 #define SEQUENCE_CHECKER(name) static_assert(true, "") 83 #define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...) EAT_CHECK_STREAM_PARAMS() 84 #define DETACH_FROM_SEQUENCE(name) 85 #endif // DCHECK_IS_ON() 86 87 namespace base { 88 89 // Do nothing implementation, for use in release mode. 90 // 91 // Note: You should almost always use the SequenceChecker class (through the 92 // above macros) to get the right version for your build configuration. 93 // Note: This is marked with "context" capability in order to support 94 // thread_annotations.h. 95 class THREAD_ANNOTATION_ATTRIBUTE__(capability("context")) 96 SequenceCheckerDoNothing { 97 public: EnableStackLogging()98 static void EnableStackLogging() {} 99 100 SequenceCheckerDoNothing() = default; 101 102 // Moving between matching sequences is allowed to help classes with 103 // SequenceCheckers that want a default move-construct/assign. 104 SequenceCheckerDoNothing(SequenceCheckerDoNothing&& other) = default; 105 SequenceCheckerDoNothing& operator=(SequenceCheckerDoNothing&& other) = 106 default; 107 SequenceCheckerDoNothing(const SequenceCheckerDoNothing&) = delete; 108 SequenceCheckerDoNothing& operator=(const SequenceCheckerDoNothing&) = delete; 109 110 [[nodiscard]] bool CalledOnValidSequence(void* = nullptr) const { 111 return true; 112 } DetachFromSequence()113 void DetachFromSequence() {} 114 }; 115 116 #if DCHECK_IS_ON() 117 using SequenceChecker = SequenceCheckerImpl; 118 #else 119 using SequenceChecker = SequenceCheckerDoNothing; 120 #endif // DCHECK_IS_ON() 121 122 #if DCHECK_IS_ON() 123 class BASE_EXPORT SCOPED_LOCKABLE ScopedValidateSequenceChecker { 124 public: 125 explicit ScopedValidateSequenceChecker(const SequenceChecker& checker) 126 EXCLUSIVE_LOCK_FUNCTION(checker); 127 ~ScopedValidateSequenceChecker() UNLOCK_FUNCTION(); 128 }; 129 #endif 130 131 } // namespace base 132 133 #endif // BASE_SEQUENCE_CHECKER_H_ 134