blob: 5914282a57c6faaae43ec76db371032415883350 [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
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020016// 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
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000021
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020022#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
27namespace 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.
33class 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
74class LOCKABLE ThreadChecker : public ThreadCheckerImpl {
75};
76#else
77class LOCKABLE ThreadChecker : public ThreadCheckerDoNothing {
78};
79#endif // ENABLE_THREAD_CHECKER
80
81#undef ENABLE_THREAD_CHECKER
82
83namespace internal {
84class SCOPED_LOCKABLE AnnounceOnThread {
85 public:
86 template<typename ThreadLikeObject>
87 explicit AnnounceOnThread(const ThreadLikeObject* thread_like_object)
88 EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
89 ~AnnounceOnThread() UNLOCK_FUNCTION() {}
90
91 template<typename ThreadLikeObject>
92 static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
93 return thread_like_object->IsCurrent();
94 }
95 static bool IsCurrent(const rtc::ThreadChecker* checker) {
96 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))
danilchap8e572f02016-05-19 06:49:03 -0700177
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000178#endif // WEBRTC_BASE_THREAD_CHECKER_H_