blob: e995b507e95a2519ce0b919a1ef5e4265e638892 [file] [log] [blame]
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +00001/*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11// Borrowed from Chromium's src/base/threading/thread_checker_unittest.cc.
12
jbauch555604a2016-04-26 03:13:22 -070013#include <memory>
14
henrik.lundin@webrtc.org18617cf2014-09-15 11:19:35 +000015#include "webrtc/base/checks.h"
kwiberg4485ffb2016-04-26 08:14:39 -070016#include "webrtc/base/constructormagic.h"
danilchap8e572f02016-05-19 06:49:03 -070017#include "webrtc/base/task_queue.h"
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000018#include "webrtc/base/thread.h"
19#include "webrtc/base/thread_checker.h"
kwibergac9f8762016-09-30 22:29:43 -070020#include "webrtc/test/gtest.h"
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000021
22// Duplicated from base/threading/thread_checker.h so that we can be
23// good citizens there and undef the macro.
kwiberg5377bc72016-10-04 13:46:56 -070024#define ENABLE_THREAD_CHECKER RTC_DCHECK_IS_ON
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000025
26namespace rtc {
27
28namespace {
29
30// Simple class to exercise the basics of ThreadChecker.
31// Both the destructor and DoStuff should verify that they were
32// called on the same thread as the constructor.
33class ThreadCheckerClass : public ThreadChecker {
34 public:
35 ThreadCheckerClass() {}
36
37 // Verifies that it was called on the same thread as the constructor.
henrikg91d6ede2015-09-17 00:24:34 -070038 void DoStuff() { RTC_DCHECK(CalledOnValidThread()); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000039
40 void DetachFromThread() {
41 ThreadChecker::DetachFromThread();
42 }
43
44 static void MethodOnDifferentThreadImpl();
45 static void DetachThenCallFromDifferentThreadImpl();
46
47 private:
henrikg3c089d72015-09-16 05:37:44 -070048 RTC_DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000049};
50
51// Calls ThreadCheckerClass::DoStuff on another thread.
52class CallDoStuffOnThread : public Thread {
53 public:
54 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
55 : Thread(),
56 thread_checker_class_(thread_checker_class) {
deadbeef37f5ecf2017-02-27 14:06:41 -080057 SetName("call_do_stuff_on_thread", nullptr);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000058 }
59
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000060 void Run() override { thread_checker_class_->DoStuff(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000061
62 // New method. Needed since Thread::Join is protected, and it is called by
63 // the TEST.
64 void Join() {
65 Thread::Join();
66 }
67
68 private:
69 ThreadCheckerClass* thread_checker_class_;
70
henrikg3c089d72015-09-16 05:37:44 -070071 RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000072};
73
74// Deletes ThreadCheckerClass on a different thread.
75class DeleteThreadCheckerClassOnThread : public Thread {
76 public:
77 explicit DeleteThreadCheckerClassOnThread(
78 ThreadCheckerClass* thread_checker_class)
79 : Thread(),
80 thread_checker_class_(thread_checker_class) {
deadbeef37f5ecf2017-02-27 14:06:41 -080081 SetName("delete_thread_checker_class_on_thread", nullptr);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000082 }
83
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000084 void Run() override { thread_checker_class_.reset(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000085
86 // New method. Needed since Thread::Join is protected, and it is called by
87 // the TEST.
88 void Join() {
89 Thread::Join();
90 }
91
92 private:
jbauch555604a2016-04-26 03:13:22 -070093 std::unique_ptr<ThreadCheckerClass> thread_checker_class_;
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000094
henrikg3c089d72015-09-16 05:37:44 -070095 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000096};
97
98} // namespace
99
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000100TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
jbauch555604a2016-04-26 03:13:22 -0700101 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000102 new ThreadCheckerClass);
103
104 // Verify that DoStuff doesn't assert.
105 thread_checker_class->DoStuff();
106
107 // Verify that the destructor doesn't assert.
108 thread_checker_class.reset();
109}
110
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000111TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
jbauch555604a2016-04-26 03:13:22 -0700112 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000113 new ThreadCheckerClass);
114
115 // Verify that the destructor doesn't assert
116 // when called on a different thread.
117 DeleteThreadCheckerClassOnThread delete_on_thread(
118 thread_checker_class.release());
119
120 delete_on_thread.Start();
121 delete_on_thread.Join();
122}
123
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000124TEST(ThreadCheckerTest, DetachFromThread) {
jbauch555604a2016-04-26 03:13:22 -0700125 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000126 new ThreadCheckerClass);
127
128 // Verify that DoStuff doesn't assert when called on a different thread after
129 // a call to DetachFromThread.
130 thread_checker_class->DetachFromThread();
131 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
132
133 call_on_thread.Start();
134 call_on_thread.Join();
135}
136
137#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
138
139void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700140 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000141 new ThreadCheckerClass);
142
143 // DoStuff should assert in debug builds only when called on a
144 // different thread.
145 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
146
147 call_on_thread.Start();
148 call_on_thread.Join();
149}
150
151#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000152TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000153 ASSERT_DEATH({
154 ThreadCheckerClass::MethodOnDifferentThreadImpl();
155 }, "");
156}
157#else
158TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
159 ThreadCheckerClass::MethodOnDifferentThreadImpl();
160}
161#endif // ENABLE_THREAD_CHECKER
162
163void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700164 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000165 new ThreadCheckerClass);
166
167 // DoStuff doesn't assert when called on a different thread
168 // after a call to DetachFromThread.
169 thread_checker_class->DetachFromThread();
170 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
171
172 call_on_thread.Start();
173 call_on_thread.Join();
174
175 // DoStuff should assert in debug builds only after moving to
176 // another thread.
177 thread_checker_class->DoStuff();
178}
179
180#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000181TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000182 ASSERT_DEATH({
183 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
184 }, "");
185}
186#else
187TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
188 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
189}
190#endif // ENABLE_THREAD_CHECKER
191
192#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
193
danilchap8e572f02016-05-19 06:49:03 -0700194class ThreadAnnotateTest {
195 public:
196 // Next two function should create warnings when compile (e.g. if used with
197 // specific T).
198 // TODO(danilchap): Find a way to test they do not compile when thread
199 // annotation checks enabled.
200 template<typename T>
201 void access_var_no_annotate() {
202 var_thread_ = 42;
203 }
204
205 template<typename T>
206 void access_fun_no_annotate() {
207 function();
208 }
209
210 // Functions below should be able to compile.
211 void access_var_annotate_thread() {
212 RTC_DCHECK_RUN_ON(thread_);
213 var_thread_ = 42;
214 }
215
216 void access_var_annotate_checker() {
217 RTC_DCHECK_RUN_ON(&checker_);
218 var_checker_ = 44;
219 }
220
221 void access_var_annotate_queue() {
222 RTC_DCHECK_RUN_ON(queue_);
223 var_queue_ = 46;
224 }
225
226 void access_fun_annotate() {
227 RTC_DCHECK_RUN_ON(thread_);
228 function();
229 }
230
231 void access_fun_and_var() {
232 RTC_DCHECK_RUN_ON(thread_);
233 fun_acccess_var();
234 }
235
236 private:
237 void function() RUN_ON(thread_) {}
238 void fun_acccess_var() RUN_ON(thread_) { var_thread_ = 13; }
239
240 rtc::Thread* thread_;
241 rtc::ThreadChecker checker_;
242 rtc::TaskQueue* queue_;
243
244 int var_thread_ ACCESS_ON(thread_);
245 int var_checker_ GUARDED_BY(checker_);
246 int var_queue_ ACCESS_ON(queue_);
247};
248
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000249// Just in case we ever get lumped together with other compilation units.
250#undef ENABLE_THREAD_CHECKER
251
252} // namespace rtc