OLD | NEW |
| (Empty) |
1 /* | |
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 | |
13 #include <memory> | |
14 | |
15 #include "webrtc/base/checks.h" | |
16 #include "webrtc/base/constructormagic.h" | |
17 #include "webrtc/base/task_queue.h" | |
18 #include "webrtc/base/thread.h" | |
19 #include "webrtc/base/thread_checker.h" | |
20 #include "webrtc/test/gtest.h" | |
21 | |
22 // Duplicated from base/threading/thread_checker.h so that we can be | |
23 // good citizens there and undef the macro. | |
24 #define ENABLE_THREAD_CHECKER RTC_DCHECK_IS_ON | |
25 | |
26 namespace rtc { | |
27 | |
28 namespace { | |
29 | |
30 // Simple class to exercise the basics of ThreadChecker. | |
31 // Both the destructor and DoStuff should verify that they were | |
32 // called on the same thread as the constructor. | |
33 class ThreadCheckerClass : public ThreadChecker { | |
34 public: | |
35 ThreadCheckerClass() {} | |
36 | |
37 // Verifies that it was called on the same thread as the constructor. | |
38 void DoStuff() { RTC_DCHECK(CalledOnValidThread()); } | |
39 | |
40 void DetachFromThread() { | |
41 ThreadChecker::DetachFromThread(); | |
42 } | |
43 | |
44 static void MethodOnDifferentThreadImpl(); | |
45 static void DetachThenCallFromDifferentThreadImpl(); | |
46 | |
47 private: | |
48 RTC_DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass); | |
49 }; | |
50 | |
51 // Calls ThreadCheckerClass::DoStuff on another thread. | |
52 class CallDoStuffOnThread : public Thread { | |
53 public: | |
54 explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class) | |
55 : Thread(), | |
56 thread_checker_class_(thread_checker_class) { | |
57 SetName("call_do_stuff_on_thread", nullptr); | |
58 } | |
59 | |
60 void Run() override { thread_checker_class_->DoStuff(); } | |
61 | |
62 // New method. Needed since Thread::Join is protected, and it is called by | |
63 // the TEST. | |
64 void Join() { | |
65 Thread::Join(); | |
66 } | |
67 | |
68 private: | |
69 ThreadCheckerClass* thread_checker_class_; | |
70 | |
71 RTC_DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread); | |
72 }; | |
73 | |
74 // Deletes ThreadCheckerClass on a different thread. | |
75 class DeleteThreadCheckerClassOnThread : public Thread { | |
76 public: | |
77 explicit DeleteThreadCheckerClassOnThread( | |
78 ThreadCheckerClass* thread_checker_class) | |
79 : Thread(), | |
80 thread_checker_class_(thread_checker_class) { | |
81 SetName("delete_thread_checker_class_on_thread", nullptr); | |
82 } | |
83 | |
84 void Run() override { thread_checker_class_.reset(); } | |
85 | |
86 // New method. Needed since Thread::Join is protected, and it is called by | |
87 // the TEST. | |
88 void Join() { | |
89 Thread::Join(); | |
90 } | |
91 | |
92 private: | |
93 std::unique_ptr<ThreadCheckerClass> thread_checker_class_; | |
94 | |
95 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread); | |
96 }; | |
97 | |
98 } // namespace | |
99 | |
100 TEST(ThreadCheckerTest, CallsAllowedOnSameThread) { | |
101 std::unique_ptr<ThreadCheckerClass> thread_checker_class( | |
102 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 | |
111 TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) { | |
112 std::unique_ptr<ThreadCheckerClass> thread_checker_class( | |
113 new ThreadCheckerClass); | |
114 | |
115 // Verify that the destructor doesn't assert | |
116 // when called on a different thread. | |
117 DeleteThreadCheckerClassOnThread delete_on_thread( | |
118 thread_checker_class.release()); | |
119 | |
120 delete_on_thread.Start(); | |
121 delete_on_thread.Join(); | |
122 } | |
123 | |
124 TEST(ThreadCheckerTest, DetachFromThread) { | |
125 std::unique_ptr<ThreadCheckerClass> thread_checker_class( | |
126 new ThreadCheckerClass); | |
127 | |
128 // Verify that DoStuff doesn't assert when called on a different thread after | |
129 // a call to DetachFromThread. | |
130 thread_checker_class->DetachFromThread(); | |
131 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); | |
132 | |
133 call_on_thread.Start(); | |
134 call_on_thread.Join(); | |
135 } | |
136 | |
137 #if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER | |
138 | |
139 void ThreadCheckerClass::MethodOnDifferentThreadImpl() { | |
140 std::unique_ptr<ThreadCheckerClass> thread_checker_class( | |
141 new ThreadCheckerClass); | |
142 | |
143 // DoStuff should assert in debug builds only when called on a | |
144 // different thread. | |
145 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); | |
146 | |
147 call_on_thread.Start(); | |
148 call_on_thread.Join(); | |
149 } | |
150 | |
151 #if ENABLE_THREAD_CHECKER | |
152 TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) { | |
153 ASSERT_DEATH({ | |
154 ThreadCheckerClass::MethodOnDifferentThreadImpl(); | |
155 }, ""); | |
156 } | |
157 #else | |
158 TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) { | |
159 ThreadCheckerClass::MethodOnDifferentThreadImpl(); | |
160 } | |
161 #endif // ENABLE_THREAD_CHECKER | |
162 | |
163 void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() { | |
164 std::unique_ptr<ThreadCheckerClass> thread_checker_class( | |
165 new ThreadCheckerClass); | |
166 | |
167 // DoStuff doesn't assert when called on a different thread | |
168 // after a call to DetachFromThread. | |
169 thread_checker_class->DetachFromThread(); | |
170 CallDoStuffOnThread call_on_thread(thread_checker_class.get()); | |
171 | |
172 call_on_thread.Start(); | |
173 call_on_thread.Join(); | |
174 | |
175 // DoStuff should assert in debug builds only after moving to | |
176 // another thread. | |
177 thread_checker_class->DoStuff(); | |
178 } | |
179 | |
180 #if ENABLE_THREAD_CHECKER | |
181 TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) { | |
182 ASSERT_DEATH({ | |
183 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); | |
184 }, ""); | |
185 } | |
186 #else | |
187 TEST(ThreadCheckerTest, DetachFromThreadInRelease) { | |
188 ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl(); | |
189 } | |
190 #endif // ENABLE_THREAD_CHECKER | |
191 | |
192 #endif // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER | |
193 | |
194 class 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. | |
200 template<typename T> | |
201 void access_var_no_annotate() { | |
202 var_thread_ = 42; | |
203 } | |
204 | |
205 template<typename T> | |
206 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: | |
237 void function() RUN_ON(thread_) {} | |
238 void fun_acccess_var() RUN_ON(thread_) { var_thread_ = 13; } | |
239 | |
240 rtc::Thread* thread_; | |
241 rtc::ThreadChecker checker_; | |
242 rtc::TaskQueue* queue_; | |
243 | |
244 int var_thread_ ACCESS_ON(thread_); | |
245 int var_checker_ GUARDED_BY(checker_); | |
246 int var_queue_ ACCESS_ON(queue_); | |
247 }; | |
248 | |
249 // Just in case we ever get lumped together with other compilation units. | |
250 #undef ENABLE_THREAD_CHECKER | |
251 | |
252 } // namespace rtc | |
OLD | NEW |