1 /* 2 * Copyright (c) 2014 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 11 // Borrowed from Chromium's src/base/threading/thread_checker_unittest.cc. 12 13 #include "testing/gtest/include/gtest/gtest.h" 14 #include "webrtc/base/checks.h" 15 #include "webrtc/base/thread.h" 16 #include "webrtc/base/thread_checker.h" 17 #include "webrtc/base/scoped_ptr.h" 18 19 // Duplicated from base/threading/thread_checker.h so that we can be 20 // good citizens there and undef the macro. 21 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) 22 #define ENABLE_THREAD_CHECKER 1 23 #else 24 #define ENABLE_THREAD_CHECKER 0 25 #endif 26 27 namespace rtc { 28 29 namespace { 30 31 // Simple class to exercise the basics of ThreadChecker. 32 // Both the destructor and DoStuff should verify that they were 33 // called on the same thread as the constructor. 34 class ThreadCheckerClass : public ThreadChecker { 35 public: 36 ThreadCheckerClass() {} 37 38 // Verifies that it was called on the same thread as the constructor. 39 void DoStuff() { RTC_DCHECK(CalledOnValidThread()); } 40 41 void DetachFromThread() { 42 ThreadChecker::DetachFromThread(); 43 } 44 45 static void MethodOnDifferentThreadImpl(); 46 static void DetachThenCallFromDifferentThreadImpl(); 47 48 private: 49 RTC_DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass); 50 }; 51 52 // Calls ThreadCheckerClass::DoStuff on another thread. 53 class CallDoStuffOnThread : public Thread { 54 public: 55 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class) 56 : Thread(), 57 thread_checker_class_(thread_checker_class) { 58 SetName("call_do_stuff_on_thread", NULL); 59 } 60 61 void Run() override { thread_checker_class_->DoStuff(); } 62 63 // New method. Needed since Thread::Join is protected, and it is called by 64 // the TEST. 65 void Join() { 66 Thread::Join(); 67 } 68 69 private: 70 ThreadCheckerClass* thread_checker_class_; 71 72 RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); 73 }; 74 75 // Deletes ThreadCheckerClass on a different thread. 76 class DeleteThreadCheckerClassOnThread : public Thread { 77 public: 78 explicit DeleteThreadCheckerClassOnThread( 79 ThreadCheckerClass* thread_checker_class) 80 : Thread(), 81 thread_checker_class_(thread_checker_class) { 82 SetName("delete_thread_checker_class_on_thread", NULL); 83 } 84 85 void Run() override { thread_checker_class_.reset(); } 86 87 // New method. Needed since Thread::Join is protected, and it is called by 88 // the TEST. 89 void Join() { 90 Thread::Join(); 91 } 92 93 private: 94 scoped_ptr<ThreadCheckerClass> thread_checker_class_; 95 96 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread); 97 }; 98 99 } // namespace 100 101 TEST(ThreadCheckerTest, CallsAllowedOnSameThread) { 102 scoped_ptr<ThreadCheckerClass> thread_checker_class( 103 new ThreadCheckerClass); 104 105 // Verify that DoStuff doesn't assert. 106 thread_checker_class->DoStuff(); 107 108 // Verify that the destructor doesn't assert. 109 thread_checker_class.reset(); 110 } 111 112 TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) { 113 scoped_ptr<ThreadCheckerClass> thread_checker_class( 114 new ThreadCheckerClass); 115 116 // Verify that the destructor doesn't assert 117 // when called on a different thread. 118 DeleteThreadCheckerClassOnThread delete_on_thread( 119 thread_checker_class.release()); 120 121 delete_on_thread.Start(); 122 delete_on_thread.Join(); 123 } 124 125 TEST(ThreadCheckerTest, DetachFromThread) { 126 scoped_ptr<ThreadCheckerClass> thread_checker_class( 127 new ThreadCheckerClass); 128 129 // Verify that DoStuff doesn't assert when called on a different thread after 130 // a call to DetachFromThread. 131 thread_checker_class->DetachFromThread(); 132 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); 133 134 call_on_thread.Start(); 135 call_on_thread.Join(); 136 } 137 138 #if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER 139 140 void ThreadCheckerClass::MethodOnDifferentThreadImpl() { 141 scoped_ptr<ThreadCheckerClass> thread_checker_class( 142 new ThreadCheckerClass); 143 144 // DoStuff should assert in debug builds only when called on a 145 // different thread. 146 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); 147 148 call_on_thread.Start(); 149 call_on_thread.Join(); 150 } 151 152 #if ENABLE_THREAD_CHECKER 153 TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { 154 ASSERT_DEATH({ 155 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 156 }, ""); 157 } 158 #else 159 TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) { 160 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 161 } 162 #endif // ENABLE_THREAD_CHECKER 163 164 void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() { 165 scoped_ptr<ThreadCheckerClass> thread_checker_class( 166 new ThreadCheckerClass); 167 168 // DoStuff doesn't assert when called on a different thread 169 // after a call to DetachFromThread. 170 thread_checker_class->DetachFromThread(); 171 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); 172 173 call_on_thread.Start(); 174 call_on_thread.Join(); 175 176 // DoStuff should assert in debug builds only after moving to 177 // another thread. 178 thread_checker_class->DoStuff(); 179 } 180 181 #if ENABLE_THREAD_CHECKER 182 TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) { 183 ASSERT_DEATH({ 184 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); 185 }, ""); 186 } 187 #else 188 TEST(ThreadCheckerTest, DetachFromThreadInRelease) { 189 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); 190 } 191 #endif // ENABLE_THREAD_CHECKER 192 193 #endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER 194 195 // Just in case we ever get lumped together with other compilation units. 196 #undef ENABLE_THREAD_CHECKER 197 198 } // namespace rtc 199