sequence_checker.h (5131B)
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 "api/task_queue/task_queue_base.h" 14 #include "rtc_base/checks.h" 15 #include "rtc_base/synchronization/sequence_checker_internal.h" 16 #include "rtc_base/thread_annotations.h" 17 18 namespace webrtc { 19 20 // SequenceChecker is a helper class used to help verify that some methods 21 // of a class are called on the same task queue or thread. A 22 // SequenceChecker is bound to a a task queue if the object is 23 // created on a task queue, or a thread otherwise. 24 // 25 // 26 // Example: 27 // class MyClass { 28 // public: 29 // void Foo() { 30 // RTC_DCHECK_RUN_ON(&sequence_checker_); 31 // ... (do stuff) ... 32 // } 33 // 34 // private: 35 // SequenceChecker sequence_checker_; 36 // } 37 // 38 // In Release mode, IsCurrent will always return true. 39 class RTC_LOCKABLE SequenceChecker 40 #if RTC_DCHECK_IS_ON 41 : public webrtc_sequence_checker_internal::SequenceCheckerImpl { 42 using Impl = webrtc_sequence_checker_internal::SequenceCheckerImpl; 43 #else 44 : public webrtc_sequence_checker_internal::SequenceCheckerDoNothing { 45 using Impl = webrtc_sequence_checker_internal::SequenceCheckerDoNothing; 46 #endif 47 public: 48 enum InitialState : bool { kDetached = false, kAttached = true }; 49 50 // TODO(tommi): We could maybe join these two ctors and have fewer factory 51 // functions. At the moment they're separate to minimize code changes when 52 // we added the second ctor as well as avoiding to have unnecessary code at 53 // the SequenceChecker which much only run for the SequenceCheckerImpl 54 // implementation. 55 // In theory we could have something like: 56 // 57 // SequenceChecker(InitialState initial_state = kAttached, 58 // TaskQueueBase* attached_queue = TaskQueueBase::Current()); 59 // 60 // But the problem with that is having the call to `Current()` exist for 61 // `SequenceCheckerDoNothing`. 62 explicit SequenceChecker(InitialState initial_state = kAttached) 63 : Impl(initial_state) {} 64 explicit SequenceChecker(TaskQueueBase* attached_queue) 65 : Impl(attached_queue) {} 66 67 // Returns true if sequence checker is attached to the current sequence. 68 bool IsCurrent() const { return Impl::IsCurrent(); } 69 // Detaches checker from sequence to which it is attached. Next attempt 70 // to do a check with this checker will result in attaching this checker 71 // to the sequence on which check was performed. 72 void Detach() { Impl::Detach(); } 73 }; 74 75 } // namespace webrtc 76 77 // RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate 78 // variables are accessed from same thread/task queue. 79 // Using tools designed to check mutexes, it checks at compile time everywhere 80 // variable is access, there is a run-time dcheck thread/task queue is correct. 81 // 82 // class SequenceCheckerExample { 83 // public: 84 // int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) { 85 // return var2_; 86 // } 87 // 88 // void CallMeFromPacer() { 89 // RTC_DCHECK_RUN_ON(&pacer_sequence_checker_) 90 // << "Should be called from pacer"; 91 // CalledFromPacer(); 92 // } 93 // 94 // private: 95 // int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_); 96 // SequenceChecker pacer_sequence_checker_; 97 // }; 98 // 99 // class TaskQueueExample { 100 // public: 101 // class Encoder { 102 // public: 103 // webrtc::TaskQueueBase& Queue() { return encoder_queue_; } 104 // void Encode() { 105 // RTC_DCHECK_RUN_ON(&encoder_queue_); 106 // DoSomething(var_); 107 // } 108 // 109 // private: 110 // webrtc::TaskQueueBase& encoder_queue_; 111 // Frame var_ RTC_GUARDED_BY(encoder_queue_); 112 // }; 113 // 114 // void Encode() { 115 // // Will fail at runtime when DCHECK is enabled: 116 // // encoder_->Encode(); 117 // // Will work: 118 // webrtc::scoped_refptr<Encoder> encoder = encoder_; 119 // encoder_->Queue().PostTask([encoder] { encoder->Encode(); }); 120 // } 121 // 122 // private: 123 // webrtc::scoped_refptr<Encoder> encoder_; 124 // } 125 126 // Document if a function expected to be called from same thread/task queue. 127 #define RTC_RUN_ON(x) \ 128 RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x)) 129 130 // Checks current code is running on the desired sequence. 131 // 132 // First statement annotates for the thread safety analyzer the check was done. 133 // Second statement validates it is running on the sequence `x`. 134 // Such annotation has to be attached to a function, and that function has to be 135 // called. Thus current implementation creates a noop lambda and calls it. 136 #define RTC_DCHECK_RUN_ON(x) \ 137 []() RTC_ASSERT_EXCLUSIVE_LOCK(x) {}(); \ 138 RTC_DCHECK((x)->IsCurrent()) \ 139 << webrtc::webrtc_sequence_checker_internal::ExpectationToString(x); 140 141 #endif // API_SEQUENCE_CHECKER_H_