1b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach// Use of this source code is governed by a BSD-style license that can be 3b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach// found in the LICENSE file. 4b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach 5b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach#include "base/basictypes.h" 6b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach#include "base/logging.h" 7b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach#include "base/memory/scoped_ptr.h" 8b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach#include "base/threading/thread_checker.h" 9b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach#include "base/threading/simple_thread.h" 10b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach#include "testing/gtest/include/gtest/gtest.h" 11b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach 12b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbachnamespace base { 13b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach 14b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach// Simple class to exercise the basics of ThreadChecker. 15b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach// Both the destructor and DoStuff should verify that they were 16b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach// called on the same thread as the constructor. 17b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbachclass ThreadCheckerClass : public ThreadChecker { 18b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach public: 19b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach ThreadCheckerClass() {} 20b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach 21b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach // Verifies that it was called on the same thread as the constructor. 22b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach void DoStuff() { 23b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach CHECK(CalledOnValidThread()); 242d24e2a396a1d211baaeedf32148a3b657240170David Blaikie } 2595a9d937728ca9cf2bf44f86ff1184df318b3bd7Benjamin Kramer 26b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach void DetachFromThread() { 27b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach ThreadChecker::DetachFromThread(); 2895a9d937728ca9cf2bf44f86ff1184df318b3bd7Benjamin Kramer } 2995a9d937728ca9cf2bf44f86ff1184df318b3bd7Benjamin Kramer 30b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach static void MethodOnDifferentThreadImpl(); 3161425c0a7f4e3608a85f7bbf254cd052a15b7446Jim Grosbach static void DetachThenCallFromDifferentThreadImpl(); 3261425c0a7f4e3608a85f7bbf254cd052a15b7446Jim Grosbach 33068c65b22d50c265b51886062b2b9c1cb696d67dDanil Malyshev private: 3461425c0a7f4e3608a85f7bbf254cd052a15b7446Jim Grosbach DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass); 3561425c0a7f4e3608a85f7bbf254cd052a15b7446Jim Grosbach}; 3661425c0a7f4e3608a85f7bbf254cd052a15b7446Jim Grosbach 3761425c0a7f4e3608a85f7bbf254cd052a15b7446Jim Grosbach// Calls ThreadCheckerClass::DoStuff on another thread. 38068c65b22d50c265b51886062b2b9c1cb696d67dDanil Malyshevclass CallDoStuffOnThread : public base::SimpleThread { 3961425c0a7f4e3608a85f7bbf254cd052a15b7446Jim Grosbach public: 4061425c0a7f4e3608a85f7bbf254cd052a15b7446Jim Grosbach CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class) 4130b9e322e159df8eaabb5b194cec6e11ba99c261Danil Malyshev : SimpleThread("call_do_stuff_on_thread"), 4230b9e322e159df8eaabb5b194cec6e11ba99c261Danil Malyshev thread_checker_class_(thread_checker_class) { 4330b9e322e159df8eaabb5b194cec6e11ba99c261Danil Malyshev } 4430b9e322e159df8eaabb5b194cec6e11ba99c261Danil Malyshev 4530b9e322e159df8eaabb5b194cec6e11ba99c261Danil Malyshev virtual void Run() { 46b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach thread_checker_class_->DoStuff(); 47b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach } 48b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach 49b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach private: 50b572830a52faad2fffc7119de53aa96c18d9bf07Jim Grosbach ThreadCheckerClass* thread_checker_class_; 51 52 DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); 53}; 54 55// Deletes ThreadCheckerClass on a different thread. 56class DeleteThreadCheckerClassOnThread : public base::SimpleThread { 57 public: 58 DeleteThreadCheckerClassOnThread(ThreadCheckerClass* thread_checker_class) 59 : SimpleThread("delete_thread_checker_class_on_thread"), 60 thread_checker_class_(thread_checker_class) { 61 } 62 63 virtual void Run() { 64 thread_checker_class_.reset(); 65 } 66 67 private: 68 scoped_ptr<ThreadCheckerClass> thread_checker_class_; 69 70 DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread); 71}; 72 73TEST(ThreadCheckerTest, CallsAllowedOnSameThread) { 74 scoped_ptr<ThreadCheckerClass> thread_checker_class( 75 new ThreadCheckerClass); 76 77 // Verify that DoStuff doesn't assert. 78 thread_checker_class->DoStuff(); 79 80 // Verify that the destructor doesn't assert. 81 thread_checker_class.reset(); 82} 83 84TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) { 85 scoped_ptr<ThreadCheckerClass> thread_checker_class( 86 new ThreadCheckerClass); 87 88 // Verify that the destructor doesn't assert 89 // when called on a different thread. 90 DeleteThreadCheckerClassOnThread delete_on_thread( 91 thread_checker_class.release()); 92 93 delete_on_thread.Start(); 94 delete_on_thread.Join(); 95} 96 97TEST(ThreadCheckerTest, DetachFromThread) { 98 scoped_ptr<ThreadCheckerClass> thread_checker_class( 99 new ThreadCheckerClass); 100 101 // Verify that DoStuff doesn't assert when called on a different thread after 102 // a call to DetachFromThread. 103 thread_checker_class->DetachFromThread(); 104 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); 105 106 call_on_thread.Start(); 107 call_on_thread.Join(); 108} 109 110#if GTEST_HAS_DEATH_TEST || NDEBUG 111 112void ThreadCheckerClass::MethodOnDifferentThreadImpl() { 113 scoped_ptr<ThreadCheckerClass> thread_checker_class( 114 new ThreadCheckerClass); 115 116 // DoStuff should assert in debug builds only when called on a 117 // different thread. 118 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); 119 120 call_on_thread.Start(); 121 call_on_thread.Join(); 122} 123 124#ifndef NDEBUG 125TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { 126 ASSERT_DEBUG_DEATH({ 127 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 128 }, ""); 129} 130#else 131TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) { 132 ThreadCheckerClass::MethodOnDifferentThreadImpl(); 133} 134#endif // NDEBUG 135 136void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() { 137 scoped_ptr<ThreadCheckerClass> thread_checker_class( 138 new ThreadCheckerClass); 139 140 // DoStuff doesn't assert when called on a different thread 141 // after a call to DetachFromThread. 142 thread_checker_class->DetachFromThread(); 143 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); 144 145 call_on_thread.Start(); 146 call_on_thread.Join(); 147 148 // DoStuff should assert in debug builds only after moving to 149 // another thread. 150 thread_checker_class->DoStuff(); 151} 152 153#ifndef NDEBUG 154TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) { 155 ASSERT_DEBUG_DEATH({ 156 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); 157 }, ""); 158} 159#else 160TEST(ThreadCheckerTest, DetachFromThreadInRelease) { 161 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); 162} 163#endif // NDEBUG 164 165#endif // GTEST_HAS_DEATH_TEST || NDEBUG 166 167} // namespace base 168