blob: ed4feef536706947b7893e0230fef6e69f8a880b [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
13#include <utility>
14
Karl Wiberg918f50c2018-07-05 11:40:33 +020015#include "absl/memory/memory.h"
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
Yves Gerey6516f762019-08-29 11:50:23 +020023DEPRECATED_SingleThreadedTaskQueueForTesting::QueuedTask::QueuedTask(
24 DEPRECATED_SingleThreadedTaskQueueForTesting::TaskId task_id,
eladalon413ee9a2017-08-22 04:02:52 -070025 int64_t earliest_execution_time,
Yves Gerey6516f762019-08-29 11:50:23 +020026 DEPRECATED_SingleThreadedTaskQueueForTesting::Task task)
eladalon413ee9a2017-08-22 04:02:52 -070027 : task_id(task_id),
28 earliest_execution_time(earliest_execution_time),
29 task(task) {}
30
Yves Gerey6516f762019-08-29 11:50:23 +020031DEPRECATED_SingleThreadedTaskQueueForTesting::QueuedTask::~QueuedTask() =
32 default;
eladalon413ee9a2017-08-22 04:02:52 -070033
Yves Gerey6516f762019-08-29 11:50:23 +020034DEPRECATED_SingleThreadedTaskQueueForTesting::
35 DEPRECATED_SingleThreadedTaskQueueForTesting(const char* name)
Niels Möllerc572ff32018-11-07 08:43:50 +010036 : thread_(Run, this, name), running_(true), next_task_id_(0) {
eladalon413ee9a2017-08-22 04:02:52 -070037 thread_.Start();
38}
39
Yves Gerey6516f762019-08-29 11:50:23 +020040DEPRECATED_SingleThreadedTaskQueueForTesting::
41 ~DEPRECATED_SingleThreadedTaskQueueForTesting() {
Tommi31d1bce2019-08-27 11:34:20 +020042 Stop();
eladalon413ee9a2017-08-22 04:02:52 -070043}
44
Yves Gerey6516f762019-08-29 11:50:23 +020045DEPRECATED_SingleThreadedTaskQueueForTesting::TaskId
46DEPRECATED_SingleThreadedTaskQueueForTesting::PostTask(Task task) {
eladalon413ee9a2017-08-22 04:02:52 -070047 return PostDelayedTask(task, 0);
48}
49
Yves Gerey6516f762019-08-29 11:50:23 +020050DEPRECATED_SingleThreadedTaskQueueForTesting::TaskId
51DEPRECATED_SingleThreadedTaskQueueForTesting::PostDelayedTask(
52 Task task,
53 int64_t delay_ms) {
eladalon413ee9a2017-08-22 04:02:52 -070054 int64_t earliest_exec_time = rtc::TimeAfter(delay_ms);
55
56 rtc::CritScope lock(&cs_);
Tommi31d1bce2019-08-27 11:34:20 +020057 if (!running_)
58 return kInvalidTaskId;
eladalon413ee9a2017-08-22 04:02:52 -070059
60 TaskId id = next_task_id_++;
61
62 // Insert after any other tasks with an earlier-or-equal target time.
63 auto it = tasks_.begin();
64 for (; it != tasks_.end(); it++) {
65 if (earliest_exec_time < (*it)->earliest_execution_time) {
66 break;
67 }
68 }
Karl Wiberg918f50c2018-07-05 11:40:33 +020069 tasks_.insert(it,
70 absl::make_unique<QueuedTask>(id, earliest_exec_time, task));
eladalon413ee9a2017-08-22 04:02:52 -070071
72 // This class is optimized for simplicty, not for performance. This will wake
73 // the thread up even if the next task in the queue is only scheduled for
74 // quite some time from now. In that case, the thread will just send itself
75 // back to sleep.
76 wake_up_.Set();
77
78 return id;
79}
80
Yves Gerey6516f762019-08-29 11:50:23 +020081void DEPRECATED_SingleThreadedTaskQueueForTesting::SendTask(Task task) {
Tommi6e4791f2019-08-14 23:05:44 +020082 RTC_DCHECK(!IsCurrent());
Niels Möllerc572ff32018-11-07 08:43:50 +010083 rtc::Event done;
Tommi31d1bce2019-08-27 11:34:20 +020084 if (PostTask([&task, &done]() {
85 task();
86 done.Set();
87 }) == kInvalidTaskId) {
88 return;
89 }
Tommi6e4791f2019-08-14 23:05:44 +020090 // Give up after 30 seconds, warn after 10.
91 RTC_CHECK(done.Wait(30000, 10000));
eladalon413ee9a2017-08-22 04:02:52 -070092}
93
Yves Gerey6516f762019-08-29 11:50:23 +020094bool DEPRECATED_SingleThreadedTaskQueueForTesting::CancelTask(TaskId task_id) {
eladalon413ee9a2017-08-22 04:02:52 -070095 rtc::CritScope lock(&cs_);
96 for (auto it = tasks_.begin(); it != tasks_.end(); it++) {
97 if ((*it)->task_id == task_id) {
98 tasks_.erase(it);
99 return true;
100 }
101 }
102 return false;
103}
104
Yves Gerey6516f762019-08-29 11:50:23 +0200105bool DEPRECATED_SingleThreadedTaskQueueForTesting::IsCurrent() {
Tommi6e4791f2019-08-14 23:05:44 +0200106 return rtc::IsThreadRefEqual(thread_.GetThreadRef(), rtc::CurrentThreadRef());
107}
108
Yves Gerey6516f762019-08-29 11:50:23 +0200109bool DEPRECATED_SingleThreadedTaskQueueForTesting::IsRunning() {
Tommi31d1bce2019-08-27 11:34:20 +0200110 RTC_DCHECK_RUN_ON(&owner_thread_checker_);
111 // We could check the |running_| flag here, but this is equivalent for the
112 // purposes of this function.
113 return thread_.IsRunning();
114}
115
Yves Gerey6516f762019-08-29 11:50:23 +0200116bool DEPRECATED_SingleThreadedTaskQueueForTesting::HasPendingTasks() const {
Tommi31d1bce2019-08-27 11:34:20 +0200117 rtc::CritScope lock(&cs_);
118 return !tasks_.empty();
119}
120
Yves Gerey6516f762019-08-29 11:50:23 +0200121void DEPRECATED_SingleThreadedTaskQueueForTesting::Stop() {
Tommi31d1bce2019-08-27 11:34:20 +0200122 RTC_DCHECK_RUN_ON(&owner_thread_checker_);
123 if (!thread_.IsRunning())
124 return;
125
126 {
127 rtc::CritScope lock(&cs_);
128 running_ = false;
129 }
130
131 wake_up_.Set();
132 thread_.Stop();
133}
134
Yves Gerey6516f762019-08-29 11:50:23 +0200135void DEPRECATED_SingleThreadedTaskQueueForTesting::Run(void* obj) {
136 static_cast<DEPRECATED_SingleThreadedTaskQueueForTesting*>(obj)->RunLoop();
eladalon413ee9a2017-08-22 04:02:52 -0700137}
138
Yves Gerey6516f762019-08-29 11:50:23 +0200139void DEPRECATED_SingleThreadedTaskQueueForTesting::RunLoop() {
eladalon413ee9a2017-08-22 04:02:52 -0700140 while (true) {
141 std::unique_ptr<QueuedTask> queued_task;
142
143 // An empty queue would lead to sleeping until the queue becoems non-empty.
Mirko Bonadeidca82bc2017-12-13 18:44:59 +0100144 // A queue where the earliest task is scheduled for later than now, will
eladalon413ee9a2017-08-22 04:02:52 -0700145 // lead to sleeping until the time of the next scheduled task (or until
146 // more tasks are scheduled).
147 int wait_time = rtc::Event::kForever;
148
149 {
150 rtc::CritScope lock(&cs_);
151 if (!running_) {
152 return;
153 }
154 if (!tasks_.empty()) {
155 int64_t remaining_delay_ms = rtc::TimeDiff(
156 tasks_.front()->earliest_execution_time, rtc::TimeMillis());
157 if (remaining_delay_ms <= 0) {
158 queued_task = std::move(tasks_.front());
159 tasks_.pop_front();
160 } else {
161 wait_time = rtc::saturated_cast<int>(remaining_delay_ms);
162 }
163 }
164 }
165
166 if (queued_task) {
167 queued_task->task();
168 } else {
169 wake_up_.Wait(wait_time);
170 }
171 }
172}
173
174} // namespace test
175} // namespace webrtc