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