OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 // static | 71 // static |
72 MessageLoop* MessageLoop::current() { | 72 MessageLoop* MessageLoop::current() { |
73 // TODO(darin): sadly, we cannot enable this yet since people call us even | 73 // TODO(darin): sadly, we cannot enable this yet since people call us even |
74 // when they have no intention of using us. | 74 // when they have no intention of using us. |
75 //DCHECK(loop) << "Ouch, did you forget to initialize me?"; | 75 //DCHECK(loop) << "Ouch, did you forget to initialize me?"; |
76 return lazy_tls_ptr.Pointer()->Get(); | 76 return lazy_tls_ptr.Pointer()->Get(); |
77 } | 77 } |
78 | 78 |
79 MessageLoop::MessageLoop(Type type) | 79 MessageLoop::MessageLoop(Type type) |
80 : type_(type), | 80 : type_(type), |
| 81 work_queue_(new TaskQueue), |
81 nestable_tasks_allowed_(true), | 82 nestable_tasks_allowed_(true), |
82 exception_restoration_(false), | 83 exception_restoration_(false), |
| 84 incoming_queue_(new TaskQueue), |
83 state_(NULL), | 85 state_(NULL), |
84 next_sequence_num_(0) { | 86 next_sequence_num_(0) { |
85 DCHECK(!current()) << "should only have one message loop per thread"; | 87 DCHECK(!current()) << "should only have one message loop per thread"; |
86 lazy_tls_ptr.Pointer()->Set(this); | 88 lazy_tls_ptr.Pointer()->Set(this); |
87 | 89 |
88 #if defined(OS_WIN) | 90 #if defined(OS_WIN) |
89 // TODO(rvargas): Get rid of the OS guards. | 91 // TODO(rvargas): Get rid of the OS guards. |
90 if (type_ == TYPE_DEFAULT) { | 92 if (type_ == TYPE_DEFAULT) { |
91 pump_ = new base::MessagePumpDefault(); | 93 pump_ = new base::MessagePumpDefault(); |
92 } else if (type_ == TYPE_IO) { | 94 } else if (type_ == TYPE_IO) { |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 } | 265 } |
264 | 266 |
265 // Warning: Don't try to short-circuit, and handle this thread's tasks more | 267 // Warning: Don't try to short-circuit, and handle this thread's tasks more |
266 // directly, as it could starve handling of foreign threads. Put every task | 268 // directly, as it could starve handling of foreign threads. Put every task |
267 // into this queue. | 269 // into this queue. |
268 | 270 |
269 scoped_refptr<base::MessagePump> pump; | 271 scoped_refptr<base::MessagePump> pump; |
270 { | 272 { |
271 AutoLock locked(incoming_queue_lock_); | 273 AutoLock locked(incoming_queue_lock_); |
272 | 274 |
273 bool was_empty = incoming_queue_.empty(); | 275 bool was_empty = incoming_queue_->empty(); |
274 incoming_queue_.push(pending_task); | 276 incoming_queue_->push(pending_task); |
275 if (!was_empty) | 277 if (!was_empty) |
276 return; // Someone else should have started the sub-pump. | 278 return; // Someone else should have started the sub-pump. |
277 | 279 |
278 pump = pump_; | 280 pump = pump_; |
279 } | 281 } |
280 // Since the incoming_queue_ may contain a task that destroys this message | 282 // Since the incoming_queue_ may contain a task that destroys this message |
281 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. | 283 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. |
282 // We use a stack-based reference to the message pump so that we can call | 284 // We use a stack-based reference to the message pump so that we can call |
283 // ScheduleWork outside of incoming_queue_lock_. | 285 // ScheduleWork outside of incoming_queue_lock_. |
284 | 286 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 PendingTask new_pending_task(pending_task); | 341 PendingTask new_pending_task(pending_task); |
340 new_pending_task.sequence_num = next_sequence_num_++; | 342 new_pending_task.sequence_num = next_sequence_num_++; |
341 delayed_work_queue_.push(new_pending_task); | 343 delayed_work_queue_.push(new_pending_task); |
342 } | 344 } |
343 | 345 |
344 void MessageLoop::ReloadWorkQueue() { | 346 void MessageLoop::ReloadWorkQueue() { |
345 // We can improve performance of our loading tasks from incoming_queue_ to | 347 // We can improve performance of our loading tasks from incoming_queue_ to |
346 // work_queue_ by waiting until the last minute (work_queue_ is empty) to | 348 // work_queue_ by waiting until the last minute (work_queue_ is empty) to |
347 // load. That reduces the number of locks-per-task significantly when our | 349 // load. That reduces the number of locks-per-task significantly when our |
348 // queues get large. | 350 // queues get large. |
349 if (!work_queue_.empty()) | 351 if (!work_queue_->empty()) |
350 return; // Wait till we *really* need to lock and load. | 352 return; // Wait till we *really* need to lock and load. |
351 | 353 |
352 // Acquire all we can from the inter-thread queue with one lock acquisition. | 354 // Acquire all we can from the inter-thread queue with one lock acquisition. |
353 { | 355 { |
354 AutoLock lock(incoming_queue_lock_); | 356 AutoLock lock(incoming_queue_lock_); |
355 if (incoming_queue_.empty()) | 357 if (incoming_queue_->empty()) |
356 return; | 358 return; |
357 std::swap(incoming_queue_, work_queue_); | 359 // std::queue does not define a swap specialization. Swap the pointers. |
358 DCHECK(incoming_queue_.empty()); | 360 incoming_queue_.swap(work_queue_); |
| 361 DCHECK(incoming_queue_->empty()); |
359 } | 362 } |
360 } | 363 } |
361 | 364 |
362 bool MessageLoop::DeletePendingTasks() { | 365 bool MessageLoop::DeletePendingTasks() { |
363 bool did_work = !work_queue_.empty(); | 366 bool did_work = !work_queue_->empty(); |
364 while (!work_queue_.empty()) { | 367 while (!work_queue_->empty()) { |
365 PendingTask pending_task = work_queue_.front(); | 368 PendingTask pending_task = work_queue_->front(); |
366 work_queue_.pop(); | 369 work_queue_->pop(); |
367 if (!pending_task.delayed_run_time.is_null()) { | 370 if (!pending_task.delayed_run_time.is_null()) { |
368 // We want to delete delayed tasks in the same order in which they would | 371 // We want to delete delayed tasks in the same order in which they would |
369 // normally be deleted in case of any funny dependencies between delayed | 372 // normally be deleted in case of any funny dependencies between delayed |
370 // tasks. | 373 // tasks. |
371 AddToDelayedWorkQueue(pending_task); | 374 AddToDelayedWorkQueue(pending_task); |
372 } else { | 375 } else { |
373 // TODO(darin): Delete all tasks once it is safe to do so. | 376 // TODO(darin): Delete all tasks once it is safe to do so. |
374 // Until it is totally safe, just do it when running Purify or | 377 // Until it is totally safe, just do it when running Purify or |
375 // Valgrind. | 378 // Valgrind. |
376 #if defined(PURIFY) | 379 #if defined(PURIFY) |
(...skipping 29 matching lines...) Expand all Loading... |
406 } | 409 } |
407 | 410 |
408 bool MessageLoop::DoWork() { | 411 bool MessageLoop::DoWork() { |
409 if (!nestable_tasks_allowed_) { | 412 if (!nestable_tasks_allowed_) { |
410 // Task can't be executed right now. | 413 // Task can't be executed right now. |
411 return false; | 414 return false; |
412 } | 415 } |
413 | 416 |
414 for (;;) { | 417 for (;;) { |
415 ReloadWorkQueue(); | 418 ReloadWorkQueue(); |
416 if (work_queue_.empty()) | 419 if (work_queue_->empty()) |
417 break; | 420 break; |
418 | 421 |
419 // Execute oldest task. | 422 // Execute oldest task. |
420 do { | 423 do { |
421 PendingTask pending_task = work_queue_.front(); | 424 PendingTask pending_task = work_queue_->front(); |
422 work_queue_.pop(); | 425 work_queue_->pop(); |
423 if (!pending_task.delayed_run_time.is_null()) { | 426 if (!pending_task.delayed_run_time.is_null()) { |
424 AddToDelayedWorkQueue(pending_task); | 427 AddToDelayedWorkQueue(pending_task); |
425 // If we changed the topmost task, then it is time to re-schedule. | 428 // If we changed the topmost task, then it is time to re-schedule. |
426 if (delayed_work_queue_.top().task == pending_task.task) | 429 if (delayed_work_queue_.top().task == pending_task.task) |
427 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); | 430 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); |
428 } else { | 431 } else { |
429 if (DeferOrRunPendingTask(pending_task)) | 432 if (DeferOrRunPendingTask(pending_task)) |
430 return true; | 433 return true; |
431 } | 434 } |
432 } while (!work_queue_.empty()); | 435 } while (!work_queue_->empty()); |
433 } | 436 } |
434 | 437 |
435 // Nothing happened. | 438 // Nothing happened. |
436 return false; | 439 return false; |
437 } | 440 } |
438 | 441 |
439 bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) { | 442 bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) { |
440 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { | 443 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { |
441 *next_delayed_work_time = Time(); | 444 *next_delayed_work_time = Time(); |
442 return false; | 445 return false; |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
622 Watcher *delegate) { | 625 Watcher *delegate) { |
623 return pump_libevent()->WatchFileDescriptor( | 626 return pump_libevent()->WatchFileDescriptor( |
624 fd, | 627 fd, |
625 persistent, | 628 persistent, |
626 static_cast<base::MessagePumpLibevent::Mode>(mode), | 629 static_cast<base::MessagePumpLibevent::Mode>(mode), |
627 controller, | 630 controller, |
628 delegate); | 631 delegate); |
629 } | 632 } |
630 | 633 |
631 #endif | 634 #endif |
OLD | NEW |