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