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 "mojo/public/cpp/utility/run_loop.h" | 5 #include "mojo/public/cpp/utility/run_loop.h" |
6 | 6 |
7 #include <assert.h> | 7 #include <assert.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <vector> | 10 #include <vector> |
(...skipping 18 matching lines...) Expand all Loading... |
29 std::vector<MojoHandleSignals> handle_signals; | 29 std::vector<MojoHandleSignals> handle_signals; |
30 MojoDeadline deadline; | 30 MojoDeadline deadline; |
31 }; | 31 }; |
32 | 32 |
33 struct RunLoop::RunState { | 33 struct RunLoop::RunState { |
34 RunState() : should_quit(false) {} | 34 RunState() : should_quit(false) {} |
35 | 35 |
36 bool should_quit; | 36 bool should_quit; |
37 }; | 37 }; |
38 | 38 |
39 RunLoop::RunLoop() : run_state_(NULL), next_handler_id_(0) { | 39 RunLoop::RunLoop() |
| 40 : run_state_(NULL), next_handler_id_(0), next_sequence_number_(0) { |
40 assert(!current()); | 41 assert(!current()); |
41 current_run_loop.Set(this); | 42 current_run_loop.Set(this); |
42 } | 43 } |
43 | 44 |
44 RunLoop::~RunLoop() { | 45 RunLoop::~RunLoop() { |
45 assert(current() == this); | 46 assert(current() == this); |
46 current_run_loop.Set(NULL); | 47 current_run_loop.Set(NULL); |
47 } | 48 } |
48 | 49 |
49 // static | 50 // static |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 | 89 |
89 bool RunLoop::HasHandler(const Handle& handle) const { | 90 bool RunLoop::HasHandler(const Handle& handle) const { |
90 return handler_data_.find(handle) != handler_data_.end(); | 91 return handler_data_.find(handle) != handler_data_.end(); |
91 } | 92 } |
92 | 93 |
93 void RunLoop::Run() { | 94 void RunLoop::Run() { |
94 assert(current() == this); | 95 assert(current() == this); |
95 RunState* old_state = run_state_; | 96 RunState* old_state = run_state_; |
96 RunState run_state; | 97 RunState run_state; |
97 run_state_ = &run_state; | 98 run_state_ = &run_state; |
98 while (!run_state.should_quit) | 99 while (!run_state.should_quit) { |
| 100 DoDelayedWork(); |
99 Wait(false); | 101 Wait(false); |
| 102 } |
100 run_state_ = old_state; | 103 run_state_ = old_state; |
101 } | 104 } |
102 | 105 |
103 void RunLoop::RunUntilIdle() { | 106 void RunLoop::RunUntilIdle() { |
104 assert(current() == this); | 107 assert(current() == this); |
105 RunState* old_state = run_state_; | 108 RunState* old_state = run_state_; |
106 RunState run_state; | 109 RunState run_state; |
107 run_state_ = &run_state; | 110 run_state_ = &run_state; |
108 while (!run_state.should_quit) { | 111 while (!run_state.should_quit) { |
109 if (!Wait(true)) | 112 DoDelayedWork(); |
| 113 if (!Wait(true) && delayed_tasks_.empty()) |
110 break; | 114 break; |
111 } | 115 } |
112 run_state_ = old_state; | 116 run_state_ = old_state; |
113 } | 117 } |
114 | 118 |
| 119 void RunLoop::DoDelayedWork() { |
| 120 MojoTimeTicks now = GetTimeTicksNow(); |
| 121 if (!delayed_tasks_.empty() && delayed_tasks_.top().run_time <= now) { |
| 122 PendingTask task = delayed_tasks_.top(); |
| 123 delayed_tasks_.pop(); |
| 124 task.task.Run(); |
| 125 } |
| 126 } |
| 127 |
115 void RunLoop::Quit() { | 128 void RunLoop::Quit() { |
116 assert(current() == this); | 129 assert(current() == this); |
117 if (run_state_) | 130 if (run_state_) |
118 run_state_->should_quit = true; | 131 run_state_->should_quit = true; |
119 } | 132 } |
120 | 133 |
| 134 void RunLoop::PostDelayedTask(const Closure& task, MojoTimeTicks delay) { |
| 135 assert(current() == this); |
| 136 MojoTimeTicks run_time = delay + GetTimeTicksNow(); |
| 137 delayed_tasks_.push(PendingTask(task, run_time, next_sequence_number_++)); |
| 138 } |
| 139 |
121 bool RunLoop::Wait(bool non_blocking) { | 140 bool RunLoop::Wait(bool non_blocking) { |
122 const WaitState wait_state = GetWaitState(non_blocking); | 141 const WaitState wait_state = GetWaitState(non_blocking); |
123 if (wait_state.handles.empty()) { | 142 if (wait_state.handles.empty() && delayed_tasks_.empty()) { |
124 Quit(); | 143 Quit(); |
125 return false; | 144 return false; |
126 } | 145 } |
127 | 146 |
128 const MojoResult result = WaitMany(wait_state.handles, | 147 const MojoResult result = WaitMany(wait_state.handles, |
129 wait_state.handle_signals, | 148 wait_state.handle_signals, |
130 wait_state.deadline); | 149 wait_state.deadline); |
131 if (result >= 0) { | 150 if (result >= 0) { |
132 const size_t index = static_cast<size_t>(result); | 151 const size_t index = static_cast<size_t>(result); |
133 assert(handler_data_.find(wait_state.handles[index]) != | 152 assert(handler_data_.find(wait_state.handles[index]) != |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 MojoTimeTicks min_time = kInvalidTimeTicks; | 218 MojoTimeTicks min_time = kInvalidTimeTicks; |
200 for (HandleToHandlerData::const_iterator i = handler_data_.begin(); | 219 for (HandleToHandlerData::const_iterator i = handler_data_.begin(); |
201 i != handler_data_.end(); ++i) { | 220 i != handler_data_.end(); ++i) { |
202 wait_state.handles.push_back(i->first); | 221 wait_state.handles.push_back(i->first); |
203 wait_state.handle_signals.push_back(i->second.handle_signals); | 222 wait_state.handle_signals.push_back(i->second.handle_signals); |
204 if (!non_blocking && i->second.deadline != kInvalidTimeTicks && | 223 if (!non_blocking && i->second.deadline != kInvalidTimeTicks && |
205 (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) { | 224 (min_time == kInvalidTimeTicks || i->second.deadline < min_time)) { |
206 min_time = i->second.deadline; | 225 min_time = i->second.deadline; |
207 } | 226 } |
208 } | 227 } |
| 228 if (!delayed_tasks_.empty()) { |
| 229 MojoTimeTicks delayed_min_time = delayed_tasks_.top().run_time; |
| 230 if (min_time == kInvalidTimeTicks) |
| 231 min_time = delayed_min_time; |
| 232 else |
| 233 min_time = std::min(min_time, delayed_min_time); |
| 234 } |
209 if (non_blocking) { | 235 if (non_blocking) { |
210 wait_state.deadline = static_cast<MojoDeadline>(0); | 236 wait_state.deadline = static_cast<MojoDeadline>(0); |
211 } else if (min_time != kInvalidTimeTicks) { | 237 } else if (min_time != kInvalidTimeTicks) { |
212 const MojoTimeTicks now = GetTimeTicksNow(); | 238 const MojoTimeTicks now = GetTimeTicksNow(); |
213 if (min_time < now) | 239 if (min_time < now) |
214 wait_state.deadline = static_cast<MojoDeadline>(0); | 240 wait_state.deadline = static_cast<MojoDeadline>(0); |
215 else | 241 else |
216 wait_state.deadline = static_cast<MojoDeadline>(min_time - now); | 242 wait_state.deadline = static_cast<MojoDeadline>(min_time - now); |
217 } | 243 } |
218 return wait_state; | 244 return wait_state; |
219 } | 245 } |
220 | 246 |
| 247 RunLoop::PendingTask::PendingTask(const Closure& task, |
| 248 MojoTimeTicks run_time, |
| 249 uint64_t sequence_number) |
| 250 : task(task), run_time(run_time), sequence_number(sequence_number) { |
| 251 } |
| 252 |
| 253 RunLoop::PendingTask::~PendingTask() { |
| 254 } |
| 255 |
| 256 bool RunLoop::PendingTask::operator<(const RunLoop::PendingTask& other) const { |
| 257 if (run_time != other.run_time) { |
| 258 // std::priority_queue<> puts the least element at the end of the queue. We |
| 259 // want the soonest eligible task to be at the head of the queue, so |
| 260 // run_times further in the future are considered lesser. |
| 261 return run_time > other.run_time; |
| 262 } |
| 263 |
| 264 return sequence_number > other.sequence_number; |
| 265 } |
| 266 |
221 } // namespace mojo | 267 } // namespace mojo |
OLD | NEW |