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" | |
11 | 12 |
12 namespace base { | 13 namespace base { |
13 namespace internal { | 14 namespace internal { |
14 | 15 |
15 IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop) | 16 IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop) |
16 : message_loop_(message_loop), | 17 : high_res_task_count_(0), |
18 message_loop_(message_loop), | |
17 next_sequence_num_(0) { | 19 next_sequence_num_(0) { |
18 } | 20 } |
19 | 21 |
20 bool IncomingTaskQueue::AddToIncomingQueue( | 22 bool IncomingTaskQueue::AddToIncomingQueue( |
21 const tracked_objects::Location& from_here, | 23 const tracked_objects::Location& from_here, |
22 const Closure& task, | 24 const Closure& task, |
23 TimeDelta delay, | 25 TimeDelta delay, |
24 bool nestable) { | 26 bool nestable) { |
25 AutoLock locked(incoming_queue_lock_); | 27 AutoLock locked(incoming_queue_lock_); |
26 PendingTask pending_task( | 28 PendingTask pending_task( |
27 from_here, task, CalculateDelayedRuntime(delay), nestable); | 29 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. | |
darin (slow to review)
2014/07/18 04:07:58
why 32ms?
jamesr
2014/07/18 04:45:37
the old comment justified this by saying that this
cpu_(ooo_6.6-7.5)
2014/07/18 22:53:10
Added the math example to the comment.
This is an
| |
33 if (delay > TimeDelta() && | |
34 delay.InMilliseconds() < (2 * Time::kMinLowResolutionThresholdMs)) { | |
35 ++high_res_task_count_; | |
36 pending_task.is_high_res = true; | |
37 } | |
38 #endif | |
28 return PostPendingTask(&pending_task); | 39 return PostPendingTask(&pending_task); |
29 } | 40 } |
30 | 41 |
31 bool IncomingTaskQueue::IsHighResolutionTimerEnabledForTesting() { | 42 bool IncomingTaskQueue::HasHighResolutionTasks() { |
32 #if defined(OS_WIN) | 43 AutoLock lock(incoming_queue_lock_); |
33 return !high_resolution_timer_expiration_.is_null(); | 44 return (high_res_task_count_ > 0); |
darin (slow to review)
2014/07/18 04:07:58
nit: unnecessary parens.
cpu_(ooo_6.6-7.5)
2014/07/18 22:53:10
Done.
| |
34 #else | |
35 return true; | |
36 #endif | |
37 } | 45 } |
38 | 46 |
39 bool IncomingTaskQueue::IsIdleForTesting() { | 47 bool IncomingTaskQueue::IsIdleForTesting() { |
40 AutoLock lock(incoming_queue_lock_); | 48 AutoLock lock(incoming_queue_lock_); |
41 return incoming_queue_.empty(); | 49 return incoming_queue_.empty(); |
42 } | 50 } |
43 | 51 |
44 void IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) { | 52 int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) { |
45 // Make sure no tasks are lost. | 53 // Make sure no tasks are lost. |
46 DCHECK(work_queue->empty()); | 54 DCHECK(work_queue->empty()); |
47 | 55 |
48 // Acquire all we can from the inter-thread queue with one lock acquisition. | 56 // Acquire all we can from the inter-thread queue with one lock acquisition. |
49 AutoLock lock(incoming_queue_lock_); | 57 AutoLock lock(incoming_queue_lock_); |
50 if (!incoming_queue_.empty()) | 58 if (!incoming_queue_.empty()) |
51 incoming_queue_.Swap(work_queue); // Constant time | 59 incoming_queue_.Swap(work_queue); |
52 | 60 |
53 DCHECK(incoming_queue_.empty()); | 61 // Reset the count of high resolution tasks since our queue is now empty. |
62 int high_res_tasks = high_res_task_count_; | |
63 high_res_task_count_ = 0; | |
64 return high_res_tasks; | |
54 } | 65 } |
55 | 66 |
56 void IncomingTaskQueue::WillDestroyCurrentMessageLoop() { | 67 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 | |
67 AutoLock lock(incoming_queue_lock_); | 68 AutoLock lock(incoming_queue_lock_); |
68 message_loop_ = NULL; | 69 message_loop_ = NULL; |
69 } | 70 } |
70 | 71 |
71 IncomingTaskQueue::~IncomingTaskQueue() { | 72 IncomingTaskQueue::~IncomingTaskQueue() { |
72 // Verify that WillDestroyCurrentMessageLoop() has been called. | 73 // Verify that WillDestroyCurrentMessageLoop() has been called. |
73 DCHECK(!message_loop_); | 74 DCHECK(!message_loop_); |
74 } | 75 } |
75 | 76 |
76 TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) { | 77 TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) { |
77 TimeTicks delayed_run_time; | 78 TimeTicks delayed_run_time; |
78 if (delay > TimeDelta()) { | 79 if (delay > TimeDelta()) |
79 delayed_run_time = TimeTicks::Now() + delay; | 80 delayed_run_time = TimeTicks::Now() + delay; |
80 | 81 else |
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 { | |
100 DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; | 82 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 | |
112 return delayed_run_time; | 83 return delayed_run_time; |
113 } | 84 } |
114 | 85 |
115 bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) { | 86 bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) { |
116 // Warning: Don't try to short-circuit, and handle this thread's tasks more | 87 // Warning: Don't try to short-circuit, and handle this thread's tasks more |
117 // directly, as it could starve handling of foreign threads. Put every task | 88 // directly, as it could starve handling of foreign threads. Put every task |
118 // into this queue. | 89 // into this queue. |
119 | 90 |
120 // This should only be called while the lock is taken. | 91 // This should only be called while the lock is taken. |
121 incoming_queue_lock_.AssertAcquired(); | 92 incoming_queue_lock_.AssertAcquired(); |
(...skipping 17 matching lines...) Expand all Loading... | |
139 pending_task->task.Reset(); | 110 pending_task->task.Reset(); |
140 | 111 |
141 // Wake up the pump. | 112 // Wake up the pump. |
142 message_loop_->ScheduleWork(was_empty); | 113 message_loop_->ScheduleWork(was_empty); |
143 | 114 |
144 return true; | 115 return true; |
145 } | 116 } |
146 | 117 |
147 } // namespace internal | 118 } // namespace internal |
148 } // namespace base | 119 } // namespace base |
OLD | NEW |