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

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

Issue 17567007: Made MessagePump a non-thread safe class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased 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"
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698