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