| 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/message_loop.h" | 5 #include "base/message_loop/message_loop.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) | 82 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) |
| 83 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) | 83 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) |
| 84 | 84 |
| 85 {-1, NULL} // The list must be null terminated, per API to histogram. | 85 {-1, NULL} // The list must be null terminated, per API to histogram. |
| 86 }; | 86 }; |
| 87 | 87 |
| 88 bool enable_histogrammer_ = false; | 88 bool enable_histogrammer_ = false; |
| 89 | 89 |
| 90 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; | 90 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; |
| 91 | 91 |
| 92 // Create a process-wide unique ID to represent this task in trace events. This | |
| 93 // will be mangled with a Process ID hash to reduce the likelyhood of colliding | |
| 94 // with MessageLoop pointers on other processes. | |
| 95 uint64 GetTaskTraceID(const PendingTask& task, MessageLoop* loop) { | |
| 96 return (static_cast<uint64>(task.sequence_num) << 32) | | |
| 97 static_cast<uint64>(reinterpret_cast<intptr_t>(loop)); | |
| 98 } | |
| 99 | |
| 100 } // namespace | 92 } // namespace |
| 101 | 93 |
| 102 //------------------------------------------------------------------------------ | 94 //------------------------------------------------------------------------------ |
| 103 | 95 |
| 104 #if defined(OS_WIN) | 96 #if defined(OS_WIN) |
| 105 | 97 |
| 106 // Upon a SEH exception in this thread, it restores the original unhandled | 98 // Upon a SEH exception in this thread, it restores the original unhandled |
| 107 // exception filter. | 99 // exception filter. |
| 108 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { | 100 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { |
| 109 ::SetUnhandledExceptionFilter(old_filter); | 101 ::SetUnhandledExceptionFilter(old_filter); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 132 MessageLoop::DestructionObserver::~DestructionObserver() { | 124 MessageLoop::DestructionObserver::~DestructionObserver() { |
| 133 } | 125 } |
| 134 | 126 |
| 135 //------------------------------------------------------------------------------ | 127 //------------------------------------------------------------------------------ |
| 136 | 128 |
| 137 MessageLoop::MessageLoop(Type type) | 129 MessageLoop::MessageLoop(Type type) |
| 138 : type_(type), | 130 : type_(type), |
| 139 nestable_tasks_allowed_(true), | 131 nestable_tasks_allowed_(true), |
| 140 exception_restoration_(false), | 132 exception_restoration_(false), |
| 141 message_histogram_(NULL), | 133 message_histogram_(NULL), |
| 142 run_loop_(NULL), | |
| 143 #if defined(OS_WIN) | 134 #if defined(OS_WIN) |
| 144 os_modal_loop_(false), | 135 os_modal_loop_(false), |
| 145 #endif // OS_WIN | 136 #endif // OS_WIN |
| 146 next_sequence_num_(0) { | 137 run_loop_(NULL) { |
| 147 DCHECK(!current()) << "should only have one message loop per thread"; | 138 DCHECK(!current()) << "should only have one message loop per thread"; |
| 148 lazy_tls_ptr.Pointer()->Set(this); | 139 lazy_tls_ptr.Pointer()->Set(this); |
| 149 | 140 |
| 150 message_loop_proxy_ = new MessageLoopProxyImpl(); | 141 message_loop_proxy_ = new MessageLoopProxyImpl(); |
| 151 thread_task_runner_handle_.reset( | 142 thread_task_runner_handle_.reset( |
| 152 new ThreadTaskRunnerHandle(message_loop_proxy_)); | 143 new ThreadTaskRunnerHandle(message_loop_proxy_)); |
| 153 | 144 |
| 154 // TODO(rvargas): Get rid of the OS guards. | 145 // TODO(rvargas): Get rid of the OS guards. |
| 155 #if defined(OS_WIN) | 146 #if defined(OS_WIN) |
| 156 #define MESSAGE_PUMP_UI new MessagePumpForUI() | 147 #define MESSAGE_PUMP_UI new MessagePumpForUI() |
| 157 #define MESSAGE_PUMP_IO new MessagePumpForIO() | 148 #define MESSAGE_PUMP_IO new MessagePumpForIO() |
| 158 #elif defined(OS_IOS) | 149 #elif defined(OS_IOS) |
| 159 #define MESSAGE_PUMP_UI MessagePumpMac::Create() | 150 #define MESSAGE_PUMP_UI MessagePumpMac::Create() |
| 160 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() | 151 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() |
| 161 #elif defined(OS_MACOSX) | 152 #elif defined(OS_MACOSX) |
| 162 #define MESSAGE_PUMP_UI MessagePumpMac::Create() | 153 #define MESSAGE_PUMP_UI MessagePumpMac::Create() |
| 163 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | 154 #define MESSAGE_PUMP_IO new MessagePumpLibevent() |
| 164 #elif defined(OS_NACL) | 155 #elif defined(OS_NACL) |
| 165 // Currently NaCl doesn't have a UI MessageLoop. | 156 // Currently NaCl doesn't have a UI MessageLoop. |
| 166 // TODO(abarth): Figure out if we need this. | 157 // TODO(abarth): Figure out if we need this. |
| 167 #define MESSAGE_PUMP_UI NULL | 158 #define MESSAGE_PUMP_UI NULL |
| 168 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and | 159 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and |
| 169 // doesn't require extra support for watching file descriptors. | 160 // doesn't require extra support for watching file descriptors. |
| 170 #define MESSAGE_PUMP_IO new MessagePumpDefault(); | 161 #define MESSAGE_PUMP_IO new MessagePumpDefault() |
| 171 #elif defined(OS_POSIX) // POSIX but not MACOSX. | 162 #elif defined(OS_POSIX) // POSIX but not MACOSX. |
| 172 #define MESSAGE_PUMP_UI new MessagePumpForUI() | 163 #define MESSAGE_PUMP_UI new MessagePumpForUI() |
| 173 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | 164 #define MESSAGE_PUMP_IO new MessagePumpLibevent() |
| 174 #else | 165 #else |
| 175 #error Not implemented | 166 #error Not implemented |
| 176 #endif | 167 #endif |
| 177 | 168 |
| 178 if (type_ == TYPE_UI) { | 169 if (type_ == TYPE_UI) { |
| 179 if (message_pump_for_ui_factory_) | 170 if (message_pump_for_ui_factory_) |
| 180 pump_ = message_pump_for_ui_factory_(); | 171 pump_.reset(message_pump_for_ui_factory_()); |
| 181 else | 172 else |
| 182 pump_ = MESSAGE_PUMP_UI; | 173 pump_.reset(MESSAGE_PUMP_UI); |
| 183 } else if (type_ == TYPE_IO) { | 174 } else if (type_ == TYPE_IO) { |
| 184 pump_ = MESSAGE_PUMP_IO; | 175 pump_.reset(MESSAGE_PUMP_IO); |
| 185 } else { | 176 } else { |
| 186 DCHECK_EQ(TYPE_DEFAULT, type_); | 177 DCHECK_EQ(TYPE_DEFAULT, type_); |
| 187 pump_ = new MessagePumpDefault(); | 178 pump_.reset(new MessagePumpDefault()); |
| 188 } | 179 } |
| 189 } | 180 } |
| 190 | 181 |
| 191 MessageLoop::~MessageLoop() { | 182 MessageLoop::~MessageLoop() { |
| 192 DCHECK_EQ(this, current()); | 183 DCHECK_EQ(this, current()); |
| 193 | 184 |
| 194 DCHECK(!run_loop_); | 185 DCHECK(!run_loop_); |
| 195 | 186 |
| 196 // Clean up any unprocessed tasks, but take care: deleting a task could | 187 // Clean up any unprocessed tasks, but take care: deleting a task could |
| 197 // result in the addition of more tasks (e.g., via DeleteSoon). We set a | 188 // result in the addition of more tasks (e.g., via DeleteSoon). We set a |
| 198 // limit on the number of times we will allow a deleted task to generate more | 189 // limit on the number of times we will allow a deleted task to generate more |
| 199 // tasks. Normally, we should only pass through this loop once or twice. If | 190 // tasks. Normally, we should only pass through this loop once or twice. If |
| 200 // we end up hitting the loop limit, then it is probably due to one task that | 191 // we end up hitting the loop limit, then it is probably due to one task that |
| 201 // is being stubborn. Inspect the queues to see who is left. | 192 // is being stubborn. Inspect the queues to see who is left. |
| 202 bool did_work; | 193 bool did_work; |
| 203 for (int i = 0; i < 100; ++i) { | 194 for (int i = 0; i < 100; ++i) { |
| 204 DeletePendingTasks(); | 195 DeletePendingTasks(); |
| 205 ReloadWorkQueue(); | 196 message_loop_proxy_->ReloadWorkQueue(&work_queue_); |
| 206 // If we end up with empty queues, then break out of the loop. | 197 // If we end up with empty queues, then break out of the loop. |
| 207 did_work = DeletePendingTasks(); | 198 did_work = DeletePendingTasks(); |
| 208 if (!did_work) | 199 if (!did_work) |
| 209 break; | 200 break; |
| 210 } | 201 } |
| 211 DCHECK(!did_work); | 202 DCHECK(!did_work); |
| 212 | 203 |
| 213 // Let interested parties have one last shot at accessing this. | 204 // Let interested parties have one last shot at accessing this. |
| 214 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, | 205 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, |
| 215 WillDestroyCurrentMessageLoop()); | 206 WillDestroyCurrentMessageLoop()); |
| 216 | 207 |
| 217 thread_task_runner_handle_.reset(); | 208 thread_task_runner_handle_.reset(); |
| 218 | 209 |
| 219 // Tell the message_loop_proxy that we are dying. | 210 // Tell the message_loop_proxy that we are dying. |
| 220 static_cast<MessageLoopProxyImpl*>(message_loop_proxy_.get())-> | 211 static_cast<MessageLoopProxyImpl*>(message_loop_proxy_.get())-> |
| 221 WillDestroyCurrentMessageLoop(); | 212 WillDestroyCurrentMessageLoop(); |
| 222 message_loop_proxy_ = NULL; | 213 message_loop_proxy_ = NULL; |
| 223 | 214 |
| 224 // OK, now make it so that no one can find us. | 215 // OK, now make it so that no one can find us. |
| 225 lazy_tls_ptr.Pointer()->Set(NULL); | 216 lazy_tls_ptr.Pointer()->Set(NULL); |
| 226 | |
| 227 #if defined(OS_WIN) | |
| 228 // If we left the high-resolution timer activated, deactivate it now. | |
| 229 // Doing this is not-critical, it is mainly to make sure we track | |
| 230 // the high resolution timer activations properly in our unit tests. | |
| 231 if (!high_resolution_timer_expiration_.is_null()) { | |
| 232 Time::ActivateHighResolutionTimer(false); | |
| 233 high_resolution_timer_expiration_ = TimeTicks(); | |
| 234 } | |
| 235 #endif | |
| 236 } | 217 } |
| 237 | 218 |
| 238 // static | 219 // static |
| 239 MessageLoop* MessageLoop::current() { | 220 MessageLoop* MessageLoop::current() { |
| 240 // TODO(darin): sadly, we cannot enable this yet since people call us even | 221 // TODO(darin): sadly, we cannot enable this yet since people call us even |
| 241 // when they have no intention of using us. | 222 // when they have no intention of using us. |
| 242 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; | 223 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; |
| 243 return lazy_tls_ptr.Pointer()->Get(); | 224 return lazy_tls_ptr.Pointer()->Get(); |
| 244 } | 225 } |
| 245 | 226 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 266 void MessageLoop::RemoveDestructionObserver( | 247 void MessageLoop::RemoveDestructionObserver( |
| 267 DestructionObserver* destruction_observer) { | 248 DestructionObserver* destruction_observer) { |
| 268 DCHECK_EQ(this, current()); | 249 DCHECK_EQ(this, current()); |
| 269 destruction_observers_.RemoveObserver(destruction_observer); | 250 destruction_observers_.RemoveObserver(destruction_observer); |
| 270 } | 251 } |
| 271 | 252 |
| 272 void MessageLoop::PostTask( | 253 void MessageLoop::PostTask( |
| 273 const tracked_objects::Location& from_here, | 254 const tracked_objects::Location& from_here, |
| 274 const Closure& task) { | 255 const Closure& task) { |
| 275 DCHECK(!task.is_null()) << from_here.ToString(); | 256 DCHECK(!task.is_null()) << from_here.ToString(); |
| 276 PendingTask pending_task( | 257 message_loop_proxy_->AddToIncomingQueue(from_here, task, TimeDelta(), true); |
| 277 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
| 278 AddToIncomingQueue(&pending_task, false); | |
| 279 } | 258 } |
| 280 | 259 |
| 281 bool MessageLoop::TryPostTask( | 260 bool MessageLoop::TryPostTask( |
| 282 const tracked_objects::Location& from_here, | 261 const tracked_objects::Location& from_here, |
| 283 const Closure& task) { | 262 const Closure& task) { |
| 284 DCHECK(!task.is_null()) << from_here.ToString(); | 263 DCHECK(!task.is_null()) << from_here.ToString(); |
| 285 PendingTask pending_task( | 264 return message_loop_proxy_->TryAddToIncomingQueue(from_here, task); |
| 286 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
| 287 return AddToIncomingQueue(&pending_task, true); | |
| 288 } | 265 } |
| 289 | 266 |
| 290 void MessageLoop::PostDelayedTask( | 267 void MessageLoop::PostDelayedTask( |
| 291 const tracked_objects::Location& from_here, | 268 const tracked_objects::Location& from_here, |
| 292 const Closure& task, | 269 const Closure& task, |
| 293 TimeDelta delay) { | 270 TimeDelta delay) { |
| 294 DCHECK(!task.is_null()) << from_here.ToString(); | 271 DCHECK(!task.is_null()) << from_here.ToString(); |
| 295 PendingTask pending_task( | 272 message_loop_proxy_->AddToIncomingQueue(from_here, task, delay, true); |
| 296 from_here, task, CalculateDelayedRuntime(delay), true); | |
| 297 AddToIncomingQueue(&pending_task, false); | |
| 298 } | 273 } |
| 299 | 274 |
| 300 void MessageLoop::PostNonNestableTask( | 275 void MessageLoop::PostNonNestableTask( |
| 301 const tracked_objects::Location& from_here, | 276 const tracked_objects::Location& from_here, |
| 302 const Closure& task) { | 277 const Closure& task) { |
| 303 DCHECK(!task.is_null()) << from_here.ToString(); | 278 DCHECK(!task.is_null()) << from_here.ToString(); |
| 304 PendingTask pending_task( | 279 message_loop_proxy_->AddToIncomingQueue(from_here, task, TimeDelta(), false); |
| 305 from_here, task, CalculateDelayedRuntime(TimeDelta()), false); | |
| 306 AddToIncomingQueue(&pending_task, false); | |
| 307 } | 280 } |
| 308 | 281 |
| 309 void MessageLoop::PostNonNestableDelayedTask( | 282 void MessageLoop::PostNonNestableDelayedTask( |
| 310 const tracked_objects::Location& from_here, | 283 const tracked_objects::Location& from_here, |
| 311 const Closure& task, | 284 const Closure& task, |
| 312 TimeDelta delay) { | 285 TimeDelta delay) { |
| 313 DCHECK(!task.is_null()) << from_here.ToString(); | 286 DCHECK(!task.is_null()) << from_here.ToString(); |
| 314 PendingTask pending_task( | 287 message_loop_proxy_->AddToIncomingQueue(from_here, task, delay, false); |
| 315 from_here, task, CalculateDelayedRuntime(delay), false); | |
| 316 AddToIncomingQueue(&pending_task, false); | |
| 317 } | 288 } |
| 318 | 289 |
| 319 void MessageLoop::Run() { | 290 void MessageLoop::Run() { |
| 320 RunLoop run_loop; | 291 RunLoop run_loop; |
| 321 run_loop.Run(); | 292 run_loop.Run(); |
| 322 } | 293 } |
| 323 | 294 |
| 324 void MessageLoop::RunUntilIdle() { | 295 void MessageLoop::RunUntilIdle() { |
| 325 RunLoop run_loop; | 296 RunLoop run_loop; |
| 326 run_loop.RunUntilIdle(); | 297 run_loop.RunUntilIdle(); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 350 | 321 |
| 351 static void QuitCurrentWhenIdle() { | 322 static void QuitCurrentWhenIdle() { |
| 352 MessageLoop::current()->QuitWhenIdle(); | 323 MessageLoop::current()->QuitWhenIdle(); |
| 353 } | 324 } |
| 354 | 325 |
| 355 // static | 326 // static |
| 356 Closure MessageLoop::QuitWhenIdleClosure() { | 327 Closure MessageLoop::QuitWhenIdleClosure() { |
| 357 return Bind(&QuitCurrentWhenIdle); | 328 return Bind(&QuitCurrentWhenIdle); |
| 358 } | 329 } |
| 359 | 330 |
| 331 scoped_refptr<MessageLoopProxy> MessageLoop::message_loop_proxy() { |
| 332 return message_loop_proxy_; |
| 333 } |
| 334 |
| 360 void MessageLoop::SetNestableTasksAllowed(bool allowed) { | 335 void MessageLoop::SetNestableTasksAllowed(bool allowed) { |
| 361 if (nestable_tasks_allowed_ != allowed) { | 336 if (nestable_tasks_allowed_ != allowed) { |
| 362 nestable_tasks_allowed_ = allowed; | 337 nestable_tasks_allowed_ = allowed; |
| 363 if (!nestable_tasks_allowed_) | 338 if (!nestable_tasks_allowed_) |
| 364 return; | 339 return; |
| 365 // Start the native pump if we are not already pumping. | 340 // Start the native pump if we are not already pumping. |
| 366 pump_->ScheduleWork(); | 341 StartPump(); |
| 367 } | 342 } |
| 368 } | 343 } |
| 369 | 344 |
| 370 bool MessageLoop::NestableTasksAllowed() const { | 345 bool MessageLoop::NestableTasksAllowed() const { |
| 371 return nestable_tasks_allowed_; | 346 return nestable_tasks_allowed_; |
| 372 } | 347 } |
| 373 | 348 |
| 374 bool MessageLoop::IsNested() { | 349 bool MessageLoop::IsNested() { |
| 375 return run_loop_->run_depth_ > 1; | 350 return run_loop_->run_depth_ > 1; |
| 376 } | 351 } |
| 377 | 352 |
| 378 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { | 353 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { |
| 379 DCHECK_EQ(this, current()); | 354 DCHECK_EQ(this, current()); |
| 380 task_observers_.AddObserver(task_observer); | 355 task_observers_.AddObserver(task_observer); |
| 381 } | 356 } |
| 382 | 357 |
| 383 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { | 358 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { |
| 384 DCHECK_EQ(this, current()); | 359 DCHECK_EQ(this, current()); |
| 385 task_observers_.RemoveObserver(task_observer); | 360 task_observers_.RemoveObserver(task_observer); |
| 386 } | 361 } |
| 387 | 362 |
| 388 void MessageLoop::AssertIdle() const { | |
| 389 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. | |
| 390 AutoLock lock(incoming_queue_lock_); | |
| 391 DCHECK(incoming_queue_.empty()); | |
| 392 } | |
| 393 | |
| 394 bool MessageLoop::is_running() const { | 363 bool MessageLoop::is_running() const { |
| 395 DCHECK_EQ(this, current()); | 364 DCHECK_EQ(this, current()); |
| 396 return run_loop_ != NULL; | 365 return run_loop_ != NULL; |
| 397 } | 366 } |
| 398 | 367 |
| 368 bool MessageLoop::IsHishResolutionTimersEnabledForTest() { |
| 369 return message_loop_proxy_->IsHishResolutionTimersEnabledForTest(); |
| 370 } |
| 371 |
| 372 bool MessageLoop::IsIdleForTest() { |
| 373 // We only check the imcoming queue|, since we don't want to lock the work |
| 374 // queue. |
| 375 return message_loop_proxy_->IsIdleForTest(); |
| 376 } |
| 377 |
| 399 //------------------------------------------------------------------------------ | 378 //------------------------------------------------------------------------------ |
| 400 | 379 |
| 401 // Runs the loop in two different SEH modes: | 380 // Runs the loop in two different SEH modes: |
| 402 // enable_SEH_restoration_ = false : any unhandled exception goes to the last | 381 // enable_SEH_restoration_ = false : any unhandled exception goes to the last |
| 403 // one that calls SetUnhandledExceptionFilter(). | 382 // one that calls SetUnhandledExceptionFilter(). |
| 404 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter | 383 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter |
| 405 // that was existed before the loop was run. | 384 // that was existed before the loop was run. |
| 406 void MessageLoop::RunHandler() { | 385 void MessageLoop::RunHandler() { |
| 407 #if defined(OS_WIN) | 386 #if defined(OS_WIN) |
| 408 if (exception_restoration_) { | 387 if (exception_restoration_) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 | 429 |
| 451 PendingTask pending_task = deferred_non_nestable_work_queue_.front(); | 430 PendingTask pending_task = deferred_non_nestable_work_queue_.front(); |
| 452 deferred_non_nestable_work_queue_.pop(); | 431 deferred_non_nestable_work_queue_.pop(); |
| 453 | 432 |
| 454 RunTask(pending_task); | 433 RunTask(pending_task); |
| 455 return true; | 434 return true; |
| 456 } | 435 } |
| 457 | 436 |
| 458 void MessageLoop::RunTask(const PendingTask& pending_task) { | 437 void MessageLoop::RunTask(const PendingTask& pending_task) { |
| 459 TRACE_EVENT_FLOW_END0("task", "MessageLoop::PostTask", | 438 TRACE_EVENT_FLOW_END0("task", "MessageLoop::PostTask", |
| 460 TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this))); | 439 TRACE_ID_MANGLE(GetTaskTraceID(pending_task))); |
| 461 TRACE_EVENT2("task", "MessageLoop::RunTask", | 440 TRACE_EVENT2("task", "MessageLoop::RunTask", |
| 462 "src_file", pending_task.posted_from.file_name(), | 441 "src_file", pending_task.posted_from.file_name(), |
| 463 "src_func", pending_task.posted_from.function_name()); | 442 "src_func", pending_task.posted_from.function_name()); |
| 464 DCHECK(nestable_tasks_allowed_); | 443 DCHECK(nestable_tasks_allowed_); |
| 465 // Execute the task and assume the worst: It is probably not reentrant. | 444 // Execute the task and assume the worst: It is probably not reentrant. |
| 466 nestable_tasks_allowed_ = false; | 445 nestable_tasks_allowed_ = false; |
| 467 | 446 |
| 468 // Before running the task, store the program counter where it was posted | 447 // Before running the task, store the program counter where it was posted |
| 469 // and deliberately alias it to ensure it is on the stack if the task | 448 // and deliberately alias it to ensure it is on the stack if the task |
| 470 // crashes. Be careful not to assume that the variable itself will have the | 449 // crashes. Be careful not to assume that the variable itself will have the |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 // and the task isn't nestable. | 482 // and the task isn't nestable. |
| 504 deferred_non_nestable_work_queue_.push(pending_task); | 483 deferred_non_nestable_work_queue_.push(pending_task); |
| 505 return false; | 484 return false; |
| 506 } | 485 } |
| 507 | 486 |
| 508 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { | 487 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { |
| 509 // Move to the delayed work queue. | 488 // Move to the delayed work queue. |
| 510 delayed_work_queue_.push(pending_task); | 489 delayed_work_queue_.push(pending_task); |
| 511 } | 490 } |
| 512 | 491 |
| 513 void MessageLoop::ReloadWorkQueue() { | |
| 514 // We can improve performance of our loading tasks from incoming_queue_ to | |
| 515 // work_queue_ by waiting until the last minute (work_queue_ is empty) to | |
| 516 // load. That reduces the number of locks-per-task significantly when our | |
| 517 // queues get large. | |
| 518 if (!work_queue_.empty()) | |
| 519 return; // Wait till we *really* need to lock and load. | |
| 520 | |
| 521 // Acquire all we can from the inter-thread queue with one lock acquisition. | |
| 522 { | |
| 523 AutoLock lock(incoming_queue_lock_); | |
| 524 if (incoming_queue_.empty()) | |
| 525 return; | |
| 526 incoming_queue_.Swap(&work_queue_); // Constant time | |
| 527 DCHECK(incoming_queue_.empty()); | |
| 528 } | |
| 529 } | |
| 530 | |
| 531 bool MessageLoop::DeletePendingTasks() { | 492 bool MessageLoop::DeletePendingTasks() { |
| 532 bool did_work = !work_queue_.empty(); | 493 bool did_work = !work_queue_.empty(); |
| 533 while (!work_queue_.empty()) { | 494 while (!work_queue_.empty()) { |
| 534 PendingTask pending_task = work_queue_.front(); | 495 PendingTask pending_task = work_queue_.front(); |
| 535 work_queue_.pop(); | 496 work_queue_.pop(); |
| 536 if (!pending_task.delayed_run_time.is_null()) { | 497 if (!pending_task.delayed_run_time.is_null()) { |
| 537 // We want to delete delayed tasks in the same order in which they would | 498 // We want to delete delayed tasks in the same order in which they would |
| 538 // normally be deleted in case of any funny dependencies between delayed | 499 // normally be deleted in case of any funny dependencies between delayed |
| 539 // tasks. | 500 // tasks. |
| 540 AddToDelayedWorkQueue(pending_task); | 501 AddToDelayedWorkQueue(pending_task); |
| 541 } | 502 } |
| 542 } | 503 } |
| 543 did_work |= !deferred_non_nestable_work_queue_.empty(); | 504 did_work |= !deferred_non_nestable_work_queue_.empty(); |
| 544 while (!deferred_non_nestable_work_queue_.empty()) { | 505 while (!deferred_non_nestable_work_queue_.empty()) { |
| 545 deferred_non_nestable_work_queue_.pop(); | 506 deferred_non_nestable_work_queue_.pop(); |
| 546 } | 507 } |
| 547 did_work |= !delayed_work_queue_.empty(); | 508 did_work |= !delayed_work_queue_.empty(); |
| 548 | 509 |
| 549 // Historically, we always delete the task regardless of valgrind status. It's | 510 // Historically, we always delete the task regardless of valgrind status. It's |
| 550 // not completely clear why we want to leak them in the loops above. This | 511 // not completely clear why we want to leak them in the loops above. This |
| 551 // code is replicating legacy behavior, and should not be considered | 512 // code is replicating legacy behavior, and should not be considered |
| 552 // absolutely "correct" behavior. See TODO above about deleting all tasks | 513 // absolutely "correct" behavior. See TODO above about deleting all tasks |
| 553 // when it's safe. | 514 // when it's safe. |
| 554 while (!delayed_work_queue_.empty()) { | 515 while (!delayed_work_queue_.empty()) { |
| 555 delayed_work_queue_.pop(); | 516 delayed_work_queue_.pop(); |
| 556 } | 517 } |
| 557 return did_work; | 518 return did_work; |
| 558 } | 519 } |
| 559 | 520 |
| 560 TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) { | 521 void MessageLoop::StartPump() { |
| 561 TimeTicks delayed_run_time; | 522 pump_->ScheduleWork(); |
| 562 if (delay > TimeDelta()) { | |
| 563 delayed_run_time = TimeTicks::Now() + delay; | |
| 564 | |
| 565 #if defined(OS_WIN) | |
| 566 if (high_resolution_timer_expiration_.is_null()) { | |
| 567 // Windows timers are granular to 15.6ms. If we only set high-res | |
| 568 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, | |
| 569 // which as a percentage is pretty inaccurate. So enable high | |
| 570 // res timers for any timer which is within 2x of the granularity. | |
| 571 // This is a tradeoff between accuracy and power management. | |
| 572 bool needs_high_res_timers = delay.InMilliseconds() < | |
| 573 (2 * Time::kMinLowResolutionThresholdMs); | |
| 574 if (needs_high_res_timers) { | |
| 575 if (Time::ActivateHighResolutionTimer(true)) { | |
| 576 high_resolution_timer_expiration_ = TimeTicks::Now() + | |
| 577 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs); | |
| 578 } | |
| 579 } | |
| 580 } | |
| 581 #endif | |
| 582 } else { | |
| 583 DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; | |
| 584 } | |
| 585 | |
| 586 #if defined(OS_WIN) | |
| 587 if (!high_resolution_timer_expiration_.is_null()) { | |
| 588 if (TimeTicks::Now() > high_resolution_timer_expiration_) { | |
| 589 Time::ActivateHighResolutionTimer(false); | |
| 590 high_resolution_timer_expiration_ = TimeTicks(); | |
| 591 } | |
| 592 } | |
| 593 #endif | |
| 594 | |
| 595 return delayed_run_time; | |
| 596 } | 523 } |
| 597 | 524 |
| 598 // Possibly called on a background thread! | 525 uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) { |
| 599 bool MessageLoop::AddToIncomingQueue(PendingTask* pending_task, | 526 return (static_cast<uint64>(task.sequence_num) << 32) | |
| 600 bool use_try_lock) { | 527 static_cast<uint64>(reinterpret_cast<intptr_t>(this)); |
| 601 // Warning: Don't try to short-circuit, and handle this thread's tasks more | |
| 602 // directly, as it could starve handling of foreign threads. Put every task | |
| 603 // into this queue. | |
| 604 | |
| 605 scoped_refptr<MessagePump> pump; | |
| 606 { | |
| 607 if (use_try_lock) { | |
| 608 if (!incoming_queue_lock_.Try()) { | |
| 609 pending_task->task.Reset(); | |
| 610 return false; | |
| 611 } | |
| 612 } else { | |
| 613 incoming_queue_lock_.Acquire(); | |
| 614 } | |
| 615 AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired()); | |
| 616 // Initialize the sequence number. The sequence number is used for delayed | |
| 617 // tasks (to faciliate FIFO sorting when two tasks have the same | |
| 618 // delayed_run_time value) and for identifying the task in about:tracing. | |
| 619 pending_task->sequence_num = next_sequence_num_++; | |
| 620 | |
| 621 TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", | |
| 622 TRACE_ID_MANGLE(GetTaskTraceID(*pending_task, this))); | |
| 623 | |
| 624 bool was_empty = incoming_queue_.empty(); | |
| 625 incoming_queue_.push(*pending_task); | |
| 626 pending_task->task.Reset(); | |
| 627 if (!was_empty) | |
| 628 return true; // Someone else should have started the sub-pump. | |
| 629 | |
| 630 pump = pump_; | |
| 631 } | |
| 632 // Since the incoming_queue_ may contain a task that destroys this message | |
| 633 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. | |
| 634 // We use a stack-based reference to the message pump so that we can call | |
| 635 // ScheduleWork outside of incoming_queue_lock_. | |
| 636 | |
| 637 pump->ScheduleWork(); | |
| 638 return true; | |
| 639 } | 528 } |
| 640 | 529 |
| 641 //------------------------------------------------------------------------------ | 530 //------------------------------------------------------------------------------ |
| 642 // Method and data for histogramming events and actions taken by each instance | 531 // Method and data for histogramming events and actions taken by each instance |
| 643 // on each thread. | 532 // on each thread. |
| 644 | 533 |
| 645 void MessageLoop::StartHistogrammer() { | 534 void MessageLoop::StartHistogrammer() { |
| 646 #if !defined(OS_NACL) // NaCl build has no metrics code. | 535 #if !defined(OS_NACL) // NaCl build has no metrics code. |
| 647 if (enable_histogrammer_ && !message_histogram_ | 536 if (enable_histogrammer_ && !message_histogram_ |
| 648 && StatisticsRecorder::IsActive()) { | 537 && StatisticsRecorder::IsActive()) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 664 #endif | 553 #endif |
| 665 } | 554 } |
| 666 | 555 |
| 667 bool MessageLoop::DoWork() { | 556 bool MessageLoop::DoWork() { |
| 668 if (!nestable_tasks_allowed_) { | 557 if (!nestable_tasks_allowed_) { |
| 669 // Task can't be executed right now. | 558 // Task can't be executed right now. |
| 670 return false; | 559 return false; |
| 671 } | 560 } |
| 672 | 561 |
| 673 for (;;) { | 562 for (;;) { |
| 674 ReloadWorkQueue(); | 563 message_loop_proxy_->ReloadWorkQueue(&work_queue_); |
| 675 if (work_queue_.empty()) | 564 if (work_queue_.empty()) |
| 676 break; | 565 break; |
| 677 | 566 |
| 678 // Execute oldest task. | 567 // Execute oldest task. |
| 679 do { | 568 do { |
| 680 PendingTask pending_task = work_queue_.front(); | 569 PendingTask pending_task = work_queue_.front(); |
| 681 work_queue_.pop(); | 570 work_queue_.pop(); |
| 682 if (!pending_task.delayed_run_time.is_null()) { | 571 if (!pending_task.delayed_run_time.is_null()) { |
| 683 AddToDelayedWorkQueue(pending_task); | 572 AddToDelayedWorkQueue(pending_task); |
| 684 // If we changed the topmost task, then it is time to reschedule. | 573 // If we changed the topmost task, then it is time to reschedule. |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 fd, | 714 fd, |
| 826 persistent, | 715 persistent, |
| 827 mode, | 716 mode, |
| 828 controller, | 717 controller, |
| 829 delegate); | 718 delegate); |
| 830 } | 719 } |
| 831 | 720 |
| 832 #endif | 721 #endif |
| 833 | 722 |
| 834 } // namespace base | 723 } // namespace base |
| OLD | NEW |