blob: 76462fd60e928e89e6501fda4659362641b6318a [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.
guidou8f901062016-10-03 08:32:31 -070024#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
25#define ENABLE_THREAD_CHECKER 1
26#else
27#define ENABLE_THREAD_CHECKER 0
28#endif
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.
henrikg91d6ede2015-09-17 00:24:34 -070042 void DoStuff() { RTC_DCHECK(CalledOnValidThread()); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000043
44 void DetachFromThread() {
45 ThreadChecker::DetachFromThread();
46 }
47
48 static void MethodOnDifferentThreadImpl();
49 static void DetachThenCallFromDifferentThreadImpl();
50
51 private:
henrikg3c089d72015-09-16 05:37:44 -070052 RTC_DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000053};
54
55// Calls ThreadCheckerClass::DoStuff on another thread.
56class CallDoStuffOnThread : public Thread {
57 public:
58 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
59 : Thread(),
60 thread_checker_class_(thread_checker_class) {
61 SetName("call_do_stuff_on_thread", NULL);
62 }
63
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000064 void Run() override { thread_checker_class_->DoStuff(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000065
66 // New method. Needed since Thread::Join is protected, and it is called by
67 // the TEST.
68 void Join() {
69 Thread::Join();
70 }
71
72 private:
73 ThreadCheckerClass* thread_checker_class_;
74
henrikg3c089d72015-09-16 05:37:44 -070075 RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000076};
77
78// Deletes ThreadCheckerClass on a different thread.
79class DeleteThreadCheckerClassOnThread : public Thread {
80 public:
81 explicit DeleteThreadCheckerClassOnThread(
82 ThreadCheckerClass* thread_checker_class)
83 : Thread(),
84 thread_checker_class_(thread_checker_class) {
85 SetName("delete_thread_checker_class_on_thread", NULL);
86 }
87
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000088 void Run() override { thread_checker_class_.reset(); }
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000089
90 // New method. Needed since Thread::Join is protected, and it is called by
91 // the TEST.
92 void Join() {
93 Thread::Join();
94 }
95
96 private:
jbauch555604a2016-04-26 03:13:22 -070097 std::unique_ptr<ThreadCheckerClass> thread_checker_class_;
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +000098
henrikg3c089d72015-09-16 05:37:44 -070099 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000100};
101
102} // namespace
103
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000104TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
jbauch555604a2016-04-26 03:13:22 -0700105 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000106 new ThreadCheckerClass);
107
108 // Verify that DoStuff doesn't assert.
109 thread_checker_class->DoStuff();
110
111 // Verify that the destructor doesn't assert.
112 thread_checker_class.reset();
113}
114
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000115TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
jbauch555604a2016-04-26 03:13:22 -0700116 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000117 new ThreadCheckerClass);
118
119 // Verify that the destructor doesn't assert
120 // when called on a different thread.
121 DeleteThreadCheckerClassOnThread delete_on_thread(
122 thread_checker_class.release());
123
124 delete_on_thread.Start();
125 delete_on_thread.Join();
126}
127
henrike@webrtc.orgc732a3e2014-10-09 22:08:15 +0000128TEST(ThreadCheckerTest, DetachFromThread) {
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
133 // a call to DetachFromThread.
134 thread_checker_class->DetachFromThread();
135 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) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000157 ASSERT_DEATH({
158 ThreadCheckerClass::MethodOnDifferentThreadImpl();
159 }, "");
160}
161#else
162TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
163 ThreadCheckerClass::MethodOnDifferentThreadImpl();
164}
165#endif // ENABLE_THREAD_CHECKER
166
167void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
jbauch555604a2016-04-26 03:13:22 -0700168 std::unique_ptr<ThreadCheckerClass> thread_checker_class(
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000169 new ThreadCheckerClass);
170
171 // DoStuff doesn't assert when called on a different thread
172 // after a call to DetachFromThread.
173 thread_checker_class->DetachFromThread();
174 CallDoStuffOnThread call_on_thread(thread_checker_class.get());
175
176 call_on_thread.Start();
177 call_on_thread.Join();
178
179 // DoStuff should assert in debug builds only after moving to
180 // another thread.
181 thread_checker_class->DoStuff();
182}
183
184#if ENABLE_THREAD_CHECKER
tommi@webrtc.org2eb16602015-02-07 19:17:47 +0000185TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000186 ASSERT_DEATH({
187 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
188 }, "");
189}
190#else
191TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
192 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
193}
194#endif // ENABLE_THREAD_CHECKER
195
196#endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
197
danilchap8e572f02016-05-19 06:49:03 -0700198class ThreadAnnotateTest {
199 public:
200 // Next two function should create warnings when compile (e.g. if used with
201 // specific T).
202 // TODO(danilchap): Find a way to test they do not compile when thread
203 // annotation checks enabled.
204 template<typename T>
205 void access_var_no_annotate() {
206 var_thread_ = 42;
207 }
208
209 template<typename T>
210 void access_fun_no_annotate() {
211 function();
212 }
213
214 // Functions below should be able to compile.
215 void access_var_annotate_thread() {
216 RTC_DCHECK_RUN_ON(thread_);
217 var_thread_ = 42;
218 }
219
220 void access_var_annotate_checker() {
221 RTC_DCHECK_RUN_ON(&checker_);
222 var_checker_ = 44;
223 }
224
225 void access_var_annotate_queue() {
226 RTC_DCHECK_RUN_ON(queue_);
227 var_queue_ = 46;
228 }
229
230 void access_fun_annotate() {
231 RTC_DCHECK_RUN_ON(thread_);
232 function();
233 }
234
235 void access_fun_and_var() {
236 RTC_DCHECK_RUN_ON(thread_);
237 fun_acccess_var();
238 }
239
240 private:
241 void function() RUN_ON(thread_) {}
242 void fun_acccess_var() RUN_ON(thread_) { var_thread_ = 13; }
243
244 rtc::Thread* thread_;
245 rtc::ThreadChecker checker_;
246 rtc::TaskQueue* queue_;
247
248 int var_thread_ ACCESS_ON(thread_);
249 int var_checker_ GUARDED_BY(checker_);
250 int var_queue_ ACCESS_ON(queue_);
251};
252
henrik.lundin@webrtc.org1e3c5c22014-06-16 11:34:44 +0000253// Just in case we ever get lumped together with other compilation units.
254#undef ENABLE_THREAD_CHECKER
255
256} // namespace rtc