• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/base_export.h"
9 #include "base/dcheck_is_on.h"
10 #include "base/macros/uniquify.h"
11 #include "base/strings/string_piece.h"
12 #include "base/thread_annotations.h"
13 #include "base/threading/thread_checker_impl.h"
14 
15 // ThreadChecker is a helper class used to help verify that some methods of a
16 // class are called from the same thread (for thread-affinity).  It supports
17 // thread safety annotations (see base/thread_annotations.h).
18 //
19 // Use the macros below instead of the ThreadChecker directly so that the unused
20 // member doesn't result in an extra byte (four when padded) per instance in
21 // production.
22 //
23 // Usage of this class should be *rare* as most classes require thread-safety
24 // but not thread-affinity. Prefer base::SequenceChecker to verify thread-safe
25 // access.
26 //
27 // Thread-affinity checks should only be required in classes that use thread-
28 // local-storage or a third-party API that does.
29 //
30 // Prefer to encode the minimum requirements of each class instead of the
31 // environment it happens to run in today. e.g. if a class requires thread-
32 // safety but not thread-affinity, use a SequenceChecker even if it happens to
33 // run on a SingleThreadTaskRunner today. That makes it easier to understand
34 // what would need to change to turn that SingleThreadTaskRunner into a
35 // SequencedTaskRunner for ease of scheduling as well as minimizes side-effects
36 // if that change is made.
37 //
38 // Debugging:
39 //   If ThreadChecker::EnableStackLogging() is called beforehand, then when
40 //   ThreadChecker fails, in addition to crashing with a stack trace of where
41 //   the violation occurred, it will also dump a stack trace of where the
42 //   checker was bound to a thread.
43 //
44 // Usage:
45 //   class MyClass {
46 //    public:
47 //     MyClass() {
48 //       // It's sometimes useful to detach on construction for objects that are
49 //       // constructed in one place and forever after used from another
50 //       // thread.
51 //       DETACH_FROM_THREAD(thread_checker_);
52 //     }
53 //
54 //     ~MyClass() {
55 //       // ThreadChecker doesn't automatically check it's destroyed on origin
56 //       // thread for the same reason it's sometimes detached in the
57 //       // constructor. It's okay to destroy off thread if the owner otherwise
58 //       // knows usage on the associated thread is done. If you're not
59 //       // detaching in the constructor, you probably want to explicitly check
60 //       // in the destructor.
61 //       DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
62 //     }
63 //
64 //     void MyMethod() {
65 //       DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
66 //       ... (do stuff) ...
67 //     }
68 //
69 //     void MyOtherMethod()
70 //         VALID_CONTEXT_REQUIRED(thread_checker_) {
71 //       foo_ = 42;
72 //     }
73 //
74 //    private:
75 //     int foo_ GUARDED_BY_CONTEXT(thread_checker_);
76 //
77 //     THREAD_CHECKER(thread_checker_);
78 //   }
79 
80 #if DCHECK_IS_ON()
81 #define THREAD_CHECKER(name) base::ThreadChecker name
82 #define DCHECK_CALLED_ON_VALID_THREAD(name, ...)   \
83   base::ScopedValidateThreadChecker BASE_UNIQUIFY( \
84       scoped_validate_thread_checker_)(name, ##__VA_ARGS__);
85 #define DETACH_FROM_THREAD(name) (name).DetachFromThread()
86 #else  // DCHECK_IS_ON()
87 #define THREAD_CHECKER(name) static_assert(true, "")
88 #define DCHECK_CALLED_ON_VALID_THREAD(name, ...) EAT_CHECK_STREAM_PARAMS()
89 #define DETACH_FROM_THREAD(name)
90 #endif  // DCHECK_IS_ON()
91 
92 namespace base {
93 
94 // Do nothing implementation, for use in release mode.
95 //
96 // Note: You should almost always use the ThreadChecker class (through the above
97 // macros) to get the right version for your build configuration.
98 // Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
99 // order to support thread_annotations.h.
100 class LOCKABLE ThreadCheckerDoNothing {
101  public:
EnableStackLogging()102   static void EnableStackLogging() {}
103 
104   ThreadCheckerDoNothing() = default;
105 
106   ThreadCheckerDoNothing(const ThreadCheckerDoNothing&) = delete;
107   ThreadCheckerDoNothing& operator=(const ThreadCheckerDoNothing&) = delete;
108 
109   // Moving between matching threads is allowed to help classes with
110   // ThreadCheckers that want a default move-construct/assign.
111   ThreadCheckerDoNothing(ThreadCheckerDoNothing&& other) = default;
112   ThreadCheckerDoNothing& operator=(ThreadCheckerDoNothing&& other) = default;
113 
114   [[nodiscard]] bool CalledOnValidThread(
115       std::unique_ptr<void*> = nullptr) const {
116     return true;
117   }
DetachFromThread()118   void DetachFromThread() {}
119 };
120 
121 // Note that ThreadCheckerImpl::CalledOnValidThread() returns false when called
122 // from tasks posted to SingleThreadTaskRunners bound to different sequences,
123 // even if the tasks happen to run on the same thread (e.g. two independent
124 // SingleThreadTaskRunners on the ThreadPool that happen to share a thread).
125 #if DCHECK_IS_ON()
126 class ThreadChecker : public ThreadCheckerImpl {
127 };
128 #else
129 class ThreadChecker : public ThreadCheckerDoNothing {
130 };
131 #endif  // DCHECK_IS_ON()
132 
133 #if DCHECK_IS_ON()
134 class BASE_EXPORT SCOPED_LOCKABLE ScopedValidateThreadChecker {
135  public:
136   explicit ScopedValidateThreadChecker(const ThreadChecker& checker)
137       EXCLUSIVE_LOCK_FUNCTION(checker);
138   ScopedValidateThreadChecker(const ThreadChecker& checker,
139                               const StringPiece& msg)
140       EXCLUSIVE_LOCK_FUNCTION(checker);
141 
142   ScopedValidateThreadChecker(const ScopedValidateThreadChecker&) = delete;
143   ScopedValidateThreadChecker& operator=(const ScopedValidateThreadChecker&) =
144       delete;
145 
146   ~ScopedValidateThreadChecker() UNLOCK_FUNCTION();
147 };
148 #endif
149 
150 }  // namespace base
151 
152 #endif  // BASE_THREADING_THREAD_CHECKER_H_
153