Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: third_party/libjingle_xmpp/task_runner/taskrunner.cc

Issue 2694903005: Add a copy of webrtc's TaskRunner abstraction, which is going to be deleted in webrtc. (Closed)
Patch Set: Delete dependencies on webrtc's rtc_task_runner. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/libjingle_xmpp/task_runner/taskrunner.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2004 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 <algorithm>
12
13 #include "third_party/libjingle_xmpp/task_runner/taskrunner.h"
14
15 #include "third_party/libjingle_xmpp/task_runner/task.h"
16 #include "third_party/webrtc/base/checks.h"
17 #include "third_party/webrtc/base/logging.h"
18
19 namespace rtc {
20
21 TaskRunner::TaskRunner()
22 : TaskParent(this) {}
23
24 TaskRunner::~TaskRunner() {
25 // this kills and deletes children silently!
26 AbortAllChildren();
27 InternalRunTasks(true);
28 }
29
30 void TaskRunner::StartTask(Task * task) {
31 tasks_.push_back(task);
32
33 // the task we just started could be about to timeout --
34 // make sure our "next timeout task" is correct
35 UpdateTaskTimeout(task, 0);
36
37 WakeTasks();
38 }
39
40 void TaskRunner::RunTasks() {
41 InternalRunTasks(false);
42 }
43
44 void TaskRunner::InternalRunTasks(bool in_destructor) {
45 // This shouldn't run while an abort is happening.
46 // If that occurs, then tasks may be deleted in this method,
47 // but pointers to them will still be in the
48 // "ChildSet copy" in TaskParent::AbortAllChildren.
49 // Subsequent use of those task may cause data corruption or crashes.
50 #if RTC_DCHECK_IS_ON
51 RTC_DCHECK(!abort_count_);
52 #endif
53 // Running continues until all tasks are Blocked (ok for a small # of tasks)
54 if (tasks_running_) {
55 return; // don't reenter
56 }
57
58 tasks_running_ = true;
59
60 int64_t previous_timeout_time = next_task_timeout();
61
62 int did_run = true;
63 while (did_run) {
64 did_run = false;
65 // use indexing instead of iterators because tasks_ may grow
66 for (size_t i = 0; i < tasks_.size(); ++i) {
67 while (!tasks_[i]->Blocked()) {
68 tasks_[i]->Step();
69 did_run = true;
70 }
71 }
72 }
73 // Tasks are deleted when running has paused
74 bool need_timeout_recalc = false;
75 for (size_t i = 0; i < tasks_.size(); ++i) {
76 if (tasks_[i]->IsDone()) {
77 Task* task = tasks_[i];
78 if (next_timeout_task_ &&
79 task->unique_id() == next_timeout_task_->unique_id()) {
80 next_timeout_task_ = NULL;
81 need_timeout_recalc = true;
82 }
83
84 #if RTC_DCHECK_IS_ON
85 deleting_task_ = task;
86 #endif
87 delete task;
88 #if RTC_DCHECK_IS_ON
89 deleting_task_ = NULL;
90 #endif
91 tasks_[i] = NULL;
92 }
93 }
94 // Finally, remove nulls
95 std::vector<Task *>::iterator it;
96 it = std::remove(tasks_.begin(),
97 tasks_.end(),
98 reinterpret_cast<Task *>(NULL));
99
100 tasks_.erase(it, tasks_.end());
101
102 if (need_timeout_recalc)
103 RecalcNextTimeout(NULL);
104
105 // Make sure that adjustments are done to account
106 // for any timeout changes (but don't call this
107 // while being destroyed since it calls a pure virtual function).
108 if (!in_destructor)
109 CheckForTimeoutChange(previous_timeout_time);
110
111 tasks_running_ = false;
112 }
113
114 void TaskRunner::PollTasks() {
115 // see if our "next potentially timed-out task" has indeed timed out.
116 // If it has, wake it up, then queue up the next task in line
117 // Repeat while we have new timed-out tasks.
118 // TODO: We need to guard against WakeTasks not updating
119 // next_timeout_task_. Maybe also add documentation in the header file once
120 // we understand this code better.
121 Task* old_timeout_task = NULL;
122 while (next_timeout_task_ &&
123 old_timeout_task != next_timeout_task_ &&
124 next_timeout_task_->TimedOut()) {
125 old_timeout_task = next_timeout_task_;
126 next_timeout_task_->Wake();
127 WakeTasks();
128 }
129 }
130
131 int64_t TaskRunner::next_task_timeout() const {
132 if (next_timeout_task_) {
133 return next_timeout_task_->timeout_time();
134 }
135 return 0;
136 }
137
138 // this function gets called frequently -- when each task changes
139 // state to something other than DONE, ERROR or BLOCKED, it calls
140 // ResetTimeout(), which will call this function to make sure that
141 // the next timeout-able task hasn't changed. The logic in this function
142 // prevents RecalcNextTimeout() from getting called in most cases,
143 // effectively making the task scheduler O-1 instead of O-N
144
145 void TaskRunner::UpdateTaskTimeout(Task* task,
146 int64_t previous_task_timeout_time) {
147 RTC_DCHECK(task != NULL);
148 int64_t previous_timeout_time = next_task_timeout();
149 bool task_is_timeout_task = next_timeout_task_ != NULL &&
150 task->unique_id() == next_timeout_task_->unique_id();
151 if (task_is_timeout_task) {
152 previous_timeout_time = previous_task_timeout_time;
153 }
154
155 // if the relevant task has a timeout, then
156 // check to see if it's closer than the current
157 // "about to timeout" task
158 if (task->timeout_time()) {
159 if (next_timeout_task_ == NULL ||
160 (task->timeout_time() <= next_timeout_task_->timeout_time())) {
161 next_timeout_task_ = task;
162 }
163 } else if (task_is_timeout_task) {
164 // otherwise, if the task doesn't have a timeout,
165 // and it used to be our "about to timeout" task,
166 // walk through all the tasks looking for the real
167 // "about to timeout" task
168 RecalcNextTimeout(task);
169 }
170
171 // Note when task_running_, then the running routine
172 // (TaskRunner::InternalRunTasks) is responsible for calling
173 // CheckForTimeoutChange.
174 if (!tasks_running_) {
175 CheckForTimeoutChange(previous_timeout_time);
176 }
177 }
178
179 void TaskRunner::RecalcNextTimeout(Task *exclude_task) {
180 // walk through all the tasks looking for the one
181 // which satisfies the following:
182 // it's not finished already
183 // we're not excluding it
184 // it has the closest timeout time
185
186 int64_t next_timeout_time = 0;
187 next_timeout_task_ = NULL;
188
189 for (size_t i = 0; i < tasks_.size(); ++i) {
190 Task *task = tasks_[i];
191 // if the task isn't complete, and it actually has a timeout time
192 if (!task->IsDone() && (task->timeout_time() > 0))
193 // if it doesn't match our "exclude" task
194 if (exclude_task == NULL ||
195 exclude_task->unique_id() != task->unique_id())
196 // if its timeout time is sooner than our current timeout time
197 if (next_timeout_time == 0 ||
198 task->timeout_time() <= next_timeout_time) {
199 // set this task as our next-to-timeout
200 next_timeout_time = task->timeout_time();
201 next_timeout_task_ = task;
202 }
203 }
204 }
205
206 void TaskRunner::CheckForTimeoutChange(int64_t previous_timeout_time) {
207 int64_t next_timeout = next_task_timeout();
208 bool timeout_change = (previous_timeout_time == 0 && next_timeout != 0) ||
209 next_timeout < previous_timeout_time ||
210 (previous_timeout_time <= CurrentTime() &&
211 previous_timeout_time != next_timeout);
212 if (timeout_change) {
213 OnTimeoutChange();
214 }
215 }
216
217 } // namespace rtc
OLDNEW
« no previous file with comments | « third_party/libjingle_xmpp/task_runner/taskrunner.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698