Chromium Code Reviews| 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" |
| 11 #include "base/debug/alias.h" | 11 #include "base/debug/alias.h" |
| 12 #include "base/debug/trace_event.h" | 12 #include "base/debug/trace_event.h" |
| 13 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
| 16 #include "base/message_loop/message_loop_proxy_impl.h" | |
| 17 #include "base/message_loop/message_pump_default.h" | 16 #include "base/message_loop/message_pump_default.h" |
| 18 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
| 19 #include "base/metrics/statistics_recorder.h" | 18 #include "base/metrics/statistics_recorder.h" |
| 20 #include "base/run_loop.h" | 19 #include "base/run_loop.h" |
| 21 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 20 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
| 22 #include "base/thread_task_runner_handle.h" | 21 #include "base/thread_task_runner_handle.h" |
| 23 #include "base/threading/thread_local.h" | 22 #include "base/threading/thread_local.h" |
| 24 #include "base/time/time.h" | 23 #include "base/time/time.h" |
| 25 #include "base/tracked_objects.h" | 24 #include "base/tracked_objects.h" |
| 26 | 25 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) | 81 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) |
| 83 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) | 82 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) |
| 84 | 83 |
| 85 {-1, NULL} // The list must be null terminated, per API to histogram. | 84 {-1, NULL} // The list must be null terminated, per API to histogram. |
| 86 }; | 85 }; |
| 87 | 86 |
| 88 bool enable_histogrammer_ = false; | 87 bool enable_histogrammer_ = false; |
| 89 | 88 |
| 90 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; | 89 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; |
| 91 | 90 |
| 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 // Returns true if MessagePump::ScheduleWork() must be called one | 91 // Returns true if MessagePump::ScheduleWork() must be called one |
| 101 // time for every task that is added to the MessageLoop incoming queue. | 92 // time for every task that is added to the MessageLoop incoming queue. |
| 102 bool AlwaysNotifyPump(MessageLoop::Type type) { | 93 bool AlwaysNotifyPump(MessageLoop::Type type) { |
| 103 #if defined(OS_ANDROID) | 94 #if defined(OS_ANDROID) |
| 104 return type == MessageLoop::TYPE_UI; | 95 return type == MessageLoop::TYPE_UI; |
| 105 #else | 96 #else |
| 106 return false; | 97 return false; |
| 107 #endif | 98 #endif |
| 108 } | 99 } |
| 109 | 100 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 139 MessageLoop::TaskObserver::~TaskObserver() { | 130 MessageLoop::TaskObserver::~TaskObserver() { |
| 140 } | 131 } |
| 141 | 132 |
| 142 MessageLoop::DestructionObserver::~DestructionObserver() { | 133 MessageLoop::DestructionObserver::~DestructionObserver() { |
| 143 } | 134 } |
| 144 | 135 |
| 145 //------------------------------------------------------------------------------ | 136 //------------------------------------------------------------------------------ |
| 146 | 137 |
| 147 MessageLoop::MessageLoop(Type type) | 138 MessageLoop::MessageLoop(Type type) |
| 148 : type_(type), | 139 : type_(type), |
| 140 exception_restoration_(false), | |
| 149 nestable_tasks_allowed_(true), | 141 nestable_tasks_allowed_(true), |
| 150 exception_restoration_(false), | |
| 151 message_histogram_(NULL), | |
| 152 run_loop_(NULL), | |
| 153 #if defined(OS_WIN) | 142 #if defined(OS_WIN) |
| 154 os_modal_loop_(false), | 143 os_modal_loop_(false), |
| 155 #endif // OS_WIN | 144 #endif // OS_WIN |
| 156 next_sequence_num_(0) { | 145 message_histogram_(NULL), |
| 146 run_loop_(NULL) { | |
| 157 DCHECK(!current()) << "should only have one message loop per thread"; | 147 DCHECK(!current()) << "should only have one message loop per thread"; |
| 158 lazy_tls_ptr.Pointer()->Set(this); | 148 lazy_tls_ptr.Pointer()->Set(this); |
| 159 | 149 |
| 160 message_loop_proxy_ = new MessageLoopProxyImpl(); | 150 incoming_task_queue_ = new internal::IncomingTaskQueue(this); |
| 151 message_loop_proxy_ = | |
| 152 new internal::MessageLoopProxyImpl(incoming_task_queue_); | |
| 161 thread_task_runner_handle_.reset( | 153 thread_task_runner_handle_.reset( |
| 162 new ThreadTaskRunnerHandle(message_loop_proxy_)); | 154 new ThreadTaskRunnerHandle(message_loop_proxy_)); |
| 163 | 155 |
| 164 // TODO(rvargas): Get rid of the OS guards. | 156 // TODO(rvargas): Get rid of the OS guards. |
| 165 #if defined(OS_WIN) | 157 #if defined(OS_WIN) |
| 166 #define MESSAGE_PUMP_UI new MessagePumpForUI() | 158 #define MESSAGE_PUMP_UI new MessagePumpForUI() |
| 167 #define MESSAGE_PUMP_IO new MessagePumpForIO() | 159 #define MESSAGE_PUMP_IO new MessagePumpForIO() |
| 168 #elif defined(OS_IOS) | 160 #elif defined(OS_IOS) |
| 169 #define MESSAGE_PUMP_UI MessagePumpMac::Create() | 161 #define MESSAGE_PUMP_UI MessagePumpMac::Create() |
| 170 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() | 162 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() |
| 171 #elif defined(OS_MACOSX) | 163 #elif defined(OS_MACOSX) |
| 172 #define MESSAGE_PUMP_UI MessagePumpMac::Create() | 164 #define MESSAGE_PUMP_UI MessagePumpMac::Create() |
| 173 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | 165 #define MESSAGE_PUMP_IO new MessagePumpLibevent() |
| 174 #elif defined(OS_NACL) | 166 #elif defined(OS_NACL) |
| 175 // Currently NaCl doesn't have a UI MessageLoop. | 167 // Currently NaCl doesn't have a UI MessageLoop. |
| 176 // TODO(abarth): Figure out if we need this. | 168 // TODO(abarth): Figure out if we need this. |
| 177 #define MESSAGE_PUMP_UI NULL | 169 #define MESSAGE_PUMP_UI NULL |
| 178 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and | 170 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and |
| 179 // doesn't require extra support for watching file descriptors. | 171 // doesn't require extra support for watching file descriptors. |
| 180 #define MESSAGE_PUMP_IO new MessagePumpDefault(); | 172 #define MESSAGE_PUMP_IO new MessagePumpDefault() |
| 181 #elif defined(OS_POSIX) // POSIX but not MACOSX. | 173 #elif defined(OS_POSIX) // POSIX but not MACOSX. |
| 182 #define MESSAGE_PUMP_UI new MessagePumpForUI() | 174 #define MESSAGE_PUMP_UI new MessagePumpForUI() |
| 183 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | 175 #define MESSAGE_PUMP_IO new MessagePumpLibevent() |
| 184 #else | 176 #else |
| 185 #error Not implemented | 177 #error Not implemented |
| 186 #endif | 178 #endif |
| 187 | 179 |
| 188 if (type_ == TYPE_UI) { | 180 if (type_ == TYPE_UI) { |
| 189 if (message_pump_for_ui_factory_) | 181 if (message_pump_for_ui_factory_) |
| 190 pump_ = message_pump_for_ui_factory_(); | 182 pump_.reset(message_pump_for_ui_factory_()); |
| 191 else | 183 else |
| 192 pump_ = MESSAGE_PUMP_UI; | 184 pump_.reset(MESSAGE_PUMP_UI); |
| 193 } else if (type_ == TYPE_IO) { | 185 } else if (type_ == TYPE_IO) { |
| 194 pump_ = MESSAGE_PUMP_IO; | 186 pump_.reset(MESSAGE_PUMP_IO); |
| 195 } else { | 187 } else { |
| 196 DCHECK_EQ(TYPE_DEFAULT, type_); | 188 DCHECK_EQ(TYPE_DEFAULT, type_); |
| 197 pump_ = new MessagePumpDefault(); | 189 pump_.reset(new MessagePumpDefault()); |
| 198 } | 190 } |
| 199 } | 191 } |
| 200 | 192 |
| 201 MessageLoop::~MessageLoop() { | 193 MessageLoop::~MessageLoop() { |
| 202 DCHECK_EQ(this, current()); | 194 DCHECK_EQ(this, current()); |
| 203 | 195 |
| 204 DCHECK(!run_loop_); | 196 DCHECK(!run_loop_); |
| 205 | 197 |
| 206 // Clean up any unprocessed tasks, but take care: deleting a task could | 198 // Clean up any unprocessed tasks, but take care: deleting a task could |
| 207 // result in the addition of more tasks (e.g., via DeleteSoon). We set a | 199 // result in the addition of more tasks (e.g., via DeleteSoon). We set a |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 219 break; | 211 break; |
| 220 } | 212 } |
| 221 DCHECK(!did_work); | 213 DCHECK(!did_work); |
| 222 | 214 |
| 223 // Let interested parties have one last shot at accessing this. | 215 // Let interested parties have one last shot at accessing this. |
| 224 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, | 216 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, |
| 225 WillDestroyCurrentMessageLoop()); | 217 WillDestroyCurrentMessageLoop()); |
| 226 | 218 |
| 227 thread_task_runner_handle_.reset(); | 219 thread_task_runner_handle_.reset(); |
| 228 | 220 |
| 229 // Tell the message_loop_proxy that we are dying. | 221 // Tell the incoming queue that we are dying. |
| 230 static_cast<MessageLoopProxyImpl*>(message_loop_proxy_.get())-> | 222 incoming_task_queue_->WillDestroyCurrentMessageLoop(); |
| 231 WillDestroyCurrentMessageLoop(); | 223 incoming_task_queue_ = NULL; |
| 232 message_loop_proxy_ = NULL; | 224 message_loop_proxy_ = NULL; |
| 233 | 225 |
| 234 // OK, now make it so that no one can find us. | 226 // OK, now make it so that no one can find us. |
| 235 lazy_tls_ptr.Pointer()->Set(NULL); | 227 lazy_tls_ptr.Pointer()->Set(NULL); |
| 236 | |
| 237 #if defined(OS_WIN) | |
| 238 // If we left the high-resolution timer activated, deactivate it now. | |
| 239 // Doing this is not-critical, it is mainly to make sure we track | |
| 240 // the high resolution timer activations properly in our unit tests. | |
| 241 if (!high_resolution_timer_expiration_.is_null()) { | |
| 242 Time::ActivateHighResolutionTimer(false); | |
| 243 high_resolution_timer_expiration_ = TimeTicks(); | |
| 244 } | |
| 245 #endif | |
| 246 } | 228 } |
| 247 | 229 |
| 248 // static | 230 // static |
| 249 MessageLoop* MessageLoop::current() { | 231 MessageLoop* MessageLoop::current() { |
| 250 // TODO(darin): sadly, we cannot enable this yet since people call us even | 232 // TODO(darin): sadly, we cannot enable this yet since people call us even |
| 251 // when they have no intention of using us. | 233 // when they have no intention of using us. |
| 252 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; | 234 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; |
| 253 return lazy_tls_ptr.Pointer()->Get(); | 235 return lazy_tls_ptr.Pointer()->Get(); |
| 254 } | 236 } |
| 255 | 237 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 276 void MessageLoop::RemoveDestructionObserver( | 258 void MessageLoop::RemoveDestructionObserver( |
| 277 DestructionObserver* destruction_observer) { | 259 DestructionObserver* destruction_observer) { |
| 278 DCHECK_EQ(this, current()); | 260 DCHECK_EQ(this, current()); |
| 279 destruction_observers_.RemoveObserver(destruction_observer); | 261 destruction_observers_.RemoveObserver(destruction_observer); |
| 280 } | 262 } |
| 281 | 263 |
| 282 void MessageLoop::PostTask( | 264 void MessageLoop::PostTask( |
| 283 const tracked_objects::Location& from_here, | 265 const tracked_objects::Location& from_here, |
| 284 const Closure& task) { | 266 const Closure& task) { |
| 285 DCHECK(!task.is_null()) << from_here.ToString(); | 267 DCHECK(!task.is_null()) << from_here.ToString(); |
| 286 PendingTask pending_task( | 268 incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true); |
| 287 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
| 288 AddToIncomingQueue(&pending_task, false); | |
| 289 } | 269 } |
| 290 | 270 |
| 291 bool MessageLoop::TryPostTask( | 271 bool MessageLoop::TryPostTask( |
| 292 const tracked_objects::Location& from_here, | 272 const tracked_objects::Location& from_here, |
| 293 const Closure& task) { | 273 const Closure& task) { |
| 294 DCHECK(!task.is_null()) << from_here.ToString(); | 274 DCHECK(!task.is_null()) << from_here.ToString(); |
| 295 PendingTask pending_task( | 275 return incoming_task_queue_->TryAddToIncomingQueue(from_here, task); |
| 296 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
| 297 return AddToIncomingQueue(&pending_task, true); | |
| 298 } | 276 } |
| 299 | 277 |
| 300 void MessageLoop::PostDelayedTask( | 278 void MessageLoop::PostDelayedTask( |
| 301 const tracked_objects::Location& from_here, | 279 const tracked_objects::Location& from_here, |
| 302 const Closure& task, | 280 const Closure& task, |
| 303 TimeDelta delay) { | 281 TimeDelta delay) { |
| 304 DCHECK(!task.is_null()) << from_here.ToString(); | 282 DCHECK(!task.is_null()) << from_here.ToString(); |
| 305 PendingTask pending_task( | 283 incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true); |
| 306 from_here, task, CalculateDelayedRuntime(delay), true); | |
| 307 AddToIncomingQueue(&pending_task, false); | |
| 308 } | 284 } |
| 309 | 285 |
| 310 void MessageLoop::PostNonNestableTask( | 286 void MessageLoop::PostNonNestableTask( |
| 311 const tracked_objects::Location& from_here, | 287 const tracked_objects::Location& from_here, |
| 312 const Closure& task) { | 288 const Closure& task) { |
| 313 DCHECK(!task.is_null()) << from_here.ToString(); | 289 DCHECK(!task.is_null()) << from_here.ToString(); |
| 314 PendingTask pending_task( | 290 incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false); |
| 315 from_here, task, CalculateDelayedRuntime(TimeDelta()), false); | |
| 316 AddToIncomingQueue(&pending_task, false); | |
| 317 } | 291 } |
| 318 | 292 |
| 319 void MessageLoop::PostNonNestableDelayedTask( | 293 void MessageLoop::PostNonNestableDelayedTask( |
| 320 const tracked_objects::Location& from_here, | 294 const tracked_objects::Location& from_here, |
| 321 const Closure& task, | 295 const Closure& task, |
| 322 TimeDelta delay) { | 296 TimeDelta delay) { |
| 323 DCHECK(!task.is_null()) << from_here.ToString(); | 297 DCHECK(!task.is_null()) << from_here.ToString(); |
| 324 PendingTask pending_task( | 298 incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false); |
| 325 from_here, task, CalculateDelayedRuntime(delay), false); | |
| 326 AddToIncomingQueue(&pending_task, false); | |
| 327 } | 299 } |
| 328 | 300 |
| 329 void MessageLoop::Run() { | 301 void MessageLoop::Run() { |
| 330 RunLoop run_loop; | 302 RunLoop run_loop; |
| 331 run_loop.Run(); | 303 run_loop.Run(); |
| 332 } | 304 } |
| 333 | 305 |
| 334 void MessageLoop::RunUntilIdle() { | 306 void MessageLoop::RunUntilIdle() { |
| 335 RunLoop run_loop; | 307 RunLoop run_loop; |
| 336 run_loop.RunUntilIdle(); | 308 run_loop.RunUntilIdle(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 388 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { | 360 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { |
| 389 DCHECK_EQ(this, current()); | 361 DCHECK_EQ(this, current()); |
| 390 task_observers_.AddObserver(task_observer); | 362 task_observers_.AddObserver(task_observer); |
| 391 } | 363 } |
| 392 | 364 |
| 393 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { | 365 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { |
| 394 DCHECK_EQ(this, current()); | 366 DCHECK_EQ(this, current()); |
| 395 task_observers_.RemoveObserver(task_observer); | 367 task_observers_.RemoveObserver(task_observer); |
| 396 } | 368 } |
| 397 | 369 |
| 398 void MessageLoop::AssertIdle() const { | |
| 399 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. | |
| 400 AutoLock lock(incoming_queue_lock_); | |
| 401 DCHECK(incoming_queue_.empty()); | |
| 402 } | |
| 403 | |
| 404 bool MessageLoop::is_running() const { | 370 bool MessageLoop::is_running() const { |
| 405 DCHECK_EQ(this, current()); | 371 DCHECK_EQ(this, current()); |
| 406 return run_loop_ != NULL; | 372 return run_loop_ != NULL; |
| 407 } | 373 } |
| 408 | 374 |
| 375 bool MessageLoop::IsHighResolutionTimerEnabledForTesting() { | |
| 376 return incoming_task_queue_->IsHighResolutionTimerEnabledForTesting(); | |
| 377 } | |
| 378 | |
| 379 bool MessageLoop::IsIdleForTesting() { | |
| 380 // We only check the imcoming queue|, since we don't want to lock the work | |
| 381 // queue. | |
| 382 return incoming_task_queue_->IsIdleForTesting(); | |
| 383 } | |
| 384 | |
| 385 void MessageLoop::LockWaitUnLockForTesting(WaitableEvent* caller_wait, | |
| 386 WaitableEvent* caller_signal) { | |
| 387 incoming_task_queue_->LockWaitUnLockForTesting(caller_wait, caller_signal); | |
| 388 } | |
| 389 | |
| 409 //------------------------------------------------------------------------------ | 390 //------------------------------------------------------------------------------ |
| 410 | 391 |
| 411 // Runs the loop in two different SEH modes: | 392 // Runs the loop in two different SEH modes: |
| 412 // enable_SEH_restoration_ = false : any unhandled exception goes to the last | 393 // enable_SEH_restoration_ = false : any unhandled exception goes to the last |
| 413 // one that calls SetUnhandledExceptionFilter(). | 394 // one that calls SetUnhandledExceptionFilter(). |
| 414 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter | 395 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter |
| 415 // that was existed before the loop was run. | 396 // that was existed before the loop was run. |
| 416 void MessageLoop::RunHandler() { | 397 void MessageLoop::RunHandler() { |
| 417 #if defined(OS_WIN) | 398 #if defined(OS_WIN) |
| 418 if (exception_restoration_) { | 399 if (exception_restoration_) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 463 | 444 |
| 464 RunTask(pending_task); | 445 RunTask(pending_task); |
| 465 return true; | 446 return true; |
| 466 } | 447 } |
| 467 | 448 |
| 468 void MessageLoop::RunTask(const PendingTask& pending_task) { | 449 void MessageLoop::RunTask(const PendingTask& pending_task) { |
| 469 tracked_objects::TrackedTime start_time = | 450 tracked_objects::TrackedTime start_time = |
| 470 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); | 451 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); |
| 471 | 452 |
| 472 TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask", | 453 TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask", |
| 473 TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this)), | 454 TRACE_ID_MANGLE(GetTaskTraceID(pending_task)), |
| 474 "queue_duration", | 455 "queue_duration", |
| 475 (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); | 456 (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); |
| 476 TRACE_EVENT2("task", "MessageLoop::RunTask", | 457 TRACE_EVENT2("task", "MessageLoop::RunTask", |
| 477 "src_file", pending_task.posted_from.file_name(), | 458 "src_file", pending_task.posted_from.file_name(), |
| 478 "src_func", pending_task.posted_from.function_name()); | 459 "src_func", pending_task.posted_from.function_name()); |
| 479 | 460 |
| 480 DCHECK(nestable_tasks_allowed_); | 461 DCHECK(nestable_tasks_allowed_); |
| 481 // Execute the task and assume the worst: It is probably not reentrant. | 462 // Execute the task and assume the worst: It is probably not reentrant. |
| 482 nestable_tasks_allowed_ = false; | 463 nestable_tasks_allowed_ = false; |
| 483 | 464 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 516 // and the task isn't nestable. | 497 // and the task isn't nestable. |
| 517 deferred_non_nestable_work_queue_.push(pending_task); | 498 deferred_non_nestable_work_queue_.push(pending_task); |
| 518 return false; | 499 return false; |
| 519 } | 500 } |
| 520 | 501 |
| 521 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { | 502 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { |
| 522 // Move to the delayed work queue. | 503 // Move to the delayed work queue. |
| 523 delayed_work_queue_.push(pending_task); | 504 delayed_work_queue_.push(pending_task); |
| 524 } | 505 } |
| 525 | 506 |
| 526 void MessageLoop::ReloadWorkQueue() { | |
| 527 // We can improve performance of our loading tasks from incoming_queue_ to | |
| 528 // work_queue_ by waiting until the last minute (work_queue_ is empty) to | |
| 529 // load. That reduces the number of locks-per-task significantly when our | |
| 530 // queues get large. | |
| 531 if (!work_queue_.empty()) | |
| 532 return; // Wait till we *really* need to lock and load. | |
| 533 | |
| 534 // Acquire all we can from the inter-thread queue with one lock acquisition. | |
| 535 { | |
| 536 AutoLock lock(incoming_queue_lock_); | |
| 537 if (incoming_queue_.empty()) | |
| 538 return; | |
| 539 incoming_queue_.Swap(&work_queue_); // Constant time | |
| 540 DCHECK(incoming_queue_.empty()); | |
| 541 } | |
| 542 } | |
| 543 | |
| 544 bool MessageLoop::DeletePendingTasks() { | 507 bool MessageLoop::DeletePendingTasks() { |
| 545 bool did_work = !work_queue_.empty(); | 508 bool did_work = !work_queue_.empty(); |
| 546 while (!work_queue_.empty()) { | 509 while (!work_queue_.empty()) { |
| 547 PendingTask pending_task = work_queue_.front(); | 510 PendingTask pending_task = work_queue_.front(); |
| 548 work_queue_.pop(); | 511 work_queue_.pop(); |
| 549 if (!pending_task.delayed_run_time.is_null()) { | 512 if (!pending_task.delayed_run_time.is_null()) { |
| 550 // We want to delete delayed tasks in the same order in which they would | 513 // We want to delete delayed tasks in the same order in which they would |
| 551 // normally be deleted in case of any funny dependencies between delayed | 514 // normally be deleted in case of any funny dependencies between delayed |
| 552 // tasks. | 515 // tasks. |
| 553 AddToDelayedWorkQueue(pending_task); | 516 AddToDelayedWorkQueue(pending_task); |
| 554 } | 517 } |
| 555 } | 518 } |
| 556 did_work |= !deferred_non_nestable_work_queue_.empty(); | 519 did_work |= !deferred_non_nestable_work_queue_.empty(); |
| 557 while (!deferred_non_nestable_work_queue_.empty()) { | 520 while (!deferred_non_nestable_work_queue_.empty()) { |
| 558 deferred_non_nestable_work_queue_.pop(); | 521 deferred_non_nestable_work_queue_.pop(); |
| 559 } | 522 } |
| 560 did_work |= !delayed_work_queue_.empty(); | 523 did_work |= !delayed_work_queue_.empty(); |
| 561 | 524 |
| 562 // Historically, we always delete the task regardless of valgrind status. It's | 525 // Historically, we always delete the task regardless of valgrind status. It's |
| 563 // not completely clear why we want to leak them in the loops above. This | 526 // not completely clear why we want to leak them in the loops above. This |
| 564 // code is replicating legacy behavior, and should not be considered | 527 // code is replicating legacy behavior, and should not be considered |
| 565 // absolutely "correct" behavior. See TODO above about deleting all tasks | 528 // absolutely "correct" behavior. See TODO above about deleting all tasks |
| 566 // when it's safe. | 529 // when it's safe. |
| 567 while (!delayed_work_queue_.empty()) { | 530 while (!delayed_work_queue_.empty()) { |
| 568 delayed_work_queue_.pop(); | 531 delayed_work_queue_.pop(); |
| 569 } | 532 } |
| 570 return did_work; | 533 return did_work; |
| 571 } | 534 } |
| 572 | 535 |
| 573 TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) { | 536 uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) { |
| 574 TimeTicks delayed_run_time; | 537 return (static_cast<uint64>(task.sequence_num) << 32) | |
| 575 if (delay > TimeDelta()) { | 538 static_cast<uint64>(reinterpret_cast<intptr_t>(this)); |
| 576 delayed_run_time = TimeTicks::Now() + delay; | |
| 577 | |
| 578 #if defined(OS_WIN) | |
| 579 if (high_resolution_timer_expiration_.is_null()) { | |
| 580 // Windows timers are granular to 15.6ms. If we only set high-res | |
| 581 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, | |
| 582 // which as a percentage is pretty inaccurate. So enable high | |
| 583 // res timers for any timer which is within 2x of the granularity. | |
| 584 // This is a tradeoff between accuracy and power management. | |
| 585 bool needs_high_res_timers = delay.InMilliseconds() < | |
| 586 (2 * Time::kMinLowResolutionThresholdMs); | |
| 587 if (needs_high_res_timers) { | |
| 588 if (Time::ActivateHighResolutionTimer(true)) { | |
| 589 high_resolution_timer_expiration_ = TimeTicks::Now() + | |
| 590 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs); | |
| 591 } | |
| 592 } | |
| 593 } | |
| 594 #endif | |
| 595 } else { | |
| 596 DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; | |
| 597 } | |
| 598 | |
| 599 #if defined(OS_WIN) | |
| 600 if (!high_resolution_timer_expiration_.is_null()) { | |
| 601 if (TimeTicks::Now() > high_resolution_timer_expiration_) { | |
| 602 Time::ActivateHighResolutionTimer(false); | |
| 603 high_resolution_timer_expiration_ = TimeTicks(); | |
| 604 } | |
| 605 } | |
| 606 #endif | |
| 607 | |
| 608 return delayed_run_time; | |
| 609 } | 539 } |
| 610 | 540 |
| 611 // Possibly called on a background thread! | 541 void MessageLoop::ReloadWorkQueue() { |
| 612 bool MessageLoop::AddToIncomingQueue(PendingTask* pending_task, | 542 // We can improve performance of our loading tasks from the incoming queue to |
| 613 bool use_try_lock) { | 543 // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to |
| 614 // Warning: Don't try to short-circuit, and handle this thread's tasks more | 544 // load. That reduces the number of locks-per-task significantly when our |
| 615 // directly, as it could starve handling of foreign threads. Put every task | 545 // queues get large. |
| 616 // into this queue. | 546 if (work_queue_.empty()) |
| 547 incoming_task_queue_->ReloadWorkQueue(&work_queue_); | |
| 548 } | |
| 617 | 549 |
| 618 scoped_refptr<MessagePump> pump; | 550 void MessageLoop::ScheduleWork(bool was_empty) { |
|
jar1
2013/07/29 23:30:50
This is (I think) where you forward the call while
| |
| 619 { | 551 // The Android UI message loop needs to get notified each time |
| 620 if (use_try_lock) { | 552 // a task is added to the incoming queue. |
| 621 if (!incoming_queue_lock_.Try()) { | 553 if (was_empty || AlwaysNotifyPump(type_)) |
| 622 pending_task->task.Reset(); | 554 pump_->ScheduleWork(); |
| 623 return false; | |
| 624 } | |
| 625 } else { | |
| 626 incoming_queue_lock_.Acquire(); | |
| 627 } | |
| 628 AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired()); | |
|
jar1
2013/07/29 23:30:50
It is very important when using locks to hold them
alexeypa (please no reviews)
2013/07/30 00:31:13
Yes, I know. Unfortunately that caused a race down
| |
| 629 // Initialize the sequence number. The sequence number is used for delayed | |
| 630 // tasks (to faciliate FIFO sorting when two tasks have the same | |
| 631 // delayed_run_time value) and for identifying the task in about:tracing. | |
| 632 pending_task->sequence_num = next_sequence_num_++; | |
| 633 | |
| 634 TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", | |
| 635 TRACE_ID_MANGLE(GetTaskTraceID(*pending_task, this))); | |
| 636 | |
| 637 bool was_empty = incoming_queue_.empty(); | |
| 638 incoming_queue_.push(*pending_task); | |
| 639 pending_task->task.Reset(); | |
| 640 // The Android UI message loop needs to get notified each time | |
| 641 // a task is added to the incoming queue. | |
| 642 if (!was_empty && !AlwaysNotifyPump(type_)) | |
| 643 return true; // Someone else should have started the sub-pump. | |
| 644 | |
| 645 pump = pump_; | |
| 646 } | |
| 647 // Since the incoming_queue_ may contain a task that destroys this message | |
| 648 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. | |
| 649 // We use a stack-based reference to the message pump so that we can call | |
| 650 // ScheduleWork outside of incoming_queue_lock_. | |
| 651 | |
| 652 pump->ScheduleWork(); | |
| 653 return true; | |
| 654 } | 555 } |
| 655 | 556 |
| 656 //------------------------------------------------------------------------------ | 557 //------------------------------------------------------------------------------ |
| 657 // Method and data for histogramming events and actions taken by each instance | 558 // Method and data for histogramming events and actions taken by each instance |
| 658 // on each thread. | 559 // on each thread. |
| 659 | 560 |
| 660 void MessageLoop::StartHistogrammer() { | 561 void MessageLoop::StartHistogrammer() { |
| 661 #if !defined(OS_NACL) // NaCl build has no metrics code. | 562 #if !defined(OS_NACL) // NaCl build has no metrics code. |
| 662 if (enable_histogrammer_ && !message_histogram_ | 563 if (enable_histogrammer_ && !message_histogram_ |
| 663 && StatisticsRecorder::IsActive()) { | 564 && StatisticsRecorder::IsActive()) { |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 840 fd, | 741 fd, |
| 841 persistent, | 742 persistent, |
| 842 mode, | 743 mode, |
| 843 controller, | 744 controller, |
| 844 delegate); | 745 delegate); |
| 845 } | 746 } |
| 846 | 747 |
| 847 #endif | 748 #endif |
| 848 | 749 |
| 849 } // namespace base | 750 } // namespace base |
| OLD | NEW |