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 ThreadCheckerImpl(); 34 ~ThreadCheckerImpl(); 35 36 // Allow move construct/assign. This must be called on |other|'s associated 37 // thread and assignment can only be made into a ThreadCheckerImpl which is 38 // detached or already associated with the current thread. 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 ThreadCheckerImpl 41 // will be bound to the current thread and |other| will be detached. 42 ThreadCheckerImpl(ThreadCheckerImpl&& other); 43 ThreadCheckerImpl& operator=(ThreadCheckerImpl&& other); 44 45 // On returning false, if logging is enabled with EnableStackLogging() and 46 // `out_bound_at` is not null, this method allocates a StackTrace and returns 47 // it in the out-parameter, storing inside it the stack from where the failing 48 // ThreadChecker was bound to its thread. 49 [[nodiscard]] bool CalledOnValidThread( 50 std::unique_ptr<debug::StackTrace>* out_bound_at = nullptr) const 51 LOCKS_EXCLUDED(lock_); 52 53 // Changes the thread that is checked for in CalledOnValidThread. This may 54 // be useful when an object may be created on one thread and then used 55 // exclusively on another thread. 56 void DetachFromThread() LOCKS_EXCLUDED(lock_); 57 58 private: 59 friend class SequenceCheckerImpl; 60 61 // Private because it's only called by 62 // `SequenceCheckerImpl::EnableStackLogging()`. 63 static void EnableStackLogging(); 64 65 // Returns ownership of a pointer to StackTrace where the ThreadCheckerImpl 66 // was bound for debug logs, or nullptr if such logging was not enabled at 67 // the time. 68 std::unique_ptr<debug::StackTrace> GetBoundAt() const 69 EXCLUSIVE_LOCKS_REQUIRED(lock_); 70 71 void EnsureAssigned() const EXCLUSIVE_LOCKS_REQUIRED(lock_); 72 73 // Members are mutable so that CalledOnValidThread() can set them. 74 75 // Synchronizes access to all members. 76 mutable base::Lock lock_; 77 78 // Stack from which this was bound (set if `EnableStackLogging()` was called). 79 mutable std::unique_ptr<debug::StackTrace> bound_at_ GUARDED_BY(lock_); 80 81 // Thread on which CalledOnValidThread() may return true. 82 mutable PlatformThreadRef thread_ref_ GUARDED_BY(lock_); 83 84 // TaskToken for which CalledOnValidThread() always returns true. This allows 85 // CalledOnValidThread() to return true when called multiple times from the 86 // same task, even if it's not running in a single-threaded context itself 87 // (allowing usage of ThreadChecker objects on the stack in the scope of one- 88 // off tasks). Note: CalledOnValidThread() may return true even if the current 89 // TaskToken is not equal to this. 90 mutable internal::TaskToken task_token_ GUARDED_BY(lock_); 91 92 // SequenceToken for which CalledOnValidThread() may return true. Used to 93 // ensure that CalledOnValidThread() doesn't return true for ThreadPool 94 // tasks that happen to run on the same thread but weren't posted to the same 95 // SingleThreadTaskRunner. 96 mutable internal::SequenceToken sequence_token_ GUARDED_BY(lock_); 97 }; 98 99 } // namespace base 100 101 #endif // BASE_THREADING_THREAD_CHECKER_IMPL_H_ 102