Line data Source code
1 : /*
2 : * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : // Borrowed from Chromium's src/base/threading/thread_checker.h.
12 :
13 : #ifndef WEBRTC_BASE_THREAD_CHECKER_H_
14 : #define WEBRTC_BASE_THREAD_CHECKER_H_
15 :
16 : // Apart from debug builds, we also enable the thread checker in
17 : // builds with RTC_DCHECK_IS_ON so that trybots and waterfall bots
18 : // with this define will get the same level of thread checking as
19 : // debug bots.
20 : #define ENABLE_THREAD_CHECKER RTC_DCHECK_IS_ON
21 :
22 : #include "webrtc/base/checks.h"
23 : #include "webrtc/base/constructormagic.h"
24 : #include "webrtc/base/thread_annotations.h"
25 : #include "webrtc/base/thread_checker_impl.h"
26 :
27 : namespace rtc {
28 :
29 : // Do nothing implementation, for use in release mode.
30 : //
31 : // Note: You should almost always use the ThreadChecker class to get the
32 : // right version for your build configuration.
33 : class ThreadCheckerDoNothing {
34 : public:
35 : bool CalledOnValidThread() const {
36 : return true;
37 : }
38 :
39 : void DetachFromThread() {}
40 : };
41 :
42 : // ThreadChecker is a helper class used to help verify that some methods of a
43 : // class are called from the same thread. It provides identical functionality to
44 : // base::NonThreadSafe, but it is meant to be held as a member variable, rather
45 : // than inherited from base::NonThreadSafe.
46 : //
47 : // While inheriting from base::NonThreadSafe may give a clear indication about
48 : // the thread-safety of a class, it may also lead to violations of the style
49 : // guide with regard to multiple inheritance. The choice between having a
50 : // ThreadChecker member and inheriting from base::NonThreadSafe should be based
51 : // on whether:
52 : // - Derived classes need to know the thread they belong to, as opposed to
53 : // having that functionality fully encapsulated in the base class.
54 : // - Derived classes should be able to reassign the base class to another
55 : // thread, via DetachFromThread.
56 : //
57 : // If neither of these are true, then having a ThreadChecker member and calling
58 : // CalledOnValidThread is the preferable solution.
59 : //
60 : // Example:
61 : // class MyClass {
62 : // public:
63 : // void Foo() {
64 : // RTC_DCHECK(thread_checker_.CalledOnValidThread());
65 : // ... (do stuff) ...
66 : // }
67 : //
68 : // private:
69 : // ThreadChecker thread_checker_;
70 : // }
71 : //
72 : // In Release mode, CalledOnValidThread will always return true.
73 : #if ENABLE_THREAD_CHECKER
74 0 : class LOCKABLE ThreadChecker : public ThreadCheckerImpl {
75 : };
76 : #else
77 : class LOCKABLE ThreadChecker : public ThreadCheckerDoNothing {
78 : };
79 : #endif // ENABLE_THREAD_CHECKER
80 :
81 : #undef ENABLE_THREAD_CHECKER
82 :
83 : namespace internal {
84 : class SCOPED_LOCKABLE AnnounceOnThread {
85 : public:
86 : template<typename ThreadLikeObject>
87 0 : explicit AnnounceOnThread(const ThreadLikeObject* thread_like_object)
88 0 : EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
89 0 : ~AnnounceOnThread() UNLOCK_FUNCTION() {}
90 :
91 : template<typename ThreadLikeObject>
92 0 : static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
93 0 : return thread_like_object->IsCurrent();
94 : }
95 0 : static bool IsCurrent(const rtc::ThreadChecker* checker) {
96 0 : return checker->CalledOnValidThread();
97 : }
98 :
99 : private:
100 : RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AnnounceOnThread);
101 : };
102 :
103 : } // namespace internal
104 : } // namespace rtc
105 :
106 : // RUN_ON/ACCESS_ON/RTC_DCHECK_RUN_ON macros allows to annotate variables are
107 : // accessed from same thread/task queue.
108 : // Using tools designed to check mutexes, it checks at compile time everywhere
109 : // variable is access, there is a run-time dcheck thread/task queue is correct.
110 : //
111 : // class ExampleThread {
112 : // public:
113 : // void NeedVar1() {
114 : // RTC_DCHECK_RUN_ON(network_thread_);
115 : // transport_->Send();
116 : // }
117 : //
118 : // private:
119 : // rtc::Thread* network_thread_;
120 : // int transport_ ACCESS_ON(network_thread_);
121 : // };
122 : //
123 : // class ExampleThreadChecker {
124 : // public:
125 : // int CalledFromPacer() RUN_ON(pacer_thread_checker_) {
126 : // return var2_;
127 : // }
128 : //
129 : // void CallMeFromPacer() {
130 : // RTC_DCHECK_RUN_ON(&pacer_thread_checker_)
131 : // << "Should be called from pacer";
132 : // CalledFromPacer();
133 : // }
134 : //
135 : // private:
136 : // int pacer_var_ ACCESS_ON(pacer_thread_checker_);
137 : // rtc::ThreadChecker pacer_thread_checker_;
138 : // };
139 : //
140 : // class TaskQueueExample {
141 : // public:
142 : // class Encoder {
143 : // public:
144 : // rtc::TaskQueue* Queue() { return encoder_queue_; }
145 : // void Encode() {
146 : // RTC_DCHECK_RUN_ON(encoder_queue_);
147 : // DoSomething(var_);
148 : // }
149 : //
150 : // private:
151 : // rtc::TaskQueue* const encoder_queue_;
152 : // Frame var_ ACCESS_ON(encoder_queue_);
153 : // };
154 : //
155 : // void Encode() {
156 : // // Will fail at runtime when DCHECK is enabled:
157 : // // encoder_->Encode();
158 : // // Will work:
159 : // rtc::scoped_ref_ptr<Encoder> encoder = encoder_;
160 : // encoder_->Queue()->PostTask([encoder] { encoder->Encode(); });
161 : // }
162 : //
163 : // private:
164 : // rtc::scoped_ref_ptr<Encoder> encoder_;
165 : // }
166 :
167 : // Document if a variable/field is not shared and should be accessed from
168 : // same thread/task queue.
169 : #define ACCESS_ON(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
170 :
171 : // Document if a function expected to be called from same thread/task queue.
172 : #define RUN_ON(x) THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
173 :
174 : #define RTC_DCHECK_RUN_ON(thread_like_object) \
175 : rtc::internal::AnnounceOnThread thread_announcer(thread_like_object); \
176 : RTC_DCHECK(rtc::internal::AnnounceOnThread::IsCurrent(thread_like_object))
177 :
178 : #endif // WEBRTC_BASE_THREAD_CHECKER_H_
|