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