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