OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/message_loop.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/compiler_specific.h" | |
11 #include "base/debug/alias.h" | |
12 #include "base/debug/trace_event.h" | |
13 #include "base/lazy_instance.h" | |
14 #include "base/logging.h" | |
15 #include "base/memory/scoped_ptr.h" | |
16 #include "base/message_loop/message_loop_proxy_impl.h" | |
17 #include "base/message_pump_default.h" | |
18 #include "base/metrics/histogram.h" | |
19 #include "base/metrics/statistics_recorder.h" | |
20 #include "base/run_loop.h" | |
21 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | |
22 #include "base/thread_task_runner_handle.h" | |
23 #include "base/threading/thread_local.h" | |
24 #include "base/time.h" | |
25 #include "base/tracked_objects.h" | |
26 | |
27 #if defined(OS_MACOSX) | |
28 #include "base/message_pump_mac.h" | |
29 #endif | |
30 #if defined(OS_POSIX) && !defined(OS_IOS) | |
31 #include "base/message_pump_libevent.h" | |
32 #endif | |
33 #if defined(OS_ANDROID) | |
34 #include "base/message_pump_android.h" | |
35 #endif | |
36 | |
37 #if defined(TOOLKIT_GTK) | |
38 #include <gdk/gdk.h> | |
39 #include <gdk/gdkx.h> | |
40 #endif | |
41 | |
42 namespace base { | |
43 | |
44 namespace { | |
45 | |
46 // A lazily created thread local storage for quick access to a thread's message | |
47 // loop, if one exists. This should be safe and free of static constructors. | |
48 LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr = | |
49 LAZY_INSTANCE_INITIALIZER; | |
50 | |
51 // Logical events for Histogram profiling. Run with -message-loop-histogrammer | |
52 // to get an accounting of messages and actions taken on each thread. | |
53 const int kTaskRunEvent = 0x1; | |
54 const int kTimerEvent = 0x2; | |
55 | |
56 // Provide range of message IDs for use in histogramming and debug display. | |
57 const int kLeastNonZeroMessageId = 1; | |
58 const int kMaxMessageId = 1099; | |
59 const int kNumberOfDistinctMessagesDisplayed = 1100; | |
60 | |
61 // Provide a macro that takes an expression (such as a constant, or macro | |
62 // constant) and creates a pair to initalize an array of pairs. In this case, | |
63 // our pair consists of the expressions value, and the "stringized" version | |
64 // of the expression (i.e., the exrpression put in quotes). For example, if | |
65 // we have: | |
66 // #define FOO 2 | |
67 // #define BAR 5 | |
68 // then the following: | |
69 // VALUE_TO_NUMBER_AND_NAME(FOO + BAR) | |
70 // will expand to: | |
71 // {7, "FOO + BAR"} | |
72 // We use the resulting array as an argument to our histogram, which reads the | |
73 // number as a bucket identifier, and proceeds to use the corresponding name | |
74 // in the pair (i.e., the quoted string) when printing out a histogram. | |
75 #define VALUE_TO_NUMBER_AND_NAME(name) {name, #name}, | |
76 | |
77 const LinearHistogram::DescriptionPair event_descriptions_[] = { | |
78 // Provide some pretty print capability in our histogram for our internal | |
79 // messages. | |
80 | |
81 // A few events we handle (kindred to messages), and used to profile actions. | |
82 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) | |
83 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) | |
84 | |
85 {-1, NULL} // The list must be null terminated, per API to histogram. | |
86 }; | |
87 | |
88 bool enable_histogrammer_ = false; | |
89 | |
90 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; | |
91 | |
92 // Create a process-wide unique ID to represent this task in trace events. This | |
93 // will be mangled with a Process ID hash to reduce the likelyhood of colliding | |
94 // with MessageLoop pointers on other processes. | |
95 uint64 GetTaskTraceID(const PendingTask& task, MessageLoop* loop) { | |
96 return (static_cast<uint64>(task.sequence_num) << 32) | | |
97 static_cast<uint64>(reinterpret_cast<intptr_t>(loop)); | |
98 } | |
99 | |
100 } // namespace | |
101 | |
102 //------------------------------------------------------------------------------ | |
103 | |
104 #if defined(OS_WIN) | |
105 | |
106 // Upon a SEH exception in this thread, it restores the original unhandled | |
107 // exception filter. | |
108 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { | |
109 ::SetUnhandledExceptionFilter(old_filter); | |
110 return EXCEPTION_CONTINUE_SEARCH; | |
111 } | |
112 | |
113 // Retrieves a pointer to the current unhandled exception filter. There | |
114 // is no standalone getter method. | |
115 static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() { | |
116 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL; | |
117 top_filter = ::SetUnhandledExceptionFilter(0); | |
118 ::SetUnhandledExceptionFilter(top_filter); | |
119 return top_filter; | |
120 } | |
121 | |
122 #endif // defined(OS_WIN) | |
123 | |
124 //------------------------------------------------------------------------------ | |
125 | |
126 MessageLoop::TaskObserver::TaskObserver() { | |
127 } | |
128 | |
129 MessageLoop::TaskObserver::~TaskObserver() { | |
130 } | |
131 | |
132 MessageLoop::DestructionObserver::~DestructionObserver() { | |
133 } | |
134 | |
135 //------------------------------------------------------------------------------ | |
136 | |
137 MessageLoop::MessageLoop(Type type) | |
138 : type_(type), | |
139 nestable_tasks_allowed_(true), | |
140 exception_restoration_(false), | |
141 message_histogram_(NULL), | |
142 run_loop_(NULL), | |
143 #if defined(OS_WIN) | |
144 os_modal_loop_(false), | |
145 #endif // OS_WIN | |
146 next_sequence_num_(0) { | |
147 DCHECK(!current()) << "should only have one message loop per thread"; | |
148 lazy_tls_ptr.Pointer()->Set(this); | |
149 | |
150 message_loop_proxy_ = new MessageLoopProxyImpl(); | |
151 thread_task_runner_handle_.reset( | |
152 new ThreadTaskRunnerHandle(message_loop_proxy_)); | |
153 | |
154 // TODO(rvargas): Get rid of the OS guards. | |
155 #if defined(OS_WIN) | |
156 #define MESSAGE_PUMP_UI new MessagePumpForUI() | |
157 #define MESSAGE_PUMP_IO new MessagePumpForIO() | |
158 #elif defined(OS_IOS) | |
159 #define MESSAGE_PUMP_UI MessagePumpMac::Create() | |
160 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() | |
161 #elif defined(OS_MACOSX) | |
162 #define MESSAGE_PUMP_UI MessagePumpMac::Create() | |
163 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | |
164 #elif defined(OS_NACL) | |
165 // Currently NaCl doesn't have a UI MessageLoop. | |
166 // TODO(abarth): Figure out if we need this. | |
167 #define MESSAGE_PUMP_UI NULL | |
168 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and | |
169 // doesn't require extra support for watching file descriptors. | |
170 #define MESSAGE_PUMP_IO new MessagePumpDefault(); | |
171 #elif defined(OS_POSIX) // POSIX but not MACOSX. | |
172 #define MESSAGE_PUMP_UI new MessagePumpForUI() | |
173 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | |
174 #else | |
175 #error Not implemented | |
176 #endif | |
177 | |
178 if (type_ == TYPE_UI) { | |
179 if (message_pump_for_ui_factory_) | |
180 pump_ = message_pump_for_ui_factory_(); | |
181 else | |
182 pump_ = MESSAGE_PUMP_UI; | |
183 } else if (type_ == TYPE_IO) { | |
184 pump_ = MESSAGE_PUMP_IO; | |
185 } else { | |
186 DCHECK_EQ(TYPE_DEFAULT, type_); | |
187 pump_ = new MessagePumpDefault(); | |
188 } | |
189 } | |
190 | |
191 MessageLoop::~MessageLoop() { | |
192 DCHECK_EQ(this, current()); | |
193 | |
194 DCHECK(!run_loop_); | |
195 | |
196 // Clean up any unprocessed tasks, but take care: deleting a task could | |
197 // result in the addition of more tasks (e.g., via DeleteSoon). We set a | |
198 // limit on the number of times we will allow a deleted task to generate more | |
199 // tasks. Normally, we should only pass through this loop once or twice. If | |
200 // we end up hitting the loop limit, then it is probably due to one task that | |
201 // is being stubborn. Inspect the queues to see who is left. | |
202 bool did_work; | |
203 for (int i = 0; i < 100; ++i) { | |
204 DeletePendingTasks(); | |
205 ReloadWorkQueue(); | |
206 // If we end up with empty queues, then break out of the loop. | |
207 did_work = DeletePendingTasks(); | |
208 if (!did_work) | |
209 break; | |
210 } | |
211 DCHECK(!did_work); | |
212 | |
213 // Let interested parties have one last shot at accessing this. | |
214 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, | |
215 WillDestroyCurrentMessageLoop()); | |
216 | |
217 thread_task_runner_handle_.reset(); | |
218 | |
219 // Tell the message_loop_proxy that we are dying. | |
220 static_cast<MessageLoopProxyImpl*>(message_loop_proxy_.get())-> | |
221 WillDestroyCurrentMessageLoop(); | |
222 message_loop_proxy_ = NULL; | |
223 | |
224 // OK, now make it so that no one can find us. | |
225 lazy_tls_ptr.Pointer()->Set(NULL); | |
226 | |
227 #if defined(OS_WIN) | |
228 // If we left the high-resolution timer activated, deactivate it now. | |
229 // Doing this is not-critical, it is mainly to make sure we track | |
230 // the high resolution timer activations properly in our unit tests. | |
231 if (!high_resolution_timer_expiration_.is_null()) { | |
232 Time::ActivateHighResolutionTimer(false); | |
233 high_resolution_timer_expiration_ = TimeTicks(); | |
234 } | |
235 #endif | |
236 } | |
237 | |
238 // static | |
239 MessageLoop* MessageLoop::current() { | |
240 // TODO(darin): sadly, we cannot enable this yet since people call us even | |
241 // when they have no intention of using us. | |
242 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; | |
243 return lazy_tls_ptr.Pointer()->Get(); | |
244 } | |
245 | |
246 // static | |
247 void MessageLoop::EnableHistogrammer(bool enable) { | |
248 enable_histogrammer_ = enable; | |
249 } | |
250 | |
251 // static | |
252 bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) { | |
253 if (message_pump_for_ui_factory_) | |
254 return false; | |
255 | |
256 message_pump_for_ui_factory_ = factory; | |
257 return true; | |
258 } | |
259 | |
260 void MessageLoop::AddDestructionObserver( | |
261 DestructionObserver* destruction_observer) { | |
262 DCHECK_EQ(this, current()); | |
263 destruction_observers_.AddObserver(destruction_observer); | |
264 } | |
265 | |
266 void MessageLoop::RemoveDestructionObserver( | |
267 DestructionObserver* destruction_observer) { | |
268 DCHECK_EQ(this, current()); | |
269 destruction_observers_.RemoveObserver(destruction_observer); | |
270 } | |
271 | |
272 void MessageLoop::PostTask( | |
273 const tracked_objects::Location& from_here, | |
274 const Closure& task) { | |
275 DCHECK(!task.is_null()) << from_here.ToString(); | |
276 PendingTask pending_task( | |
277 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
278 AddToIncomingQueue(&pending_task, false); | |
279 } | |
280 | |
281 bool MessageLoop::TryPostTask( | |
282 const tracked_objects::Location& from_here, | |
283 const Closure& task) { | |
284 DCHECK(!task.is_null()) << from_here.ToString(); | |
285 PendingTask pending_task( | |
286 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
287 return AddToIncomingQueue(&pending_task, true); | |
288 } | |
289 | |
290 void MessageLoop::PostDelayedTask( | |
291 const tracked_objects::Location& from_here, | |
292 const Closure& task, | |
293 TimeDelta delay) { | |
294 DCHECK(!task.is_null()) << from_here.ToString(); | |
295 PendingTask pending_task( | |
296 from_here, task, CalculateDelayedRuntime(delay), true); | |
297 AddToIncomingQueue(&pending_task, false); | |
298 } | |
299 | |
300 void MessageLoop::PostNonNestableTask( | |
301 const tracked_objects::Location& from_here, | |
302 const Closure& task) { | |
303 DCHECK(!task.is_null()) << from_here.ToString(); | |
304 PendingTask pending_task( | |
305 from_here, task, CalculateDelayedRuntime(TimeDelta()), false); | |
306 AddToIncomingQueue(&pending_task, false); | |
307 } | |
308 | |
309 void MessageLoop::PostNonNestableDelayedTask( | |
310 const tracked_objects::Location& from_here, | |
311 const Closure& task, | |
312 TimeDelta delay) { | |
313 DCHECK(!task.is_null()) << from_here.ToString(); | |
314 PendingTask pending_task( | |
315 from_here, task, CalculateDelayedRuntime(delay), false); | |
316 AddToIncomingQueue(&pending_task, false); | |
317 } | |
318 | |
319 void MessageLoop::Run() { | |
320 RunLoop run_loop; | |
321 run_loop.Run(); | |
322 } | |
323 | |
324 void MessageLoop::RunUntilIdle() { | |
325 RunLoop run_loop; | |
326 run_loop.RunUntilIdle(); | |
327 } | |
328 | |
329 void MessageLoop::QuitWhenIdle() { | |
330 DCHECK_EQ(this, current()); | |
331 if (run_loop_) { | |
332 run_loop_->quit_when_idle_received_ = true; | |
333 } else { | |
334 NOTREACHED() << "Must be inside Run to call Quit"; | |
335 } | |
336 } | |
337 | |
338 void MessageLoop::QuitNow() { | |
339 DCHECK_EQ(this, current()); | |
340 if (run_loop_) { | |
341 pump_->Quit(); | |
342 } else { | |
343 NOTREACHED() << "Must be inside Run to call Quit"; | |
344 } | |
345 } | |
346 | |
347 bool MessageLoop::IsType(Type type) const { | |
348 return type_ == type; | |
349 } | |
350 | |
351 static void QuitCurrentWhenIdle() { | |
352 MessageLoop::current()->QuitWhenIdle(); | |
353 } | |
354 | |
355 // static | |
356 Closure MessageLoop::QuitWhenIdleClosure() { | |
357 return Bind(&QuitCurrentWhenIdle); | |
358 } | |
359 | |
360 void MessageLoop::SetNestableTasksAllowed(bool allowed) { | |
361 if (nestable_tasks_allowed_ != allowed) { | |
362 nestable_tasks_allowed_ = allowed; | |
363 if (!nestable_tasks_allowed_) | |
364 return; | |
365 // Start the native pump if we are not already pumping. | |
366 pump_->ScheduleWork(); | |
367 } | |
368 } | |
369 | |
370 bool MessageLoop::NestableTasksAllowed() const { | |
371 return nestable_tasks_allowed_; | |
372 } | |
373 | |
374 bool MessageLoop::IsNested() { | |
375 return run_loop_->run_depth_ > 1; | |
376 } | |
377 | |
378 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { | |
379 DCHECK_EQ(this, current()); | |
380 task_observers_.AddObserver(task_observer); | |
381 } | |
382 | |
383 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { | |
384 DCHECK_EQ(this, current()); | |
385 task_observers_.RemoveObserver(task_observer); | |
386 } | |
387 | |
388 void MessageLoop::AssertIdle() const { | |
389 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. | |
390 AutoLock lock(incoming_queue_lock_); | |
391 DCHECK(incoming_queue_.empty()); | |
392 } | |
393 | |
394 bool MessageLoop::is_running() const { | |
395 DCHECK_EQ(this, current()); | |
396 return run_loop_ != NULL; | |
397 } | |
398 | |
399 //------------------------------------------------------------------------------ | |
400 | |
401 // Runs the loop in two different SEH modes: | |
402 // enable_SEH_restoration_ = false : any unhandled exception goes to the last | |
403 // one that calls SetUnhandledExceptionFilter(). | |
404 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter | |
405 // that was existed before the loop was run. | |
406 void MessageLoop::RunHandler() { | |
407 #if defined(OS_WIN) | |
408 if (exception_restoration_) { | |
409 RunInternalInSEHFrame(); | |
410 return; | |
411 } | |
412 #endif | |
413 | |
414 RunInternal(); | |
415 } | |
416 | |
417 #if defined(OS_WIN) | |
418 __declspec(noinline) void MessageLoop::RunInternalInSEHFrame() { | |
419 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter(); | |
420 __try { | |
421 RunInternal(); | |
422 } __except(SEHFilter(current_filter)) { | |
423 } | |
424 return; | |
425 } | |
426 #endif | |
427 | |
428 void MessageLoop::RunInternal() { | |
429 DCHECK_EQ(this, current()); | |
430 | |
431 StartHistogrammer(); | |
432 | |
433 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) | |
434 if (run_loop_->dispatcher_ && type() == TYPE_UI) { | |
435 static_cast<MessagePumpForUI*>(pump_.get())-> | |
436 RunWithDispatcher(this, run_loop_->dispatcher_); | |
437 return; | |
438 } | |
439 #endif | |
440 | |
441 pump_->Run(this); | |
442 } | |
443 | |
444 bool MessageLoop::ProcessNextDelayedNonNestableTask() { | |
445 if (run_loop_->run_depth_ != 1) | |
446 return false; | |
447 | |
448 if (deferred_non_nestable_work_queue_.empty()) | |
449 return false; | |
450 | |
451 PendingTask pending_task = deferred_non_nestable_work_queue_.front(); | |
452 deferred_non_nestable_work_queue_.pop(); | |
453 | |
454 RunTask(pending_task); | |
455 return true; | |
456 } | |
457 | |
458 void MessageLoop::RunTask(const PendingTask& pending_task) { | |
459 TRACE_EVENT_FLOW_END0("task", "MessageLoop::PostTask", | |
460 TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this))); | |
461 TRACE_EVENT2("task", "MessageLoop::RunTask", | |
462 "src_file", pending_task.posted_from.file_name(), | |
463 "src_func", pending_task.posted_from.function_name()); | |
464 DCHECK(nestable_tasks_allowed_); | |
465 // Execute the task and assume the worst: It is probably not reentrant. | |
466 nestable_tasks_allowed_ = false; | |
467 | |
468 // Before running the task, store the program counter where it was posted | |
469 // and deliberately alias it to ensure it is on the stack if the task | |
470 // crashes. Be careful not to assume that the variable itself will have the | |
471 // expected value when displayed by the optimizer in an optimized build. | |
472 // Look at a memory dump of the stack. | |
473 const void* program_counter = | |
474 pending_task.posted_from.program_counter(); | |
475 debug::Alias(&program_counter); | |
476 | |
477 HistogramEvent(kTaskRunEvent); | |
478 | |
479 tracked_objects::TrackedTime start_time = | |
480 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); | |
481 | |
482 FOR_EACH_OBSERVER(TaskObserver, task_observers_, | |
483 WillProcessTask(pending_task)); | |
484 pending_task.task.Run(); | |
485 FOR_EACH_OBSERVER(TaskObserver, task_observers_, | |
486 DidProcessTask(pending_task)); | |
487 | |
488 tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, | |
489 start_time, tracked_objects::ThreadData::NowForEndOfRun()); | |
490 | |
491 nestable_tasks_allowed_ = true; | |
492 } | |
493 | |
494 bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { | |
495 if (pending_task.nestable || run_loop_->run_depth_ == 1) { | |
496 RunTask(pending_task); | |
497 // Show that we ran a task (Note: a new one might arrive as a | |
498 // consequence!). | |
499 return true; | |
500 } | |
501 | |
502 // We couldn't run the task now because we're in a nested message loop | |
503 // and the task isn't nestable. | |
504 deferred_non_nestable_work_queue_.push(pending_task); | |
505 return false; | |
506 } | |
507 | |
508 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { | |
509 // Move to the delayed work queue. | |
510 delayed_work_queue_.push(pending_task); | |
511 } | |
512 | |
513 void MessageLoop::ReloadWorkQueue() { | |
514 // We can improve performance of our loading tasks from incoming_queue_ to | |
515 // work_queue_ by waiting until the last minute (work_queue_ is empty) to | |
516 // load. That reduces the number of locks-per-task significantly when our | |
517 // queues get large. | |
518 if (!work_queue_.empty()) | |
519 return; // Wait till we *really* need to lock and load. | |
520 | |
521 // Acquire all we can from the inter-thread queue with one lock acquisition. | |
522 { | |
523 AutoLock lock(incoming_queue_lock_); | |
524 if (incoming_queue_.empty()) | |
525 return; | |
526 incoming_queue_.Swap(&work_queue_); // Constant time | |
527 DCHECK(incoming_queue_.empty()); | |
528 } | |
529 } | |
530 | |
531 bool MessageLoop::DeletePendingTasks() { | |
532 bool did_work = !work_queue_.empty(); | |
533 while (!work_queue_.empty()) { | |
534 PendingTask pending_task = work_queue_.front(); | |
535 work_queue_.pop(); | |
536 if (!pending_task.delayed_run_time.is_null()) { | |
537 // We want to delete delayed tasks in the same order in which they would | |
538 // normally be deleted in case of any funny dependencies between delayed | |
539 // tasks. | |
540 AddToDelayedWorkQueue(pending_task); | |
541 } | |
542 } | |
543 did_work |= !deferred_non_nestable_work_queue_.empty(); | |
544 while (!deferred_non_nestable_work_queue_.empty()) { | |
545 deferred_non_nestable_work_queue_.pop(); | |
546 } | |
547 did_work |= !delayed_work_queue_.empty(); | |
548 | |
549 // Historically, we always delete the task regardless of valgrind status. It's | |
550 // not completely clear why we want to leak them in the loops above. This | |
551 // code is replicating legacy behavior, and should not be considered | |
552 // absolutely "correct" behavior. See TODO above about deleting all tasks | |
553 // when it's safe. | |
554 while (!delayed_work_queue_.empty()) { | |
555 delayed_work_queue_.pop(); | |
556 } | |
557 return did_work; | |
558 } | |
559 | |
560 TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) { | |
561 TimeTicks delayed_run_time; | |
562 if (delay > TimeDelta()) { | |
563 delayed_run_time = TimeTicks::Now() + delay; | |
564 | |
565 #if defined(OS_WIN) | |
566 if (high_resolution_timer_expiration_.is_null()) { | |
567 // Windows timers are granular to 15.6ms. If we only set high-res | |
568 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, | |
569 // which as a percentage is pretty inaccurate. So enable high | |
570 // res timers for any timer which is within 2x of the granularity. | |
571 // This is a tradeoff between accuracy and power management. | |
572 bool needs_high_res_timers = delay.InMilliseconds() < | |
573 (2 * Time::kMinLowResolutionThresholdMs); | |
574 if (needs_high_res_timers) { | |
575 if (Time::ActivateHighResolutionTimer(true)) { | |
576 high_resolution_timer_expiration_ = TimeTicks::Now() + | |
577 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs); | |
578 } | |
579 } | |
580 } | |
581 #endif | |
582 } else { | |
583 DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; | |
584 } | |
585 | |
586 #if defined(OS_WIN) | |
587 if (!high_resolution_timer_expiration_.is_null()) { | |
588 if (TimeTicks::Now() > high_resolution_timer_expiration_) { | |
589 Time::ActivateHighResolutionTimer(false); | |
590 high_resolution_timer_expiration_ = TimeTicks(); | |
591 } | |
592 } | |
593 #endif | |
594 | |
595 return delayed_run_time; | |
596 } | |
597 | |
598 // Possibly called on a background thread! | |
599 bool MessageLoop::AddToIncomingQueue(PendingTask* pending_task, | |
600 bool use_try_lock) { | |
601 // Warning: Don't try to short-circuit, and handle this thread's tasks more | |
602 // directly, as it could starve handling of foreign threads. Put every task | |
603 // into this queue. | |
604 | |
605 scoped_refptr<MessagePump> pump; | |
606 { | |
607 if (use_try_lock) { | |
608 if (!incoming_queue_lock_.Try()) { | |
609 pending_task->task.Reset(); | |
610 return false; | |
611 } | |
612 } else { | |
613 incoming_queue_lock_.Acquire(); | |
614 } | |
615 AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired()); | |
616 // Initialize the sequence number. The sequence number is used for delayed | |
617 // tasks (to faciliate FIFO sorting when two tasks have the same | |
618 // delayed_run_time value) and for identifying the task in about:tracing. | |
619 pending_task->sequence_num = next_sequence_num_++; | |
620 | |
621 TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", | |
622 TRACE_ID_MANGLE(GetTaskTraceID(*pending_task, this))); | |
623 | |
624 bool was_empty = incoming_queue_.empty(); | |
625 incoming_queue_.push(*pending_task); | |
626 pending_task->task.Reset(); | |
627 if (!was_empty) | |
628 return true; // Someone else should have started the sub-pump. | |
629 | |
630 pump = pump_; | |
631 } | |
632 // Since the incoming_queue_ may contain a task that destroys this message | |
633 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. | |
634 // We use a stack-based reference to the message pump so that we can call | |
635 // ScheduleWork outside of incoming_queue_lock_. | |
636 | |
637 pump->ScheduleWork(); | |
638 return true; | |
639 } | |
640 | |
641 //------------------------------------------------------------------------------ | |
642 // Method and data for histogramming events and actions taken by each instance | |
643 // on each thread. | |
644 | |
645 void MessageLoop::StartHistogrammer() { | |
646 #if !defined(OS_NACL) // NaCl build has no metrics code. | |
647 if (enable_histogrammer_ && !message_histogram_ | |
648 && StatisticsRecorder::IsActive()) { | |
649 DCHECK(!thread_name_.empty()); | |
650 message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription( | |
651 "MsgLoop:" + thread_name_, | |
652 kLeastNonZeroMessageId, kMaxMessageId, | |
653 kNumberOfDistinctMessagesDisplayed, | |
654 message_histogram_->kHexRangePrintingFlag, | |
655 event_descriptions_); | |
656 } | |
657 #endif | |
658 } | |
659 | |
660 void MessageLoop::HistogramEvent(int event) { | |
661 #if !defined(OS_NACL) | |
662 if (message_histogram_) | |
663 message_histogram_->Add(event); | |
664 #endif | |
665 } | |
666 | |
667 bool MessageLoop::DoWork() { | |
668 if (!nestable_tasks_allowed_) { | |
669 // Task can't be executed right now. | |
670 return false; | |
671 } | |
672 | |
673 for (;;) { | |
674 ReloadWorkQueue(); | |
675 if (work_queue_.empty()) | |
676 break; | |
677 | |
678 // Execute oldest task. | |
679 do { | |
680 PendingTask pending_task = work_queue_.front(); | |
681 work_queue_.pop(); | |
682 if (!pending_task.delayed_run_time.is_null()) { | |
683 AddToDelayedWorkQueue(pending_task); | |
684 // If we changed the topmost task, then it is time to reschedule. | |
685 if (delayed_work_queue_.top().task.Equals(pending_task.task)) | |
686 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); | |
687 } else { | |
688 if (DeferOrRunPendingTask(pending_task)) | |
689 return true; | |
690 } | |
691 } while (!work_queue_.empty()); | |
692 } | |
693 | |
694 // Nothing happened. | |
695 return false; | |
696 } | |
697 | |
698 bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) { | |
699 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { | |
700 recent_time_ = *next_delayed_work_time = TimeTicks(); | |
701 return false; | |
702 } | |
703 | |
704 // When we "fall behind," there will be a lot of tasks in the delayed work | |
705 // queue that are ready to run. To increase efficiency when we fall behind, | |
706 // we will only call Time::Now() intermittently, and then process all tasks | |
707 // that are ready to run before calling it again. As a result, the more we | |
708 // fall behind (and have a lot of ready-to-run delayed tasks), the more | |
709 // efficient we'll be at handling the tasks. | |
710 | |
711 TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time; | |
712 if (next_run_time > recent_time_) { | |
713 recent_time_ = TimeTicks::Now(); // Get a better view of Now(); | |
714 if (next_run_time > recent_time_) { | |
715 *next_delayed_work_time = next_run_time; | |
716 return false; | |
717 } | |
718 } | |
719 | |
720 PendingTask pending_task = delayed_work_queue_.top(); | |
721 delayed_work_queue_.pop(); | |
722 | |
723 if (!delayed_work_queue_.empty()) | |
724 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; | |
725 | |
726 return DeferOrRunPendingTask(pending_task); | |
727 } | |
728 | |
729 bool MessageLoop::DoIdleWork() { | |
730 if (ProcessNextDelayedNonNestableTask()) | |
731 return true; | |
732 | |
733 if (run_loop_->quit_when_idle_received_) | |
734 pump_->Quit(); | |
735 | |
736 return false; | |
737 } | |
738 | |
739 void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here, | |
740 void(*deleter)(const void*), | |
741 const void* object) { | |
742 PostNonNestableTask(from_here, Bind(deleter, object)); | |
743 } | |
744 | |
745 void MessageLoop::ReleaseSoonInternal( | |
746 const tracked_objects::Location& from_here, | |
747 void(*releaser)(const void*), | |
748 const void* object) { | |
749 PostNonNestableTask(from_here, Bind(releaser, object)); | |
750 } | |
751 | |
752 //------------------------------------------------------------------------------ | |
753 // MessageLoopForUI | |
754 | |
755 #if defined(OS_WIN) | |
756 void MessageLoopForUI::DidProcessMessage(const MSG& message) { | |
757 pump_win()->DidProcessMessage(message); | |
758 } | |
759 #endif // defined(OS_WIN) | |
760 | |
761 #if defined(OS_ANDROID) | |
762 void MessageLoopForUI::Start() { | |
763 // No Histogram support for UI message loop as it is managed by Java side | |
764 static_cast<MessagePumpForUI*>(pump_.get())->Start(this); | |
765 } | |
766 #endif | |
767 | |
768 #if defined(OS_IOS) | |
769 void MessageLoopForUI::Attach() { | |
770 static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this); | |
771 } | |
772 #endif | |
773 | |
774 #if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) | |
775 void MessageLoopForUI::AddObserver(Observer* observer) { | |
776 pump_ui()->AddObserver(observer); | |
777 } | |
778 | |
779 void MessageLoopForUI::RemoveObserver(Observer* observer) { | |
780 pump_ui()->RemoveObserver(observer); | |
781 } | |
782 | |
783 #endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) | |
784 | |
785 //------------------------------------------------------------------------------ | |
786 // MessageLoopForIO | |
787 | |
788 #if defined(OS_WIN) | |
789 | |
790 void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { | |
791 pump_io()->RegisterIOHandler(file, handler); | |
792 } | |
793 | |
794 bool MessageLoopForIO::RegisterJobObject(HANDLE job, IOHandler* handler) { | |
795 return pump_io()->RegisterJobObject(job, handler); | |
796 } | |
797 | |
798 bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { | |
799 return pump_io()->WaitForIOCompletion(timeout, filter); | |
800 } | |
801 | |
802 #elif defined(OS_IOS) | |
803 | |
804 bool MessageLoopForIO::WatchFileDescriptor(int fd, | |
805 bool persistent, | |
806 Mode mode, | |
807 FileDescriptorWatcher *controller, | |
808 Watcher *delegate) { | |
809 return pump_io()->WatchFileDescriptor( | |
810 fd, | |
811 persistent, | |
812 mode, | |
813 controller, | |
814 delegate); | |
815 } | |
816 | |
817 #elif defined(OS_POSIX) && !defined(OS_NACL) | |
818 | |
819 bool MessageLoopForIO::WatchFileDescriptor(int fd, | |
820 bool persistent, | |
821 Mode mode, | |
822 FileDescriptorWatcher *controller, | |
823 Watcher *delegate) { | |
824 return pump_libevent()->WatchFileDescriptor( | |
825 fd, | |
826 persistent, | |
827 mode, | |
828 controller, | |
829 delegate); | |
830 } | |
831 | |
832 #endif | |
833 | |
834 } // namespace base | |
OLD | NEW |