blob: ad0450871a1e26772224f5bcf90aec9fb094e98b [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:
Yves Gerey665174f2018-06-19 15:03:05 +020035 bool CalledOnValidThread() const { return true; }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020036
37 void DetachFromThread() {}
38};
39
40// ThreadChecker is a helper class used to help verify that some methods of a
41// class are called from the same thread. It provides identical functionality to
42// base::NonThreadSafe, but it is meant to be held as a member variable, rather
43// than inherited from base::NonThreadSafe.
44//
45// While inheriting from base::NonThreadSafe may give a clear indication about
46// the thread-safety of a class, it may also lead to violations of the style
47// guide with regard to multiple inheritance. The choice between having a
48// ThreadChecker member and inheriting from base::NonThreadSafe should be based
49// on whether:
50// - Derived classes need to know the thread they belong to, as opposed to
51// having that functionality fully encapsulated in the base class.
52// - Derived classes should be able to reassign the base class to another
53// thread, via DetachFromThread.
54//
55// If neither of these are true, then having a ThreadChecker member and calling
56// CalledOnValidThread is the preferable solution.
57//
58// Example:
59// class MyClass {
60// public:
61// void Foo() {
62// RTC_DCHECK(thread_checker_.CalledOnValidThread());
63// ... (do stuff) ...
64// }
65//
66// private:
67// ThreadChecker thread_checker_;
68// }
69//
70// In Release mode, CalledOnValidThread will always return true.
danilchap47791cf2017-09-13 01:25:46 -070071#if RTC_ENABLE_THREAD_CHECKER
danilchap3c6abd22017-09-06 05:46:29 -070072class RTC_LOCKABLE ThreadChecker : public ThreadCheckerImpl {};
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020073#else
danilchap3c6abd22017-09-06 05:46:29 -070074class RTC_LOCKABLE ThreadChecker : public ThreadCheckerDoNothing {};
danilchap47791cf2017-09-13 01:25:46 -070075#endif // RTC_ENABLE_THREAD_CHECKER
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020076
danilchap47791cf2017-09-13 01:25:46 -070077#undef RTC_ENABLE_THREAD_CHECKER
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020078
79namespace internal {
danilchap3c6abd22017-09-06 05:46:29 -070080class RTC_SCOPED_LOCKABLE AnnounceOnThread {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020081 public:
danilchap3c6abd22017-09-06 05:46:29 -070082 template <typename ThreadLikeObject>
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020083 explicit AnnounceOnThread(const ThreadLikeObject* thread_like_object)
danilchap3c6abd22017-09-06 05:46:29 -070084 RTC_EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
85 ~AnnounceOnThread() RTC_UNLOCK_FUNCTION() {}
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020086
Yves Gerey665174f2018-06-19 15:03:05 +020087 template <typename ThreadLikeObject>
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020088 static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
89 return thread_like_object->IsCurrent();
90 }
91 static bool IsCurrent(const rtc::ThreadChecker* checker) {
92 return checker->CalledOnValidThread();
93 }
94
95 private:
96 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AnnounceOnThread);
97};
98
99} // namespace internal
100} // namespace rtc
101
Niels Möller1e062892018-02-07 10:18:32 +0100102// RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate
danilchap5301e3c2017-09-06 04:10:21 -0700103// variables are accessed from same thread/task queue.
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200104// Using tools designed to check mutexes, it checks at compile time everywhere
105// variable is access, there is a run-time dcheck thread/task queue is correct.
106//
107// class ExampleThread {
108// public:
109// void NeedVar1() {
110// RTC_DCHECK_RUN_ON(network_thread_);
111// transport_->Send();
112// }
113//
114// private:
115// rtc::Thread* network_thread_;
Niels Möller1e062892018-02-07 10:18:32 +0100116// int transport_ RTC_GUARDED_BY(network_thread_);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200117// };
118//
119// class ExampleThreadChecker {
120// public:
danilchap5301e3c2017-09-06 04:10:21 -0700121// int CalledFromPacer() RTC_RUN_ON(pacer_thread_checker_) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200122// return var2_;
123// }
124//
125// void CallMeFromPacer() {
126// RTC_DCHECK_RUN_ON(&pacer_thread_checker_)
127// << "Should be called from pacer";
128// CalledFromPacer();
129// }
130//
131// private:
Niels Möller1e062892018-02-07 10:18:32 +0100132// int pacer_var_ RTC_GUARDED_BY(pacer_thread_checker_);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200133// rtc::ThreadChecker pacer_thread_checker_;
134// };
135//
136// class TaskQueueExample {
137// public:
138// class Encoder {
139// public:
140// rtc::TaskQueue* Queue() { return encoder_queue_; }
141// void Encode() {
142// RTC_DCHECK_RUN_ON(encoder_queue_);
143// DoSomething(var_);
144// }
145//
146// private:
147// rtc::TaskQueue* const encoder_queue_;
Niels Möller1e062892018-02-07 10:18:32 +0100148// Frame var_ RTC_GUARDED_BY(encoder_queue_);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200149// };
150//
151// void Encode() {
152// // Will fail at runtime when DCHECK is enabled:
153// // encoder_->Encode();
154// // Will work:
155// rtc::scoped_ref_ptr<Encoder> encoder = encoder_;
156// encoder_->Queue()->PostTask([encoder] { encoder->Encode(); });
157// }
158//
159// private:
160// rtc::scoped_ref_ptr<Encoder> encoder_;
161// }
162
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200163// Document if a function expected to be called from same thread/task queue.
Yves Gerey665174f2018-06-19 15:03:05 +0200164#define RTC_RUN_ON(x) \
165 RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200166
Yves Gerey665174f2018-06-19 15:03:05 +0200167#define RTC_DCHECK_RUN_ON(thread_like_object) \
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200168 rtc::internal::AnnounceOnThread thread_announcer(thread_like_object); \
169 RTC_DCHECK(rtc::internal::AnnounceOnThread::IsCurrent(thread_like_object))
danilchap8e572f02016-05-19 06:49:03 -0700170
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200171#endif // RTC_BASE_THREAD_CHECKER_H_