Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: base/message_loop.cc

Issue 483: Eliminate the TimerManager by pulling its priority queue into MessageLoop.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/message_loop.h ('k') | base/message_loop_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 "base/message_loop.h" 5 #include "base/message_loop.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #if defined(OS_WIN)
10 #include <mmsystem.h>
11 #endif
12
9 #include "base/compiler_specific.h" 13 #include "base/compiler_specific.h"
10 #include "base/logging.h" 14 #include "base/logging.h"
11 #include "base/message_pump_default.h" 15 #include "base/message_pump_default.h"
12 #include "base/string_util.h" 16 #include "base/string_util.h"
13 #include "base/thread_local_storage.h" 17 #include "base/thread_local_storage.h"
14 18
15 // a TLS index to the message loop for the current thread 19 // a TLS index to the message loop for the current thread
16 // Note that if we start doing complex stuff in other static initializers 20 // Note that if we start doing complex stuff in other static initializers
17 // this could cause problems. 21 // this could cause problems.
18 // TODO(evanm): this shouldn't rely on static initialization. 22 // TODO(evanm): this shouldn't rely on static initialization.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 ::SetUnhandledExceptionFilter(top_filter); 54 ::SetUnhandledExceptionFilter(top_filter);
51 return top_filter; 55 return top_filter;
52 } 56 }
53 57
54 #endif // defined(OS_WIN) 58 #endif // defined(OS_WIN)
55 59
56 //------------------------------------------------------------------------------ 60 //------------------------------------------------------------------------------
57 61
58 MessageLoop::MessageLoop(Type type) 62 MessageLoop::MessageLoop(Type type)
59 : type_(type), 63 : type_(type),
60 ALLOW_THIS_IN_INITIALIZER_LIST(timer_manager_(this)),
61 nestable_tasks_allowed_(true), 64 nestable_tasks_allowed_(true),
62 exception_restoration_(false), 65 exception_restoration_(false),
63 state_(NULL) { 66 state_(NULL),
67 next_sequence_num_(0) {
64 DCHECK(!tls_index_.Get()) << "should only have one message loop per thread"; 68 DCHECK(!tls_index_.Get()) << "should only have one message loop per thread";
65 tls_index_.Set(this); 69 tls_index_.Set(this);
66 70
71 // TODO(darin): This does not seem like the best place for this code to live!
72 #if defined(OS_WIN)
73 // We've experimented with all sorts of timers, and initially tried
74 // to avoid using timeBeginPeriod because it does affect the system
75 // globally. However, after much investigation, it turns out that all
76 // of the major plugins (flash, windows media 9-11, and quicktime)
77 // already use timeBeginPeriod to increase the speed of the clock.
78 // Since the browser must work with these plugins, the browser already
79 // needs to support a fast clock. We may as well use this ourselves,
80 // as it really is the best timer mechanism for our needs.
81 timeBeginPeriod(1);
82 #endif
83
67 // TODO(darin): Choose the pump based on the requested type. 84 // TODO(darin): Choose the pump based on the requested type.
68 #if defined(OS_WIN) 85 #if defined(OS_WIN)
69 if (type_ == TYPE_DEFAULT) { 86 if (type_ == TYPE_DEFAULT) {
70 pump_ = new base::MessagePumpDefault(); 87 pump_ = new base::MessagePumpDefault();
71 } else { 88 } else {
72 pump_ = new base::MessagePumpWin(); 89 pump_ = new base::MessagePumpWin();
73 } 90 }
74 #else 91 #else
75 pump_ = new base::MessagePumpDefault(); 92 pump_ = new base::MessagePumpDefault();
76 #endif 93 #endif
(...skipping 11 matching lines...) Expand all
88 105
89 DCHECK(!state_); 106 DCHECK(!state_);
90 107
91 // Most tasks that have not been Run() are deleted in the |timer_manager_| 108 // Most tasks that have not been Run() are deleted in the |timer_manager_|
92 // destructor after we remove our tls index. We delete the tasks in our 109 // destructor after we remove our tls index. We delete the tasks in our
93 // queues here so their destuction is similar to the tasks in the 110 // queues here so their destuction is similar to the tasks in the
94 // |timer_manager_|. 111 // |timer_manager_|.
95 DeletePendingTasks(); 112 DeletePendingTasks();
96 ReloadWorkQueue(); 113 ReloadWorkQueue();
97 DeletePendingTasks(); 114 DeletePendingTasks();
115
116 #if defined(OS_WIN)
117 // Match timeBeginPeriod() from construction.
118 timeEndPeriod(1);
119 #endif
98 } 120 }
99 121
100 void MessageLoop::AddDestructionObserver(DestructionObserver *obs) { 122 void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
101 DCHECK(this == current()); 123 DCHECK(this == current());
102 destruction_observers_.AddObserver(obs); 124 destruction_observers_.AddObserver(obs);
103 } 125 }
104 126
105 void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) { 127 void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
106 DCHECK(this == current()); 128 DCHECK(this == current());
107 destruction_observers_.RemoveObserver(obs); 129 destruction_observers_.RemoveObserver(obs);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 pump_->Run(this); 177 pump_->Run(this);
156 } 178 }
157 179
158 //------------------------------------------------------------------------------ 180 //------------------------------------------------------------------------------
159 // Wrapper functions for use in above message loop framework. 181 // Wrapper functions for use in above message loop framework.
160 182
161 bool MessageLoop::ProcessNextDelayedNonNestableTask() { 183 bool MessageLoop::ProcessNextDelayedNonNestableTask() {
162 if (state_->run_depth != 1) 184 if (state_->run_depth != 1)
163 return false; 185 return false;
164 186
165 if (delayed_non_nestable_queue_.Empty()) 187 if (deferred_non_nestable_work_queue_.empty())
166 return false; 188 return false;
167 189
168 RunTask(delayed_non_nestable_queue_.Pop()); 190 Task* task = deferred_non_nestable_work_queue_.front().task;
191 deferred_non_nestable_work_queue_.pop();
192
193 RunTask(task);
169 return true; 194 return true;
170 } 195 }
171 196
172 //------------------------------------------------------------------------------ 197 //------------------------------------------------------------------------------
173 198
174 void MessageLoop::Quit() { 199 void MessageLoop::Quit() {
175 DCHECK(current() == this); 200 DCHECK(current() == this);
176 if (state_) { 201 if (state_) {
177 state_->quit_received = true; 202 state_->quit_received = true;
178 } else { 203 } else {
179 NOTREACHED() << "Must be inside Run to call Quit"; 204 NOTREACHED() << "Must be inside Run to call Quit";
180 } 205 }
181 } 206 }
182 207
208 void MessageLoop::PostTask(
209 const tracked_objects::Location& from_here, Task* task) {
210 PostTask_Helper(from_here, task, 0, true);
211 }
212
213 void MessageLoop::PostDelayedTask(
214 const tracked_objects::Location& from_here, Task* task, int delay_ms) {
215 PostTask_Helper(from_here, task, delay_ms, true);
216 }
217
218 void MessageLoop::PostNonNestableTask(
219 const tracked_objects::Location& from_here, Task* task) {
220 PostTask_Helper(from_here, task, 0, false);
221 }
222
223 void MessageLoop::PostNonNestableDelayedTask(
224 const tracked_objects::Location& from_here, Task* task, int delay_ms) {
225 PostTask_Helper(from_here, task, delay_ms, false);
226 }
227
183 // Possibly called on a background thread! 228 // Possibly called on a background thread!
184 void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here, 229 void MessageLoop::PostTask_Helper(
185 Task* task, int delay_ms) { 230 const tracked_objects::Location& from_here, Task* task, int delay_ms,
231 bool nestable) {
186 task->SetBirthPlace(from_here); 232 task->SetBirthPlace(from_here);
187 233
188 DCHECK(!task->owned_by_message_loop_); 234 PendingTask pending_task(task, nestable);
189 task->owned_by_message_loop_ = true;
190 235
191 if (delay_ms > 0) { 236 if (delay_ms > 0) {
192 task->delayed_run_time_ = 237 pending_task.delayed_run_time =
193 Time::Now() + TimeDelta::FromMilliseconds(delay_ms); 238 Time::Now() + TimeDelta::FromMilliseconds(delay_ms);
194 } else { 239 } else {
195 DCHECK(delay_ms == 0) << "delay should not be negative"; 240 DCHECK(delay_ms == 0) << "delay should not be negative";
196 } 241 }
197 242
198 PostTaskInternal(task);
199 }
200
201 void MessageLoop::PostTaskInternal(Task* task) {
202 // Warning: Don't try to short-circuit, and handle this thread's tasks more 243 // Warning: Don't try to short-circuit, and handle this thread's tasks more
203 // directly, as it could starve handling of foreign threads. Put every task 244 // directly, as it could starve handling of foreign threads. Put every task
204 // into this queue. 245 // into this queue.
205 246
206 scoped_refptr<base::MessagePump> pump; 247 scoped_refptr<base::MessagePump> pump;
207 { 248 {
208 AutoLock locked(incoming_queue_lock_); 249 AutoLock locked(incoming_queue_lock_);
209 250
210 bool was_empty = incoming_queue_.Empty(); 251 bool was_empty = incoming_queue_.empty();
211 incoming_queue_.Push(task); 252 incoming_queue_.push(pending_task);
212 if (!was_empty) 253 if (!was_empty)
213 return; // Someone else should have started the sub-pump. 254 return; // Someone else should have started the sub-pump.
214 255
215 pump = pump_; 256 pump = pump_;
216 } 257 }
217 // Since the incoming_queue_ may contain a task that destroys this message 258 // Since the incoming_queue_ may contain a task that destroys this message
218 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. 259 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
219 // We use a stack-based reference to the message pump so that we can call 260 // We use a stack-based reference to the message pump so that we can call
220 // ScheduleWork outside of incoming_queue_lock_. 261 // ScheduleWork outside of incoming_queue_lock_.
221 262
222 pump->ScheduleWork(); 263 pump->ScheduleWork();
223 } 264 }
224 265
225 void MessageLoop::SetNestableTasksAllowed(bool allowed) { 266 void MessageLoop::SetNestableTasksAllowed(bool allowed) {
226 if (nestable_tasks_allowed_ != allowed) { 267 if (nestable_tasks_allowed_ != allowed) {
227 nestable_tasks_allowed_ = allowed; 268 nestable_tasks_allowed_ = allowed;
228 if (!nestable_tasks_allowed_) 269 if (!nestable_tasks_allowed_)
229 return; 270 return;
230 // Start the native pump if we are not already pumping. 271 // Start the native pump if we are not already pumping.
231 pump_->ScheduleWork(); 272 pump_->ScheduleWork();
232 } 273 }
233 } 274 }
234 275
235 bool MessageLoop::NestableTasksAllowed() const { 276 bool MessageLoop::NestableTasksAllowed() const {
236 return nestable_tasks_allowed_; 277 return nestable_tasks_allowed_;
237 } 278 }
238 279
239 //------------------------------------------------------------------------------ 280 //------------------------------------------------------------------------------
240 281
241 bool MessageLoop::RunTimerTask(Timer* timer) {
242 HistogramEvent(kTimerEvent);
243
244 Task* task = timer->task();
245 if (task->owned_by_message_loop_) {
246 // We constructed it through PostDelayedTask().
247 DCHECK(!timer->repeating());
248 timer->set_task(NULL);
249 delete timer;
250 task->ResetBirthTime();
251 return QueueOrRunTask(task);
252 }
253
254 // This is an unknown timer task, and we *can't* delay running it, as a user
255 // might try to cancel it with TimerManager at any moment.
256 DCHECK(nestable_tasks_allowed_);
257 RunTask(task);
258 return true;
259 }
260
261 void MessageLoop::DiscardTimer(Timer* timer) {
262 Task* task = timer->task();
263 if (task->owned_by_message_loop_) {
264 DCHECK(!timer->repeating());
265 timer->set_task(NULL);
266 delete timer; // We constructed it through PostDelayedTask().
267 delete task; // We were given ouwnership in PostTask().
268 }
269 }
270
271 bool MessageLoop::QueueOrRunTask(Task* new_task) {
272 if (!nestable_tasks_allowed_) {
273 // Task can't be executed right now. Add it to the queue.
274 if (new_task)
275 work_queue_.Push(new_task);
276 return false;
277 }
278
279 // Queue new_task first so we execute the task in FIFO order.
280 if (new_task)
281 work_queue_.Push(new_task);
282
283 // Execute oldest task.
284 while (!work_queue_.Empty()) {
285 Task* task = work_queue_.Pop();
286 if (task->nestable() || state_->run_depth == 1) {
287 RunTask(task);
288 // Show that we ran a task (Note: a new one might arrive as a
289 // consequence!).
290 return true;
291 }
292 // We couldn't run the task now because we're in a nested message loop
293 // and the task isn't nestable.
294 delayed_non_nestable_queue_.Push(task);
295 }
296
297 // Nothing happened.
298 return false;
299 }
300
301 void MessageLoop::RunTask(Task* task) { 282 void MessageLoop::RunTask(Task* task) {
302 BeforeTaskRunSetup();
303 HistogramEvent(kTaskRunEvent);
304 // task may self-delete during Run() if we don't happen to own it.
305 // ...so check *before* we Run, since we can't check after.
306 bool we_own_task = task->owned_by_message_loop_;
307 task->Run();
308 if (we_own_task)
309 task->RecycleOrDelete(); // Relinquish control, and probably delete.
310 AfterTaskRunRestore();
311 }
312
313 void MessageLoop::BeforeTaskRunSetup() {
314 DCHECK(nestable_tasks_allowed_); 283 DCHECK(nestable_tasks_allowed_);
315 // Execute the task and assume the worst: It is probably not reentrant. 284 // Execute the task and assume the worst: It is probably not reentrant.
316 nestable_tasks_allowed_ = false; 285 nestable_tasks_allowed_ = false;
286
287 HistogramEvent(kTaskRunEvent);
288 task->Run();
289 delete task;
290
291 nestable_tasks_allowed_ = true;
317 } 292 }
318 293
319 void MessageLoop::AfterTaskRunRestore() { 294 bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
320 nestable_tasks_allowed_ = true; 295 if (pending_task.nestable || state_->run_depth == 1) {
296 RunTask(pending_task.task);
297 // Show that we ran a task (Note: a new one might arrive as a
298 // consequence!).
299 return true;
300 }
301
302 // We couldn't run the task now because we're in a nested message loop
303 // and the task isn't nestable.
304 deferred_non_nestable_work_queue_.push(pending_task);
305 return false;
321 } 306 }
322 307
323 void MessageLoop::ReloadWorkQueue() { 308 void MessageLoop::ReloadWorkQueue() {
324 // We can improve performance of our loading tasks from incoming_queue_ to 309 // We can improve performance of our loading tasks from incoming_queue_ to
325 // work_queue_ by waiting until the last minute (work_queue_ is empty) to 310 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
326 // load. That reduces the number of locks-per-task significantly when our 311 // load. That reduces the number of locks-per-task significantly when our
327 // queues get large. The optimization is disabled on threads that make use 312 // queues get large.
328 // of the priority queue (prioritization requires all our tasks to be in the 313 if (!work_queue_.empty())
329 // work_queue_ ASAP).
330 if (!work_queue_.Empty() && !work_queue_.use_priority_queue())
331 return; // Wait till we *really* need to lock and load. 314 return; // Wait till we *really* need to lock and load.
332 315
333 // Acquire all we can from the inter-thread queue with one lock acquisition. 316 // Acquire all we can from the inter-thread queue with one lock acquisition.
334 TaskQueue new_task_list; // Null terminated list.
335 { 317 {
336 AutoLock lock(incoming_queue_lock_); 318 AutoLock lock(incoming_queue_lock_);
337 if (incoming_queue_.Empty()) 319 if (incoming_queue_.empty())
338 return; 320 return;
339 std::swap(incoming_queue_, new_task_list); 321 std::swap(incoming_queue_, work_queue_);
340 DCHECK(incoming_queue_.Empty()); 322 DCHECK(incoming_queue_.empty());
341 } // Release lock.
342
343 while (!new_task_list.Empty()) {
344 Task* task = new_task_list.Pop();
345 DCHECK(task->owned_by_message_loop_);
346
347 // TODO(darin): We should probably postpone starting the timer until we
348 // process the work queue as starting the timer here breaks the FIFO
349 // ordering of tasks.
350 if (!task->delayed_run_time_.is_null()) {
351 timer_manager_.StartTimer(new Timer(task->delayed_run_time_, task));
352 } else {
353 work_queue_.Push(task);
354 }
355 } 323 }
356 } 324 }
357 325
358 void MessageLoop::DeletePendingTasks() { 326 void MessageLoop::DeletePendingTasks() {
359 /* Comment this out as it's causing crashes. 327 /* Comment this out as it's causing crashes.
360 while (!work_queue_.Empty()) { 328 while (!work_queue_.Empty()) {
361 Task* task = work_queue_.Pop(); 329 Task* task = work_queue_.Pop();
362 if (task->is_owned_by_message_loop()) 330 if (task->is_owned_by_message_loop())
363 delete task; 331 delete task;
364 } 332 }
365 333
366 while (!delayed_non_nestable_queue_.Empty()) { 334 while (!delayed_non_nestable_queue_.Empty()) {
367 Task* task = delayed_non_nestable_queue_.Pop(); 335 Task* task = delayed_non_nestable_queue_.Pop();
368 if (task->is_owned_by_message_loop()) 336 if (task->is_owned_by_message_loop())
369 delete task; 337 delete task;
370 } 338 }
371 */ 339 */
372 } 340 }
373 341
374 void MessageLoop::DidChangeNextTimerExpiry() { 342 bool MessageLoop::DoWork() {
375 Time next_delayed_work_time = timer_manager_.GetNextFireTime(); 343 if (!nestable_tasks_allowed_) {
376 if (next_delayed_work_time.is_null()) 344 // Task can't be executed right now.
377 return; 345 return false;
346 }
378 347
379 // Simulates malfunctioning, early firing timers. Pending tasks should only 348 for (;;) {
380 // be invoked when the delay they specify has elapsed. 349 ReloadWorkQueue();
381 if (timer_manager_.use_broken_delay()) 350 if (work_queue_.empty())
382 next_delayed_work_time = Time::Now() + TimeDelta::FromMilliseconds(10); 351 break;
383 352
384 pump_->ScheduleDelayedWork(next_delayed_work_time); 353 // Execute oldest task.
385 } 354 do {
355 PendingTask pending_task = work_queue_.front();
356 work_queue_.pop();
357 if (!pending_task.delayed_run_time.is_null()) {
358 bool was_empty = delayed_work_queue_.empty();
386 359
387 bool MessageLoop::DoWork() { 360 // Move to the delayed work queue. Initialize the sequence number
388 ReloadWorkQueue(); 361 // before inserting into the delayed_work_queue_. The sequence number
389 return QueueOrRunTask(NULL); 362 // is used to faciliate FIFO sorting when two tasks have the same
363 // delayed_run_time value.
364 pending_task.sequence_num = next_sequence_num_++;
365 delayed_work_queue_.push(pending_task);
366
367 if (was_empty) // We only schedule the next delayed work item.
368 pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
369 } else {
370 if (DeferOrRunPendingTask(pending_task))
371 return true;
372 }
373 } while (!work_queue_.empty());
374 }
375
376 // Nothing happened.
377 return false;
390 } 378 }
391 379
392 bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) { 380 bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) {
393 bool did_work = timer_manager_.RunSomePendingTimers(); 381 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
382 *next_delayed_work_time = Time();
383 return false;
384 }
385
386 if (delayed_work_queue_.top().delayed_run_time > Time::Now()) {
387 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
388 return false;
389 }
394 390
395 // We may not have run any timers, but we may still have future timers to 391 PendingTask pending_task = delayed_work_queue_.top();
396 // run, so we need to inform the pump again of pending timers. 392 delayed_work_queue_.pop();
397 *next_delayed_work_time = timer_manager_.GetNextFireTime(); 393
394 if (!delayed_work_queue_.empty())
395 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
398 396
399 return did_work; 397 return DeferOrRunPendingTask(pending_task);
400 } 398 }
401 399
402 bool MessageLoop::DoIdleWork() { 400 bool MessageLoop::DoIdleWork() {
403 if (ProcessNextDelayedNonNestableTask()) 401 if (ProcessNextDelayedNonNestableTask())
404 return true; 402 return true;
405 403
406 if (state_->quit_received) 404 if (state_->quit_received)
407 pump_->Quit(); 405 pump_->Quit();
408 406
409 return false; 407 return false;
(...skipping 17 matching lines...) Expand all
427 #if defined(OS_WIN) 425 #if defined(OS_WIN)
428 dispatcher = NULL; 426 dispatcher = NULL;
429 #endif 427 #endif
430 } 428 }
431 429
432 MessageLoop::AutoRunState::~AutoRunState() { 430 MessageLoop::AutoRunState::~AutoRunState() {
433 loop_->state_ = previous_state_; 431 loop_->state_ = previous_state_;
434 } 432 }
435 433
436 //------------------------------------------------------------------------------ 434 //------------------------------------------------------------------------------
437 // Implementation of the work_queue_ as a ProiritizedTaskQueue 435 // MessageLoop::PendingTask
438 436
439 void MessageLoop::PrioritizedTaskQueue::push(Task * task) { 437 bool MessageLoop::PendingTask::operator<(const PendingTask& other) const {
440 queue_.push(PrioritizedTask(task, --next_sequence_number_)); 438 // Since the top of a priority queue is defined as the "greatest" element, we
441 } 439 // need to invert the comparison here. We want the smaller time to be at the
440 // top of the heap.
442 441
443 bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < ( 442 if (delayed_run_time < other.delayed_run_time)
444 PrioritizedTask const & right) const { 443 return false;
445 int compare = task_->priority() - right.task_->priority();
446 if (compare)
447 return compare < 0;
448 // Don't compare directly, but rather subtract. This handles overflow
449 // as sequence numbers wrap around.
450 compare = sequence_number_ - right.sequence_number_;
451 DCHECK(compare); // Sequence number are unique for a "long time."
452 // Make sure we don't starve anything with a low priority.
453 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping.
454 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping.
455 return compare < 0;
456 }
457 444
458 //------------------------------------------------------------------------------ 445 if (delayed_run_time > other.delayed_run_time)
459 // Implementation of a TaskQueue as a null terminated list, with end pointers. 446 return true;
460 447
461 void MessageLoop::TaskQueue::Push(Task* task) { 448 // If the times happen to match, then we use the sequence number to decide.
462 if (!first_) 449 // Compare the difference to support integer roll-over.
463 first_ = task; 450 return (sequence_num - other.sequence_num) > 0;
464 else
465 last_->set_next_task(task);
466 last_ = task;
467 }
468
469 Task* MessageLoop::TaskQueue::Pop() {
470 DCHECK((!first_) == !last_);
471 Task* task = first_;
472 if (first_) {
473 first_ = task->next_task();
474 if (!first_)
475 last_ = NULL;
476 else
477 task->set_next_task(NULL);
478 }
479 return task;
480 }
481
482 //------------------------------------------------------------------------------
483 // Implementation of a Task queue that automatically switches into a priority
484 // queue if it observes any non-zero priorities on tasks.
485
486 void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) {
487 if (use_priority_queue_) {
488 prioritized_queue_.push(task);
489 } else {
490 queue_.Push(task);
491 if (task->priority()) {
492 use_priority_queue_ = true; // From now on.
493 while (!queue_.Empty())
494 prioritized_queue_.push(queue_.Pop());
495 }
496 }
497 }
498
499 Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() {
500 if (!use_priority_queue_)
501 return queue_.Pop();
502 Task* task = prioritized_queue_.front();
503 prioritized_queue_.pop();
504 return task;
505 }
506
507 bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() {
508 if (use_priority_queue_)
509 return prioritized_queue_.empty();
510 return queue_.Empty();
511 } 451 }
512 452
513 //------------------------------------------------------------------------------ 453 //------------------------------------------------------------------------------
514 // Method and data for histogramming events and actions taken by each instance 454 // Method and data for histogramming events and actions taken by each instance
515 // on each thread. 455 // on each thread.
516 456
517 // static 457 // static
518 bool MessageLoop::enable_histogrammer_ = false; 458 bool MessageLoop::enable_histogrammer_ = false;
519 459
520 // static 460 // static
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 //------------------------------------------------------------------------------ 543 //------------------------------------------------------------------------------
604 // MessageLoopForIO 544 // MessageLoopForIO
605 545
606 #if defined(OS_WIN) 546 #if defined(OS_WIN)
607 547
608 void MessageLoopForIO::WatchObject(HANDLE object, Watcher* watcher) { 548 void MessageLoopForIO::WatchObject(HANDLE object, Watcher* watcher) {
609 pump_win()->WatchObject(object, watcher); 549 pump_win()->WatchObject(object, watcher);
610 } 550 }
611 551
612 #endif // defined(OS_WIN) 552 #endif // defined(OS_WIN)
OLDNEW
« no previous file with comments | « base/message_loop.h ('k') | base/message_loop_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698