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/logging.h" 6 #include "base/macros.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 // Duplicated from base/threading/non_thread_safe.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_NON_THREAD_SAFE 1 16 #else 17 #define ENABLE_NON_THREAD_SAFE 0 18 #endif 19 20 namespace base { 21 22 namespace { 23 24 // Simple class to exersice the basics of NonThreadSafe. 25 // Both the destructor and DoStuff should verify that they were 26 // called on the same thread as the constructor. 27 class NonThreadSafeClass : public NonThreadSafe { 28 public: 29 NonThreadSafeClass() {} 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 NonThreadSafe::DetachFromThread(); 38 } 39 40 static void MethodOnDifferentThreadImpl(); 41 static void DestructorOnDifferentThreadImpl(); 42 43 private: 44 DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass); 45 }; 46 47 // Calls NonThreadSafeClass::DoStuff on another thread. 48 class CallDoStuffOnThread : public SimpleThread { 49 public: 50 explicit CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class) 51 : SimpleThread("call_do_stuff_on_thread"), 52 non_thread_safe_class_(non_thread_safe_class) { 53 } 54 55 void Run() override { non_thread_safe_class_->DoStuff(); } 56 57 private: 58 NonThreadSafeClass* non_thread_safe_class_; 59 60 DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); 61 }; 62 63 // Deletes NonThreadSafeClass on a different thread. 64 class DeleteNonThreadSafeClassOnThread : public SimpleThread { 65 public: 66 explicit DeleteNonThreadSafeClassOnThread( 67 NonThreadSafeClass* non_thread_safe_class) 68 : SimpleThread("delete_non_thread_safe_class_on_thread"), 69 non_thread_safe_class_(non_thread_safe_class) { 70 } 71 72 void Run() override { non_thread_safe_class_.reset(); } 73 74 private: 75 scoped_ptr<NonThreadSafeClass> non_thread_safe_class_; 76 77 DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread); 78 }; 79 80 } // namespace 81 82 TEST(NonThreadSafeTest, CallsAllowedOnSameThread) { 83 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 84 new NonThreadSafeClass); 85 86 // Verify that DoStuff doesn't assert. 87 non_thread_safe_class->DoStuff(); 88 89 // Verify that the destructor doesn't assert. 90 non_thread_safe_class.reset(); 91 } 92 93 TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) { 94 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 95 new NonThreadSafeClass); 96 97 // Verify that the destructor doesn't assert when called on a different thread 98 // after a detach. 99 non_thread_safe_class->DetachFromThread(); 100 DeleteNonThreadSafeClassOnThread delete_on_thread( 101 non_thread_safe_class.release()); 102 103 delete_on_thread.Start(); 104 delete_on_thread.Join(); 105 } 106 107 #if GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE 108 109 void NonThreadSafeClass::MethodOnDifferentThreadImpl() { 110 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 111 new NonThreadSafeClass); 112 113 // Verify that DoStuff asserts in debug builds only when called 114 // on a different thread. 115 CallDoStuffOnThread call_on_thread(non_thread_safe_class.get()); 116 117 call_on_thread.Start(); 118 call_on_thread.Join(); 119 } 120 121 #if ENABLE_NON_THREAD_SAFE 122 TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { 123 ASSERT_DEATH({ 124 NonThreadSafeClass::MethodOnDifferentThreadImpl(); 125 }, ""); 126 } 127 #else 128 TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) { 129 NonThreadSafeClass::MethodOnDifferentThreadImpl(); 130 } 131 #endif // ENABLE_NON_THREAD_SAFE 132 133 void NonThreadSafeClass::DestructorOnDifferentThreadImpl() { 134 scoped_ptr<NonThreadSafeClass> non_thread_safe_class( 135 new NonThreadSafeClass); 136 137 // Verify that the destructor asserts in debug builds only 138 // when called on a different thread. 139 DeleteNonThreadSafeClassOnThread delete_on_thread( 140 non_thread_safe_class.release()); 141 142 delete_on_thread.Start(); 143 delete_on_thread.Join(); 144 } 145 146 #if ENABLE_NON_THREAD_SAFE 147 TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) { 148 ASSERT_DEATH({ 149 NonThreadSafeClass::DestructorOnDifferentThreadImpl(); 150 }, ""); 151 } 152 #else 153 TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) { 154 NonThreadSafeClass::DestructorOnDifferentThreadImpl(); 155 } 156 #endif // ENABLE_NON_THREAD_SAFE 157 158 #endif // GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE 159 160 // Just in case we ever get lumped together with other compilation units. 161 #undef ENABLE_NON_THREAD_SAFE 162 163 } // namespace base 164