Home | History | Annotate | Download | only in message_loop
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/message_loop/incoming_task_queue.h"
      6 
      7 #include "base/location.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/synchronization/waitable_event.h"
     10 #include "base/time/time.h"
     11 
     12 namespace base {
     13 namespace internal {
     14 
     15 IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
     16     : high_res_task_count_(0),
     17       message_loop_(message_loop),
     18       next_sequence_num_(0) {
     19 }
     20 
     21 bool IncomingTaskQueue::AddToIncomingQueue(
     22     const tracked_objects::Location& from_here,
     23     const Closure& task,
     24     TimeDelta delay,
     25     bool nestable) {
     26   AutoLock locked(incoming_queue_lock_);
     27   PendingTask pending_task(
     28       from_here, task, CalculateDelayedRuntime(delay), nestable);
     29 #if defined(OS_WIN)
     30   // We consider the task needs a high resolution timer if the delay is
     31   // more than 0 and less than 32ms. This caps the relative error to
     32   // less than 50% : a 33ms wait can wake at 48ms since the default
     33   // resolution on Windows is between 10 and 15ms.
     34   if (delay > TimeDelta() &&
     35       delay.InMilliseconds() < (2 * Time::kMinLowResolutionThresholdMs)) {
     36     ++high_res_task_count_;
     37     pending_task.is_high_res = true;
     38   }
     39 #endif
     40   return PostPendingTask(&pending_task);
     41 }
     42 
     43 bool IncomingTaskQueue::HasHighResolutionTasks() {
     44   AutoLock lock(incoming_queue_lock_);
     45   return high_res_task_count_ > 0;
     46 }
     47 
     48 bool IncomingTaskQueue::IsIdleForTesting() {
     49   AutoLock lock(incoming_queue_lock_);
     50   return incoming_queue_.empty();
     51 }
     52 
     53 int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
     54   // Make sure no tasks are lost.
     55   DCHECK(work_queue->empty());
     56 
     57   // Acquire all we can from the inter-thread queue with one lock acquisition.
     58   AutoLock lock(incoming_queue_lock_);
     59   if (!incoming_queue_.empty())
     60     incoming_queue_.Swap(work_queue);
     61 
     62   // Reset the count of high resolution tasks since our queue is now empty.
     63   int high_res_tasks = high_res_task_count_;
     64   high_res_task_count_ = 0;
     65   return high_res_tasks;
     66 }
     67 
     68 void IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
     69   AutoLock lock(incoming_queue_lock_);
     70   message_loop_ = NULL;
     71 }
     72 
     73 IncomingTaskQueue::~IncomingTaskQueue() {
     74   // Verify that WillDestroyCurrentMessageLoop() has been called.
     75   DCHECK(!message_loop_);
     76 }
     77 
     78 TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) {
     79   TimeTicks delayed_run_time;
     80   if (delay > TimeDelta())
     81     delayed_run_time = TimeTicks::Now() + delay;
     82   else
     83     DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative";
     84   return delayed_run_time;
     85 }
     86 
     87 bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {
     88   // Warning: Don't try to short-circuit, and handle this thread's tasks more
     89   // directly, as it could starve handling of foreign threads.  Put every task
     90   // into this queue.
     91 
     92   // This should only be called while the lock is taken.
     93   incoming_queue_lock_.AssertAcquired();
     94 
     95   if (!message_loop_) {
     96     pending_task->task.Reset();
     97     return false;
     98   }
     99 
    100   // Initialize the sequence number. The sequence number is used for delayed
    101   // tasks (to faciliate FIFO sorting when two tasks have the same
    102   // delayed_run_time value) and for identifying the task in about:tracing.
    103   pending_task->sequence_num = next_sequence_num_++;
    104 
    105   message_loop_->task_annotator()->DidQueueTask("MessageLoop::PostTask",
    106                                                 *pending_task);
    107 
    108   bool was_empty = incoming_queue_.empty();
    109   incoming_queue_.push(*pending_task);
    110   pending_task->task.Reset();
    111 
    112   // Wake up the pump.
    113   message_loop_->ScheduleWork(was_empty);
    114 
    115   return true;
    116 }
    117 
    118 }  // namespace internal
    119 }  // namespace base
    120