Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: base/timer.cc

Issue 483: Eliminate the TimerManager by pulling its priority queue into MessageLoop.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/timer.h ('k') | base/timer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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/timer.h" 5 #include "base/timer.h"
6 6
7 #include <math.h>
8 #if defined(OS_WIN)
9 #include <mmsystem.h>
10 #endif
11
12 #include "base/atomic_sequence_num.h"
13 #include "base/logging.h"
14 #include "base/message_loop.h" 7 #include "base/message_loop.h"
15 #include "base/task.h"
16 8
17 namespace base { 9 namespace base {
18 10
19 // A sequence number for all allocated times (used to break ties when
20 // comparing times in the TimerManager, and assure FIFO execution sequence).
21 static AtomicSequenceNumber timer_id_counter_(base::LINKER_INITIALIZED);
22
23 //-----------------------------------------------------------------------------
24 // Timer
25
26 Timer::Timer(int delay, Task* task, bool repeating)
27 : task_(task),
28 delay_(delay),
29 repeating_(repeating) {
30 timer_id_ = timer_id_counter_.GetNext();
31 DCHECK(delay >= 0);
32 Reset();
33 }
34
35 Timer::Timer(Time fire_time, Task* task)
36 : fire_time_(fire_time),
37 task_(task),
38 repeating_(false) {
39 timer_id_ = timer_id_counter_.GetNext();
40
41 // TODO(darin): kill off this stuff. because we are forced to compute 'now'
42 // in order to determine the delay, it is possible that our fire time could
43 // be in the past. /sigh/
44 creation_time_ = Time::Now();
45 delay_ = static_cast<int>((fire_time_ - creation_time_).InMilliseconds());
46 if (delay_ < 0)
47 delay_ = 0;
48 }
49
50 void Timer::Reset() {
51 creation_time_ = Time::Now();
52 fire_time_ = creation_time_ + TimeDelta::FromMilliseconds(delay_);
53 DHISTOGRAM_COUNTS(L"Timer.Durations", delay_);
54 }
55
56 //-----------------------------------------------------------------------------
57 // TimerPQueue
58
59 void TimerPQueue::RemoveTimer(Timer* timer) {
60 const std::vector<Timer*>::iterator location =
61 find(c.begin(), c.end(), timer);
62 if (location != c.end()) {
63 c.erase(location);
64 make_heap(c.begin(), c.end(), TimerComparison());
65 }
66 }
67
68 bool TimerPQueue::ContainsTimer(const Timer* timer) const {
69 return find(c.begin(), c.end(), timer) != c.end();
70 }
71
72 //-----------------------------------------------------------------------------
73 // TimerManager
74
75 TimerManager::TimerManager(MessageLoop* message_loop)
76 : use_broken_delay_(false),
77 message_loop_(message_loop) {
78 #if defined(OS_WIN)
79 // We've experimented with all sorts of timers, and initially tried
80 // to avoid using timeBeginPeriod because it does affect the system
81 // globally. However, after much investigation, it turns out that all
82 // of the major plugins (flash, windows media 9-11, and quicktime)
83 // already use timeBeginPeriod to increase the speed of the clock.
84 // Since the browser must work with these plugins, the browser already
85 // needs to support a fast clock. We may as well use this ourselves,
86 // as it really is the best timer mechanism for our needs.
87 timeBeginPeriod(1);
88 #endif
89 }
90
91 TimerManager::~TimerManager() {
92 #if defined(OS_WIN)
93 // Match timeBeginPeriod() from construction.
94 timeEndPeriod(1);
95 #endif
96
97 // Be nice to unit tests, and discard and delete all timers along with the
98 // embedded task objects by handing off to MessageLoop (which would have Run()
99 // and optionally deleted the objects).
100 while (timers_.size()) {
101 Timer* pending = timers_.top();
102 timers_.pop();
103 message_loop_->DiscardTimer(pending);
104 }
105 }
106
107
108 Timer* TimerManager::StartTimer(int delay, Task* task, bool repeating) {
109 Timer* t = new Timer(delay, task, repeating);
110 StartTimer(t);
111 return t;
112 }
113
114 void TimerManager::StopTimer(Timer* timer) {
115 // Make sure the timer is actually running.
116 if (!IsTimerRunning(timer))
117 return;
118 // Kill the active timer, and remove the pending entry from the queue.
119 if (timer != timers_.top()) {
120 timers_.RemoveTimer(timer);
121 } else {
122 timers_.pop();
123 DidChangeNextTimer();
124 }
125 }
126
127 void TimerManager::ResetTimer(Timer* timer) {
128 StopTimer(timer);
129 timer->Reset();
130 StartTimer(timer);
131 }
132
133 bool TimerManager::IsTimerRunning(const Timer* timer) const {
134 return timers_.ContainsTimer(timer);
135 }
136
137 Timer* TimerManager::PeekTopTimer() {
138 if (timers_.empty())
139 return NULL;
140 return timers_.top();
141 }
142
143 bool TimerManager::RunSomePendingTimers() {
144 bool did_work = false;
145 // Process a small group of timers. Cap the maximum number of timers we can
146 // process so we don't deny cycles to other parts of the process when lots of
147 // timers have been set.
148 const int kMaxTimersPerCall = 2;
149 for (int i = 0; i < kMaxTimersPerCall; ++i) {
150 if (timers_.empty() || timers_.top()->fire_time() > Time::Now())
151 break;
152
153 // Get a pending timer. Deal with updating the timers_ queue and setting
154 // the TopTimer. We'll execute the timer task only after the timer queue
155 // is back in a consistent state.
156 Timer* pending = timers_.top();
157
158 // If pending task isn't invoked_later, then it must be possible to run it
159 // now (i.e., current task needs to be reentrant).
160 // TODO(jar): We may block tasks that we can queue from being popped.
161 if (!message_loop_->NestableTasksAllowed() &&
162 !pending->task()->owned_by_message_loop_)
163 break;
164
165 timers_.pop();
166 did_work = true;
167
168 // If the timer is repeating, add it back to the list of timers to process.
169 if (pending->repeating()) {
170 pending->Reset();
171 timers_.push(pending);
172 }
173
174 message_loop_->RunTimerTask(pending);
175 }
176
177 // Restart the WM_TIMER (if necessary).
178 if (did_work)
179 DidChangeNextTimer();
180
181 return did_work;
182 }
183
184 // Note: Caller is required to call timer->Reset() before calling StartTimer().
185 // TODO(jar): change API so that Reset() is called as part of StartTimer, making
186 // the API a little less error prone.
187 void TimerManager::StartTimer(Timer* timer) {
188 // Make sure the timer is not running.
189 if (IsTimerRunning(timer))
190 return;
191
192 timers_.push(timer); // Priority queue will sort the timer into place.
193
194 if (timers_.top() == timer) // We are new head of queue.
195 DidChangeNextTimer();
196 }
197
198 Time TimerManager::GetNextFireTime() const {
199 if (timers_.empty())
200 return Time();
201
202 return timers_.top()->fire_time();
203 }
204
205 void TimerManager::DidChangeNextTimer() {
206 // Determine if the next timer expiry actually changed...
207 if (!timers_.empty()) {
208 const Time& expiry = timers_.top()->fire_time();
209 if (expiry == next_timer_expiry_)
210 return;
211 next_timer_expiry_ = expiry;
212 } else {
213 next_timer_expiry_ = Time();
214 }
215 message_loop_->DidChangeNextTimerExpiry();
216 }
217
218 //----------------------------------------------------------------------------- 11 //-----------------------------------------------------------------------------
219 // BaseTimer_Helper 12 // BaseTimer_Helper
220 13
221 void BaseTimer_Helper::OrphanDelayedTask() { 14 void BaseTimer_Helper::OrphanDelayedTask() {
222 if (delayed_task_) { 15 if (delayed_task_) {
223 delayed_task_->timer_ = NULL; 16 delayed_task_->timer_ = NULL;
224 delayed_task_ = NULL; 17 delayed_task_ = NULL;
225 } 18 }
226 } 19 }
227 20
228 void BaseTimer_Helper::InitiateDelayedTask(TimerTask* timer_task) { 21 void BaseTimer_Helper::InitiateDelayedTask(TimerTask* timer_task) {
229 OrphanDelayedTask(); 22 OrphanDelayedTask();
230 23
231 delayed_task_ = timer_task; 24 delayed_task_ = timer_task;
232 delayed_task_->timer_ = this; 25 delayed_task_->timer_ = this;
233 MessageLoop::current()->PostDelayedTask( 26 MessageLoop::current()->PostDelayedTask(
234 FROM_HERE, timer_task, 27 FROM_HERE, timer_task,
235 static_cast<int>(timer_task->delay_.InMilliseconds())); 28 static_cast<int>(timer_task->delay_.InMilliseconds()));
236 } 29 }
237 30
238 } // namespace base 31 } // namespace base
OLDNEW
« no previous file with comments | « base/timer.h ('k') | base/timer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698