| 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 |