Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: trunk/src/base/message_loop/message_loop.cc

Issue 19737005: Revert 212948 "Made MessagePump a non-thread safe class." (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « trunk/src/base/message_loop/message_loop.h ('k') | trunk/src/base/message_loop/message_loop_proxy_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698