xref: /aosp_15_r20/external/cronet/base/threading/thread_checker.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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