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/threading/non_thread_safe.h"
      6 
      7 #include <memory>
      8 
      9 #include "base/logging.h"
     10 #include "base/macros.h"
     11 #include "base/test/gtest_util.h"
     12 #include "base/threading/simple_thread.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 namespace base {
     16 
     17 namespace {
     18 
     19 // Simple class to exersice the basics of NonThreadSafe.
     20 // Both the destructor and DoStuff should verify that they were
     21 // called on the same thread as the constructor.
     22 class NonThreadSafeClass : public NonThreadSafe {
     23  public:
     24   NonThreadSafeClass() {}
     25 
     26   // Verifies that it was called on the same thread as the constructor.
     27   void DoStuff() {
     28     DCHECK(CalledOnValidThread());
     29   }
     30 
     31   void DetachFromThread() {
     32     NonThreadSafe::DetachFromThread();
     33   }
     34 
     35   static void MethodOnDifferentThreadImpl();
     36   static void DestructorOnDifferentThreadImpl();
     37 
     38  private:
     39   DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass);
     40 };
     41 
     42 // Calls NonThreadSafeClass::DoStuff on another thread.
     43 class CallDoStuffOnThread : public SimpleThread {
     44  public:
     45   explicit CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class)
     46       : SimpleThread("call_do_stuff_on_thread"),
     47         non_thread_safe_class_(non_thread_safe_class) {
     48   }
     49 
     50   void Run() override { non_thread_safe_class_->DoStuff(); }
     51 
     52  private:
     53   NonThreadSafeClass* non_thread_safe_class_;
     54 
     55   DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
     56 };
     57 
     58 // Deletes NonThreadSafeClass on a different thread.
     59 class DeleteNonThreadSafeClassOnThread : public SimpleThread {
     60  public:
     61   explicit DeleteNonThreadSafeClassOnThread(
     62       NonThreadSafeClass* non_thread_safe_class)
     63       : SimpleThread("delete_non_thread_safe_class_on_thread"),
     64         non_thread_safe_class_(non_thread_safe_class) {
     65   }
     66 
     67   void Run() override { non_thread_safe_class_.reset(); }
     68 
     69  private:
     70   std::unique_ptr<NonThreadSafeClass> non_thread_safe_class_;
     71 
     72   DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread);
     73 };
     74 
     75 }  // namespace
     76 
     77 TEST(NonThreadSafeTest, CallsAllowedOnSameThread) {
     78   std::unique_ptr<NonThreadSafeClass> non_thread_safe_class(
     79       new NonThreadSafeClass);
     80 
     81   // Verify that DoStuff doesn't assert.
     82   non_thread_safe_class->DoStuff();
     83 
     84   // Verify that the destructor doesn't assert.
     85   non_thread_safe_class.reset();
     86 }
     87 
     88 TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) {
     89   std::unique_ptr<NonThreadSafeClass> non_thread_safe_class(
     90       new NonThreadSafeClass);
     91 
     92   // Verify that the destructor doesn't assert when called on a different thread
     93   // after a detach.
     94   non_thread_safe_class->DetachFromThread();
     95   DeleteNonThreadSafeClassOnThread delete_on_thread(
     96       non_thread_safe_class.release());
     97 
     98   delete_on_thread.Start();
     99   delete_on_thread.Join();
    100 }
    101 
    102 void NonThreadSafeClass::MethodOnDifferentThreadImpl() {
    103   std::unique_ptr<NonThreadSafeClass> non_thread_safe_class(
    104       new NonThreadSafeClass);
    105 
    106   // Verify that DoStuff asserts in debug builds only when called
    107   // on a different thread.
    108   CallDoStuffOnThread call_on_thread(non_thread_safe_class.get());
    109 
    110   call_on_thread.Start();
    111   call_on_thread.Join();
    112 }
    113 
    114 #if DCHECK_IS_ON()
    115 TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
    116   ASSERT_DCHECK_DEATH({ NonThreadSafeClass::MethodOnDifferentThreadImpl(); });
    117 }
    118 #else
    119 TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
    120   NonThreadSafeClass::MethodOnDifferentThreadImpl();
    121 }
    122 #endif  // DCHECK_IS_ON()
    123 
    124 void NonThreadSafeClass::DestructorOnDifferentThreadImpl() {
    125   std::unique_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 #if DCHECK_IS_ON()
    138 TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
    139   ASSERT_DCHECK_DEATH(
    140       { NonThreadSafeClass::DestructorOnDifferentThreadImpl(); });
    141 }
    142 #else
    143 TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
    144   NonThreadSafeClass::DestructorOnDifferentThreadImpl();
    145 }
    146 #endif  // DCHECK_IS_ON()
    147 
    148 }  // namespace base
    149