| // Copyright 2014 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "media/base/fake_single_thread_task_runner.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "base/location.h" | 
 | #include "base/logging.h" | 
 | #include "base/time/tick_clock.h" | 
 |  | 
 | namespace media { | 
 |  | 
 | FakeSingleThreadTaskRunner::FakeSingleThreadTaskRunner( | 
 |     base::SimpleTestTickClock* clock) | 
 |     : clock_(clock), fail_on_next_task_(false) {} | 
 |  | 
 | FakeSingleThreadTaskRunner::~FakeSingleThreadTaskRunner() = default; | 
 |  | 
 | bool FakeSingleThreadTaskRunner::PostDelayedTask( | 
 |     const base::Location& from_here, | 
 |     base::OnceClosure task, | 
 |     base::TimeDelta delay) { | 
 |   if (fail_on_next_task_) { | 
 |     LOG(FATAL) << "Infinite task posting loop detected.  Possibly caused by " | 
 |                << from_here.ToString() << " posting a task with delay " | 
 |                << delay.InMicroseconds() << " usec."; | 
 |   } | 
 |  | 
 |   CHECK_LE(base::TimeDelta(), delay); | 
 |   const base::TimeTicks run_time = clock_->NowTicks() + delay; | 
 |  | 
 |   // If there are one or more tasks with the exact same run time, schedule this | 
 |   // task to occur after them.  This mimics the FIFO ordering behavior when | 
 |   // scheduling delayed tasks to be run via base::MessageLoop in a | 
 |   // multi-threaded application. | 
 |   if (!tasks_.empty()) { | 
 |     const auto after_it = | 
 |         tasks_.lower_bound(TaskKey(run_time + base::Microseconds(1), 0)); | 
 |     if (after_it != tasks_.begin()) { | 
 |       auto it = after_it; | 
 |       --it; | 
 |       if (it->first.first == run_time) { | 
 |         tasks_.insert(after_it /* hint */, | 
 |                       std::make_pair(TaskKey(run_time, it->first.second + 1), | 
 |                                      std::move(task))); | 
 |         return true; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   // No tasks have the exact same run time, so just do a simple insert. | 
 |   tasks_.insert(std::make_pair(TaskKey(run_time, 0), std::move(task))); | 
 |   return true; | 
 | } | 
 |  | 
 | bool FakeSingleThreadTaskRunner::RunsTasksInCurrentSequence() const { | 
 |   return true; | 
 | } | 
 |  | 
 | void FakeSingleThreadTaskRunner::RunTasks() { | 
 |   while (true) { | 
 |     // Run all tasks equal or older than current time. | 
 |     const auto it = tasks_.begin(); | 
 |     if (it == tasks_.end()) | 
 |       return;  // No more tasks. | 
 |  | 
 |     if (clock_->NowTicks() < it->first.first) | 
 |       return; | 
 |  | 
 |     base::OnceClosure task = std::move(it->second); | 
 |     tasks_.erase(it); | 
 |     std::move(task).Run(); | 
 |   } | 
 | } | 
 |  | 
 | void FakeSingleThreadTaskRunner::Sleep(base::TimeDelta t) { | 
 |   CHECK_LE(base::TimeDelta(), t); | 
 |   const base::TimeTicks run_until = clock_->NowTicks() + t; | 
 |  | 
 |   while (1) { | 
 |     // Run up to 100000 tasks that were scheduled to run during the sleep | 
 |     // period. 100000 should be enough for everybody (see comments below). | 
 |     for (int i = 0; i < 100000; i++) { | 
 |       const auto it = tasks_.begin(); | 
 |       if (it == tasks_.end() || run_until < it->first.first) { | 
 |         clock_->Advance(run_until - clock_->NowTicks()); | 
 |         return; | 
 |       } | 
 |  | 
 |       clock_->Advance(it->first.first - clock_->NowTicks()); | 
 |       base::OnceClosure task = std::move(it->second); | 
 |       tasks_.erase(it); | 
 |       std::move(task).Run(); | 
 |     } | 
 |  | 
 |     // If this point is reached, there's likely some sort of case where a new | 
 |     // non-delayed task is being posted every time a task is popped and invoked | 
 |     // from the queue. If that happens, set fail_on_next_task_ to true and throw | 
 |     // an error when the next task is posted, where we might be able to identify | 
 |     // the caller causing the problem via logging. | 
 |     fail_on_next_task_ = true; | 
 |   } | 
 | } | 
 |  | 
 | bool FakeSingleThreadTaskRunner::PostNonNestableDelayedTask( | 
 |     const base::Location& from_here, | 
 |     base::OnceClosure task, | 
 |     base::TimeDelta delay) { | 
 |   NOTIMPLEMENTED(); | 
 |   return false; | 
 | } | 
 |  | 
 | }  // namespace media |