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/threading/simple_thread.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 // Duplicated from base/threading/non_thread_safe.h so that we can be
     15 // good citizens there and undef the macro.
     16 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
     17 #define ENABLE_NON_THREAD_SAFE 1
     18 #else
     19 #define ENABLE_NON_THREAD_SAFE 0
     20 #endif
     21 
     22 namespace base {
     23 
     24 namespace {
     25 
     26 // Simple class to exersice the basics of NonThreadSafe.
     27 // Both the destructor and DoStuff should verify that they were
     28 // called on the same thread as the constructor.
     29 class NonThreadSafeClass : public NonThreadSafe {
     30  public:
     31   NonThreadSafeClass() {}
     32 
     33   // Verifies that it was called on the same thread as the constructor.
     34   void DoStuff() {
     35     DCHECK(CalledOnValidThread());
     36   }
     37 
     38   void DetachFromThread() {
     39     NonThreadSafe::DetachFromThread();
     40   }
     41 
     42   static void MethodOnDifferentThreadImpl();
     43   static void DestructorOnDifferentThreadImpl();
     44 
     45  private:
     46   DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass);
     47 };
     48 
     49 // Calls NonThreadSafeClass::DoStuff on another thread.
     50 class CallDoStuffOnThread : public SimpleThread {
     51  public:
     52   explicit CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class)
     53       : SimpleThread("call_do_stuff_on_thread"),
     54         non_thread_safe_class_(non_thread_safe_class) {
     55   }
     56 
     57   void Run() override { non_thread_safe_class_->DoStuff(); }
     58 
     59  private:
     60   NonThreadSafeClass* non_thread_safe_class_;
     61 
     62   DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
     63 };
     64 
     65 // Deletes NonThreadSafeClass on a different thread.
     66 class DeleteNonThreadSafeClassOnThread : public SimpleThread {
     67  public:
     68   explicit DeleteNonThreadSafeClassOnThread(
     69       NonThreadSafeClass* non_thread_safe_class)
     70       : SimpleThread("delete_non_thread_safe_class_on_thread"),
     71         non_thread_safe_class_(non_thread_safe_class) {
     72   }
     73 
     74   void Run() override { non_thread_safe_class_.reset(); }
     75 
     76  private:
     77   std::unique_ptr<NonThreadSafeClass> non_thread_safe_class_;
     78 
     79   DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread);
     80 };
     81 
     82 }  // namespace
     83 
     84 TEST(NonThreadSafeTest, CallsAllowedOnSameThread) {
     85   std::unique_ptr<NonThreadSafeClass> non_thread_safe_class(
     86       new NonThreadSafeClass);
     87 
     88   // Verify that DoStuff doesn't assert.
     89   non_thread_safe_class->DoStuff();
     90 
     91   // Verify that the destructor doesn't assert.
     92   non_thread_safe_class.reset();
     93 }
     94 
     95 TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) {
     96   std::unique_ptr<NonThreadSafeClass> non_thread_safe_class(
     97       new NonThreadSafeClass);
     98 
     99   // Verify that the destructor doesn't assert when called on a different thread
    100   // after a detach.
    101   non_thread_safe_class->DetachFromThread();
    102   DeleteNonThreadSafeClassOnThread delete_on_thread(
    103       non_thread_safe_class.release());
    104 
    105   delete_on_thread.Start();
    106   delete_on_thread.Join();
    107 }
    108 
    109 #if GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE
    110 
    111 void NonThreadSafeClass::MethodOnDifferentThreadImpl() {
    112   std::unique_ptr<NonThreadSafeClass> non_thread_safe_class(
    113       new NonThreadSafeClass);
    114 
    115   // Verify that DoStuff asserts in debug builds only when called
    116   // on a different thread.
    117   CallDoStuffOnThread call_on_thread(non_thread_safe_class.get());
    118 
    119   call_on_thread.Start();
    120   call_on_thread.Join();
    121 }
    122 
    123 #if ENABLE_NON_THREAD_SAFE
    124 TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
    125   ASSERT_DEATH({
    126       NonThreadSafeClass::MethodOnDifferentThreadImpl();
    127     }, "");
    128 }
    129 #else
    130 TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
    131   NonThreadSafeClass::MethodOnDifferentThreadImpl();
    132 }
    133 #endif  // ENABLE_NON_THREAD_SAFE
    134 
    135 void NonThreadSafeClass::DestructorOnDifferentThreadImpl() {
    136   std::unique_ptr<NonThreadSafeClass> non_thread_safe_class(
    137       new NonThreadSafeClass);
    138 
    139   // Verify that the destructor asserts in debug builds only
    140   // when called on a different thread.
    141   DeleteNonThreadSafeClassOnThread delete_on_thread(
    142       non_thread_safe_class.release());
    143 
    144   delete_on_thread.Start();
    145   delete_on_thread.Join();
    146 }
    147 
    148 #if ENABLE_NON_THREAD_SAFE
    149 TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
    150   ASSERT_DEATH({
    151       NonThreadSafeClass::DestructorOnDifferentThreadImpl();
    152     }, "");
    153 }
    154 #else
    155 TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
    156   NonThreadSafeClass::DestructorOnDifferentThreadImpl();
    157 }
    158 #endif  // ENABLE_NON_THREAD_SAFE
    159 
    160 #endif  // GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE
    161 
    162 // Just in case we ever get lumped together with other compilation units.
    163 #undef ENABLE_NON_THREAD_SAFE
    164 
    165 }  // namespace base
    166