blob: a40196ff74536bd2d5d98ae81a108752695c7445 [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>
Yves Gerey3e707812018-11-28 16:47:49 +010014#include <utility>
jbauch555604a2016-04-26 03:13:22 -070015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "rtc_base/constructor_magic.h"
18#include "rtc_base/null_socket_server.h"
19#include "rtc_base/socket_server.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/task_queue.h"
21#include "rtc_base/thread.h"
22#include "rtc_base/thread_checker.h"
23#include "test/gtest.h"
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000024
25// Duplicated from base/threading/thread_checker.h so that we can be
26// good citizens there and undef the macro.
kwiberg5377bc72016-10-04 13:46:56 -070027#define ENABLE_THREAD_CHECKER RTC_DCHECK_IS_ON
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000028
29namespace rtc {
30
31namespace {
32
33// Simple class to exercise the basics of ThreadChecker.
34// Both the destructor and DoStuff should verify that they were
35// called on the same thread as the constructor.
36class ThreadCheckerClass : public ThreadChecker {
37 public:
38 ThreadCheckerClass() {}
39
40 // Verifies that it was called on the same thread as the constructor.
henrikg91d6ede2015-09-17 00:24:34 -070041 void DoStuff() { RTC_DCHECK(CalledOnValidThread()); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000042
Yves Gerey665174f2018-06-19 15:03:05 +020043 void DetachFromThread() { ThreadChecker::DetachFromThread(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000044
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.
Yves Gerey665174f2018-06-19 15:03:05 +020065 void Join() { Thread::Join(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000066
67 private:
68 ThreadCheckerClass* thread_checker_class_;
69
henrikg3c089d72015-09-16 05:37:44 -070070 RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000071};
72
73// Deletes ThreadCheckerClass on a different thread.
74class DeleteThreadCheckerClassOnThread : public Thread {
75 public:
76 explicit DeleteThreadCheckerClassOnThread(
tommie7251592017-07-14 14:44:46 -070077 std::unique_ptr<ThreadCheckerClass> thread_checker_class)
78 : Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())),
79 thread_checker_class_(std::move(thread_checker_class)) {
deadbeef37f5ecf2017-02-27 14:06:41 -080080 SetName("delete_thread_checker_class_on_thread", nullptr);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000081 }
82
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000083 void Run() override { thread_checker_class_.reset(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000084
85 // New method. Needed since Thread::Join is protected, and it is called by
86 // the TEST.
Yves Gerey665174f2018-06-19 15:03:05 +020087 void Join() { Thread::Join(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000088
tommie7251592017-07-14 14:44:46 -070089 bool has_been_deleted() const { return !thread_checker_class_; }
90
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000091 private:
jbauch555604a2016-04-26 03:13:22 -070092 std::unique_ptr<ThreadCheckerClass> thread_checker_class_;
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000093
henrikg3c089d72015-09-16 05:37:44 -070094 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000095};
96
97} // namespace
98
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +000099TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
jbauch555604a2016-04-26 03:13:22 -0700100 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000101 new ThreadCheckerClass);
102
103 // Verify that DoStuff doesn't assert.
104 thread_checker_class->DoStuff();
105
106 // Verify that the destructor doesn't assert.
107 thread_checker_class.reset();
108}
109
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000110TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
jbauch555604a2016-04-26 03:13:22 -0700111 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000112 new ThreadCheckerClass);
113
114 // Verify that the destructor doesn't assert
115 // when called on a different thread.
116 DeleteThreadCheckerClassOnThread delete_on_thread(
tommie7251592017-07-14 14:44:46 -0700117 std::move(thread_checker_class));
118
119 EXPECT_FALSE(delete_on_thread.has_been_deleted());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000120
121 delete_on_thread.Start();
122 delete_on_thread.Join();
tommie7251592017-07-14 14:44:46 -0700123
124 EXPECT_TRUE(delete_on_thread.has_been_deleted());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000125}
126
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000127TEST(ThreadCheckerTest, DetachFromThread) {
jbauch555604a2016-04-26 03:13:22 -0700128 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000129 new ThreadCheckerClass);
130
131 // Verify that DoStuff doesn't assert when called on a different thread after
132 // a call to DetachFromThread.
133 thread_checker_class->DetachFromThread();
134 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
135
136 call_on_thread.Start();
137 call_on_thread.Join();
138}
139
140#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
141
142void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700143 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000144 new ThreadCheckerClass);
145
146 // DoStuff should assert in debug builds only when called on a
147 // different thread.
148 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
149
150 call_on_thread.Start();
151 call_on_thread.Join();
152}
153
154#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000155TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
Yves Gerey665174f2018-06-19 15:03:05 +0200156 ASSERT_DEATH({ ThreadCheckerClass::MethodOnDifferentThreadImpl(); }, "");
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000157}
158#else
159TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
160 ThreadCheckerClass::MethodOnDifferentThreadImpl();
161}
162#endif // ENABLE_THREAD_CHECKER
163
164void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700165 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000166 new ThreadCheckerClass);
167
168 // DoStuff doesn't assert when called on a different thread
169 // after a call to DetachFromThread.
170 thread_checker_class->DetachFromThread();
171 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
172
173 call_on_thread.Start();
174 call_on_thread.Join();
175
176 // DoStuff should assert in debug builds only after moving to
177 // another thread.
178 thread_checker_class->DoStuff();
179}
180
181#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000182TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
Yves Gerey665174f2018-06-19 15:03:05 +0200183 ASSERT_DEATH({ ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); },
184 "");
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000185}
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.
Yves Gerey665174f2018-06-19 15:03:05 +0200200 template <typename T>
danilchap8e572f02016-05-19 06:49:03 -0700201 void access_var_no_annotate() {
202 var_thread_ = 42;
203 }
204
Yves Gerey665174f2018-06-19 15:03:05 +0200205 template <typename T>
danilchap8e572f02016-05-19 06:49:03 -0700206 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:
danilchap5301e3c2017-09-06 04:10:21 -0700237 void function() RTC_RUN_ON(thread_) {}
238 void fun_acccess_var() RTC_RUN_ON(thread_) { var_thread_ = 13; }
danilchap8e572f02016-05-19 06:49:03 -0700239
240 rtc::Thread* thread_;
241 rtc::ThreadChecker checker_;
242 rtc::TaskQueue* queue_;
243
Niels Möller1e062892018-02-07 10:18:32 +0100244 int var_thread_ RTC_GUARDED_BY(thread_);
danilchap5301e3c2017-09-06 04:10:21 -0700245 int var_checker_ RTC_GUARDED_BY(checker_);
Niels Möller1e062892018-02-07 10:18:32 +0100246 int var_queue_ RTC_GUARDED_BY(queue_);
danilchap8e572f02016-05-19 06:49:03 -0700247};
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