1 /*
2 * Copyright (c) 2012 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 #include "modules/utility/source/process_thread_impl.h"
12
13 #include <memory>
14 #include <utility>
15
16 #include "api/task_queue/queued_task.h"
17 #include "api/task_queue/task_queue_test.h"
18 #include "modules/include/module.h"
19 #include "rtc_base/location.h"
20 #include "rtc_base/time_utils.h"
21 #include "test/gmock.h"
22 #include "test/gtest.h"
23
24 namespace webrtc {
25
26 using ::testing::_;
27 using ::testing::DoAll;
28 using ::testing::InSequence;
29 using ::testing::Invoke;
30 using ::testing::Return;
31 using ::testing::SetArgPointee;
32
33 // The length of time, in milliseconds, to wait for an event to become signaled.
34 // Set to a fairly large value as there is quite a bit of variation on some
35 // Windows bots.
36 static const int kEventWaitTimeout = 500;
37
38 class MockModule : public Module {
39 public:
40 MOCK_METHOD(int64_t, TimeUntilNextProcess, (), (override));
41 MOCK_METHOD(void, Process, (), (override));
42 MOCK_METHOD(void, ProcessThreadAttached, (ProcessThread*), (override));
43 };
44
45 class RaiseEventTask : public QueuedTask {
46 public:
RaiseEventTask(rtc::Event * event)47 RaiseEventTask(rtc::Event* event) : event_(event) {}
Run()48 bool Run() override {
49 event_->Set();
50 return true;
51 }
52
53 private:
54 rtc::Event* event_;
55 };
56
ACTION_P(SetEvent,event)57 ACTION_P(SetEvent, event) {
58 event->Set();
59 }
60
ACTION_P(Increment,counter)61 ACTION_P(Increment, counter) {
62 ++(*counter);
63 }
64
ACTION_P(SetTimestamp,ptr)65 ACTION_P(SetTimestamp, ptr) {
66 *ptr = rtc::TimeMillis();
67 }
68
TEST(ProcessThreadImpl,StartStop)69 TEST(ProcessThreadImpl, StartStop) {
70 ProcessThreadImpl thread("ProcessThread");
71 thread.Start();
72 thread.Stop();
73 }
74
TEST(ProcessThreadImpl,MultipleStartStop)75 TEST(ProcessThreadImpl, MultipleStartStop) {
76 ProcessThreadImpl thread("ProcessThread");
77 for (int i = 0; i < 5; ++i) {
78 thread.Start();
79 thread.Stop();
80 }
81 }
82
83 // Verifies that we get at least call back to Process() on the worker thread.
TEST(ProcessThreadImpl,ProcessCall)84 TEST(ProcessThreadImpl, ProcessCall) {
85 ProcessThreadImpl thread("ProcessThread");
86 thread.Start();
87
88 rtc::Event event;
89
90 MockModule module;
91 EXPECT_CALL(module, TimeUntilNextProcess())
92 .WillOnce(Return(0))
93 .WillRepeatedly(Return(1));
94 EXPECT_CALL(module, Process())
95 .WillOnce(DoAll(SetEvent(&event), Return()))
96 .WillRepeatedly(Return());
97 EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
98
99 thread.RegisterModule(&module, RTC_FROM_HERE);
100 EXPECT_TRUE(event.Wait(kEventWaitTimeout));
101
102 EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
103 thread.Stop();
104 }
105
106 // Same as ProcessCall except the module is registered before the
107 // call to Start().
TEST(ProcessThreadImpl,ProcessCall2)108 TEST(ProcessThreadImpl, ProcessCall2) {
109 ProcessThreadImpl thread("ProcessThread");
110 rtc::Event event;
111
112 MockModule module;
113 EXPECT_CALL(module, TimeUntilNextProcess())
114 .WillOnce(Return(0))
115 .WillRepeatedly(Return(1));
116 EXPECT_CALL(module, Process())
117 .WillOnce(DoAll(SetEvent(&event), Return()))
118 .WillRepeatedly(Return());
119
120 thread.RegisterModule(&module, RTC_FROM_HERE);
121
122 EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
123 thread.Start();
124 EXPECT_TRUE(event.Wait(kEventWaitTimeout));
125
126 EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
127 thread.Stop();
128 }
129
130 // Tests setting up a module for callbacks and then unregister that module.
131 // After unregistration, we should not receive any further callbacks.
TEST(ProcessThreadImpl,Deregister)132 TEST(ProcessThreadImpl, Deregister) {
133 ProcessThreadImpl thread("ProcessThread");
134 rtc::Event event;
135
136 int process_count = 0;
137 MockModule module;
138 EXPECT_CALL(module, TimeUntilNextProcess())
139 .WillOnce(Return(0))
140 .WillRepeatedly(Return(1));
141 EXPECT_CALL(module, Process())
142 .WillOnce(DoAll(SetEvent(&event), Increment(&process_count), Return()))
143 .WillRepeatedly(DoAll(Increment(&process_count), Return()));
144
145 thread.RegisterModule(&module, RTC_FROM_HERE);
146
147 EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
148 thread.Start();
149
150 EXPECT_TRUE(event.Wait(kEventWaitTimeout));
151
152 EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
153 thread.DeRegisterModule(&module);
154
155 EXPECT_GE(process_count, 1);
156 int count_after_deregister = process_count;
157
158 // We shouldn't get any more callbacks.
159 EXPECT_FALSE(event.Wait(20));
160 EXPECT_EQ(count_after_deregister, process_count);
161 thread.Stop();
162 }
163
164 // Helper function for testing receiving a callback after a certain amount of
165 // time. There's some variance of timing built into it to reduce chance of
166 // flakiness on bots.
ProcessCallAfterAFewMs(int64_t milliseconds)167 void ProcessCallAfterAFewMs(int64_t milliseconds) {
168 ProcessThreadImpl thread("ProcessThread");
169 thread.Start();
170
171 rtc::Event event;
172
173 MockModule module;
174 int64_t start_time = 0;
175 int64_t called_time = 0;
176 EXPECT_CALL(module, TimeUntilNextProcess())
177 .WillOnce(DoAll(SetTimestamp(&start_time), Return(milliseconds)))
178 .WillRepeatedly(Return(milliseconds));
179 EXPECT_CALL(module, Process())
180 .WillOnce(DoAll(SetTimestamp(&called_time), SetEvent(&event), Return()))
181 .WillRepeatedly(Return());
182
183 EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
184 thread.RegisterModule(&module, RTC_FROM_HERE);
185
186 // Add a buffer of 50ms due to slowness of some trybots
187 // (e.g. win_drmemory_light)
188 EXPECT_TRUE(event.Wait(milliseconds + 50));
189
190 EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
191 thread.Stop();
192
193 ASSERT_GT(start_time, 0);
194 ASSERT_GT(called_time, 0);
195 // Use >= instead of > since due to rounding and timer accuracy (or lack
196 // thereof), can make the test run in "0"ms time.
197 EXPECT_GE(called_time, start_time);
198 // Check for an acceptable range.
199 uint32_t diff = called_time - start_time;
200 EXPECT_GE(diff, milliseconds - 15);
201 EXPECT_LT(diff, milliseconds + 15);
202 }
203
204 // DISABLED for now since the virtual build bots are too slow :(
205 // TODO(tommi): Fix.
TEST(ProcessThreadImpl,DISABLED_ProcessCallAfter5ms)206 TEST(ProcessThreadImpl, DISABLED_ProcessCallAfter5ms) {
207 ProcessCallAfterAFewMs(5);
208 }
209
210 // DISABLED for now since the virtual build bots are too slow :(
211 // TODO(tommi): Fix.
TEST(ProcessThreadImpl,DISABLED_ProcessCallAfter50ms)212 TEST(ProcessThreadImpl, DISABLED_ProcessCallAfter50ms) {
213 ProcessCallAfterAFewMs(50);
214 }
215
216 // DISABLED for now since the virtual build bots are too slow :(
217 // TODO(tommi): Fix.
TEST(ProcessThreadImpl,DISABLED_ProcessCallAfter200ms)218 TEST(ProcessThreadImpl, DISABLED_ProcessCallAfter200ms) {
219 ProcessCallAfterAFewMs(200);
220 }
221
222 // Runs callbacks with the goal of getting up to 50 callbacks within a second
223 // (on average 1 callback every 20ms). On real hardware, we're usually pretty
224 // close to that, but the test bots that run on virtual machines, will
225 // typically be in the range 30-40 callbacks.
226 // DISABLED for now since this can take up to 2 seconds to run on the slowest
227 // build bots.
228 // TODO(tommi): Fix.
TEST(ProcessThreadImpl,DISABLED_Process50Times)229 TEST(ProcessThreadImpl, DISABLED_Process50Times) {
230 ProcessThreadImpl thread("ProcessThread");
231 thread.Start();
232
233 rtc::Event event;
234
235 MockModule module;
236 int callback_count = 0;
237 // Ask for a callback after 20ms.
238 EXPECT_CALL(module, TimeUntilNextProcess()).WillRepeatedly(Return(20));
239 EXPECT_CALL(module, Process())
240 .WillRepeatedly(DoAll(Increment(&callback_count), Return()));
241
242 EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
243 thread.RegisterModule(&module, RTC_FROM_HERE);
244
245 EXPECT_TRUE(event.Wait(1000));
246
247 EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
248 thread.Stop();
249
250 printf("Callback count: %i\n", callback_count);
251 // Check that we got called back up to 50 times.
252 // Some of the try bots run on slow virtual machines, so the lower bound
253 // is much more relaxed to avoid flakiness.
254 EXPECT_GE(callback_count, 25);
255 EXPECT_LE(callback_count, 50);
256 }
257
258 // Tests that we can wake up the worker thread to give us a callback right
259 // away when we know the thread is sleeping.
TEST(ProcessThreadImpl,WakeUp)260 TEST(ProcessThreadImpl, WakeUp) {
261 ProcessThreadImpl thread("ProcessThread");
262 thread.Start();
263
264 rtc::Event started;
265 rtc::Event called;
266
267 MockModule module;
268 int64_t start_time;
269 int64_t called_time;
270
271 // Ask for a callback after 1000ms.
272 // TimeUntilNextProcess will be called twice.
273 // The first time we use it to get the thread into a waiting state.
274 // Then we wake the thread and there should not be another call made to
275 // TimeUntilNextProcess before Process() is called.
276 // The second time TimeUntilNextProcess is then called, is after Process
277 // has been called and we don't expect any more calls.
278 EXPECT_CALL(module, TimeUntilNextProcess())
279 .WillOnce(
280 DoAll(SetTimestamp(&start_time), SetEvent(&started), Return(1000)))
281 .WillOnce(Return(1000));
282 EXPECT_CALL(module, Process())
283 .WillOnce(DoAll(SetTimestamp(&called_time), SetEvent(&called), Return()))
284 .WillRepeatedly(Return());
285
286 EXPECT_CALL(module, ProcessThreadAttached(&thread)).Times(1);
287 thread.RegisterModule(&module, RTC_FROM_HERE);
288
289 EXPECT_TRUE(started.Wait(kEventWaitTimeout));
290 thread.WakeUp(&module);
291 EXPECT_TRUE(called.Wait(kEventWaitTimeout));
292
293 EXPECT_CALL(module, ProcessThreadAttached(nullptr)).Times(1);
294 thread.Stop();
295
296 EXPECT_GE(called_time, start_time);
297 uint32_t diff = called_time - start_time;
298 // We should have been called back much quicker than 1sec.
299 EXPECT_LE(diff, 100u);
300 }
301
302 // Tests that we can post a task that gets run straight away on the worker
303 // thread.
TEST(ProcessThreadImpl,PostTask)304 TEST(ProcessThreadImpl, PostTask) {
305 ProcessThreadImpl thread("ProcessThread");
306 rtc::Event task_ran;
307 std::unique_ptr<RaiseEventTask> task(new RaiseEventTask(&task_ran));
308 thread.Start();
309 thread.PostTask(std::move(task));
310 EXPECT_TRUE(task_ran.Wait(kEventWaitTimeout));
311 thread.Stop();
312 }
313
314 class ProcessThreadFactory : public TaskQueueFactory {
315 public:
316 ~ProcessThreadFactory() override = default;
CreateTaskQueue(absl::string_view name,Priority priority) const317 std::unique_ptr<TaskQueueBase, TaskQueueDeleter> CreateTaskQueue(
318 absl::string_view name,
319 Priority priority) const override {
320 ProcessThreadImpl* process_thread = new ProcessThreadImpl("thread");
321 process_thread->Start();
322 return std::unique_ptr<TaskQueueBase, TaskQueueDeleter>(process_thread);
323 }
324 };
325
326 INSTANTIATE_TEST_SUITE_P(
327 ProcessThread,
328 TaskQueueTest,
329 testing::Values(std::make_unique<ProcessThreadFactory>));
330
331 } // namespace webrtc
332