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/non_thread_safe.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 exersice the basics of NonThreadSafe.
     15 // Both the destructor and DoStuff should verify that they were
     16 // called on the same thread as the constructor.
     17 class NonThreadSafeClass : public NonThreadSafe {
     18  public:
     19   NonThreadSafeClass() {}
     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     NonThreadSafe::DetachFromThread();
     28   }
     29 
     30   static void MethodOnDifferentThreadImpl();
     31   static void DestructorOnDifferentThreadImpl();
     32 
     33  private:
     34   DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass);
     35 };
     36 
     37 // Calls NonThreadSafeClass::DoStuff on another thread.
     38 class CallDoStuffOnThread : public SimpleThread {
     39  public:
     40   CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class)
     41       : SimpleThread("call_do_stuff_on_thread"),
     42         non_thread_safe_class_(non_thread_safe_class) {
     43   }
     44 
     45   virtual void Run() {
     46     non_thread_safe_class_->DoStuff();
     47   }
     48 
     49  private:
     50   NonThreadSafeClass* non_thread_safe_class_;
     51 
     52   DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
     53 };
     54 
     55 // Deletes NonThreadSafeClass on a different thread.
     56 class DeleteNonThreadSafeClassOnThread : public SimpleThread {
     57  public:
     58   DeleteNonThreadSafeClassOnThread(NonThreadSafeClass* non_thread_safe_class)
     59       : SimpleThread("delete_non_thread_safe_class_on_thread"),
     60         non_thread_safe_class_(non_thread_safe_class) {
     61   }
     62 
     63   virtual void Run() {
     64     non_thread_safe_class_.reset();
     65   }
     66 
     67  private:
     68   scoped_ptr<NonThreadSafeClass> non_thread_safe_class_;
     69 
     70   DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread);
     71 };
     72 
     73 TEST(NonThreadSafeTest, CallsAllowedOnSameThread) {
     74   scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
     75       new NonThreadSafeClass);
     76 
     77   // Verify that DoStuff doesn't assert.
     78   non_thread_safe_class->DoStuff();
     79 
     80   // Verify that the destructor doesn't assert.
     81   non_thread_safe_class.reset();
     82 }
     83 
     84 TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) {
     85   scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
     86       new NonThreadSafeClass);
     87 
     88   // Verify that the destructor doesn't assert when called on a different thread
     89   // after a detach.
     90   non_thread_safe_class->DetachFromThread();
     91   DeleteNonThreadSafeClassOnThread delete_on_thread(
     92       non_thread_safe_class.release());
     93 
     94   delete_on_thread.Start();
     95   delete_on_thread.Join();
     96 }
     97 
     98 #if GTEST_HAS_DEATH_TEST || NDEBUG
     99 
    100 void NonThreadSafeClass::MethodOnDifferentThreadImpl() {
    101   scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
    102       new NonThreadSafeClass);
    103 
    104   // Verify that DoStuff asserts in debug builds only when called
    105   // on a different thread.
    106   CallDoStuffOnThread call_on_thread(non_thread_safe_class.get());
    107 
    108   call_on_thread.Start();
    109   call_on_thread.Join();
    110 }
    111 
    112 #ifndef NDEBUG
    113 TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
    114   ASSERT_DEBUG_DEATH({
    115       NonThreadSafeClass::MethodOnDifferentThreadImpl();
    116     }, "");
    117 }
    118 #else
    119 TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
    120   NonThreadSafeClass::MethodOnDifferentThreadImpl();
    121 }
    122 #endif  // NDEBUG
    123 
    124 void NonThreadSafeClass::DestructorOnDifferentThreadImpl() {
    125   scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
    126       new NonThreadSafeClass);
    127 
    128   // Verify that the destructor asserts in debug builds only
    129   // when called on a different thread.
    130   DeleteNonThreadSafeClassOnThread delete_on_thread(
    131       non_thread_safe_class.release());
    132 
    133   delete_on_thread.Start();
    134   delete_on_thread.Join();
    135 }
    136 
    137 #ifndef NDEBUG
    138 TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
    139   ASSERT_DEBUG_DEATH({
    140       NonThreadSafeClass::DestructorOnDifferentThreadImpl();
    141     }, "");
    142 }
    143 #else
    144 TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
    145   NonThreadSafeClass::DestructorOnDifferentThreadImpl();
    146 }
    147 #endif  // NDEBUG
    148 
    149 #endif  // GTEST_HAS_DEATH_TEST || NDEBUG
    150 
    151 }  // namespace base
    152