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