Home | History | Annotate | Download | only in threading
      1 // Copyright (c) 2011 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 namespace base {
     13 
     14 // Simple class to exercise the basics of ThreadChecker.
     15 // Both the destructor and DoStuff should verify that they were
     16 // called on the same thread as the constructor.
     17 class ThreadCheckerClass : public ThreadChecker {
     18  public:
     19   ThreadCheckerClass() {}
     20 
     21   // Verifies that it was called on the same thread as the constructor.
     22   void DoStuff() {
     23     CHECK(CalledOnValidThread());
     24   }
     25 
     26   void DetachFromThread() {
     27     ThreadChecker::DetachFromThread();
     28   }
     29 
     30   static void MethodOnDifferentThreadImpl();
     31   static void DetachThenCallFromDifferentThreadImpl();
     32 
     33  private:
     34   DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
     35 };
     36 
     37 // Calls ThreadCheckerClass::DoStuff on another thread.
     38 class CallDoStuffOnThread : public base::SimpleThread {
     39  public:
     40   CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
     41       : SimpleThread("call_do_stuff_on_thread"),
     42         thread_checker_class_(thread_checker_class) {
     43   }
     44 
     45   virtual void Run() {
     46     thread_checker_class_->DoStuff();
     47   }
     48 
     49  private:
     50   ThreadCheckerClass* thread_checker_class_;
     51 
     52   DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
     53 };
     54 
     55 // Deletes ThreadCheckerClass on a different thread.
     56 class 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 
     73 TEST(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 
     84 TEST(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 
     97 TEST(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 
    112 void 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
    125 TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
    126   ASSERT_DEBUG_DEATH({
    127       ThreadCheckerClass::MethodOnDifferentThreadImpl();
    128     }, "");
    129 }
    130 #else
    131 TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
    132   ThreadCheckerClass::MethodOnDifferentThreadImpl();
    133 }
    134 #endif  // NDEBUG
    135 
    136 void 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
    154 TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
    155   ASSERT_DEBUG_DEATH({
    156     ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
    157     }, "");
    158 }
    159 #else
    160 TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
    161   ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
    162 }
    163 #endif  // NDEBUG
    164 
    165 #endif  // GTEST_HAS_DEATH_TEST || NDEBUG
    166 
    167 }  // namespace base
    168