1 // Copyright (c) 2011 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/non_thread_safe.h" 9 #include "base/threading/simple_thread.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace base { 13 14 // Simple class to exersice the basics of NonThreadSafe. 15 // Both the destructor and DoStuff should verify that they were 16 // called on the same thread as the constructor. 17 class NonThreadSafeClass : public NonThreadSafe { 18 public: 19 NonThreadSafeClass() {} 20 21 // Verifies that it was called on the same thread as the constructor. 22 void DoStuff() { 23 CHECK(CalledOnValidThread()); 24 } 25 26 void DetachFromThread() { 27 NonThreadSafe::DetachFromThread(); 28 } 29 30 static void MethodOnDifferentThreadImpl(); 31 static void DestructorOnDifferentThreadImpl(); 32 33 private: 34 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass); 35 }; 36 37 // Calls NonThreadSafeClass::DoStuff on another thread. 38 class CallDoStuffOnThread : public SimpleThread { 39 public: 40 CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class) 41 : SimpleThread("call_do_stuff_on_thread"), 42 non_thread_safe_class_(non_thread_safe_class) { 43 } 44 45 virtual void Run() { 46 non_thread_safe_class_->DoStuff(); 47 } 48 49 private: 50 NonThreadSafeClass* non_thread_safe_class_; 51 52 DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); 53 }; 54 55 // Deletes NonThreadSafeClass on a different thread. 56 class DeleteNonThreadSafeClassOnThread : public SimpleThread { 57 public: 58 DeleteNonThreadSafeClassOnThread(NonThreadSafeClass* non_thread_safe_class) 59 : SimpleThread("delete_non_thread_safe_class_on_thread"), 60 non_thread_safe_class_(non_thread_safe_class) { 61 } 62 63 virtual void Run() { 64 non_thread_safe_class_.reset(); 65 } 66 67 private: 68 scoped_ptr<NonThreadSafeClass> non_thread_safe_class_; 69 70 DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread); 71 }; 72 73 TEST(NonThreadSafeTest, CallsAllowedOnSameThread) { 74 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 75 new NonThreadSafeClass); 76 77 // Verify that DoStuff doesn't assert. 78 non_thread_safe_class->DoStuff(); 79 80 // Verify that the destructor doesn't assert. 81 non_thread_safe_class.reset(); 82 } 83 84 TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) { 85 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 86 new NonThreadSafeClass); 87 88 // Verify that the destructor doesn't assert when called on a different thread 89 // after a detach. 90 non_thread_safe_class->DetachFromThread(); 91 DeleteNonThreadSafeClassOnThread delete_on_thread( 92 non_thread_safe_class.release()); 93 94 delete_on_thread.Start(); 95 delete_on_thread.Join(); 96 } 97 98 #if GTEST_HAS_DEATH_TEST || NDEBUG 99 100 void NonThreadSafeClass::MethodOnDifferentThreadImpl() { 101 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 102 new NonThreadSafeClass); 103 104 // Verify that DoStuff asserts in debug builds only when called 105 // on a different thread. 106 CallDoStuffOnThread call_on_thread(non_thread_safe_class.get()); 107 108 call_on_thread.Start(); 109 call_on_thread.Join(); 110 } 111 112 #ifndef NDEBUG 113 TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { 114 ASSERT_DEBUG_DEATH({ 115 NonThreadSafeClass::MethodOnDifferentThreadImpl(); 116 }, ""); 117 } 118 #else 119 TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) { 120 NonThreadSafeClass::MethodOnDifferentThreadImpl(); 121 } 122 #endif // NDEBUG 123 124 void NonThreadSafeClass::DestructorOnDifferentThreadImpl() { 125 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 126 new NonThreadSafeClass); 127 128 // Verify that the destructor asserts in debug builds only 129 // when called on a different thread. 130 DeleteNonThreadSafeClassOnThread delete_on_thread( 131 non_thread_safe_class.release()); 132 133 delete_on_thread.Start(); 134 delete_on_thread.Join(); 135 } 136 137 #ifndef NDEBUG 138 TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) { 139 ASSERT_DEBUG_DEATH({ 140 NonThreadSafeClass::DestructorOnDifferentThreadImpl(); 141 }, ""); 142 } 143 #else 144 TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) { 145 NonThreadSafeClass::DestructorOnDifferentThreadImpl(); 146 } 147 #endif // NDEBUG 148 149 #endif // GTEST_HAS_DEATH_TEST || NDEBUG 150 151 } // namespace base 152