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