| OLD | NEW | 
|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/incoming_task_queue.h" | 5 #include "base/message_loop/incoming_task_queue.h" | 
| 6 | 6 | 
| 7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" | 
| 8 #include "base/location.h" | 8 #include "base/location.h" | 
| 9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" | 
| 10 #include "base/synchronization/waitable_event.h" | 10 #include "base/synchronization/waitable_event.h" | 
| 11 #include "base/time/time.h" |  | 
| 12 | 11 | 
| 13 namespace base { | 12 namespace base { | 
| 14 namespace internal { | 13 namespace internal { | 
| 15 | 14 | 
| 16 IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop) | 15 IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop) | 
| 17     : high_res_task_count_(0), | 16     : message_loop_(message_loop), | 
| 18       message_loop_(message_loop), |  | 
| 19       next_sequence_num_(0) { | 17       next_sequence_num_(0) { | 
| 20 } | 18 } | 
| 21 | 19 | 
| 22 bool IncomingTaskQueue::AddToIncomingQueue( | 20 bool IncomingTaskQueue::AddToIncomingQueue( | 
| 23     const tracked_objects::Location& from_here, | 21     const tracked_objects::Location& from_here, | 
| 24     const Closure& task, | 22     const Closure& task, | 
| 25     TimeDelta delay, | 23     TimeDelta delay, | 
| 26     bool nestable) { | 24     bool nestable) { | 
| 27   AutoLock locked(incoming_queue_lock_); | 25   AutoLock locked(incoming_queue_lock_); | 
| 28   PendingTask pending_task( | 26   PendingTask pending_task( | 
| 29       from_here, task, CalculateDelayedRuntime(delay), nestable); | 27       from_here, task, CalculateDelayedRuntime(delay), nestable); | 
| 30 #if defined(OS_WIN) |  | 
| 31   // We consider the task needs a high resolution timer if the delay is |  | 
| 32   // more than 0 and less than 32ms. This caps the relative error to |  | 
| 33   // less than 50% : a 33ms wait can wake at 48ms since the default |  | 
| 34   // resolution on Windows is between 10 and 15ms. |  | 
| 35   if (delay > TimeDelta() && |  | 
| 36       delay.InMilliseconds() < (2 * Time::kMinLowResolutionThresholdMs)) { |  | 
| 37     ++high_res_task_count_; |  | 
| 38     pending_task.is_high_res = true; |  | 
| 39   } |  | 
| 40 #endif |  | 
| 41   return PostPendingTask(&pending_task); | 28   return PostPendingTask(&pending_task); | 
| 42 } | 29 } | 
| 43 | 30 | 
| 44 bool IncomingTaskQueue::HasHighResolutionTasks() { | 31 bool IncomingTaskQueue::IsHighResolutionTimerEnabledForTesting() { | 
| 45   AutoLock lock(incoming_queue_lock_); | 32 #if defined(OS_WIN) | 
| 46   return high_res_task_count_ > 0; | 33   return !high_resolution_timer_expiration_.is_null(); | 
|  | 34 #else | 
|  | 35   return true; | 
|  | 36 #endif | 
| 47 } | 37 } | 
| 48 | 38 | 
| 49 bool IncomingTaskQueue::IsIdleForTesting() { | 39 bool IncomingTaskQueue::IsIdleForTesting() { | 
| 50   AutoLock lock(incoming_queue_lock_); | 40   AutoLock lock(incoming_queue_lock_); | 
| 51   return incoming_queue_.empty(); | 41   return incoming_queue_.empty(); | 
| 52 } | 42 } | 
| 53 | 43 | 
| 54 int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) { | 44 void IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) { | 
| 55   // Make sure no tasks are lost. | 45   // Make sure no tasks are lost. | 
| 56   DCHECK(work_queue->empty()); | 46   DCHECK(work_queue->empty()); | 
| 57 | 47 | 
| 58   // Acquire all we can from the inter-thread queue with one lock acquisition. | 48   // Acquire all we can from the inter-thread queue with one lock acquisition. | 
| 59   AutoLock lock(incoming_queue_lock_); | 49   AutoLock lock(incoming_queue_lock_); | 
| 60   if (!incoming_queue_.empty()) | 50   if (!incoming_queue_.empty()) | 
| 61     incoming_queue_.Swap(work_queue); | 51     incoming_queue_.Swap(work_queue);  // Constant time | 
| 62 | 52 | 
| 63   // Reset the count of high resolution tasks since our queue is now empty. | 53   DCHECK(incoming_queue_.empty()); | 
| 64   int high_res_tasks = high_res_task_count_; |  | 
| 65   high_res_task_count_ = 0; |  | 
| 66   return high_res_tasks; |  | 
| 67 } | 54 } | 
| 68 | 55 | 
| 69 void IncomingTaskQueue::WillDestroyCurrentMessageLoop() { | 56 void IncomingTaskQueue::WillDestroyCurrentMessageLoop() { | 
|  | 57 #if defined(OS_WIN) | 
|  | 58   // If we left the high-resolution timer activated, deactivate it now. | 
|  | 59   // Doing this is not-critical, it is mainly to make sure we track | 
|  | 60   // the high resolution timer activations properly in our unit tests. | 
|  | 61   if (!high_resolution_timer_expiration_.is_null()) { | 
|  | 62     Time::ActivateHighResolutionTimer(false); | 
|  | 63     high_resolution_timer_expiration_ = TimeTicks(); | 
|  | 64   } | 
|  | 65 #endif | 
|  | 66 | 
| 70   AutoLock lock(incoming_queue_lock_); | 67   AutoLock lock(incoming_queue_lock_); | 
| 71   message_loop_ = NULL; | 68   message_loop_ = NULL; | 
| 72 } | 69 } | 
| 73 | 70 | 
| 74 IncomingTaskQueue::~IncomingTaskQueue() { | 71 IncomingTaskQueue::~IncomingTaskQueue() { | 
| 75   // Verify that WillDestroyCurrentMessageLoop() has been called. | 72   // Verify that WillDestroyCurrentMessageLoop() has been called. | 
| 76   DCHECK(!message_loop_); | 73   DCHECK(!message_loop_); | 
| 77 } | 74 } | 
| 78 | 75 | 
| 79 TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) { | 76 TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) { | 
| 80   TimeTicks delayed_run_time; | 77   TimeTicks delayed_run_time; | 
| 81   if (delay > TimeDelta()) | 78   if (delay > TimeDelta()) { | 
| 82     delayed_run_time = TimeTicks::Now() + delay; | 79     delayed_run_time = TimeTicks::Now() + delay; | 
| 83   else | 80 | 
|  | 81 #if defined(OS_WIN) | 
|  | 82     if (high_resolution_timer_expiration_.is_null()) { | 
|  | 83       // Windows timers are granular to 15.6ms.  If we only set high-res | 
|  | 84       // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, | 
|  | 85       // which as a percentage is pretty inaccurate.  So enable high | 
|  | 86       // res timers for any timer which is within 2x of the granularity. | 
|  | 87       // This is a tradeoff between accuracy and power management. | 
|  | 88       bool needs_high_res_timers = delay.InMilliseconds() < | 
|  | 89           (2 * Time::kMinLowResolutionThresholdMs); | 
|  | 90       if (needs_high_res_timers) { | 
|  | 91         if (Time::ActivateHighResolutionTimer(true)) { | 
|  | 92           high_resolution_timer_expiration_ = TimeTicks::Now() + | 
|  | 93               TimeDelta::FromMilliseconds( | 
|  | 94                   MessageLoop::kHighResolutionTimerModeLeaseTimeMs); | 
|  | 95         } | 
|  | 96       } | 
|  | 97     } | 
|  | 98 #endif | 
|  | 99   } else { | 
| 84     DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; | 100     DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; | 
|  | 101   } | 
|  | 102 | 
|  | 103 #if defined(OS_WIN) | 
|  | 104   if (!high_resolution_timer_expiration_.is_null()) { | 
|  | 105     if (TimeTicks::Now() > high_resolution_timer_expiration_) { | 
|  | 106       Time::ActivateHighResolutionTimer(false); | 
|  | 107       high_resolution_timer_expiration_ = TimeTicks(); | 
|  | 108     } | 
|  | 109   } | 
|  | 110 #endif | 
|  | 111 | 
| 85   return delayed_run_time; | 112   return delayed_run_time; | 
| 86 } | 113 } | 
| 87 | 114 | 
| 88 bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) { | 115 bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) { | 
| 89   // Warning: Don't try to short-circuit, and handle this thread's tasks more | 116   // Warning: Don't try to short-circuit, and handle this thread's tasks more | 
| 90   // directly, as it could starve handling of foreign threads.  Put every task | 117   // directly, as it could starve handling of foreign threads.  Put every task | 
| 91   // into this queue. | 118   // into this queue. | 
| 92 | 119 | 
| 93   // This should only be called while the lock is taken. | 120   // This should only be called while the lock is taken. | 
| 94   incoming_queue_lock_.AssertAcquired(); | 121   incoming_queue_lock_.AssertAcquired(); | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 112   pending_task->task.Reset(); | 139   pending_task->task.Reset(); | 
| 113 | 140 | 
| 114   // Wake up the pump. | 141   // Wake up the pump. | 
| 115   message_loop_->ScheduleWork(was_empty); | 142   message_loop_->ScheduleWork(was_empty); | 
| 116 | 143 | 
| 117   return true; | 144   return true; | 
| 118 } | 145 } | 
| 119 | 146 | 
| 120 }  // namespace internal | 147 }  // namespace internal | 
| 121 }  // namespace base | 148 }  // namespace base | 
| OLD | NEW | 
|---|