blob: fe644fa14e3205d4ac6a9d386e3661a1942316a2 [file] [log] [blame]
Sebastian Janssondf5e4e02019-03-29 10:34:45 +01001/*
2 * Copyright 2019 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#ifndef RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_
11#define RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_
12
13#include "api/task_queue/task_queue_base.h"
14#include "rtc_base/critical_section.h"
15#include "rtc_base/platform_thread_types.h"
Mirko Bonadei35214fc2019-09-23 14:54:28 +020016#include "rtc_base/system/rtc_export.h"
Sebastian Janssondf5e4e02019-03-29 10:34:45 +010017#include "rtc_base/thread_annotations.h"
18
19namespace webrtc {
20// Real implementation of SequenceChecker, for use in debug mode, or
21// for temporary use in release mode (e.g. to RTC_CHECK on a threading issue
22// seen only in the wild).
23//
24// Note: You should almost always use the SequenceChecker class to get the
25// right version for your build configuration.
Mirko Bonadei35214fc2019-09-23 14:54:28 +020026class RTC_EXPORT SequenceCheckerImpl {
Sebastian Janssondf5e4e02019-03-29 10:34:45 +010027 public:
28 SequenceCheckerImpl();
29 ~SequenceCheckerImpl();
30
31 bool IsCurrent() const;
32 // Changes the task queue or thread that is checked for in IsCurrent. This can
33 // be useful when an object may be created on one task queue / thread and then
34 // used exclusively on another thread.
35 void Detach();
36
37 private:
38 rtc::CriticalSection lock_;
39 // These are mutable so that IsCurrent can set them.
40 mutable bool attached_ RTC_GUARDED_BY(lock_);
41 mutable rtc::PlatformThreadRef valid_thread_ RTC_GUARDED_BY(lock_);
42 mutable const TaskQueueBase* valid_queue_ RTC_GUARDED_BY(lock_);
43 mutable const void* valid_system_queue_ RTC_GUARDED_BY(lock_);
44};
45
46// Do nothing implementation, for use in release mode.
47//
48// Note: You should almost always use the SequenceChecker class to get the
49// right version for your build configuration.
50class SequenceCheckerDoNothing {
51 public:
52 bool IsCurrent() const { return true; }
53 void Detach() {}
54};
55
56// SequenceChecker is a helper class used to help verify that some methods
57// of a class are called on the same task queue or thread. A
58// SequenceChecker is bound to a a task queue if the object is
59// created on a task queue, or a thread otherwise.
60//
61//
62// Example:
63// class MyClass {
64// public:
65// void Foo() {
66// RTC_DCHECK_RUN_ON(sequence_checker_);
67// ... (do stuff) ...
68// }
69//
70// private:
71// SequenceChecker sequence_checker_;
72// }
73//
74// In Release mode, IsCurrent will always return true.
75#if RTC_DCHECK_IS_ON
76class RTC_LOCKABLE SequenceChecker : public SequenceCheckerImpl {};
77#else
78class RTC_LOCKABLE SequenceChecker : public SequenceCheckerDoNothing {};
79#endif // RTC_ENABLE_THREAD_CHECKER
80
81namespace webrtc_seq_check_impl {
82// Helper class used by RTC_DCHECK_RUN_ON (see example usage below).
83class RTC_SCOPED_LOCKABLE SequenceCheckerScope {
84 public:
85 template <typename ThreadLikeObject>
86 explicit SequenceCheckerScope(const ThreadLikeObject* thread_like_object)
87 RTC_EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {}
88 SequenceCheckerScope(const SequenceCheckerScope&) = delete;
89 SequenceCheckerScope& operator=(const SequenceCheckerScope&) = delete;
90 ~SequenceCheckerScope() RTC_UNLOCK_FUNCTION() {}
91
92 template <typename ThreadLikeObject>
93 static bool IsCurrent(const ThreadLikeObject* thread_like_object) {
94 return thread_like_object->IsCurrent();
95 }
96};
97} // namespace webrtc_seq_check_impl
98} // namespace webrtc
99
100// RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate
101// variables are accessed from same thread/task queue.
102// Using tools designed to check mutexes, it checks at compile time everywhere
103// variable is access, there is a run-time dcheck thread/task queue is correct.
104//
105// class ThreadExample {
106// public:
107// void NeedVar1() {
108// RTC_DCHECK_RUN_ON(network_thread_);
109// transport_->Send();
110// }
111//
112// private:
113// rtc::Thread* network_thread_;
114// int transport_ RTC_GUARDED_BY(network_thread_);
115// };
116//
117// class SequenceCheckerExample {
118// public:
119// int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) {
120// return var2_;
121// }
122//
123// void CallMeFromPacer() {
124// RTC_DCHECK_RUN_ON(&pacer_sequence_checker_)
125// << "Should be called from pacer";
126// CalledFromPacer();
127// }
128//
129// private:
130// int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_);
131// SequenceChecker pacer_sequence_checker_;
132// };
133//
134// class TaskQueueExample {
135// public:
136// class Encoder {
137// public:
138// rtc::TaskQueue* Queue() { return encoder_queue_; }
139// void Encode() {
140// RTC_DCHECK_RUN_ON(encoder_queue_);
141// DoSomething(var_);
142// }
143//
144// private:
145// rtc::TaskQueue* const encoder_queue_;
146// Frame var_ RTC_GUARDED_BY(encoder_queue_);
147// };
148//
149// void Encode() {
150// // Will fail at runtime when DCHECK is enabled:
151// // encoder_->Encode();
152// // Will work:
153// rtc::scoped_refptr<Encoder> encoder = encoder_;
154// encoder_->Queue()->PostTask([encoder] { encoder->Encode(); });
155// }
156//
157// private:
158// rtc::scoped_refptr<Encoder> encoder_;
159// }
160
161// Document if a function expected to be called from same thread/task queue.
162#define RTC_RUN_ON(x) \
163 RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
164
165#define RTC_DCHECK_RUN_ON(x) \
166 webrtc::webrtc_seq_check_impl::SequenceCheckerScope seq_check_scope(x); \
167 RTC_DCHECK((x)->IsCurrent())
168
169#endif // RTC_BASE_SYNCHRONIZATION_SEQUENCE_CHECKER_H_