Index: webrtc/base/thread_checker.h |
diff --git a/webrtc/base/thread_checker.h b/webrtc/base/thread_checker.h |
index 6cd7d7b9e0e83e7ef1194e933022dba7b3cbb1ba..265b2affcb7e15907ab4fce2167e1e73876cb7b5 100644 |
--- a/webrtc/base/thread_checker.h |
+++ b/webrtc/base/thread_checker.h |
@@ -28,6 +28,9 @@ |
#define ENABLE_THREAD_CHECKER 0 |
#endif |
+#include "webrtc/base/checks.h" |
+#include "webrtc/base/constructormagic.h" |
+#include "webrtc/base/thread_annotations.h" |
#include "webrtc/base/thread_checker_impl.h" |
namespace rtc { |
@@ -77,15 +80,101 @@ class ThreadCheckerDoNothing { |
// |
// In Release mode, CalledOnValidThread will always return true. |
#if ENABLE_THREAD_CHECKER |
-class ThreadChecker : public ThreadCheckerImpl { |
+class LOCKABLE ThreadChecker : public ThreadCheckerImpl { |
}; |
#else |
-class ThreadChecker : public ThreadCheckerDoNothing { |
+class LOCKABLE ThreadChecker : public ThreadCheckerDoNothing { |
}; |
#endif // ENABLE_THREAD_CHECKER |
#undef ENABLE_THREAD_CHECKER |
+namespace internal { |
+class SCOPED_LOCKABLE AnnounceOnThread { |
+ public: |
+ template<typename ThreadLikeObject> |
+ explicit AnnounceOnThread(const ThreadLikeObject* thread_like_object) |
+ EXCLUSIVE_LOCK_FUNCTION(thread_like_object) {} |
+ ~AnnounceOnThread() UNLOCK_FUNCTION() {} |
+ |
+ template<typename ThreadLikeObject> |
+ static bool IsCurrent(const ThreadLikeObject* thread_like_object) { |
+ return thread_like_object->IsCurrent(); |
+ } |
+ static bool IsCurrent(const rtc::ThreadChecker* checker) { |
+ return checker->CalledOnValidThread(); |
+ } |
+ |
+ private: |
+ RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AnnounceOnThread); |
+}; |
+ |
+} // namespace internal |
} // namespace rtc |
+// RUN_ON/ACCESS_ON/RTC_DCHECK_RUN_ON macros allows to annotate variables are |
+// accessed from same thread/task queue. |
+// Using tools designed to check mutexes, it checks at compile time everywhere |
+// variable is access, there is a run-time dcheck thread/task queue is correct. |
+// |
+// class ExampleThread { |
+// public: |
+// void NeedVar1() { |
+// RTC_DCHECK_RUN_ON(network_thread_); |
+// transport_->Send(); |
+// } |
+// |
+// private: |
+// rtc::Thread* network_thread_; |
+// int transport_ ACCESS_ON(network_thread_); |
+// }; |
+// |
+// class ExampleThreadChecker { |
+// public: |
+// int CalledFromPacer() RUN_ON(pacer_thread_checker_) { |
+// return var2_; |
+// } |
+// |
+// void CallMeFromPacer() { |
+// RTC_DCHECK_RUN_ON(&pacer_thread_checker_) |
+// << "Should be called from pacer"; |
+// CalledFromPacer(); |
+// } |
+// |
+// private: |
+// int pacer_var_ ACCESS_ON(pacer_thread_checker_); |
+// rtc::ThreadChecker pacer_thread_checker_; |
+// }; |
+// |
+// class TaskQueueExample { |
+// public: |
+// class Encoder { |
+// public: |
+// rtc::TaskQueue* Queue() { return encoder_queue_; } |
+// void Encode() { |
+// RTC_DCHECK_RUN_ON(encoder_queue_); |
+// DoSomething(var_); |
+// } |
+// |
+// private: |
+// rtc::TaskQueue* const encoder_queue_; |
+// Frame var_ ACCESS_ON(encoder_queue_); |
+// }; |
+// |
+// void Encode() { |
+// // Will fail at runtime when DCHECK is enabled: |
+// // encoder_->Encode(); |
+// // Will work: |
+// rtc::scoped_ref_ptr<Encoder> encoder = encoder_; |
+// encoder_->Queue()->PostTask([encoder] { encoder->Encode(); }); |
+// } |
+// |
+// private: |
+// rtc::scoped_ref_ptr<Encoder> encoder_; |
+// } |
+ |
+#define RTC_DCHECK_RUN_ON(thread_like_object) \ |
+ rtc::internal::AnnounceOnThread thread_announcer(thread_like_object); \ |
+ RTC_DCHECK(rtc::internal::AnnounceOnThread::IsCurrent(thread_like_object)) |
+ |
#endif // WEBRTC_BASE_THREAD_CHECKER_H_ |