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