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/logging.h"
      6 #include "base/macros.h"
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/threading/simple_thread.h"
      9 #include "base/threading/thread_checker.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   void Run() override { thread_checker_class_->DoStuff(); }
     56 
     57  private:
     58   ThreadCheckerClass* thread_checker_class_;
     59 
     60   DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
     61 };
     62 
     63 // Deletes ThreadCheckerClass on a different thread.
     64 class DeleteThreadCheckerClassOnThread : public base::SimpleThread {
     65  public:
     66   explicit DeleteThreadCheckerClassOnThread(
     67       ThreadCheckerClass* thread_checker_class)
     68       : SimpleThread("delete_thread_checker_class_on_thread"),
     69         thread_checker_class_(thread_checker_class) {
     70   }
     71 
     72   void Run() override { thread_checker_class_.reset(); }
     73 
     74  private:
     75   scoped_ptr<ThreadCheckerClass> thread_checker_class_;
     76 
     77   DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
     78 };
     79 
     80 }  // namespace
     81 
     82 TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
     83   scoped_ptr<ThreadCheckerClass> thread_checker_class(
     84       new ThreadCheckerClass);
     85 
     86   // Verify that DoStuff doesn't assert.
     87   thread_checker_class->DoStuff();
     88 
     89   // Verify that the destructor doesn't assert.
     90   thread_checker_class.reset();
     91 }
     92 
     93 TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
     94   scoped_ptr<ThreadCheckerClass> thread_checker_class(
     95       new ThreadCheckerClass);
     96 
     97   // Verify that the destructor doesn't assert
     98   // when called on a different thread.
     99   DeleteThreadCheckerClassOnThread delete_on_thread(
    100       thread_checker_class.release());
    101 
    102   delete_on_thread.Start();
    103   delete_on_thread.Join();
    104 }
    105 
    106 TEST(ThreadCheckerTest, DetachFromThread) {
    107   scoped_ptr<ThreadCheckerClass> thread_checker_class(
    108       new ThreadCheckerClass);
    109 
    110   // Verify that DoStuff doesn't assert when called on a different thread after
    111   // a call to DetachFromThread.
    112   thread_checker_class->DetachFromThread();
    113   CallDoStuffOnThread call_on_thread(thread_checker_class.get());
    114 
    115   call_on_thread.Start();
    116   call_on_thread.Join();
    117 }
    118 
    119 #if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
    120 
    121 void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
    122   scoped_ptr<ThreadCheckerClass> thread_checker_class(
    123       new ThreadCheckerClass);
    124 
    125   // DoStuff should assert in debug builds only when called on a
    126   // different thread.
    127   CallDoStuffOnThread call_on_thread(thread_checker_class.get());
    128 
    129   call_on_thread.Start();
    130   call_on_thread.Join();
    131 }
    132 
    133 #if ENABLE_THREAD_CHECKER
    134 TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
    135   ASSERT_DEATH({
    136       ThreadCheckerClass::MethodOnDifferentThreadImpl();
    137     }, "");
    138 }
    139 #else
    140 TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
    141   ThreadCheckerClass::MethodOnDifferentThreadImpl();
    142 }
    143 #endif  // ENABLE_THREAD_CHECKER
    144 
    145 void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
    146   scoped_ptr<ThreadCheckerClass> thread_checker_class(
    147       new ThreadCheckerClass);
    148 
    149   // DoStuff doesn't assert when called on a different thread
    150   // after a call to DetachFromThread.
    151   thread_checker_class->DetachFromThread();
    152   CallDoStuffOnThread call_on_thread(thread_checker_class.get());
    153 
    154   call_on_thread.Start();
    155   call_on_thread.Join();
    156 
    157   // DoStuff should assert in debug builds only after moving to
    158   // another thread.
    159   thread_checker_class->DoStuff();
    160 }
    161 
    162 #if ENABLE_THREAD_CHECKER
    163 TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
    164   ASSERT_DEATH({
    165     ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
    166     }, "");
    167 }
    168 #else
    169 TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
    170   ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
    171 }
    172 #endif  // ENABLE_THREAD_CHECKER
    173 
    174 #endif  // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
    175 
    176 // Just in case we ever get lumped together with other compilation units.
    177 #undef ENABLE_THREAD_CHECKER
    178 
    179 }  // namespace base
    180