1 // Copyright 2011 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_IMPL_H_ 6 #define BASE_THREADING_THREAD_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 class SequenceCheckerImpl; 22 23 // Real implementation of ThreadChecker, for use in debug mode, or for temporary 24 // use in release mode (e.g. to CHECK on a threading issue seen only in the 25 // wild). 26 // 27 // Note: You should almost always use the ThreadChecker class to get the right 28 // version for your build configuration. 29 // Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in 30 // order to support thread_annotations.h. 31 class LOCKABLE BASE_EXPORT ThreadCheckerImpl { 32 public: 33 static void EnableStackLogging(); 34 35 ThreadCheckerImpl(); 36 ~ThreadCheckerImpl(); 37 38 // Allow move construct/assign. This must be called on |other|'s associated 39 // thread and assignment can only be made into a ThreadCheckerImpl which is 40 // detached or already associated with the current thread. This isn't 41 // thread-safe (|this| and |other| shouldn't be in use while this move is 42 // performed). If the assignment was legal, the resulting ThreadCheckerImpl 43 // will be bound to the current thread and |other| will be detached. 44 ThreadCheckerImpl(ThreadCheckerImpl&& other); 45 ThreadCheckerImpl& operator=(ThreadCheckerImpl&& other); 46 47 // On returning false, if logging is enabled with EnableStackLogging() and 48 // `out_bound_at` is not null, this method allocates a StackTrace and returns 49 // it in the out-parameter, storing inside it the stack from where the failing 50 // ThreadChecker was bound to its thread. 51 [[nodiscard]] bool CalledOnValidThread( 52 std::unique_ptr<debug::StackTrace>* out_bound_at = nullptr) const 53 LOCKS_EXCLUDED(lock_); 54 55 // Changes the thread that is checked for in CalledOnValidThread. This may 56 // be useful when an object may be created on one thread and then used 57 // exclusively on another thread. 58 void DetachFromThread() LOCKS_EXCLUDED(lock_); 59 60 private: 61 // This shares storage with SequenceCheckerImpl. 62 friend class SequenceCheckerImpl; 63 64 [[nodiscard]] bool CalledOnValidThreadInternal( 65 std::unique_ptr<debug::StackTrace>* out_bound_at) const 66 EXCLUSIVE_LOCKS_REQUIRED(lock_); 67 68 // Returns ownership of a pointer to StackTrace where the ThreadCheckerImpl 69 // was bound for debug logs, or nullptr if such logging was not enabled at 70 // the time. 71 std::unique_ptr<debug::StackTrace> GetBoundAt() const 72 EXCLUSIVE_LOCKS_REQUIRED(lock_); 73 74 void EnsureAssigned() const EXCLUSIVE_LOCKS_REQUIRED(lock_); 75 76 // Members are mutable so that CalledOnValidThread() can set them. 77 78 // Synchronizes access to all members. 79 mutable base::Lock lock_; 80 81 // The location where the ThreadChecker was bound to the current 82 // thread/task/sequence. Default-initialized with 0 frames until bound. 83 mutable std::unique_ptr<debug::StackTrace> bound_at_ GUARDED_BY(lock_); 84 85 // Thread on which CalledOnValidThread() may return true. 86 mutable PlatformThreadRef thread_id_ GUARDED_BY(lock_); 87 88 // TaskToken for which CalledOnValidThread() always returns true. This allows 89 // CalledOnValidThread() to return true when called multiple times from the 90 // same task, even if it's not running in a single-threaded context itself 91 // (allowing usage of ThreadChecker objects on the stack in the scope of one- 92 // off tasks). Note: CalledOnValidThread() may return true even if the current 93 // TaskToken is not equal to this. 94 mutable TaskToken task_token_ GUARDED_BY(lock_); 95 96 // SequenceToken for which CalledOnValidThread() may return true. Used to 97 // ensure that CalledOnValidThread() doesn't return true for ThreadPool 98 // tasks that happen to run on the same thread but weren't posted to the same 99 // SingleThreadTaskRunner. 100 // 101 // Also used for SequenceCheckerImpl's CalledOnValidSequence(), as this shares 102 // storage. See SequenceCheckerImpl. 103 mutable SequenceToken sequence_token_ GUARDED_BY(lock_); 104 }; 105 106 } // namespace base 107 108 #endif // BASE_THREADING_THREAD_CHECKER_IMPL_H_ 109