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