blob: 028e9bf367ecb3e7eeacae68bc73db2a641de0b7 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#ifndef RTC_BASE_THREAD_CHECKER_H_
14#define RTC_BASE_THREAD_CHECKER_H_
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000015
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.
danilchap47791cf2017-09-13 01:25:46 -070020#define RTC_ENABLE_THREAD_CHECKER RTC_DCHECK_IS_ON
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000021
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/checks.h"
23#include "rtc_base/constructormagic.h"
24#include "rtc_base/thread_annotations.h"
25#include "rtc_base/thread_checker_impl.h"
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020026
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.
danilchap47791cf2017-09-13 01:25:46 -070073#if RTC_ENABLE_THREAD_CHECKER
danilchap3c6abd22017-09-06 05:46:29 -070074class RTC_LOCKABLE ThreadChecker : public ThreadCheckerImpl {};
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020075#else
danilchap3c6abd22017-09-06 05:46:29 -070076class RTC_LOCKABLE ThreadChecker : public ThreadCheckerDoNothing {};
danilchap47791cf2017-09-13 01:25:46 -070077#endif // RTC_ENABLE_THREAD_CHECKER
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020078
danilchap47791cf2017-09-13 01:25:46 -070079#undef RTC_ENABLE_THREAD_CHECKER
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020080
81namespace internal {
danilchap3c6abd22017-09-06 05:46:29 -070082class RTC_SCOPED_LOCKABLE AnnounceOnThread {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020083 public:
danilchap3c6abd22017-09-06 05:46:29 -070084 template <typename ThreadLikeObject>
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020085 explicit AnnounceOnThread(const ThreadLikeObject* thread_like_object)
danilchap3c6abd22017-09-06 05:46:29 -070086 RTC_EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
87 ~AnnounceOnThread() RTC_UNLOCK_FUNCTION() {}
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020088
89 template<typename ThreadLikeObject>
90 static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
91 return thread_like_object->IsCurrent();
92 }
93 static bool IsCurrent(const rtc::ThreadChecker* checker) {
94 return checker->CalledOnValidThread();
95 }
96
97 private:
98 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AnnounceOnThread);
99};
100
101} // namespace internal
102} // namespace rtc
103
danilchap5301e3c2017-09-06 04:10:21 -0700104// RTC_RUN_ON/RTC_ACCESS_ON/RTC_DCHECK_RUN_ON macros allows to annotate
105// variables are accessed from same thread/task queue.
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200106// Using tools designed to check mutexes, it checks at compile time everywhere
107// variable is access, there is a run-time dcheck thread/task queue is correct.
108//
109// class ExampleThread {
110// public:
111// void NeedVar1() {
112// RTC_DCHECK_RUN_ON(network_thread_);
113// transport_->Send();
114// }
115//
116// private:
117// rtc::Thread* network_thread_;
danilchap5301e3c2017-09-06 04:10:21 -0700118// int transport_ RTC_ACCESS_ON(network_thread_);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200119// };
120//
121// class ExampleThreadChecker {
122// public:
danilchap5301e3c2017-09-06 04:10:21 -0700123// int CalledFromPacer() RTC_RUN_ON(pacer_thread_checker_) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200124// return var2_;
125// }
126//
127// void CallMeFromPacer() {
128// RTC_DCHECK_RUN_ON(&pacer_thread_checker_)
129// << "Should be called from pacer";
130// CalledFromPacer();
131// }
132//
133// private:
danilchap5301e3c2017-09-06 04:10:21 -0700134// int pacer_var_ RTC_ACCESS_ON(pacer_thread_checker_);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200135// rtc::ThreadChecker pacer_thread_checker_;
136// };
137//
138// class TaskQueueExample {
139// public:
140// class Encoder {
141// public:
142// rtc::TaskQueue* Queue() { return encoder_queue_; }
143// void Encode() {
144// RTC_DCHECK_RUN_ON(encoder_queue_);
145// DoSomething(var_);
146// }
147//
148// private:
149// rtc::TaskQueue* const encoder_queue_;
danilchap5301e3c2017-09-06 04:10:21 -0700150// Frame var_ RTC_ACCESS_ON(encoder_queue_);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200151// };
152//
153// void Encode() {
154// // Will fail at runtime when DCHECK is enabled:
155// // encoder_->Encode();
156// // Will work:
157// rtc::scoped_ref_ptr<Encoder> encoder = encoder_;
158// encoder_->Queue()->PostTask([encoder] { encoder->Encode(); });
159// }
160//
161// private:
162// rtc::scoped_ref_ptr<Encoder> encoder_;
163// }
164
165// Document if a variable/field is not shared and should be accessed from
166// same thread/task queue.
danilchap5301e3c2017-09-06 04:10:21 -0700167#define RTC_ACCESS_ON(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200168
169// Document if a function expected to be called from same thread/task queue.
danilchap5301e3c2017-09-06 04:10:21 -0700170#define RTC_RUN_ON(x) RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200171
172#define RTC_DCHECK_RUN_ON(thread_like_object) \
173 rtc::internal::AnnounceOnThread thread_announcer(thread_like_object); \
174 RTC_DCHECK(rtc::internal::AnnounceOnThread::IsCurrent(thread_like_object))
danilchap8e572f02016-05-19 06:49:03 -0700175
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200176#endif // RTC_BASE_THREAD_CHECKER_H_