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