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 API_SEQUENCE_CHECKER_H_ 11 #define API_SEQUENCE_CHECKER_H_ 12 13 #include "rtc_base/checks.h" 14 #include "rtc_base/synchronization/sequence_checker_internal.h" 15 #include "rtc_base/thread_annotations.h" 16 17 namespace webrtc { 18 19 // SequenceChecker is a helper class used to help verify that some methods 20 // of a class are called on the same task queue or thread. A 21 // SequenceChecker is bound to a a task queue if the object is 22 // created on a task queue, or a thread otherwise. 23 // 24 // 25 // Example: 26 // class MyClass { 27 // public: 28 // void Foo() { 29 // RTC_DCHECK_RUN_ON(&sequence_checker_); 30 // ... (do stuff) ... 31 // } 32 // 33 // private: 34 // SequenceChecker sequence_checker_; 35 // } 36 // 37 // In Release mode, IsCurrent will always return true. 38 class RTC_LOCKABLE SequenceChecker 39 #if RTC_DCHECK_IS_ON 40 : public webrtc_sequence_checker_internal::SequenceCheckerImpl { 41 using Impl = webrtc_sequence_checker_internal::SequenceCheckerImpl; 42 #else 43 : public webrtc_sequence_checker_internal::SequenceCheckerDoNothing { 44 using Impl = webrtc_sequence_checker_internal::SequenceCheckerDoNothing; 45 #endif 46 public: 47 // Returns true if sequence checker is attached to the current sequence. IsCurrent()48 bool IsCurrent() const { return Impl::IsCurrent(); } 49 // Detaches checker from sequence to which it is attached. Next attempt 50 // to do a check with this checker will result in attaching this checker 51 // to the sequence on which check was performed. Detach()52 void Detach() { Impl::Detach(); } 53 }; 54 55 } // namespace webrtc 56 57 // RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate 58 // variables are accessed from same thread/task queue. 59 // Using tools designed to check mutexes, it checks at compile time everywhere 60 // variable is access, there is a run-time dcheck thread/task queue is correct. 61 // 62 // class SequenceCheckerExample { 63 // public: 64 // int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) { 65 // return var2_; 66 // } 67 // 68 // void CallMeFromPacer() { 69 // RTC_DCHECK_RUN_ON(&pacer_sequence_checker_) 70 // << "Should be called from pacer"; 71 // CalledFromPacer(); 72 // } 73 // 74 // private: 75 // int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_); 76 // SequenceChecker pacer_sequence_checker_; 77 // }; 78 // 79 // class TaskQueueExample { 80 // public: 81 // class Encoder { 82 // public: 83 // rtc::TaskQueueBase& Queue() { return encoder_queue_; } 84 // void Encode() { 85 // RTC_DCHECK_RUN_ON(&encoder_queue_); 86 // DoSomething(var_); 87 // } 88 // 89 // private: 90 // rtc::TaskQueueBase& encoder_queue_; 91 // Frame var_ RTC_GUARDED_BY(encoder_queue_); 92 // }; 93 // 94 // void Encode() { 95 // // Will fail at runtime when DCHECK is enabled: 96 // // encoder_->Encode(); 97 // // Will work: 98 // rtc::scoped_refptr<Encoder> encoder = encoder_; 99 // encoder_->Queue().PostTask([encoder] { encoder->Encode(); }); 100 // } 101 // 102 // private: 103 // rtc::scoped_refptr<Encoder> encoder_; 104 // } 105 106 // Document if a function expected to be called from same thread/task queue. 107 #define RTC_RUN_ON(x) \ 108 RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x)) 109 110 // Checks current code is running on the desired sequence. 111 // 112 // First statement validates it is running on the sequence `x`. 113 // Second statement annotates for the thread safety analyzer the check was done. 114 // Such annotation has to be attached to a function, and that function has to be 115 // called. Thus current implementation creates a noop lambda and calls it. 116 #define RTC_DCHECK_RUN_ON(x) \ 117 RTC_DCHECK((x)->IsCurrent()) \ 118 << webrtc::webrtc_sequence_checker_internal::ExpectationToString(x); \ 119 []() RTC_ASSERT_EXCLUSIVE_LOCK(x) {}() 120 121 #endif // API_SEQUENCE_CHECKER_H_ 122