blob: 071815d1360b920720e8e947ad8c2e3484cd67df [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "rtc_base/checks.h"
16#include "rtc_base/constructormagic.h"
17#include "rtc_base/nullsocketserver.h"
18#include "rtc_base/task_queue.h"
19#include "rtc_base/thread.h"
20#include "rtc_base/thread_checker.h"
21#include "test/gtest.h"
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000022
23// Duplicated from base/threading/thread_checker.h so that we can be
24// good citizens there and undef the macro.
kwiberg5377bc72016-10-04 13:46:56 -070025#define ENABLE_THREAD_CHECKER RTC_DCHECK_IS_ON
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000026
27namespace rtc {
28
29namespace {
30
31// Simple class to exercise the basics of ThreadChecker.
32// Both the destructor and DoStuff should verify that they were
33// called on the same thread as the constructor.
34class ThreadCheckerClass : public ThreadChecker {
35 public:
36 ThreadCheckerClass() {}
37
38 // Verifies that it was called on the same thread as the constructor.
henrikg91d6ede2015-09-17 00:24:34 -070039 void DoStuff() { RTC_DCHECK(CalledOnValidThread()); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000040
41 void DetachFromThread() {
42 ThreadChecker::DetachFromThread();
43 }
44
45 static void MethodOnDifferentThreadImpl();
46 static void DetachThenCallFromDifferentThreadImpl();
47
48 private:
henrikg3c089d72015-09-16 05:37:44 -070049 RTC_DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000050};
51
52// Calls ThreadCheckerClass::DoStuff on another thread.
53class CallDoStuffOnThread : public Thread {
54 public:
55 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
tommie7251592017-07-14 14:44:46 -070056 : Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())),
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000057 thread_checker_class_(thread_checker_class) {
deadbeef37f5ecf2017-02-27 14:06:41 -080058 SetName("call_do_stuff_on_thread", nullptr);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000059 }
60
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000061 void Run() override { thread_checker_class_->DoStuff(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000062
63 // New method. Needed since Thread::Join is protected, and it is called by
64 // the TEST.
65 void Join() {
66 Thread::Join();
67 }
68
69 private:
70 ThreadCheckerClass* thread_checker_class_;
71
henrikg3c089d72015-09-16 05:37:44 -070072 RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000073};
74
75// Deletes ThreadCheckerClass on a different thread.
76class DeleteThreadCheckerClassOnThread : public Thread {
77 public:
78 explicit DeleteThreadCheckerClassOnThread(
tommie7251592017-07-14 14:44:46 -070079 std::unique_ptr<ThreadCheckerClass> thread_checker_class)
80 : Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())),
81 thread_checker_class_(std::move(thread_checker_class)) {
deadbeef37f5ecf2017-02-27 14:06:41 -080082 SetName("delete_thread_checker_class_on_thread", nullptr);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000083 }
84
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000085 void Run() override { thread_checker_class_.reset(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000086
87 // New method. Needed since Thread::Join is protected, and it is called by
88 // the TEST.
89 void Join() {
90 Thread::Join();
91 }
92
tommie7251592017-07-14 14:44:46 -070093 bool has_been_deleted() const { return !thread_checker_class_; }
94
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000095 private:
jbauch555604a2016-04-26 03:13:22 -070096 std::unique_ptr<ThreadCheckerClass> thread_checker_class_;
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000097
henrikg3c089d72015-09-16 05:37:44 -070098 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000099};
100
101} // namespace
102
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000103TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
jbauch555604a2016-04-26 03:13:22 -0700104 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000105 new ThreadCheckerClass);
106
107 // Verify that DoStuff doesn't assert.
108 thread_checker_class->DoStuff();
109
110 // Verify that the destructor doesn't assert.
111 thread_checker_class.reset();
112}
113
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000114TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
jbauch555604a2016-04-26 03:13:22 -0700115 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000116 new ThreadCheckerClass);
117
118 // Verify that the destructor doesn't assert
119 // when called on a different thread.
120 DeleteThreadCheckerClassOnThread delete_on_thread(
tommie7251592017-07-14 14:44:46 -0700121 std::move(thread_checker_class));
122
123 EXPECT_FALSE(delete_on_thread.has_been_deleted());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000124
125 delete_on_thread.Start();
126 delete_on_thread.Join();
tommie7251592017-07-14 14:44:46 -0700127
128 EXPECT_TRUE(delete_on_thread.has_been_deleted());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000129}
130
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000131TEST(ThreadCheckerTest, DetachFromThread) {
jbauch555604a2016-04-26 03:13:22 -0700132 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000133 new ThreadCheckerClass);
134
135 // Verify that DoStuff doesn't assert when called on a different thread after
136 // a call to DetachFromThread.
137 thread_checker_class->DetachFromThread();
138 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
139
140 call_on_thread.Start();
141 call_on_thread.Join();
142}
143
144#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
145
146void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700147 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000148 new ThreadCheckerClass);
149
150 // DoStuff should assert in debug builds only when called on a
151 // different thread.
152 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
153
154 call_on_thread.Start();
155 call_on_thread.Join();
156}
157
158#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000159TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000160 ASSERT_DEATH({
161 ThreadCheckerClass::MethodOnDifferentThreadImpl();
162 }, "");
163}
164#else
165TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
166 ThreadCheckerClass::MethodOnDifferentThreadImpl();
167}
168#endif // ENABLE_THREAD_CHECKER
169
170void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700171 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000172 new ThreadCheckerClass);
173
174 // DoStuff doesn't assert when called on a different thread
175 // after a call to DetachFromThread.
176 thread_checker_class->DetachFromThread();
177 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
178
179 call_on_thread.Start();
180 call_on_thread.Join();
181
182 // DoStuff should assert in debug builds only after moving to
183 // another thread.
184 thread_checker_class->DoStuff();
185}
186
187#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000188TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000189 ASSERT_DEATH({
190 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
191 }, "");
192}
193#else
194TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
195 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
196}
197#endif // ENABLE_THREAD_CHECKER
198
199#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
200
danilchap8e572f02016-05-19 06:49:03 -0700201class ThreadAnnotateTest {
202 public:
203 // Next two function should create warnings when compile (e.g. if used with
204 // specific T).
205 // TODO(danilchap): Find a way to test they do not compile when thread
206 // annotation checks enabled.
207 template<typename T>
208 void access_var_no_annotate() {
209 var_thread_ = 42;
210 }
211
212 template<typename T>
213 void access_fun_no_annotate() {
214 function();
215 }
216
217 // Functions below should be able to compile.
218 void access_var_annotate_thread() {
219 RTC_DCHECK_RUN_ON(thread_);
220 var_thread_ = 42;
221 }
222
223 void access_var_annotate_checker() {
224 RTC_DCHECK_RUN_ON(&checker_);
225 var_checker_ = 44;
226 }
227
228 void access_var_annotate_queue() {
229 RTC_DCHECK_RUN_ON(queue_);
230 var_queue_ = 46;
231 }
232
233 void access_fun_annotate() {
234 RTC_DCHECK_RUN_ON(thread_);
235 function();
236 }
237
238 void access_fun_and_var() {
239 RTC_DCHECK_RUN_ON(thread_);
240 fun_acccess_var();
241 }
242
243 private:
danilchap5301e3c2017-09-06 04:10:21 -0700244 void function() RTC_RUN_ON(thread_) {}
245 void fun_acccess_var() RTC_RUN_ON(thread_) { var_thread_ = 13; }
danilchap8e572f02016-05-19 06:49:03 -0700246
247 rtc::Thread* thread_;
248 rtc::ThreadChecker checker_;
249 rtc::TaskQueue* queue_;
250
danilchap5301e3c2017-09-06 04:10:21 -0700251 int var_thread_ RTC_ACCESS_ON(thread_);
252 int var_checker_ RTC_GUARDED_BY(checker_);
253 int var_queue_ RTC_ACCESS_ON(queue_);
danilchap8e572f02016-05-19 06:49:03 -0700254};
255
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000256// Just in case we ever get lumped together with other compilation units.
257#undef ENABLE_THREAD_CHECKER
258
259} // namespace rtc