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