blob: 265b2affcb7e15907ab4fce2167e1e73876cb7b5 [file] [log] [blame]
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +00001/*
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 DCHECK_ALWAYS_ON so that trybots and waterfall bots
18// with this define will get the same level of thread checking as
19// debug bots.
20//
henrikg91d6ede2015-09-17 00:24:34 -070021// Note that this does not perfectly match situations where RTC_DCHECK is
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000022// enabled. For example a non-official release build may have
23// DCHECK_ALWAYS_ON undefined (and therefore ThreadChecker would be
henrikg91d6ede2015-09-17 00:24:34 -070024// disabled) but have RTC_DCHECKs enabled at runtime.
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000025#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
26#define ENABLE_THREAD_CHECKER 1
27#else
28#define ENABLE_THREAD_CHECKER 0
29#endif
30
danilchap8e572f02016-05-19 06:49:03 -070031#include "webrtc/base/checks.h"
32#include "webrtc/base/constructormagic.h"
33#include "webrtc/base/thread_annotations.h"
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000034#include "webrtc/base/thread_checker_impl.h"
35
36namespace rtc {
37
38// Do nothing implementation, for use in release mode.
39//
40// Note: You should almost always use the ThreadChecker class to get the
41// right version for your build configuration.
42class ThreadCheckerDoNothing {
43 public:
44 bool CalledOnValidThread() const {
45 return true;
46 }
47
48 void DetachFromThread() {}
49};
50
51// ThreadChecker is a helper class used to help verify that some methods of a
52// class are called from the same thread. It provides identical functionality to
53// base::NonThreadSafe, but it is meant to be held as a member variable, rather
54// than inherited from base::NonThreadSafe.
55//
56// While inheriting from base::NonThreadSafe may give a clear indication about
57// the thread-safety of a class, it may also lead to violations of the style
58// guide with regard to multiple inheritance. The choice between having a
59// ThreadChecker member and inheriting from base::NonThreadSafe should be based
60// on whether:
61// - Derived classes need to know the thread they belong to, as opposed to
62// having that functionality fully encapsulated in the base class.
63// - Derived classes should be able to reassign the base class to another
64// thread, via DetachFromThread.
65//
66// If neither of these are true, then having a ThreadChecker member and calling
67// CalledOnValidThread is the preferable solution.
68//
69// Example:
70// class MyClass {
71// public:
72// void Foo() {
henrikg91d6ede2015-09-17 00:24:34 -070073// RTC_DCHECK(thread_checker_.CalledOnValidThread());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000074// ... (do stuff) ...
75// }
76//
77// private:
78// ThreadChecker thread_checker_;
79// }
80//
81// In Release mode, CalledOnValidThread will always return true.
82#if ENABLE_THREAD_CHECKER
danilchap8e572f02016-05-19 06:49:03 -070083class LOCKABLE ThreadChecker : public ThreadCheckerImpl {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000084};
85#else
danilchap8e572f02016-05-19 06:49:03 -070086class LOCKABLE ThreadChecker : public ThreadCheckerDoNothing {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000087};
88#endif // ENABLE_THREAD_CHECKER
89
90#undef ENABLE_THREAD_CHECKER
91
danilchap8e572f02016-05-19 06:49:03 -070092namespace internal {
93class SCOPED_LOCKABLE AnnounceOnThread {
94 public:
95 template<typename ThreadLikeObject>
96 explicit AnnounceOnThread(const ThreadLikeObject* thread_like_object)
97 EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
98 ~AnnounceOnThread() UNLOCK_FUNCTION() {}
99
100 template<typename ThreadLikeObject>
101 static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
102 return thread_like_object->IsCurrent();
103 }
104 static bool IsCurrent(const rtc::ThreadChecker* checker) {
105 return checker->CalledOnValidThread();
106 }
107
108 private:
109 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AnnounceOnThread);
110};
111
112} // namespace internal
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000113} // namespace rtc
114
danilchap8e572f02016-05-19 06:49:03 -0700115// RUN_ON/ACCESS_ON/RTC_DCHECK_RUN_ON macros allows to annotate variables are
116// accessed from same thread/task queue.
117// Using tools designed to check mutexes, it checks at compile time everywhere
118// variable is access, there is a run-time dcheck thread/task queue is correct.
119//
120// class ExampleThread {
121// public:
122// void NeedVar1() {
123// RTC_DCHECK_RUN_ON(network_thread_);
124// transport_->Send();
125// }
126//
127// private:
128// rtc::Thread* network_thread_;
129// int transport_ ACCESS_ON(network_thread_);
130// };
131//
132// class ExampleThreadChecker {
133// public:
134// int CalledFromPacer() RUN_ON(pacer_thread_checker_) {
135// return var2_;
136// }
137//
138// void CallMeFromPacer() {
139// RTC_DCHECK_RUN_ON(&pacer_thread_checker_)
140// << "Should be called from pacer";
141// CalledFromPacer();
142// }
143//
144// private:
145// int pacer_var_ ACCESS_ON(pacer_thread_checker_);
146// rtc::ThreadChecker pacer_thread_checker_;
147// };
148//
149// class TaskQueueExample {
150// public:
151// class Encoder {
152// public:
153// rtc::TaskQueue* Queue() { return encoder_queue_; }
154// void Encode() {
155// RTC_DCHECK_RUN_ON(encoder_queue_);
156// DoSomething(var_);
157// }
158//
159// private:
160// rtc::TaskQueue* const encoder_queue_;
161// Frame var_ ACCESS_ON(encoder_queue_);
162// };
163//
164// void Encode() {
165// // Will fail at runtime when DCHECK is enabled:
166// // encoder_->Encode();
167// // Will work:
168// rtc::scoped_ref_ptr<Encoder> encoder = encoder_;
169// encoder_->Queue()->PostTask([encoder] { encoder->Encode(); });
170// }
171//
172// private:
173// rtc::scoped_ref_ptr<Encoder> encoder_;
174// }
175
176#define RTC_DCHECK_RUN_ON(thread_like_object) \
177 rtc::internal::AnnounceOnThread thread_announcer(thread_like_object); \
178 RTC_DCHECK(rtc::internal::AnnounceOnThread::IsCurrent(thread_like_object))
179
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000180#endif // WEBRTC_BASE_THREAD_CHECKER_H_