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