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 |