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_IMPL_H_ 6 #define BASE_SEQUENCE_CHECKER_IMPL_H_ 7 8 #include <memory> 9 10 #include "base/base_export.h" 11 #include "base/sequence_token.h" 12 #include "base/synchronization/lock.h" 13 #include "base/thread_annotations.h" 14 #include "base/threading/platform_thread_ref.h" 15 16 namespace base { 17 namespace debug { 18 class StackTrace; 19 } 20 21 // Real implementation of SequenceChecker for use in debug mode or for temporary 22 // use in release mode (e.g. to CHECK on a threading issue seen only in the 23 // wild). 24 // 25 // Note: You should almost always use the SequenceChecker class to get the right 26 // version for your build configuration. 27 // Note: This is marked with "context" capability in order to support 28 // thread_annotations.h. 29 class THREAD_ANNOTATION_ATTRIBUTE__(capability("context")) 30 BASE_EXPORT SequenceCheckerImpl { 31 public: 32 static void EnableStackLogging(); 33 34 SequenceCheckerImpl(); 35 36 // Allow move construct/assign. This must be called on |other|'s associated 37 // sequence and assignment can only be made into a SequenceCheckerImpl which 38 // is detached or already associated with the current sequence. This isn't 39 // thread-safe (|this| and |other| shouldn't be in use while this move is 40 // performed). If the assignment was legal, the resulting SequenceCheckerImpl 41 // will be bound to the current sequence and |other| will be detached. 42 SequenceCheckerImpl(SequenceCheckerImpl&& other); 43 SequenceCheckerImpl& operator=(SequenceCheckerImpl&& other); 44 SequenceCheckerImpl(const SequenceCheckerImpl&) = delete; 45 SequenceCheckerImpl& operator=(const SequenceCheckerImpl&) = delete; 46 ~SequenceCheckerImpl(); 47 48 // Returns true if called in sequence with previous calls to this method and 49 // the constructor. 50 // On returning false, if logging is enabled with EnableStackLogging() and 51 // `out_bound_at` is not null, this method allocates a StackTrace and returns 52 // it in the out-parameter, storing inside it the stack from where the failing 53 // SequenceChecker was bound to its sequence. Otherwise, out_bound_at is left 54 // untouched. 55 [[nodiscard]] bool CalledOnValidSequence( 56 std::unique_ptr<debug::StackTrace>* out_bound_at = nullptr) const; 57 58 // Unbinds the checker from the currently associated sequence. The checker 59 // will be re-bound on the next call to CalledOnValidSequence(). 60 void DetachFromSequence(); 61 62 private: 63 void EnsureAssigned() const EXCLUSIVE_LOCKS_REQUIRED(lock_); 64 65 // Members are mutable so that `CalledOnValidSequence()` can set them. 66 67 mutable Lock lock_; 68 69 // Stack from which this was bound (set if `EnableStackLogging()` was called). 70 mutable std::unique_ptr<debug::StackTrace> bound_at_ GUARDED_BY(lock_); 71 72 // Sequence to which this is bound. 73 mutable internal::SequenceToken sequence_token_ GUARDED_BY(lock_); 74 75 // Thread to which this is bound. Only used to evaluate 76 // `CalledOnValidSequence()` after TLS destruction. 77 mutable PlatformThreadRef thread_ref_ GUARDED_BY(lock_); 78 }; 79 80 } // namespace base 81 82 #endif // BASE_SEQUENCE_CHECKER_IMPL_H_ 83