| Index: mojo/public/cpp/utility/lib/run_loop.cc
|
| diff --git a/mojo/public/cpp/utility/lib/run_loop.cc b/mojo/public/cpp/utility/lib/run_loop.cc
|
| index f523eaeaead103139e89dd4fdeb8183512284426..66630ebb5b05416a4b02c39a0954bd2af193f261 100644
|
| --- a/mojo/public/cpp/utility/lib/run_loop.cc
|
| +++ b/mojo/public/cpp/utility/lib/run_loop.cc
|
| @@ -36,7 +36,8 @@ struct RunLoop::RunState {
|
| bool should_quit;
|
| };
|
|
|
| -RunLoop::RunLoop() : run_state_(NULL), next_handler_id_(0) {
|
| +RunLoop::RunLoop()
|
| + : run_state_(NULL), next_handler_id_(0), next_sequence_number_(0) {
|
| assert(!current());
|
| current_run_loop.Set(this);
|
| }
|
| @@ -95,8 +96,10 @@ void RunLoop::Run() {
|
| RunState* old_state = run_state_;
|
| RunState run_state;
|
| run_state_ = &run_state;
|
| - while (!run_state.should_quit)
|
| + while (!run_state.should_quit) {
|
| + DoDelayedWork();
|
| Wait(false);
|
| + }
|
| run_state_ = old_state;
|
| }
|
|
|
| @@ -106,21 +109,37 @@ void RunLoop::RunUntilIdle() {
|
| RunState run_state;
|
| run_state_ = &run_state;
|
| while (!run_state.should_quit) {
|
| - if (!Wait(true))
|
| + DoDelayedWork();
|
| + if (!Wait(true) && delayed_tasks_.empty())
|
| break;
|
| }
|
| run_state_ = old_state;
|
| }
|
|
|
| +void RunLoop::DoDelayedWork() {
|
| + MojoTimeTicks now = GetTimeTicksNow();
|
| + if (!delayed_tasks_.empty() && delayed_tasks_.top().run_time <= now) {
|
| + PendingTask task = delayed_tasks_.top();
|
| + delayed_tasks_.pop();
|
| + task.task.Run();
|
| + }
|
| +}
|
| +
|
| void RunLoop::Quit() {
|
| assert(current() == this);
|
| if (run_state_)
|
| run_state_->should_quit = true;
|
| }
|
|
|
| +void RunLoop::PostDelayedTask(const Closure& task, MojoTimeTicks delay) {
|
| + assert(current() == this);
|
| + MojoTimeTicks run_time = delay + GetTimeTicksNow();
|
| + delayed_tasks_.push(PendingTask(task, run_time, next_sequence_number_++));
|
| +}
|
| +
|
| bool RunLoop::Wait(bool non_blocking) {
|
| const WaitState wait_state = GetWaitState(non_blocking);
|
| - if (wait_state.handles.empty()) {
|
| + if (wait_state.handles.empty() && delayed_tasks_.empty()) {
|
| Quit();
|
| return false;
|
| }
|
| @@ -206,6 +225,13 @@ RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const {
|
| min_time = i->second.deadline;
|
| }
|
| }
|
| + if (!delayed_tasks_.empty()) {
|
| + MojoTimeTicks delayed_min_time = delayed_tasks_.top().run_time;
|
| + if (min_time == kInvalidTimeTicks)
|
| + min_time = delayed_min_time;
|
| + else
|
| + min_time = std::min(min_time, delayed_min_time);
|
| + }
|
| if (non_blocking) {
|
| wait_state.deadline = static_cast<MojoDeadline>(0);
|
| } else if (min_time != kInvalidTimeTicks) {
|
| @@ -218,4 +244,24 @@ RunLoop::WaitState RunLoop::GetWaitState(bool non_blocking) const {
|
| return wait_state;
|
| }
|
|
|
| +RunLoop::PendingTask::PendingTask(const Closure& task,
|
| + MojoTimeTicks run_time,
|
| + uint64_t sequence_number)
|
| + : task(task), run_time(run_time), sequence_number(sequence_number) {
|
| +}
|
| +
|
| +RunLoop::PendingTask::~PendingTask() {
|
| +}
|
| +
|
| +bool RunLoop::PendingTask::operator<(const RunLoop::PendingTask& other) const {
|
| + if (run_time != other.run_time) {
|
| + // std::priority_queue<> puts the least element at the end of the queue. We
|
| + // want the soonest eligible task to be at the head of the queue, so
|
| + // run_times further in the future are considered lesser.
|
| + return run_time > other.run_time;
|
| + }
|
| +
|
| + return sequence_number > other.sequence_number;
|
| +}
|
| +
|
| } // namespace mojo
|
|
|