blob: 9c0942f884ded986d809d60865492f0a8a848df6 [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
Yves Gerey665174f2018-06-19 15:03:05 +020041 void DetachFromThread() { ThreadChecker::DetachFromThread(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000042
43 static void MethodOnDifferentThreadImpl();
44 static void DetachThenCallFromDifferentThreadImpl();
45
46 private:
henrikg3c089d72015-09-16 05:37:44 -070047 RTC_DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000048};
49
50// Calls ThreadCheckerClass::DoStuff on another thread.
51class CallDoStuffOnThread : public Thread {
52 public:
53 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
tommie7251592017-07-14 14:44:46 -070054 : Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())),
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000055 thread_checker_class_(thread_checker_class) {
deadbeef37f5ecf2017-02-27 14:06:41 -080056 SetName("call_do_stuff_on_thread", nullptr);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000057 }
58
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000059 void Run() override { thread_checker_class_->DoStuff(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000060
61 // New method. Needed since Thread::Join is protected, and it is called by
62 // the TEST.
Yves Gerey665174f2018-06-19 15:03:05 +020063 void Join() { Thread::Join(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000064
65 private:
66 ThreadCheckerClass* thread_checker_class_;
67
henrikg3c089d72015-09-16 05:37:44 -070068 RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000069};
70
71// Deletes ThreadCheckerClass on a different thread.
72class DeleteThreadCheckerClassOnThread : public Thread {
73 public:
74 explicit DeleteThreadCheckerClassOnThread(
tommie7251592017-07-14 14:44:46 -070075 std::unique_ptr<ThreadCheckerClass> thread_checker_class)
76 : Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())),
77 thread_checker_class_(std::move(thread_checker_class)) {
deadbeef37f5ecf2017-02-27 14:06:41 -080078 SetName("delete_thread_checker_class_on_thread", nullptr);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000079 }
80
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000081 void Run() override { thread_checker_class_.reset(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000082
83 // New method. Needed since Thread::Join is protected, and it is called by
84 // the TEST.
Yves Gerey665174f2018-06-19 15:03:05 +020085 void Join() { Thread::Join(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000086
tommie7251592017-07-14 14:44:46 -070087 bool has_been_deleted() const { return !thread_checker_class_; }
88
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000089 private:
jbauch555604a2016-04-26 03:13:22 -070090 std::unique_ptr<ThreadCheckerClass> thread_checker_class_;
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000091
henrikg3c089d72015-09-16 05:37:44 -070092 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000093};
94
95} // namespace
96
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +000097TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
jbauch555604a2016-04-26 03:13:22 -070098 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000099 new ThreadCheckerClass);
100
101 // Verify that DoStuff doesn't assert.
102 thread_checker_class->DoStuff();
103
104 // Verify that the destructor doesn't assert.
105 thread_checker_class.reset();
106}
107
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000108TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
jbauch555604a2016-04-26 03:13:22 -0700109 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000110 new ThreadCheckerClass);
111
112 // Verify that the destructor doesn't assert
113 // when called on a different thread.
114 DeleteThreadCheckerClassOnThread delete_on_thread(
tommie7251592017-07-14 14:44:46 -0700115 std::move(thread_checker_class));
116
117 EXPECT_FALSE(delete_on_thread.has_been_deleted());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000118
119 delete_on_thread.Start();
120 delete_on_thread.Join();
tommie7251592017-07-14 14:44:46 -0700121
122 EXPECT_TRUE(delete_on_thread.has_been_deleted());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000123}
124
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000125TEST(ThreadCheckerTest, DetachFromThread) {
jbauch555604a2016-04-26 03:13:22 -0700126 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000127 new ThreadCheckerClass);
128
129 // Verify that DoStuff doesn't assert when called on a different thread after
130 // a call to DetachFromThread.
131 thread_checker_class->DetachFromThread();
132 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
133
134 call_on_thread.Start();
135 call_on_thread.Join();
136}
137
138#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
139
140void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700141 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000142 new ThreadCheckerClass);
143
144 // DoStuff should assert in debug builds only when called on a
145 // different thread.
146 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
147
148 call_on_thread.Start();
149 call_on_thread.Join();
150}
151
152#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000153TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
Yves Gerey665174f2018-06-19 15:03:05 +0200154 ASSERT_DEATH({ ThreadCheckerClass::MethodOnDifferentThreadImpl(); }, "");
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000155}
156#else
157TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
158 ThreadCheckerClass::MethodOnDifferentThreadImpl();
159}
160#endif // ENABLE_THREAD_CHECKER
161
162void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700163 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000164 new ThreadCheckerClass);
165
166 // DoStuff doesn't assert when called on a different thread
167 // after a call to DetachFromThread.
168 thread_checker_class->DetachFromThread();
169 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
170
171 call_on_thread.Start();
172 call_on_thread.Join();
173
174 // DoStuff should assert in debug builds only after moving to
175 // another thread.
176 thread_checker_class->DoStuff();
177}
178
179#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000180TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
Yves Gerey665174f2018-06-19 15:03:05 +0200181 ASSERT_DEATH({ ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); },
182 "");
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000183}
184#else
185TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
186 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
187}
188#endif // ENABLE_THREAD_CHECKER
189
190#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
191
danilchap8e572f02016-05-19 06:49:03 -0700192class ThreadAnnotateTest {
193 public:
194 // Next two function should create warnings when compile (e.g. if used with
195 // specific T).
196 // TODO(danilchap): Find a way to test they do not compile when thread
197 // annotation checks enabled.
Yves Gerey665174f2018-06-19 15:03:05 +0200198 template <typename T>
danilchap8e572f02016-05-19 06:49:03 -0700199 void access_var_no_annotate() {
200 var_thread_ = 42;
201 }
202
Yves Gerey665174f2018-06-19 15:03:05 +0200203 template <typename T>
danilchap8e572f02016-05-19 06:49:03 -0700204 void access_fun_no_annotate() {
205 function();
206 }
207
208 // Functions below should be able to compile.
209 void access_var_annotate_thread() {
210 RTC_DCHECK_RUN_ON(thread_);
211 var_thread_ = 42;
212 }
213
214 void access_var_annotate_checker() {
215 RTC_DCHECK_RUN_ON(&checker_);
216 var_checker_ = 44;
217 }
218
219 void access_var_annotate_queue() {
220 RTC_DCHECK_RUN_ON(queue_);
221 var_queue_ = 46;
222 }
223
224 void access_fun_annotate() {
225 RTC_DCHECK_RUN_ON(thread_);
226 function();
227 }
228
229 void access_fun_and_var() {
230 RTC_DCHECK_RUN_ON(thread_);
231 fun_acccess_var();
232 }
233
234 private:
danilchap5301e3c2017-09-06 04:10:21 -0700235 void function() RTC_RUN_ON(thread_) {}
236 void fun_acccess_var() RTC_RUN_ON(thread_) { var_thread_ = 13; }
danilchap8e572f02016-05-19 06:49:03 -0700237
238 rtc::Thread* thread_;
239 rtc::ThreadChecker checker_;
240 rtc::TaskQueue* queue_;
241
Niels Möller1e062892018-02-07 10:18:32 +0100242 int var_thread_ RTC_GUARDED_BY(thread_);
danilchap5301e3c2017-09-06 04:10:21 -0700243 int var_checker_ RTC_GUARDED_BY(checker_);
Niels Möller1e062892018-02-07 10:18:32 +0100244 int var_queue_ RTC_GUARDED_BY(queue_);
danilchap8e572f02016-05-19 06:49:03 -0700245};
246
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000247// Just in case we ever get lumped together with other compilation units.
248#undef ENABLE_THREAD_CHECKER
249
250} // namespace rtc