blob: b5927043f06ef87a295c763212d6932c7a45d074 [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
Jonas Olssona4d87372019-07-05 19:08:33 +020013#include "rtc_base/thread_checker.h"
14
jbauch555604a2016-04-26 03:13:22 -070015#include <memory>
Yves Gerey3e707812018-11-28 16:47:49 +010016#include <utility>
jbauch555604a2016-04-26 03:13:22 -070017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/constructor_magic.h"
20#include "rtc_base/null_socket_server.h"
21#include "rtc_base/socket_server.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/task_queue.h"
23#include "rtc_base/thread.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "test/gtest.h"
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000025
26// Duplicated from base/threading/thread_checker.h so that we can be
27// good citizens there and undef the macro.
kwiberg5377bc72016-10-04 13:46:56 -070028#define ENABLE_THREAD_CHECKER RTC_DCHECK_IS_ON
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000029
30namespace rtc {
31
32namespace {
33
34// Simple class to exercise the basics of ThreadChecker.
35// Both the destructor and DoStuff should verify that they were
36// called on the same thread as the constructor.
37class ThreadCheckerClass : public ThreadChecker {
38 public:
39 ThreadCheckerClass() {}
40
41 // Verifies that it was called on the same thread as the constructor.
Sebastian Janssonc01367d2019-04-08 15:20:44 +020042 void DoStuff() { RTC_DCHECK(IsCurrent()); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000043
Sebastian Janssonc01367d2019-04-08 15:20:44 +020044 void Detach() { ThreadChecker::Detach(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000045
46 static void MethodOnDifferentThreadImpl();
47 static void DetachThenCallFromDifferentThreadImpl();
48
49 private:
henrikg3c089d72015-09-16 05:37:44 -070050 RTC_DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000051};
52
53// Calls ThreadCheckerClass::DoStuff on another thread.
54class CallDoStuffOnThread : public Thread {
55 public:
56 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
tommie7251592017-07-14 14:44:46 -070057 : Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())),
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000058 thread_checker_class_(thread_checker_class) {
deadbeef37f5ecf2017-02-27 14:06:41 -080059 SetName("call_do_stuff_on_thread", nullptr);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000060 }
61
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000062 void Run() override { thread_checker_class_->DoStuff(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000063
64 // New method. Needed since Thread::Join is protected, and it is called by
65 // the TEST.
Yves Gerey665174f2018-06-19 15:03:05 +020066 void Join() { Thread::Join(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000067
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(
tommie7251592017-07-14 14:44:46 -070078 std::unique_ptr<ThreadCheckerClass> thread_checker_class)
79 : Thread(std::unique_ptr<SocketServer>(new rtc::NullSocketServer())),
80 thread_checker_class_(std::move(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.
Yves Gerey665174f2018-06-19 15:03:05 +020088 void Join() { Thread::Join(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000089
tommie7251592017-07-14 14:44:46 -070090 bool has_been_deleted() const { return !thread_checker_class_; }
91
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000092 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(
tommie7251592017-07-14 14:44:46 -0700118 std::move(thread_checker_class));
119
120 EXPECT_FALSE(delete_on_thread.has_been_deleted());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000121
122 delete_on_thread.Start();
123 delete_on_thread.Join();
tommie7251592017-07-14 14:44:46 -0700124
125 EXPECT_TRUE(delete_on_thread.has_been_deleted());
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000126}
127
Sebastian Janssonc01367d2019-04-08 15:20:44 +0200128TEST(ThreadCheckerTest, Detach) {
jbauch555604a2016-04-26 03:13:22 -0700129 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000130 new ThreadCheckerClass);
131
132 // Verify that DoStuff doesn't assert when called on a different thread after
Sebastian Janssonc01367d2019-04-08 15:20:44 +0200133 // a call to Detach.
134 thread_checker_class->Detach();
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000135 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
136
137 call_on_thread.Start();
138 call_on_thread.Join();
139}
140
141#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
142
143void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700144 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000145 new ThreadCheckerClass);
146
147 // DoStuff should assert in debug builds only when called on a
148 // different thread.
149 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
150
151 call_on_thread.Start();
152 call_on_thread.Join();
153}
154
155#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000156TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
Yves Gerey665174f2018-06-19 15:03:05 +0200157 ASSERT_DEATH({ ThreadCheckerClass::MethodOnDifferentThreadImpl(); }, "");
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000158}
159#else
160TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
161 ThreadCheckerClass::MethodOnDifferentThreadImpl();
162}
163#endif // ENABLE_THREAD_CHECKER
164
165void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700166 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000167 new ThreadCheckerClass);
168
169 // DoStuff doesn't assert when called on a different thread
Sebastian Janssonc01367d2019-04-08 15:20:44 +0200170 // after a call to Detach.
171 thread_checker_class->Detach();
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000172 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
173
174 call_on_thread.Start();
175 call_on_thread.Join();
176
177 // DoStuff should assert in debug builds only after moving to
178 // another thread.
179 thread_checker_class->DoStuff();
180}
181
182#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000183TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
Yves Gerey665174f2018-06-19 15:03:05 +0200184 ASSERT_DEATH({ ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); },
185 "");
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000186}
187#else
188TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
189 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
190}
191#endif // ENABLE_THREAD_CHECKER
192
193#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
194
danilchap8e572f02016-05-19 06:49:03 -0700195class ThreadAnnotateTest {
196 public:
197 // Next two function should create warnings when compile (e.g. if used with
198 // specific T).
199 // TODO(danilchap): Find a way to test they do not compile when thread
200 // annotation checks enabled.
Yves Gerey665174f2018-06-19 15:03:05 +0200201 template <typename T>
danilchap8e572f02016-05-19 06:49:03 -0700202 void access_var_no_annotate() {
203 var_thread_ = 42;
204 }
205
Yves Gerey665174f2018-06-19 15:03:05 +0200206 template <typename T>
danilchap8e572f02016-05-19 06:49:03 -0700207 void access_fun_no_annotate() {
208 function();
209 }
210
211 // Functions below should be able to compile.
212 void access_var_annotate_thread() {
213 RTC_DCHECK_RUN_ON(thread_);
214 var_thread_ = 42;
215 }
216
217 void access_var_annotate_checker() {
218 RTC_DCHECK_RUN_ON(&checker_);
219 var_checker_ = 44;
220 }
221
222 void access_var_annotate_queue() {
223 RTC_DCHECK_RUN_ON(queue_);
224 var_queue_ = 46;
225 }
226
227 void access_fun_annotate() {
228 RTC_DCHECK_RUN_ON(thread_);
229 function();
230 }
231
232 void access_fun_and_var() {
233 RTC_DCHECK_RUN_ON(thread_);
234 fun_acccess_var();
235 }
236
237 private:
danilchap5301e3c2017-09-06 04:10:21 -0700238 void function() RTC_RUN_ON(thread_) {}
239 void fun_acccess_var() RTC_RUN_ON(thread_) { var_thread_ = 13; }
danilchap8e572f02016-05-19 06:49:03 -0700240
241 rtc::Thread* thread_;
242 rtc::ThreadChecker checker_;
243 rtc::TaskQueue* queue_;
244
Niels Möller1e062892018-02-07 10:18:32 +0100245 int var_thread_ RTC_GUARDED_BY(thread_);
danilchap5301e3c2017-09-06 04:10:21 -0700246 int var_checker_ RTC_GUARDED_BY(checker_);
Niels Möller1e062892018-02-07 10:18:32 +0100247 int var_queue_ RTC_GUARDED_BY(queue_);
danilchap8e572f02016-05-19 06:49:03 -0700248};
249
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000250// Just in case we ever get lumped together with other compilation units.
251#undef ENABLE_THREAD_CHECKER
252
253} // namespace rtc