blob: d4ef105c8a0b1b6927bcd4f69da715c7eefd30a6 [file] [log] [blame]
tommic06b1332016-05-14 11:31:40 -07001/*
2 * Copyright 2016 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
tommi0b942152017-03-10 09:33:53 -080011#if defined(WEBRTC_WIN)
12// clang-format off
13#include <windows.h> // Must come first.
14#include <mmsystem.h>
15// clang-format on
16#endif
17
Yves Gerey3e707812018-11-28 16:47:49 +010018#include <stdint.h>
tommic06b1332016-05-14 11:31:40 -070019#include <memory>
Yves Gerey3e707812018-11-28 16:47:49 +010020#include <utility>
tommic06b1332016-05-14 11:31:40 -070021#include <vector>
22
Yves Gerey3e707812018-11-28 16:47:49 +010023#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/bind.h"
25#include "rtc_base/event.h"
Yves Gerey3e707812018-11-28 16:47:49 +010026#include "rtc_base/task_queue.h"
Tommi68561562018-02-13 19:47:50 +010027#include "rtc_base/task_queue_for_test.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/time_utils.h"
Yves Gerey3e707812018-11-28 16:47:49 +010029#include "test/gtest.h"
tommic06b1332016-05-14 11:31:40 -070030
Tommi68561562018-02-13 19:47:50 +010031using rtc::test::TaskQueueForTest;
32
tommic06b1332016-05-14 11:31:40 -070033namespace rtc {
Tommi68561562018-02-13 19:47:50 +010034
tommi0b942152017-03-10 09:33:53 -080035namespace {
36// Noop on all platforms except Windows, where it turns on high precision
37// multimedia timers which increases the precision of TimeMillis() while in
38// scope.
39class EnableHighResTimers {
40 public:
41#if !defined(WEBRTC_WIN)
42 EnableHighResTimers() {}
43#else
44 EnableHighResTimers() : enabled_(timeBeginPeriod(1) == TIMERR_NOERROR) {}
45 ~EnableHighResTimers() {
46 if (enabled_)
47 timeEndPeriod(1);
48 }
49
50 private:
51 const bool enabled_;
52#endif
53};
tommic06b1332016-05-14 11:31:40 -070054
nisse2c7b7a62017-09-04 05:18:21 -070055void CheckCurrent(Event* signal, TaskQueue* queue) {
tommic06b1332016-05-14 11:31:40 -070056 EXPECT_TRUE(queue->IsCurrent());
57 if (signal)
58 signal->Set();
59}
60
61} // namespace
62
63TEST(TaskQueueTest, Construct) {
64 static const char kQueueName[] = "Construct";
65 TaskQueue queue(kQueueName);
66 EXPECT_FALSE(queue.IsCurrent());
67}
68
69TEST(TaskQueueTest, PostAndCheckCurrent) {
70 static const char kQueueName[] = "PostAndCheckCurrent";
Niels Möllerc572ff32018-11-07 08:43:50 +010071 Event event;
tommic06b1332016-05-14 11:31:40 -070072 TaskQueue queue(kQueueName);
73
74 // We're not running a task, so there shouldn't be a current queue.
75 EXPECT_FALSE(queue.IsCurrent());
76 EXPECT_FALSE(TaskQueue::Current());
77
nisse2c7b7a62017-09-04 05:18:21 -070078 queue.PostTask(Bind(&CheckCurrent, &event, &queue));
tommic06b1332016-05-14 11:31:40 -070079 EXPECT_TRUE(event.Wait(1000));
80}
81
82TEST(TaskQueueTest, PostCustomTask) {
83 static const char kQueueName[] = "PostCustomImplementation";
Tommi68561562018-02-13 19:47:50 +010084 TaskQueueForTest queue(kQueueName);
tommic06b1332016-05-14 11:31:40 -070085
86 class CustomTask : public QueuedTask {
87 public:
Tommi68561562018-02-13 19:47:50 +010088 CustomTask() {}
89 bool ran() const { return ran_; }
tommic06b1332016-05-14 11:31:40 -070090
91 private:
92 bool Run() override {
Tommi68561562018-02-13 19:47:50 +010093 ran_ = true;
94 return false; // Never allow the task to be deleted by the queue.
tommic06b1332016-05-14 11:31:40 -070095 }
96
Tommi68561562018-02-13 19:47:50 +010097 bool ran_ = false;
98 } my_task;
tommic06b1332016-05-14 11:31:40 -070099
Tommi68561562018-02-13 19:47:50 +0100100 queue.SendTask(&my_task);
101 EXPECT_TRUE(my_task.ran());
tommic06b1332016-05-14 11:31:40 -0700102}
103
104TEST(TaskQueueTest, PostLambda) {
Tommi68561562018-02-13 19:47:50 +0100105 TaskQueueForTest queue("PostLambda");
106 bool ran = false;
107 queue.SendTask([&ran]() { ran = true; });
108 EXPECT_TRUE(ran);
tommic06b1332016-05-14 11:31:40 -0700109}
110
tommiede07592017-02-27 07:16:10 -0800111TEST(TaskQueueTest, PostDelayedZero) {
112 static const char kQueueName[] = "PostDelayedZero";
Niels Möllerc572ff32018-11-07 08:43:50 +0100113 Event event;
tommiede07592017-02-27 07:16:10 -0800114 TaskQueue queue(kQueueName);
115
116 queue.PostDelayedTask([&event]() { event.Set(); }, 0);
117 EXPECT_TRUE(event.Wait(1000));
118}
119
tommic06b1332016-05-14 11:31:40 -0700120TEST(TaskQueueTest, PostFromQueue) {
121 static const char kQueueName[] = "PostFromQueue";
Niels Möllerc572ff32018-11-07 08:43:50 +0100122 Event event;
tommic06b1332016-05-14 11:31:40 -0700123 TaskQueue queue(kQueueName);
124
tommic06b1332016-05-14 11:31:40 -0700125 queue.PostTask(
126 [&event, &queue]() { queue.PostTask([&event]() { event.Set(); }); });
127 EXPECT_TRUE(event.Wait(1000));
128}
129
tommic5b435d2016-10-31 02:17:11 -0700130TEST(TaskQueueTest, PostDelayed) {
tommic06b1332016-05-14 11:31:40 -0700131 static const char kQueueName[] = "PostDelayed";
Niels Möllerc572ff32018-11-07 08:43:50 +0100132 Event event;
tommi5bdee472017-03-03 05:20:12 -0800133 TaskQueue queue(kQueueName, TaskQueue::Priority::HIGH);
tommic06b1332016-05-14 11:31:40 -0700134
tommic06b1332016-05-14 11:31:40 -0700135 uint32_t start = Time();
nisse2c7b7a62017-09-04 05:18:21 -0700136 queue.PostDelayedTask(Bind(&CheckCurrent, &event, &queue), 100);
tommic06b1332016-05-14 11:31:40 -0700137 EXPECT_TRUE(event.Wait(1000));
138 uint32_t end = Time();
tommic5b435d2016-10-31 02:17:11 -0700139 // These tests are a little relaxed due to how "powerful" our test bots can
tommi67fcad82016-11-16 10:50:24 -0800140 // be. Most recently we've seen windows bots fire the callback after 94-99ms,
tommic5b435d2016-10-31 02:17:11 -0700141 // which is why we have a little bit of leeway backwards as well.
tommi67fcad82016-11-16 10:50:24 -0800142 EXPECT_GE(end - start, 90u);
143 EXPECT_NEAR(end - start, 190u, 100u); // Accept 90-290.
tommic06b1332016-05-14 11:31:40 -0700144}
145
tommi0b942152017-03-10 09:33:53 -0800146// This task needs to be run manually due to the slowness of some of our bots.
147// TODO(tommi): Can we run this on the perf bots?
148TEST(TaskQueueTest, DISABLED_PostDelayedHighRes) {
149 EnableHighResTimers high_res_scope;
150
151 static const char kQueueName[] = "PostDelayedHighRes";
Niels Möllerc572ff32018-11-07 08:43:50 +0100152 Event event;
tommi0b942152017-03-10 09:33:53 -0800153 TaskQueue queue(kQueueName, TaskQueue::Priority::HIGH);
154
155 uint32_t start = Time();
nisse2c7b7a62017-09-04 05:18:21 -0700156 queue.PostDelayedTask(Bind(&CheckCurrent, &event, &queue), 3);
tommi0b942152017-03-10 09:33:53 -0800157 EXPECT_TRUE(event.Wait(1000));
158 uint32_t end = TimeMillis();
159 // These tests are a little relaxed due to how "powerful" our test bots can
160 // be. Most recently we've seen windows bots fire the callback after 94-99ms,
161 // which is why we have a little bit of leeway backwards as well.
162 EXPECT_GE(end - start, 3u);
163 EXPECT_NEAR(end - start, 3, 3u);
164}
165
tommic06b1332016-05-14 11:31:40 -0700166TEST(TaskQueueTest, PostMultipleDelayed) {
167 static const char kQueueName[] = "PostMultipleDelayed";
168 TaskQueue queue(kQueueName);
169
170 std::vector<std::unique_ptr<Event>> events;
tommif9d91542017-02-17 02:47:11 -0800171 for (int i = 0; i < 100; ++i) {
Niels Möllerc572ff32018-11-07 08:43:50 +0100172 events.push_back(absl::make_unique<Event>());
Yves Gerey665174f2018-06-19 15:03:05 +0200173 queue.PostDelayedTask(Bind(&CheckCurrent, events.back().get(), &queue), i);
tommic06b1332016-05-14 11:31:40 -0700174 }
175
176 for (const auto& e : events)
tommif9d91542017-02-17 02:47:11 -0800177 EXPECT_TRUE(e->Wait(1000));
tommic06b1332016-05-14 11:31:40 -0700178}
179
180TEST(TaskQueueTest, PostDelayedAfterDestruct) {
181 static const char kQueueName[] = "PostDelayedAfterDestruct";
Niels Möllerc572ff32018-11-07 08:43:50 +0100182 Event run;
183 Event deleted;
tommic06b1332016-05-14 11:31:40 -0700184 {
185 TaskQueue queue(kQueueName);
Danil Chapovalova36631c2018-09-24 20:27:22 +0200186 queue.PostDelayedTask(
187 rtc::NewClosure([&run] { run.Set(); }, [&deleted] { deleted.Set(); }),
188 100);
tommic06b1332016-05-14 11:31:40 -0700189 }
Danil Chapovalova36631c2018-09-24 20:27:22 +0200190 // Task might outlive the TaskQueue, but still should be deleted.
191 EXPECT_TRUE(deleted.Wait(200));
192 EXPECT_FALSE(run.Wait(0)); // and should not run.
tommic06b1332016-05-14 11:31:40 -0700193}
194
tommic06b1332016-05-14 11:31:40 -0700195TEST(TaskQueueTest, PostAndReuse) {
196 static const char kPostQueue[] = "PostQueue";
197 static const char kReplyQueue[] = "ReplyQueue";
Niels Möllerc572ff32018-11-07 08:43:50 +0100198 Event event;
tommic06b1332016-05-14 11:31:40 -0700199 TaskQueue post_queue(kPostQueue);
200 TaskQueue reply_queue(kReplyQueue);
201
202 int call_count = 0;
203
204 class ReusedTask : public QueuedTask {
205 public:
206 ReusedTask(int* counter, TaskQueue* reply_queue, Event* event)
207 : counter_(counter), reply_queue_(reply_queue), event_(event) {
208 EXPECT_EQ(0, *counter_);
209 }
210
211 private:
212 bool Run() override {
213 if (++(*counter_) == 1) {
214 std::unique_ptr<QueuedTask> myself(this);
215 reply_queue_->PostTask(std::move(myself));
216 // At this point, the object is owned by reply_queue_ and it's
217 // theoratically possible that the object has been deleted (e.g. if
218 // posting wasn't possible). So, don't touch any member variables here.
219
220 // Indicate to the current queue that ownership has been transferred.
221 return false;
222 } else {
223 EXPECT_EQ(2, *counter_);
224 EXPECT_TRUE(reply_queue_->IsCurrent());
225 event_->Set();
226 return true; // Indicate that the object should be deleted.
227 }
228 }
229
230 int* const counter_;
231 TaskQueue* const reply_queue_;
232 Event* const event_;
233 };
234
Danil Chapovalov6f09ae22017-10-12 14:39:25 +0200235 std::unique_ptr<ReusedTask> task(
tommic06b1332016-05-14 11:31:40 -0700236 new ReusedTask(&call_count, &reply_queue, &event));
237
238 post_queue.PostTask(std::move(task));
239 EXPECT_TRUE(event.Wait(1000));
240}
241
Danil Chapovalov6f09ae22017-10-12 14:39:25 +0200242TEST(TaskQueueTest, PostCopyableClosure) {
243 struct CopyableClosure {
244 CopyableClosure(int* num_copies, int* num_moves, Event* event)
245 : num_copies(num_copies), num_moves(num_moves), event(event) {}
246 CopyableClosure(const CopyableClosure& other)
247 : num_copies(other.num_copies),
248 num_moves(other.num_moves),
249 event(other.event) {
250 ++*num_copies;
251 }
252 CopyableClosure(CopyableClosure&& other)
253 : num_copies(other.num_copies),
254 num_moves(other.num_moves),
255 event(other.event) {
256 ++*num_moves;
257 }
258 void operator()() { event->Set(); }
259
260 int* num_copies;
261 int* num_moves;
262 Event* event;
263 };
264
265 int num_copies = 0;
266 int num_moves = 0;
Niels Möllerc572ff32018-11-07 08:43:50 +0100267 Event event;
Danil Chapovalov6f09ae22017-10-12 14:39:25 +0200268
269 static const char kPostQueue[] = "PostCopyableClosure";
270 TaskQueue post_queue(kPostQueue);
271 {
272 CopyableClosure closure(&num_copies, &num_moves, &event);
273 post_queue.PostTask(closure);
274 // Destroy closure to check with msan and tsan posted task has own copy.
275 }
276
277 EXPECT_TRUE(event.Wait(1000));
278 EXPECT_EQ(num_copies, 1);
279 EXPECT_EQ(num_moves, 0);
280}
281
282TEST(TaskQueueTest, PostMoveOnlyClosure) {
283 struct SomeState {
284 explicit SomeState(Event* event) : event(event) {}
285 ~SomeState() { event->Set(); }
286 Event* event;
287 };
288 struct MoveOnlyClosure {
289 MoveOnlyClosure(int* num_moves, std::unique_ptr<SomeState> state)
290 : num_moves(num_moves), state(std::move(state)) {}
291 MoveOnlyClosure(const MoveOnlyClosure&) = delete;
292 MoveOnlyClosure(MoveOnlyClosure&& other)
293 : num_moves(other.num_moves), state(std::move(other.state)) {
294 ++*num_moves;
295 }
296 void operator()() { state.reset(); }
297
298 int* num_moves;
299 std::unique_ptr<SomeState> state;
300 };
301
302 int num_moves = 0;
Niels Möllerc572ff32018-11-07 08:43:50 +0100303 Event event;
Danil Chapovalov6f09ae22017-10-12 14:39:25 +0200304 std::unique_ptr<SomeState> state(new SomeState(&event));
305
306 static const char kPostQueue[] = "PostMoveOnlyClosure";
307 TaskQueue post_queue(kPostQueue);
308 post_queue.PostTask(MoveOnlyClosure(&num_moves, std::move(state)));
309
310 EXPECT_TRUE(event.Wait(1000));
311 EXPECT_EQ(num_moves, 1);
312}
313
314TEST(TaskQueueTest, PostMoveOnlyCleanup) {
315 struct SomeState {
316 explicit SomeState(Event* event) : event(event) {}
317 ~SomeState() { event->Set(); }
318 Event* event;
319 };
320 struct MoveOnlyClosure {
321 void operator()() { state.reset(); }
322
323 std::unique_ptr<SomeState> state;
324 };
325
Niels Möllerc572ff32018-11-07 08:43:50 +0100326 Event event_run;
327 Event event_cleanup;
Danil Chapovalov6f09ae22017-10-12 14:39:25 +0200328 std::unique_ptr<SomeState> state_run(new SomeState(&event_run));
329 std::unique_ptr<SomeState> state_cleanup(new SomeState(&event_cleanup));
330
331 static const char kPostQueue[] = "PostMoveOnlyCleanup";
332 TaskQueue post_queue(kPostQueue);
333 post_queue.PostTask(NewClosure(MoveOnlyClosure{std::move(state_run)},
334 MoveOnlyClosure{std::move(state_cleanup)}));
335
336 EXPECT_TRUE(event_cleanup.Wait(1000));
337 // Expect run closure to complete before cleanup closure.
338 EXPECT_TRUE(event_run.Wait(0));
339}
340
tommic06b1332016-05-14 11:31:40 -0700341// Tests posting more messages than a queue can queue up.
342// In situations like that, tasks will get dropped.
343TEST(TaskQueueTest, PostALot) {
344 // To destruct the event after the queue has gone out of scope.
Niels Möllerc572ff32018-11-07 08:43:50 +0100345 Event event;
tommic06b1332016-05-14 11:31:40 -0700346
347 int tasks_executed = 0;
348 int tasks_cleaned_up = 0;
349 static const int kTaskCount = 0xffff;
350
351 {
352 static const char kQueueName[] = "PostALot";
353 TaskQueue queue(kQueueName);
354
355 // On linux, the limit of pending bytes in the pipe buffer is 0xffff.
356 // So here we post a total of 0xffff+1 messages, which triggers a failure
357 // case inside of the libevent queue implementation.
358
359 queue.PostTask([&event]() { event.Wait(Event::kForever); });
360 for (int i = 0; i < kTaskCount; ++i)
361 queue.PostTask(NewClosure([&tasks_executed]() { ++tasks_executed; },
362 [&tasks_cleaned_up]() { ++tasks_cleaned_up; }));
363 event.Set(); // Unblock the first task.
364 }
365
366 EXPECT_GE(tasks_cleaned_up, tasks_executed);
367 EXPECT_EQ(kTaskCount, tasks_cleaned_up);
tommic06b1332016-05-14 11:31:40 -0700368}
369
370} // namespace rtc