OLD | NEW |
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/message_loop.h" | 5 #include "base/message_loop.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
| 9 #if defined(OS_WIN) |
| 10 #include <mmsystem.h> |
| 11 #endif |
| 12 |
9 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
10 #include "base/logging.h" | 14 #include "base/logging.h" |
11 #include "base/message_pump_default.h" | 15 #include "base/message_pump_default.h" |
12 #include "base/string_util.h" | 16 #include "base/string_util.h" |
13 #include "base/thread_local_storage.h" | 17 #include "base/thread_local_storage.h" |
14 | 18 |
15 // a TLS index to the message loop for the current thread | 19 // a TLS index to the message loop for the current thread |
16 // Note that if we start doing complex stuff in other static initializers | 20 // Note that if we start doing complex stuff in other static initializers |
17 // this could cause problems. | 21 // this could cause problems. |
18 // TODO(evanm): this shouldn't rely on static initialization. | 22 // TODO(evanm): this shouldn't rely on static initialization. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 ::SetUnhandledExceptionFilter(top_filter); | 54 ::SetUnhandledExceptionFilter(top_filter); |
51 return top_filter; | 55 return top_filter; |
52 } | 56 } |
53 | 57 |
54 #endif // defined(OS_WIN) | 58 #endif // defined(OS_WIN) |
55 | 59 |
56 //------------------------------------------------------------------------------ | 60 //------------------------------------------------------------------------------ |
57 | 61 |
58 MessageLoop::MessageLoop(Type type) | 62 MessageLoop::MessageLoop(Type type) |
59 : type_(type), | 63 : type_(type), |
60 ALLOW_THIS_IN_INITIALIZER_LIST(timer_manager_(this)), | |
61 nestable_tasks_allowed_(true), | 64 nestable_tasks_allowed_(true), |
62 exception_restoration_(false), | 65 exception_restoration_(false), |
63 state_(NULL) { | 66 state_(NULL), |
| 67 next_sequence_num_(0) { |
64 DCHECK(!tls_index_.Get()) << "should only have one message loop per thread"; | 68 DCHECK(!tls_index_.Get()) << "should only have one message loop per thread"; |
65 tls_index_.Set(this); | 69 tls_index_.Set(this); |
66 | 70 |
| 71 // TODO(darin): This does not seem like the best place for this code to live! |
| 72 #if defined(OS_WIN) |
| 73 // We've experimented with all sorts of timers, and initially tried |
| 74 // to avoid using timeBeginPeriod because it does affect the system |
| 75 // globally. However, after much investigation, it turns out that all |
| 76 // of the major plugins (flash, windows media 9-11, and quicktime) |
| 77 // already use timeBeginPeriod to increase the speed of the clock. |
| 78 // Since the browser must work with these plugins, the browser already |
| 79 // needs to support a fast clock. We may as well use this ourselves, |
| 80 // as it really is the best timer mechanism for our needs. |
| 81 timeBeginPeriod(1); |
| 82 #endif |
| 83 |
67 // TODO(darin): Choose the pump based on the requested type. | 84 // TODO(darin): Choose the pump based on the requested type. |
68 #if defined(OS_WIN) | 85 #if defined(OS_WIN) |
69 if (type_ == TYPE_DEFAULT) { | 86 if (type_ == TYPE_DEFAULT) { |
70 pump_ = new base::MessagePumpDefault(); | 87 pump_ = new base::MessagePumpDefault(); |
71 } else { | 88 } else { |
72 pump_ = new base::MessagePumpWin(); | 89 pump_ = new base::MessagePumpWin(); |
73 } | 90 } |
74 #else | 91 #else |
75 pump_ = new base::MessagePumpDefault(); | 92 pump_ = new base::MessagePumpDefault(); |
76 #endif | 93 #endif |
(...skipping 11 matching lines...) Expand all Loading... |
88 | 105 |
89 DCHECK(!state_); | 106 DCHECK(!state_); |
90 | 107 |
91 // Most tasks that have not been Run() are deleted in the |timer_manager_| | 108 // Most tasks that have not been Run() are deleted in the |timer_manager_| |
92 // destructor after we remove our tls index. We delete the tasks in our | 109 // destructor after we remove our tls index. We delete the tasks in our |
93 // queues here so their destuction is similar to the tasks in the | 110 // queues here so their destuction is similar to the tasks in the |
94 // |timer_manager_|. | 111 // |timer_manager_|. |
95 DeletePendingTasks(); | 112 DeletePendingTasks(); |
96 ReloadWorkQueue(); | 113 ReloadWorkQueue(); |
97 DeletePendingTasks(); | 114 DeletePendingTasks(); |
| 115 |
| 116 #if defined(OS_WIN) |
| 117 // Match timeBeginPeriod() from construction. |
| 118 timeEndPeriod(1); |
| 119 #endif |
98 } | 120 } |
99 | 121 |
100 void MessageLoop::AddDestructionObserver(DestructionObserver *obs) { | 122 void MessageLoop::AddDestructionObserver(DestructionObserver *obs) { |
101 DCHECK(this == current()); | 123 DCHECK(this == current()); |
102 destruction_observers_.AddObserver(obs); | 124 destruction_observers_.AddObserver(obs); |
103 } | 125 } |
104 | 126 |
105 void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) { | 127 void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) { |
106 DCHECK(this == current()); | 128 DCHECK(this == current()); |
107 destruction_observers_.RemoveObserver(obs); | 129 destruction_observers_.RemoveObserver(obs); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 pump_->Run(this); | 177 pump_->Run(this); |
156 } | 178 } |
157 | 179 |
158 //------------------------------------------------------------------------------ | 180 //------------------------------------------------------------------------------ |
159 // Wrapper functions for use in above message loop framework. | 181 // Wrapper functions for use in above message loop framework. |
160 | 182 |
161 bool MessageLoop::ProcessNextDelayedNonNestableTask() { | 183 bool MessageLoop::ProcessNextDelayedNonNestableTask() { |
162 if (state_->run_depth != 1) | 184 if (state_->run_depth != 1) |
163 return false; | 185 return false; |
164 | 186 |
165 if (delayed_non_nestable_queue_.Empty()) | 187 if (deferred_non_nestable_work_queue_.empty()) |
166 return false; | 188 return false; |
167 | 189 |
168 RunTask(delayed_non_nestable_queue_.Pop()); | 190 Task* task = deferred_non_nestable_work_queue_.front().task; |
| 191 deferred_non_nestable_work_queue_.pop(); |
| 192 |
| 193 RunTask(task); |
169 return true; | 194 return true; |
170 } | 195 } |
171 | 196 |
172 //------------------------------------------------------------------------------ | 197 //------------------------------------------------------------------------------ |
173 | 198 |
174 void MessageLoop::Quit() { | 199 void MessageLoop::Quit() { |
175 DCHECK(current() == this); | 200 DCHECK(current() == this); |
176 if (state_) { | 201 if (state_) { |
177 state_->quit_received = true; | 202 state_->quit_received = true; |
178 } else { | 203 } else { |
179 NOTREACHED() << "Must be inside Run to call Quit"; | 204 NOTREACHED() << "Must be inside Run to call Quit"; |
180 } | 205 } |
181 } | 206 } |
182 | 207 |
| 208 void MessageLoop::PostTask( |
| 209 const tracked_objects::Location& from_here, Task* task) { |
| 210 PostTask_Helper(from_here, task, 0, true); |
| 211 } |
| 212 |
| 213 void MessageLoop::PostDelayedTask( |
| 214 const tracked_objects::Location& from_here, Task* task, int delay_ms) { |
| 215 PostTask_Helper(from_here, task, delay_ms, true); |
| 216 } |
| 217 |
| 218 void MessageLoop::PostNonNestableTask( |
| 219 const tracked_objects::Location& from_here, Task* task) { |
| 220 PostTask_Helper(from_here, task, 0, false); |
| 221 } |
| 222 |
| 223 void MessageLoop::PostNonNestableDelayedTask( |
| 224 const tracked_objects::Location& from_here, Task* task, int delay_ms) { |
| 225 PostTask_Helper(from_here, task, delay_ms, false); |
| 226 } |
| 227 |
183 // Possibly called on a background thread! | 228 // Possibly called on a background thread! |
184 void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here, | 229 void MessageLoop::PostTask_Helper( |
185 Task* task, int delay_ms) { | 230 const tracked_objects::Location& from_here, Task* task, int delay_ms, |
| 231 bool nestable) { |
186 task->SetBirthPlace(from_here); | 232 task->SetBirthPlace(from_here); |
187 | 233 |
188 DCHECK(!task->owned_by_message_loop_); | 234 PendingTask pending_task(task, nestable); |
189 task->owned_by_message_loop_ = true; | |
190 | 235 |
191 if (delay_ms > 0) { | 236 if (delay_ms > 0) { |
192 task->delayed_run_time_ = | 237 pending_task.delayed_run_time = |
193 Time::Now() + TimeDelta::FromMilliseconds(delay_ms); | 238 Time::Now() + TimeDelta::FromMilliseconds(delay_ms); |
194 } else { | 239 } else { |
195 DCHECK(delay_ms == 0) << "delay should not be negative"; | 240 DCHECK(delay_ms == 0) << "delay should not be negative"; |
196 } | 241 } |
197 | 242 |
198 PostTaskInternal(task); | |
199 } | |
200 | |
201 void MessageLoop::PostTaskInternal(Task* task) { | |
202 // Warning: Don't try to short-circuit, and handle this thread's tasks more | 243 // Warning: Don't try to short-circuit, and handle this thread's tasks more |
203 // directly, as it could starve handling of foreign threads. Put every task | 244 // directly, as it could starve handling of foreign threads. Put every task |
204 // into this queue. | 245 // into this queue. |
205 | 246 |
206 scoped_refptr<base::MessagePump> pump; | 247 scoped_refptr<base::MessagePump> pump; |
207 { | 248 { |
208 AutoLock locked(incoming_queue_lock_); | 249 AutoLock locked(incoming_queue_lock_); |
209 | 250 |
210 bool was_empty = incoming_queue_.Empty(); | 251 bool was_empty = incoming_queue_.empty(); |
211 incoming_queue_.Push(task); | 252 incoming_queue_.push(pending_task); |
212 if (!was_empty) | 253 if (!was_empty) |
213 return; // Someone else should have started the sub-pump. | 254 return; // Someone else should have started the sub-pump. |
214 | 255 |
215 pump = pump_; | 256 pump = pump_; |
216 } | 257 } |
217 // Since the incoming_queue_ may contain a task that destroys this message | 258 // Since the incoming_queue_ may contain a task that destroys this message |
218 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. | 259 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. |
219 // We use a stack-based reference to the message pump so that we can call | 260 // We use a stack-based reference to the message pump so that we can call |
220 // ScheduleWork outside of incoming_queue_lock_. | 261 // ScheduleWork outside of incoming_queue_lock_. |
221 | 262 |
222 pump->ScheduleWork(); | 263 pump->ScheduleWork(); |
223 } | 264 } |
224 | 265 |
225 void MessageLoop::SetNestableTasksAllowed(bool allowed) { | 266 void MessageLoop::SetNestableTasksAllowed(bool allowed) { |
226 if (nestable_tasks_allowed_ != allowed) { | 267 if (nestable_tasks_allowed_ != allowed) { |
227 nestable_tasks_allowed_ = allowed; | 268 nestable_tasks_allowed_ = allowed; |
228 if (!nestable_tasks_allowed_) | 269 if (!nestable_tasks_allowed_) |
229 return; | 270 return; |
230 // Start the native pump if we are not already pumping. | 271 // Start the native pump if we are not already pumping. |
231 pump_->ScheduleWork(); | 272 pump_->ScheduleWork(); |
232 } | 273 } |
233 } | 274 } |
234 | 275 |
235 bool MessageLoop::NestableTasksAllowed() const { | 276 bool MessageLoop::NestableTasksAllowed() const { |
236 return nestable_tasks_allowed_; | 277 return nestable_tasks_allowed_; |
237 } | 278 } |
238 | 279 |
239 //------------------------------------------------------------------------------ | 280 //------------------------------------------------------------------------------ |
240 | 281 |
241 bool MessageLoop::RunTimerTask(Timer* timer) { | |
242 HistogramEvent(kTimerEvent); | |
243 | |
244 Task* task = timer->task(); | |
245 if (task->owned_by_message_loop_) { | |
246 // We constructed it through PostDelayedTask(). | |
247 DCHECK(!timer->repeating()); | |
248 timer->set_task(NULL); | |
249 delete timer; | |
250 task->ResetBirthTime(); | |
251 return QueueOrRunTask(task); | |
252 } | |
253 | |
254 // This is an unknown timer task, and we *can't* delay running it, as a user | |
255 // might try to cancel it with TimerManager at any moment. | |
256 DCHECK(nestable_tasks_allowed_); | |
257 RunTask(task); | |
258 return true; | |
259 } | |
260 | |
261 void MessageLoop::DiscardTimer(Timer* timer) { | |
262 Task* task = timer->task(); | |
263 if (task->owned_by_message_loop_) { | |
264 DCHECK(!timer->repeating()); | |
265 timer->set_task(NULL); | |
266 delete timer; // We constructed it through PostDelayedTask(). | |
267 delete task; // We were given ouwnership in PostTask(). | |
268 } | |
269 } | |
270 | |
271 bool MessageLoop::QueueOrRunTask(Task* new_task) { | |
272 if (!nestable_tasks_allowed_) { | |
273 // Task can't be executed right now. Add it to the queue. | |
274 if (new_task) | |
275 work_queue_.Push(new_task); | |
276 return false; | |
277 } | |
278 | |
279 // Queue new_task first so we execute the task in FIFO order. | |
280 if (new_task) | |
281 work_queue_.Push(new_task); | |
282 | |
283 // Execute oldest task. | |
284 while (!work_queue_.Empty()) { | |
285 Task* task = work_queue_.Pop(); | |
286 if (task->nestable() || state_->run_depth == 1) { | |
287 RunTask(task); | |
288 // Show that we ran a task (Note: a new one might arrive as a | |
289 // consequence!). | |
290 return true; | |
291 } | |
292 // We couldn't run the task now because we're in a nested message loop | |
293 // and the task isn't nestable. | |
294 delayed_non_nestable_queue_.Push(task); | |
295 } | |
296 | |
297 // Nothing happened. | |
298 return false; | |
299 } | |
300 | |
301 void MessageLoop::RunTask(Task* task) { | 282 void MessageLoop::RunTask(Task* task) { |
302 BeforeTaskRunSetup(); | |
303 HistogramEvent(kTaskRunEvent); | |
304 // task may self-delete during Run() if we don't happen to own it. | |
305 // ...so check *before* we Run, since we can't check after. | |
306 bool we_own_task = task->owned_by_message_loop_; | |
307 task->Run(); | |
308 if (we_own_task) | |
309 task->RecycleOrDelete(); // Relinquish control, and probably delete. | |
310 AfterTaskRunRestore(); | |
311 } | |
312 | |
313 void MessageLoop::BeforeTaskRunSetup() { | |
314 DCHECK(nestable_tasks_allowed_); | 283 DCHECK(nestable_tasks_allowed_); |
315 // Execute the task and assume the worst: It is probably not reentrant. | 284 // Execute the task and assume the worst: It is probably not reentrant. |
316 nestable_tasks_allowed_ = false; | 285 nestable_tasks_allowed_ = false; |
| 286 |
| 287 HistogramEvent(kTaskRunEvent); |
| 288 task->Run(); |
| 289 delete task; |
| 290 |
| 291 nestable_tasks_allowed_ = true; |
317 } | 292 } |
318 | 293 |
319 void MessageLoop::AfterTaskRunRestore() { | 294 bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { |
320 nestable_tasks_allowed_ = true; | 295 if (pending_task.nestable || state_->run_depth == 1) { |
| 296 RunTask(pending_task.task); |
| 297 // Show that we ran a task (Note: a new one might arrive as a |
| 298 // consequence!). |
| 299 return true; |
| 300 } |
| 301 |
| 302 // We couldn't run the task now because we're in a nested message loop |
| 303 // and the task isn't nestable. |
| 304 deferred_non_nestable_work_queue_.push(pending_task); |
| 305 return false; |
321 } | 306 } |
322 | 307 |
323 void MessageLoop::ReloadWorkQueue() { | 308 void MessageLoop::ReloadWorkQueue() { |
324 // We can improve performance of our loading tasks from incoming_queue_ to | 309 // We can improve performance of our loading tasks from incoming_queue_ to |
325 // work_queue_ by waiting until the last minute (work_queue_ is empty) to | 310 // work_queue_ by waiting until the last minute (work_queue_ is empty) to |
326 // load. That reduces the number of locks-per-task significantly when our | 311 // load. That reduces the number of locks-per-task significantly when our |
327 // queues get large. The optimization is disabled on threads that make use | 312 // queues get large. |
328 // of the priority queue (prioritization requires all our tasks to be in the | 313 if (!work_queue_.empty()) |
329 // work_queue_ ASAP). | |
330 if (!work_queue_.Empty() && !work_queue_.use_priority_queue()) | |
331 return; // Wait till we *really* need to lock and load. | 314 return; // Wait till we *really* need to lock and load. |
332 | 315 |
333 // Acquire all we can from the inter-thread queue with one lock acquisition. | 316 // Acquire all we can from the inter-thread queue with one lock acquisition. |
334 TaskQueue new_task_list; // Null terminated list. | |
335 { | 317 { |
336 AutoLock lock(incoming_queue_lock_); | 318 AutoLock lock(incoming_queue_lock_); |
337 if (incoming_queue_.Empty()) | 319 if (incoming_queue_.empty()) |
338 return; | 320 return; |
339 std::swap(incoming_queue_, new_task_list); | 321 std::swap(incoming_queue_, work_queue_); |
340 DCHECK(incoming_queue_.Empty()); | 322 DCHECK(incoming_queue_.empty()); |
341 } // Release lock. | |
342 | |
343 while (!new_task_list.Empty()) { | |
344 Task* task = new_task_list.Pop(); | |
345 DCHECK(task->owned_by_message_loop_); | |
346 | |
347 // TODO(darin): We should probably postpone starting the timer until we | |
348 // process the work queue as starting the timer here breaks the FIFO | |
349 // ordering of tasks. | |
350 if (!task->delayed_run_time_.is_null()) { | |
351 timer_manager_.StartTimer(new Timer(task->delayed_run_time_, task)); | |
352 } else { | |
353 work_queue_.Push(task); | |
354 } | |
355 } | 323 } |
356 } | 324 } |
357 | 325 |
358 void MessageLoop::DeletePendingTasks() { | 326 void MessageLoop::DeletePendingTasks() { |
359 /* Comment this out as it's causing crashes. | 327 /* Comment this out as it's causing crashes. |
360 while (!work_queue_.Empty()) { | 328 while (!work_queue_.Empty()) { |
361 Task* task = work_queue_.Pop(); | 329 Task* task = work_queue_.Pop(); |
362 if (task->is_owned_by_message_loop()) | 330 if (task->is_owned_by_message_loop()) |
363 delete task; | 331 delete task; |
364 } | 332 } |
365 | 333 |
366 while (!delayed_non_nestable_queue_.Empty()) { | 334 while (!delayed_non_nestable_queue_.Empty()) { |
367 Task* task = delayed_non_nestable_queue_.Pop(); | 335 Task* task = delayed_non_nestable_queue_.Pop(); |
368 if (task->is_owned_by_message_loop()) | 336 if (task->is_owned_by_message_loop()) |
369 delete task; | 337 delete task; |
370 } | 338 } |
371 */ | 339 */ |
372 } | 340 } |
373 | 341 |
374 void MessageLoop::DidChangeNextTimerExpiry() { | 342 bool MessageLoop::DoWork() { |
375 Time next_delayed_work_time = timer_manager_.GetNextFireTime(); | 343 if (!nestable_tasks_allowed_) { |
376 if (next_delayed_work_time.is_null()) | 344 // Task can't be executed right now. |
377 return; | 345 return false; |
| 346 } |
378 | 347 |
379 // Simulates malfunctioning, early firing timers. Pending tasks should only | 348 for (;;) { |
380 // be invoked when the delay they specify has elapsed. | 349 ReloadWorkQueue(); |
381 if (timer_manager_.use_broken_delay()) | 350 if (work_queue_.empty()) |
382 next_delayed_work_time = Time::Now() + TimeDelta::FromMilliseconds(10); | 351 break; |
383 | 352 |
384 pump_->ScheduleDelayedWork(next_delayed_work_time); | 353 // Execute oldest task. |
385 } | 354 do { |
| 355 PendingTask pending_task = work_queue_.front(); |
| 356 work_queue_.pop(); |
| 357 if (!pending_task.delayed_run_time.is_null()) { |
| 358 bool was_empty = delayed_work_queue_.empty(); |
386 | 359 |
387 bool MessageLoop::DoWork() { | 360 // Move to the delayed work queue. Initialize the sequence number |
388 ReloadWorkQueue(); | 361 // before inserting into the delayed_work_queue_. The sequence number |
389 return QueueOrRunTask(NULL); | 362 // is used to faciliate FIFO sorting when two tasks have the same |
| 363 // delayed_run_time value. |
| 364 pending_task.sequence_num = next_sequence_num_++; |
| 365 delayed_work_queue_.push(pending_task); |
| 366 |
| 367 if (was_empty) // We only schedule the next delayed work item. |
| 368 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); |
| 369 } else { |
| 370 if (DeferOrRunPendingTask(pending_task)) |
| 371 return true; |
| 372 } |
| 373 } while (!work_queue_.empty()); |
| 374 } |
| 375 |
| 376 // Nothing happened. |
| 377 return false; |
390 } | 378 } |
391 | 379 |
392 bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) { | 380 bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) { |
393 bool did_work = timer_manager_.RunSomePendingTimers(); | 381 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { |
| 382 *next_delayed_work_time = Time(); |
| 383 return false; |
| 384 } |
| 385 |
| 386 if (delayed_work_queue_.top().delayed_run_time > Time::Now()) { |
| 387 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; |
| 388 return false; |
| 389 } |
394 | 390 |
395 // We may not have run any timers, but we may still have future timers to | 391 PendingTask pending_task = delayed_work_queue_.top(); |
396 // run, so we need to inform the pump again of pending timers. | 392 delayed_work_queue_.pop(); |
397 *next_delayed_work_time = timer_manager_.GetNextFireTime(); | 393 |
| 394 if (!delayed_work_queue_.empty()) |
| 395 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; |
398 | 396 |
399 return did_work; | 397 return DeferOrRunPendingTask(pending_task); |
400 } | 398 } |
401 | 399 |
402 bool MessageLoop::DoIdleWork() { | 400 bool MessageLoop::DoIdleWork() { |
403 if (ProcessNextDelayedNonNestableTask()) | 401 if (ProcessNextDelayedNonNestableTask()) |
404 return true; | 402 return true; |
405 | 403 |
406 if (state_->quit_received) | 404 if (state_->quit_received) |
407 pump_->Quit(); | 405 pump_->Quit(); |
408 | 406 |
409 return false; | 407 return false; |
(...skipping 17 matching lines...) Expand all Loading... |
427 #if defined(OS_WIN) | 425 #if defined(OS_WIN) |
428 dispatcher = NULL; | 426 dispatcher = NULL; |
429 #endif | 427 #endif |
430 } | 428 } |
431 | 429 |
432 MessageLoop::AutoRunState::~AutoRunState() { | 430 MessageLoop::AutoRunState::~AutoRunState() { |
433 loop_->state_ = previous_state_; | 431 loop_->state_ = previous_state_; |
434 } | 432 } |
435 | 433 |
436 //------------------------------------------------------------------------------ | 434 //------------------------------------------------------------------------------ |
437 // Implementation of the work_queue_ as a ProiritizedTaskQueue | 435 // MessageLoop::PendingTask |
438 | 436 |
439 void MessageLoop::PrioritizedTaskQueue::push(Task * task) { | 437 bool MessageLoop::PendingTask::operator<(const PendingTask& other) const { |
440 queue_.push(PrioritizedTask(task, --next_sequence_number_)); | 438 // Since the top of a priority queue is defined as the "greatest" element, we |
441 } | 439 // need to invert the comparison here. We want the smaller time to be at the |
| 440 // top of the heap. |
442 | 441 |
443 bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < ( | 442 if (delayed_run_time < other.delayed_run_time) |
444 PrioritizedTask const & right) const { | 443 return false; |
445 int compare = task_->priority() - right.task_->priority(); | |
446 if (compare) | |
447 return compare < 0; | |
448 // Don't compare directly, but rather subtract. This handles overflow | |
449 // as sequence numbers wrap around. | |
450 compare = sequence_number_ - right.sequence_number_; | |
451 DCHECK(compare); // Sequence number are unique for a "long time." | |
452 // Make sure we don't starve anything with a low priority. | |
453 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping. | |
454 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping. | |
455 return compare < 0; | |
456 } | |
457 | 444 |
458 //------------------------------------------------------------------------------ | 445 if (delayed_run_time > other.delayed_run_time) |
459 // Implementation of a TaskQueue as a null terminated list, with end pointers. | 446 return true; |
460 | 447 |
461 void MessageLoop::TaskQueue::Push(Task* task) { | 448 // If the times happen to match, then we use the sequence number to decide. |
462 if (!first_) | 449 // Compare the difference to support integer roll-over. |
463 first_ = task; | 450 return (sequence_num - other.sequence_num) > 0; |
464 else | |
465 last_->set_next_task(task); | |
466 last_ = task; | |
467 } | |
468 | |
469 Task* MessageLoop::TaskQueue::Pop() { | |
470 DCHECK((!first_) == !last_); | |
471 Task* task = first_; | |
472 if (first_) { | |
473 first_ = task->next_task(); | |
474 if (!first_) | |
475 last_ = NULL; | |
476 else | |
477 task->set_next_task(NULL); | |
478 } | |
479 return task; | |
480 } | |
481 | |
482 //------------------------------------------------------------------------------ | |
483 // Implementation of a Task queue that automatically switches into a priority | |
484 // queue if it observes any non-zero priorities on tasks. | |
485 | |
486 void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) { | |
487 if (use_priority_queue_) { | |
488 prioritized_queue_.push(task); | |
489 } else { | |
490 queue_.Push(task); | |
491 if (task->priority()) { | |
492 use_priority_queue_ = true; // From now on. | |
493 while (!queue_.Empty()) | |
494 prioritized_queue_.push(queue_.Pop()); | |
495 } | |
496 } | |
497 } | |
498 | |
499 Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() { | |
500 if (!use_priority_queue_) | |
501 return queue_.Pop(); | |
502 Task* task = prioritized_queue_.front(); | |
503 prioritized_queue_.pop(); | |
504 return task; | |
505 } | |
506 | |
507 bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() { | |
508 if (use_priority_queue_) | |
509 return prioritized_queue_.empty(); | |
510 return queue_.Empty(); | |
511 } | 451 } |
512 | 452 |
513 //------------------------------------------------------------------------------ | 453 //------------------------------------------------------------------------------ |
514 // Method and data for histogramming events and actions taken by each instance | 454 // Method and data for histogramming events and actions taken by each instance |
515 // on each thread. | 455 // on each thread. |
516 | 456 |
517 // static | 457 // static |
518 bool MessageLoop::enable_histogrammer_ = false; | 458 bool MessageLoop::enable_histogrammer_ = false; |
519 | 459 |
520 // static | 460 // static |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 //------------------------------------------------------------------------------ | 543 //------------------------------------------------------------------------------ |
604 // MessageLoopForIO | 544 // MessageLoopForIO |
605 | 545 |
606 #if defined(OS_WIN) | 546 #if defined(OS_WIN) |
607 | 547 |
608 void MessageLoopForIO::WatchObject(HANDLE object, Watcher* watcher) { | 548 void MessageLoopForIO::WatchObject(HANDLE object, Watcher* watcher) { |
609 pump_win()->WatchObject(object, watcher); | 549 pump_win()->WatchObject(object, watcher); |
610 } | 550 } |
611 | 551 |
612 #endif // defined(OS_WIN) | 552 #endif // defined(OS_WIN) |
OLD | NEW |