• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
NonThreadSafeClass()19   NonThreadSafeClass() {}
20 
21   // Verifies that it was called on the same thread as the constructor.
DoStuff()22   void DoStuff() {
23     CHECK(CalledOnValidThread());
24   }
25 
DetachFromThread()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:
CallDoStuffOnThread(NonThreadSafeClass * non_thread_safe_class)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 
Run()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:
DeleteNonThreadSafeClassOnThread(NonThreadSafeClass * non_thread_safe_class)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 
Run()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 
TEST(NonThreadSafeTest,CallsAllowedOnSameThread)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 
TEST(NonThreadSafeTest,DetachThenDestructOnDifferentThread)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 
MethodOnDifferentThreadImpl()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
TEST(NonThreadSafeDeathTest,MethodNotAllowedOnDifferentThreadInDebug)113 TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
114   ASSERT_DEBUG_DEATH({
115       NonThreadSafeClass::MethodOnDifferentThreadImpl();
116     }, "");
117 }
118 #else
TEST(NonThreadSafeTest,MethodAllowedOnDifferentThreadInRelease)119 TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
120   NonThreadSafeClass::MethodOnDifferentThreadImpl();
121 }
122 #endif  // NDEBUG
123 
DestructorOnDifferentThreadImpl()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
TEST(NonThreadSafeDeathTest,DestructorNotAllowedOnDifferentThreadInDebug)138 TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
139   ASSERT_DEBUG_DEATH({
140       NonThreadSafeClass::DestructorOnDifferentThreadImpl();
141     }, "");
142 }
143 #else
TEST(NonThreadSafeTest,DestructorAllowedOnDifferentThreadInRelease)144 TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
145   NonThreadSafeClass::DestructorOnDifferentThreadImpl();
146 }
147 #endif  // NDEBUG
148 
149 #endif  // GTEST_HAS_DEATH_TEST || NDEBUG
150 
151 }  // namespace base
152