blob: 9fbb24ac8818a9bff54a35bb64c0119c892a9028 [file] [log] [blame]
eladalon413ee9a2017-08-22 04:02:52 -07001/*
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 06:47:31 +020011#include "test/single_threaded_task_queue.h"
eladalon413ee9a2017-08-22 04:02:52 -070012
Mirko Bonadei317a1f02019-09-17 17:06:18 +020013#include <memory>
eladalon413ee9a2017-08-22 04:02:52 -070014#include <utility>
15
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/checks.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010017#include "rtc_base/numerics/safe_conversions.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "rtc_base/time_utils.h"
eladalon413ee9a2017-08-22 04:02:52 -070019
20namespace webrtc {
21namespace test {
22
Danil Chapovalov71037a82019-09-25 17:21:52 +020023DEPRECATED_SingleThreadedTaskQueueForTesting::StoredTask::StoredTask(
Yves Gerey6516f762019-08-29 11:50:23 +020024 DEPRECATED_SingleThreadedTaskQueueForTesting::TaskId task_id,
Danil Chapovalov71037a82019-09-25 17:21:52 +020025 std::unique_ptr<QueuedTask> task)
26 : task_id(task_id), task(std::move(task)) {}
eladalon413ee9a2017-08-22 04:02:52 -070027
Danil Chapovalov71037a82019-09-25 17:21:52 +020028DEPRECATED_SingleThreadedTaskQueueForTesting::StoredTask::~StoredTask() =
Yves Gerey6516f762019-08-29 11:50:23 +020029 default;
eladalon413ee9a2017-08-22 04:02:52 -070030
Yves Gerey6516f762019-08-29 11:50:23 +020031DEPRECATED_SingleThreadedTaskQueueForTesting::
32 DEPRECATED_SingleThreadedTaskQueueForTesting(const char* name)
Niels Möllerc572ff32018-11-07 08:43:50 +010033 : thread_(Run, this, name), running_(true), next_task_id_(0) {
eladalon413ee9a2017-08-22 04:02:52 -070034 thread_.Start();
35}
36
Yves Gerey6516f762019-08-29 11:50:23 +020037DEPRECATED_SingleThreadedTaskQueueForTesting::
38 ~DEPRECATED_SingleThreadedTaskQueueForTesting() {
Tommi31d1bce2019-08-27 11:34:20 +020039 Stop();
eladalon413ee9a2017-08-22 04:02:52 -070040}
41
Yves Gerey6516f762019-08-29 11:50:23 +020042DEPRECATED_SingleThreadedTaskQueueForTesting::TaskId
Danil Chapovalov71037a82019-09-25 17:21:52 +020043DEPRECATED_SingleThreadedTaskQueueForTesting::PostDelayed(
44 std::unique_ptr<QueuedTask> task,
Yves Gerey6516f762019-08-29 11:50:23 +020045 int64_t delay_ms) {
eladalon413ee9a2017-08-22 04:02:52 -070046 int64_t earliest_exec_time = rtc::TimeAfter(delay_ms);
47
48 rtc::CritScope lock(&cs_);
Tommi31d1bce2019-08-27 11:34:20 +020049 if (!running_)
50 return kInvalidTaskId;
eladalon413ee9a2017-08-22 04:02:52 -070051
52 TaskId id = next_task_id_++;
53
54 // Insert after any other tasks with an earlier-or-equal target time.
Danil Chapovalov71037a82019-09-25 17:21:52 +020055 // Note: multimap has promise "The order of the key-value pairs whose keys
56 // compare equivalent is the order of insertion and does not change."
57 tasks_.emplace(std::piecewise_construct,
58 std::forward_as_tuple(earliest_exec_time),
59 std::forward_as_tuple(id, std::move(task)));
eladalon413ee9a2017-08-22 04:02:52 -070060
61 // This class is optimized for simplicty, not for performance. This will wake
62 // the thread up even if the next task in the queue is only scheduled for
63 // quite some time from now. In that case, the thread will just send itself
64 // back to sleep.
65 wake_up_.Set();
66
67 return id;
68}
69
Yves Gerey6516f762019-08-29 11:50:23 +020070void DEPRECATED_SingleThreadedTaskQueueForTesting::SendTask(Task task) {
Tommi6e4791f2019-08-14 23:05:44 +020071 RTC_DCHECK(!IsCurrent());
Niels Möllerc572ff32018-11-07 08:43:50 +010072 rtc::Event done;
Tommi31d1bce2019-08-27 11:34:20 +020073 if (PostTask([&task, &done]() {
74 task();
75 done.Set();
76 }) == kInvalidTaskId) {
77 return;
78 }
Tommi6e4791f2019-08-14 23:05:44 +020079 // Give up after 30 seconds, warn after 10.
80 RTC_CHECK(done.Wait(30000, 10000));
eladalon413ee9a2017-08-22 04:02:52 -070081}
82
Yves Gerey6516f762019-08-29 11:50:23 +020083bool DEPRECATED_SingleThreadedTaskQueueForTesting::CancelTask(TaskId task_id) {
eladalon413ee9a2017-08-22 04:02:52 -070084 rtc::CritScope lock(&cs_);
85 for (auto it = tasks_.begin(); it != tasks_.end(); it++) {
Danil Chapovalov71037a82019-09-25 17:21:52 +020086 if (it->second.task_id == task_id) {
eladalon413ee9a2017-08-22 04:02:52 -070087 tasks_.erase(it);
88 return true;
89 }
90 }
91 return false;
92}
93
Yves Gerey6516f762019-08-29 11:50:23 +020094bool DEPRECATED_SingleThreadedTaskQueueForTesting::IsCurrent() {
Tommi6e4791f2019-08-14 23:05:44 +020095 return rtc::IsThreadRefEqual(thread_.GetThreadRef(), rtc::CurrentThreadRef());
96}
97
Yves Gerey6516f762019-08-29 11:50:23 +020098bool DEPRECATED_SingleThreadedTaskQueueForTesting::IsRunning() {
Tommi31d1bce2019-08-27 11:34:20 +020099 RTC_DCHECK_RUN_ON(&owner_thread_checker_);
100 // We could check the |running_| flag here, but this is equivalent for the
101 // purposes of this function.
102 return thread_.IsRunning();
103}
104
Yves Gerey6516f762019-08-29 11:50:23 +0200105bool DEPRECATED_SingleThreadedTaskQueueForTesting::HasPendingTasks() const {
Tommi31d1bce2019-08-27 11:34:20 +0200106 rtc::CritScope lock(&cs_);
107 return !tasks_.empty();
108}
109
Yves Gerey6516f762019-08-29 11:50:23 +0200110void DEPRECATED_SingleThreadedTaskQueueForTesting::Stop() {
Tommi31d1bce2019-08-27 11:34:20 +0200111 RTC_DCHECK_RUN_ON(&owner_thread_checker_);
112 if (!thread_.IsRunning())
113 return;
114
115 {
116 rtc::CritScope lock(&cs_);
117 running_ = false;
118 }
119
120 wake_up_.Set();
121 thread_.Stop();
122}
123
Yves Gerey6516f762019-08-29 11:50:23 +0200124void DEPRECATED_SingleThreadedTaskQueueForTesting::Run(void* obj) {
125 static_cast<DEPRECATED_SingleThreadedTaskQueueForTesting*>(obj)->RunLoop();
eladalon413ee9a2017-08-22 04:02:52 -0700126}
127
Yves Gerey6516f762019-08-29 11:50:23 +0200128void DEPRECATED_SingleThreadedTaskQueueForTesting::RunLoop() {
Danil Chapovalov71037a82019-09-25 17:21:52 +0200129 CurrentTaskQueueSetter set_current(this);
eladalon413ee9a2017-08-22 04:02:52 -0700130 while (true) {
131 std::unique_ptr<QueuedTask> queued_task;
132
133 // An empty queue would lead to sleeping until the queue becoems non-empty.
Mirko Bonadeidca82bc2017-12-13 18:44:59 +0100134 // A queue where the earliest task is scheduled for later than now, will
eladalon413ee9a2017-08-22 04:02:52 -0700135 // lead to sleeping until the time of the next scheduled task (or until
136 // more tasks are scheduled).
137 int wait_time = rtc::Event::kForever;
138
139 {
140 rtc::CritScope lock(&cs_);
141 if (!running_) {
142 return;
143 }
144 if (!tasks_.empty()) {
Danil Chapovalov71037a82019-09-25 17:21:52 +0200145 auto next_delayed_task = tasks_.begin();
146 int64_t earliest_exec_time = next_delayed_task->first;
147 int64_t remaining_delay_ms =
148 rtc::TimeDiff(earliest_exec_time, rtc::TimeMillis());
eladalon413ee9a2017-08-22 04:02:52 -0700149 if (remaining_delay_ms <= 0) {
Danil Chapovalov71037a82019-09-25 17:21:52 +0200150 queued_task = std::move(next_delayed_task->second.task);
151 tasks_.erase(next_delayed_task);
eladalon413ee9a2017-08-22 04:02:52 -0700152 } else {
153 wait_time = rtc::saturated_cast<int>(remaining_delay_ms);
154 }
155 }
156 }
157
158 if (queued_task) {
Danil Chapovalov71037a82019-09-25 17:21:52 +0200159 if (!queued_task->Run()) {
160 queued_task.release();
161 }
eladalon413ee9a2017-08-22 04:02:52 -0700162 } else {
163 wake_up_.Wait(wait_time);
164 }
165 }
166}
167
Danil Chapovalov71037a82019-09-25 17:21:52 +0200168void DEPRECATED_SingleThreadedTaskQueueForTesting::Delete() {
169 Stop();
170 delete this;
171}
172
eladalon413ee9a2017-08-22 04:02:52 -0700173} // namespace test
174} // namespace webrtc