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 20namespace base { 21 22namespace { 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. 27class 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. 48class 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. 66class 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 86TEST(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 97TEST(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 110TEST(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 125void 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 138TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { 139 ASSERT_DEATH({ 140 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 141 }, ""); 142} 143#else 144TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) { 145 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 146} 147#endif // ENABLE_THREAD_CHECKER 148 149void 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 167TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) { 168 ASSERT_DEATH({ 169 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); 170 }, ""); 171} 172#else 173TEST(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