sequence_checker.h 6.0 KB

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