blob: 965cb475473b18a2238b9cd66a1bee6514f498b5 [file] [log] [blame]
eladalon413ee9a2017-08-22 11:02:521/*
2 * Copyright (c) 2017 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
Mirko Bonadei92ea95e2017-09-15 04:47:3111#include "test/single_threaded_task_queue.h"
eladalon413ee9a2017-08-22 11:02:5212
13#include <utility>
14
Karl Wiberg918f50c2018-07-05 09:40:3315#include "absl/memory/memory.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3116#include "rtc_base/checks.h"
Karl Wiberge40468b2017-11-22 09:42:2617#include "rtc_base/numerics/safe_conversions.h"
Steve Anton10542f22019-01-11 17:11:0018#include "rtc_base/time_utils.h"
eladalon413ee9a2017-08-22 11:02:5219
20namespace webrtc {
21namespace test {
22
23SingleThreadedTaskQueueForTesting::QueuedTask::QueuedTask(
24 SingleThreadedTaskQueueForTesting::TaskId task_id,
25 int64_t earliest_execution_time,
26 SingleThreadedTaskQueueForTesting::Task task)
27 : task_id(task_id),
28 earliest_execution_time(earliest_execution_time),
29 task(task) {}
30
31SingleThreadedTaskQueueForTesting::QueuedTask::~QueuedTask() = default;
32
33SingleThreadedTaskQueueForTesting::SingleThreadedTaskQueueForTesting(
34 const char* name)
Niels Möllerc572ff32018-11-07 07:43:5035 : thread_(Run, this, name), running_(true), next_task_id_(0) {
eladalon413ee9a2017-08-22 11:02:5236 thread_.Start();
37}
38
39SingleThreadedTaskQueueForTesting::~SingleThreadedTaskQueueForTesting() {
40 RTC_DCHECK_RUN_ON(&owner_thread_checker_);
41 {
42 rtc::CritScope lock(&cs_);
43 running_ = false;
44 }
45 wake_up_.Set();
46 thread_.Stop();
47}
48
49SingleThreadedTaskQueueForTesting::TaskId
50SingleThreadedTaskQueueForTesting::PostTask(Task task) {
51 return PostDelayedTask(task, 0);
52}
53
54SingleThreadedTaskQueueForTesting::TaskId
55SingleThreadedTaskQueueForTesting::PostDelayedTask(Task task,
56 int64_t delay_ms) {
57 int64_t earliest_exec_time = rtc::TimeAfter(delay_ms);
58
59 rtc::CritScope lock(&cs_);
60
61 TaskId id = next_task_id_++;
62
63 // Insert after any other tasks with an earlier-or-equal target time.
64 auto it = tasks_.begin();
65 for (; it != tasks_.end(); it++) {
66 if (earliest_exec_time < (*it)->earliest_execution_time) {
67 break;
68 }
69 }
Karl Wiberg918f50c2018-07-05 09:40:3370 tasks_.insert(it,
71 absl::make_unique<QueuedTask>(id, earliest_exec_time, task));
eladalon413ee9a2017-08-22 11:02:5272
73 // This class is optimized for simplicty, not for performance. This will wake
74 // the thread up even if the next task in the queue is only scheduled for
75 // quite some time from now. In that case, the thread will just send itself
76 // back to sleep.
77 wake_up_.Set();
78
79 return id;
80}
81
82void SingleThreadedTaskQueueForTesting::SendTask(Task task) {
Niels Möllerc572ff32018-11-07 07:43:5083 rtc::Event done;
eladalon413ee9a2017-08-22 11:02:5284 PostTask([&task, &done]() {
85 task();
86 done.Set();
87 });
88 done.Wait(rtc::Event::kForever);
89}
90
91bool SingleThreadedTaskQueueForTesting::CancelTask(TaskId task_id) {
92 rtc::CritScope lock(&cs_);
93 for (auto it = tasks_.begin(); it != tasks_.end(); it++) {
94 if ((*it)->task_id == task_id) {
95 tasks_.erase(it);
96 return true;
97 }
98 }
99 return false;
100}
101
102void SingleThreadedTaskQueueForTesting::Run(void* obj) {
103 static_cast<SingleThreadedTaskQueueForTesting*>(obj)->RunLoop();
104}
105
106void SingleThreadedTaskQueueForTesting::RunLoop() {
107 while (true) {
108 std::unique_ptr<QueuedTask> queued_task;
109
110 // An empty queue would lead to sleeping until the queue becoems non-empty.
Mirko Bonadeidca82bc2017-12-13 17:44:59111 // A queue where the earliest task is scheduled for later than now, will
eladalon413ee9a2017-08-22 11:02:52112 // lead to sleeping until the time of the next scheduled task (or until
113 // more tasks are scheduled).
114 int wait_time = rtc::Event::kForever;
115
116 {
117 rtc::CritScope lock(&cs_);
118 if (!running_) {
119 return;
120 }
121 if (!tasks_.empty()) {
122 int64_t remaining_delay_ms = rtc::TimeDiff(
123 tasks_.front()->earliest_execution_time, rtc::TimeMillis());
124 if (remaining_delay_ms <= 0) {
125 queued_task = std::move(tasks_.front());
126 tasks_.pop_front();
127 } else {
128 wait_time = rtc::saturated_cast<int>(remaining_delay_ms);
129 }
130 }
131 }
132
133 if (queued_task) {
134 queued_task->task();
135 } else {
136 wake_up_.Wait(wait_time);
137 }
138 }
139}
140
141} // namespace test
142} // namespace webrtc