• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
NonThreadSafeClass()24   NonThreadSafeClass() {}
25 
26   // Verifies that it was called on the same thread as the constructor.
DoStuff()27   void DoStuff() {
28     DCHECK(CalledOnValidThread());
29   }
30 
DetachFromThread()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:
CallDoStuffOnThread(NonThreadSafeClass * non_thread_safe_class)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 
Run()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:
DeleteNonThreadSafeClassOnThread(NonThreadSafeClass * non_thread_safe_class)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 
Run()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 
TEST(NonThreadSafeTest,CallsAllowedOnSameThread)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 
TEST(NonThreadSafeTest,DetachThenDestructOnDifferentThread)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 
MethodOnDifferentThreadImpl()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()
TEST(NonThreadSafeDeathTest,MethodNotAllowedOnDifferentThreadInDebug)115 TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
116   ASSERT_DCHECK_DEATH({ NonThreadSafeClass::MethodOnDifferentThreadImpl(); });
117 }
118 #else
TEST(NonThreadSafeTest,MethodAllowedOnDifferentThreadInRelease)119 TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
120   NonThreadSafeClass::MethodOnDifferentThreadImpl();
121 }
122 #endif  // DCHECK_IS_ON()
123 
DestructorOnDifferentThreadImpl()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()
TEST(NonThreadSafeDeathTest,DestructorNotAllowedOnDifferentThreadInDebug)138 TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
139   ASSERT_DCHECK_DEATH(
140       { NonThreadSafeClass::DestructorOnDifferentThreadImpl(); });
141 }
142 #else
TEST(NonThreadSafeTest,DestructorAllowedOnDifferentThreadInRelease)143 TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
144   NonThreadSafeClass::DestructorOnDifferentThreadImpl();
145 }
146 #endif  // DCHECK_IS_ON()
147 
148 }  // namespace base
149