| OLD | NEW |
| (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 "webrtc/base/task.h" | |
| 12 #include "webrtc/base/checks.h" | |
| 13 #include "webrtc/base/taskrunner.h" | |
| 14 | |
| 15 namespace rtc { | |
| 16 | |
| 17 int32_t Task::unique_id_seed_ = 0; | |
| 18 | |
| 19 Task::Task(TaskParent *parent) | |
| 20 : TaskParent(this, parent), | |
| 21 state_(STATE_INIT), | |
| 22 blocked_(false), | |
| 23 done_(false), | |
| 24 aborted_(false), | |
| 25 busy_(false), | |
| 26 error_(false), | |
| 27 start_time_(0), | |
| 28 timeout_time_(0), | |
| 29 timeout_seconds_(0), | |
| 30 timeout_suspended_(false) { | |
| 31 unique_id_ = unique_id_seed_++; | |
| 32 | |
| 33 // sanity check that we didn't roll-over our id seed | |
| 34 RTC_DCHECK(unique_id_ < unique_id_seed_); | |
| 35 } | |
| 36 | |
| 37 Task::~Task() { | |
| 38 // Is this task being deleted in the correct manner? | |
| 39 #if RTC_DCHECK_IS_ON | |
| 40 RTC_DCHECK(!done_ || GetRunner()->is_ok_to_delete(this)); | |
| 41 #endif | |
| 42 RTC_DCHECK(state_ == STATE_INIT || done_); | |
| 43 RTC_DCHECK(state_ == STATE_INIT || blocked_); | |
| 44 | |
| 45 // If the task is being deleted without being done, it | |
| 46 // means that it hasn't been removed from its parent. | |
| 47 // This happens if a task is deleted outside of TaskRunner. | |
| 48 if (!done_) { | |
| 49 Stop(); | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 int64_t Task::CurrentTime() { | |
| 54 return GetRunner()->CurrentTime(); | |
| 55 } | |
| 56 | |
| 57 int64_t Task::ElapsedTime() { | |
| 58 return CurrentTime() - start_time_; | |
| 59 } | |
| 60 | |
| 61 void Task::Start() { | |
| 62 if (state_ != STATE_INIT) | |
| 63 return; | |
| 64 // Set the start time before starting the task. Otherwise if the task | |
| 65 // finishes quickly and deletes the Task object, setting start_time_ | |
| 66 // will crash. | |
| 67 start_time_ = CurrentTime(); | |
| 68 GetRunner()->StartTask(this); | |
| 69 } | |
| 70 | |
| 71 void Task::Step() { | |
| 72 if (done_) { | |
| 73 #if RTC_DCHECK_IS_ON | |
| 74 // we do not know how !blocked_ happens when done_ - should be impossible. | |
| 75 // But it causes problems, so in retail build, we force blocked_, and | |
| 76 // under debug we assert. | |
| 77 RTC_DCHECK(blocked_); | |
| 78 #else | |
| 79 blocked_ = true; | |
| 80 #endif | |
| 81 return; | |
| 82 } | |
| 83 | |
| 84 // Async Error() was called | |
| 85 if (error_) { | |
| 86 done_ = true; | |
| 87 state_ = STATE_ERROR; | |
| 88 blocked_ = true; | |
| 89 // obsolete - an errored task is not considered done now | |
| 90 // SignalDone(); | |
| 91 | |
| 92 Stop(); | |
| 93 #if RTC_DCHECK_IS_ON | |
| 94 // verify that stop removed this from its parent | |
| 95 RTC_DCHECK(!parent()->IsChildTask(this)); | |
| 96 #endif | |
| 97 return; | |
| 98 } | |
| 99 | |
| 100 busy_ = true; | |
| 101 int new_state = Process(state_); | |
| 102 busy_ = false; | |
| 103 | |
| 104 if (aborted_) { | |
| 105 Abort(true); // no need to wake because we're awake | |
| 106 return; | |
| 107 } | |
| 108 | |
| 109 if (new_state == STATE_BLOCKED) { | |
| 110 blocked_ = true; | |
| 111 // Let the timeout continue | |
| 112 } else { | |
| 113 state_ = new_state; | |
| 114 blocked_ = false; | |
| 115 ResetTimeout(); | |
| 116 } | |
| 117 | |
| 118 if (new_state == STATE_DONE) { | |
| 119 done_ = true; | |
| 120 } else if (new_state == STATE_ERROR) { | |
| 121 done_ = true; | |
| 122 error_ = true; | |
| 123 } | |
| 124 | |
| 125 if (done_) { | |
| 126 // obsolete - call this yourself | |
| 127 // SignalDone(); | |
| 128 | |
| 129 Stop(); | |
| 130 #if RTC_DCHECK_IS_ON | |
| 131 // verify that stop removed this from its parent | |
| 132 RTC_DCHECK(!parent()->IsChildTask(this)); | |
| 133 #endif | |
| 134 blocked_ = true; | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 void Task::Abort(bool nowake) { | |
| 139 // Why only check for done_ (instead of "aborted_ || done_")? | |
| 140 // | |
| 141 // If aborted_ && !done_, it means the logic for aborting still | |
| 142 // needs to be executed (because busy_ must have been true when | |
| 143 // Abort() was previously called). | |
| 144 if (done_) | |
| 145 return; | |
| 146 aborted_ = true; | |
| 147 if (!busy_) { | |
| 148 done_ = true; | |
| 149 blocked_ = true; | |
| 150 error_ = true; | |
| 151 | |
| 152 // "done_" is set before calling "Stop()" to ensure that this code | |
| 153 // doesn't execute more than once (recursively) for the same task. | |
| 154 Stop(); | |
| 155 #if RTC_DCHECK_IS_ON | |
| 156 // verify that stop removed this from its parent | |
| 157 RTC_DCHECK(!parent()->IsChildTask(this)); | |
| 158 #endif | |
| 159 if (!nowake) { | |
| 160 // WakeTasks to self-delete. | |
| 161 // Don't call Wake() because it is a no-op after "done_" is set. | |
| 162 // Even if Wake() did run, it clears "blocked_" which isn't desireable. | |
| 163 GetRunner()->WakeTasks(); | |
| 164 } | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 void Task::Wake() { | |
| 169 if (done_) | |
| 170 return; | |
| 171 if (blocked_) { | |
| 172 blocked_ = false; | |
| 173 GetRunner()->WakeTasks(); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 void Task::Error() { | |
| 178 if (error_ || done_) | |
| 179 return; | |
| 180 error_ = true; | |
| 181 Wake(); | |
| 182 } | |
| 183 | |
| 184 std::string Task::GetStateName(int state) const { | |
| 185 switch (state) { | |
| 186 case STATE_BLOCKED: return "BLOCKED"; | |
| 187 case STATE_INIT: return "INIT"; | |
| 188 case STATE_START: return "START"; | |
| 189 case STATE_DONE: return "DONE"; | |
| 190 case STATE_ERROR: return "ERROR"; | |
| 191 case STATE_RESPONSE: return "RESPONSE"; | |
| 192 } | |
| 193 return "??"; | |
| 194 } | |
| 195 | |
| 196 int Task::Process(int state) { | |
| 197 int newstate = STATE_ERROR; | |
| 198 | |
| 199 if (TimedOut()) { | |
| 200 ClearTimeout(); | |
| 201 newstate = OnTimeout(); | |
| 202 SignalTimeout(); | |
| 203 } else { | |
| 204 switch (state) { | |
| 205 case STATE_INIT: | |
| 206 newstate = STATE_START; | |
| 207 break; | |
| 208 case STATE_START: | |
| 209 newstate = ProcessStart(); | |
| 210 break; | |
| 211 case STATE_RESPONSE: | |
| 212 newstate = ProcessResponse(); | |
| 213 break; | |
| 214 case STATE_DONE: | |
| 215 case STATE_ERROR: | |
| 216 newstate = STATE_BLOCKED; | |
| 217 break; | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 return newstate; | |
| 222 } | |
| 223 | |
| 224 void Task::Stop() { | |
| 225 // No need to wake because we're either awake or in abort | |
| 226 TaskParent::OnStopped(this); | |
| 227 } | |
| 228 | |
| 229 int Task::ProcessResponse() { | |
| 230 return STATE_DONE; | |
| 231 } | |
| 232 | |
| 233 void Task::set_timeout_seconds(const int timeout_seconds) { | |
| 234 timeout_seconds_ = timeout_seconds; | |
| 235 ResetTimeout(); | |
| 236 } | |
| 237 | |
| 238 bool Task::TimedOut() { | |
| 239 return timeout_seconds_ && | |
| 240 timeout_time_ && | |
| 241 CurrentTime() >= timeout_time_; | |
| 242 } | |
| 243 | |
| 244 void Task::ResetTimeout() { | |
| 245 int64_t previous_timeout_time = timeout_time_; | |
| 246 bool timeout_allowed = (state_ != STATE_INIT) | |
| 247 && (state_ != STATE_DONE) | |
| 248 && (state_ != STATE_ERROR); | |
| 249 if (timeout_seconds_ && timeout_allowed && !timeout_suspended_) | |
| 250 timeout_time_ = CurrentTime() + | |
| 251 (timeout_seconds_ * kSecToMsec * kMsecTo100ns); | |
| 252 else | |
| 253 timeout_time_ = 0; | |
| 254 | |
| 255 GetRunner()->UpdateTaskTimeout(this, previous_timeout_time); | |
| 256 } | |
| 257 | |
| 258 void Task::ClearTimeout() { | |
| 259 int64_t previous_timeout_time = timeout_time_; | |
| 260 timeout_time_ = 0; | |
| 261 GetRunner()->UpdateTaskTimeout(this, previous_timeout_time); | |
| 262 } | |
| 263 | |
| 264 void Task::SuspendTimeout() { | |
| 265 if (!timeout_suspended_) { | |
| 266 timeout_suspended_ = true; | |
| 267 ResetTimeout(); | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 void Task::ResumeTimeout() { | |
| 272 if (timeout_suspended_) { | |
| 273 timeout_suspended_ = false; | |
| 274 ResetTimeout(); | |
| 275 } | |
| 276 } | |
| 277 | |
| 278 int Task::OnTimeout() { | |
| 279 // by default, we are finished after timing out | |
| 280 return STATE_DONE; | |
| 281 } | |
| 282 | |
| 283 } // namespace rtc | |
| OLD | NEW |