| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/fake_single_thread_task_runner.h" | 5 #include "media/base/fake_single_thread_task_runner.h" |
| 6 | 6 |
| 7 #include "base/location.h" | 7 #include "base/location.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/time/tick_clock.h" | 9 #include "base/time/tick_clock.h" |
| 10 | 10 |
| 11 namespace media { | 11 namespace media { |
| 12 | 12 |
| 13 FakeSingleThreadTaskRunner::FakeSingleThreadTaskRunner( | 13 FakeSingleThreadTaskRunner::FakeSingleThreadTaskRunner( |
| 14 base::SimpleTestTickClock* clock) | 14 base::SimpleTestTickClock* clock) |
| 15 : clock_(clock), fail_on_next_task_(false) {} | 15 : clock_(clock), fail_on_next_task_(false) {} |
| 16 | 16 |
| 17 FakeSingleThreadTaskRunner::~FakeSingleThreadTaskRunner() {} | 17 FakeSingleThreadTaskRunner::~FakeSingleThreadTaskRunner() {} |
| 18 | 18 |
| 19 bool FakeSingleThreadTaskRunner::PostDelayedTask( | 19 bool FakeSingleThreadTaskRunner::PostDelayedTask( |
| 20 const tracked_objects::Location& from_here, | 20 const tracked_objects::Location& from_here, |
| 21 const base::Closure& task, | 21 base::OnceClosure task, |
| 22 base::TimeDelta delay) { | 22 base::TimeDelta delay) { |
| 23 if (fail_on_next_task_) { | 23 if (fail_on_next_task_) { |
| 24 LOG(FATAL) << "Infinite task posting loop detected. Possibly caused by " | 24 LOG(FATAL) << "Infinite task posting loop detected. Possibly caused by " |
| 25 << from_here.ToString() << " posting a task with delay " | 25 << from_here.ToString() << " posting a task with delay " |
| 26 << delay.InMicroseconds() << " usec."; | 26 << delay.InMicroseconds() << " usec."; |
| 27 } | 27 } |
| 28 | 28 |
| 29 CHECK_LE(base::TimeDelta(), delay); | 29 CHECK_LE(base::TimeDelta(), delay); |
| 30 const base::TimeTicks run_time = clock_->NowTicks() + delay; | 30 const base::TimeTicks run_time = clock_->NowTicks() + delay; |
| 31 | 31 |
| 32 // If there are one or more tasks with the exact same run time, schedule this | 32 // If there are one or more tasks with the exact same run time, schedule this |
| 33 // task to occur after them. This mimics the FIFO ordering behavior when | 33 // task to occur after them. This mimics the FIFO ordering behavior when |
| 34 // scheduling delayed tasks to be run via base::MessageLoop in a | 34 // scheduling delayed tasks to be run via base::MessageLoop in a |
| 35 // multi-threaded application. | 35 // multi-threaded application. |
| 36 if (!tasks_.empty()) { | 36 if (!tasks_.empty()) { |
| 37 const auto after_it = tasks_.lower_bound( | 37 const auto after_it = tasks_.lower_bound( |
| 38 TaskKey(run_time + base::TimeDelta::FromMicroseconds(1), 0)); | 38 TaskKey(run_time + base::TimeDelta::FromMicroseconds(1), 0)); |
| 39 if (after_it != tasks_.begin()) { | 39 if (after_it != tasks_.begin()) { |
| 40 auto it = after_it; | 40 auto it = after_it; |
| 41 --it; | 41 --it; |
| 42 if (it->first.first == run_time) { | 42 if (it->first.first == run_time) { |
| 43 tasks_.insert( | 43 tasks_.insert(after_it /* hint */, |
| 44 after_it /* hint */, | 44 std::make_pair(TaskKey(run_time, it->first.second + 1), |
| 45 std::make_pair(TaskKey(run_time, it->first.second + 1), task)); | 45 std::move(task))); |
| 46 return true; | 46 return true; |
| 47 } | 47 } |
| 48 } | 48 } |
| 49 } | 49 } |
| 50 | 50 |
| 51 // No tasks have the exact same run time, so just do a simple insert. | 51 // No tasks have the exact same run time, so just do a simple insert. |
| 52 tasks_.insert(std::make_pair(TaskKey(run_time, 0), task)); | 52 tasks_.insert(std::make_pair(TaskKey(run_time, 0), std::move(task))); |
| 53 return true; | 53 return true; |
| 54 } | 54 } |
| 55 | 55 |
| 56 bool FakeSingleThreadTaskRunner::RunsTasksOnCurrentThread() const { | 56 bool FakeSingleThreadTaskRunner::RunsTasksOnCurrentThread() const { |
| 57 return true; | 57 return true; |
| 58 } | 58 } |
| 59 | 59 |
| 60 void FakeSingleThreadTaskRunner::RunTasks() { | 60 void FakeSingleThreadTaskRunner::RunTasks() { |
| 61 while (true) { | 61 while (true) { |
| 62 // Run all tasks equal or older than current time. | 62 // Run all tasks equal or older than current time. |
| 63 const auto it = tasks_.begin(); | 63 const auto it = tasks_.begin(); |
| 64 if (it == tasks_.end()) | 64 if (it == tasks_.end()) |
| 65 return; // No more tasks. | 65 return; // No more tasks. |
| 66 | 66 |
| 67 if (clock_->NowTicks() < it->first.first) | 67 if (clock_->NowTicks() < it->first.first) |
| 68 return; | 68 return; |
| 69 | 69 |
| 70 const base::Closure task = it->second; | 70 base::OnceClosure task = std::move(it->second); |
| 71 tasks_.erase(it); | 71 tasks_.erase(it); |
| 72 task.Run(); | 72 std::move(task).Run(); |
| 73 } | 73 } |
| 74 } | 74 } |
| 75 | 75 |
| 76 void FakeSingleThreadTaskRunner::Sleep(base::TimeDelta t) { | 76 void FakeSingleThreadTaskRunner::Sleep(base::TimeDelta t) { |
| 77 CHECK_LE(base::TimeDelta(), t); | 77 CHECK_LE(base::TimeDelta(), t); |
| 78 const base::TimeTicks run_until = clock_->NowTicks() + t; | 78 const base::TimeTicks run_until = clock_->NowTicks() + t; |
| 79 | 79 |
| 80 while (1) { | 80 while (1) { |
| 81 // Run up to 100000 tasks that were scheduled to run during the sleep | 81 // Run up to 100000 tasks that were scheduled to run during the sleep |
| 82 // period. 100000 should be enough for everybody (see comments below). | 82 // period. 100000 should be enough for everybody (see comments below). |
| 83 for (int i = 0; i < 100000; i++) { | 83 for (int i = 0; i < 100000; i++) { |
| 84 const auto it = tasks_.begin(); | 84 const auto it = tasks_.begin(); |
| 85 if (it == tasks_.end() || run_until < it->first.first) { | 85 if (it == tasks_.end() || run_until < it->first.first) { |
| 86 clock_->Advance(run_until - clock_->NowTicks()); | 86 clock_->Advance(run_until - clock_->NowTicks()); |
| 87 return; | 87 return; |
| 88 } | 88 } |
| 89 | 89 |
| 90 clock_->Advance(it->first.first - clock_->NowTicks()); | 90 clock_->Advance(it->first.first - clock_->NowTicks()); |
| 91 const base::Closure task = it->second; | 91 base::OnceClosure task = std::move(it->second); |
| 92 tasks_.erase(it); | 92 tasks_.erase(it); |
| 93 task.Run(); | 93 std::move(task).Run(); |
| 94 } | 94 } |
| 95 | 95 |
| 96 // If this point is reached, there's likely some sort of case where a new | 96 // If this point is reached, there's likely some sort of case where a new |
| 97 // non-delayed task is being posted every time a task is popped and invoked | 97 // non-delayed task is being posted every time a task is popped and invoked |
| 98 // from the queue. If that happens, set fail_on_next_task_ to true and throw | 98 // from the queue. If that happens, set fail_on_next_task_ to true and throw |
| 99 // an error when the next task is posted, where we might be able to identify | 99 // an error when the next task is posted, where we might be able to identify |
| 100 // the caller causing the problem via logging. | 100 // the caller causing the problem via logging. |
| 101 fail_on_next_task_ = true; | 101 fail_on_next_task_ = true; |
| 102 } | 102 } |
| 103 } | 103 } |
| 104 | 104 |
| 105 bool FakeSingleThreadTaskRunner::PostNonNestableDelayedTask( | 105 bool FakeSingleThreadTaskRunner::PostNonNestableDelayedTask( |
| 106 const tracked_objects::Location& from_here, | 106 const tracked_objects::Location& from_here, |
| 107 const base::Closure& task, | 107 base::OnceClosure task, |
| 108 base::TimeDelta delay) { | 108 base::TimeDelta delay) { |
| 109 NOTIMPLEMENTED(); | 109 NOTIMPLEMENTED(); |
| 110 return false; | 110 return false; |
| 111 } | 111 } |
| 112 | 112 |
| 113 } // namespace media | 113 } // namespace media |
| OLD | NEW |