blob: cd44b922f160ac02a63e556bd92eb518fb1f9512 [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// Copyright (c) 2006-2008 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.
initial.commit3f4a7322008-07-27 06:49:38 +09004
darin@google.com6ddeb842008-08-15 16:31:20 +09005#include "base/message_loop.h"
6
darin@google.com981f3552008-08-16 12:09:05 +09007#include <algorithm>
8
mmentovai@google.comfa5f9932008-08-22 07:26:06 +09009#include "base/compiler_specific.h"
initial.commit3f4a7322008-07-27 06:49:38 +090010#include "base/logging.h"
darin@google.com12d40bb2008-08-20 03:36:23 +090011#include "base/message_pump_default.h"
initial.commit3f4a7322008-07-27 06:49:38 +090012#include "base/string_util.h"
13#include "base/thread_local_storage.h"
initial.commit3f4a7322008-07-27 06:49:38 +090014
15// a TLS index to the message loop for the current thread
16// Note that if we start doing complex stuff in other static initializers
17// this could cause problems.
evanm@google.comf26fd3a2008-08-21 07:54:52 +090018// TODO(evanm): this shouldn't rely on static initialization.
19// static
20TLSSlot MessageLoop::tls_index_;
initial.commit3f4a7322008-07-27 06:49:38 +090021
22//------------------------------------------------------------------------------
23
initial.commit3f4a7322008-07-27 06:49:38 +090024// Logical events for Histogram profiling. Run with -message-loop-histogrammer
25// to get an accounting of messages and actions taken on each thread.
darin@google.com981f3552008-08-16 12:09:05 +090026static const int kTaskRunEvent = 0x1;
27static const int kTimerEvent = 0x2;
initial.commit3f4a7322008-07-27 06:49:38 +090028
29// Provide range of message IDs for use in histogramming and debug display.
30static const int kLeastNonZeroMessageId = 1;
31static const int kMaxMessageId = 1099;
32static const int kNumberOfDistinctMessagesDisplayed = 1100;
33
34//------------------------------------------------------------------------------
35
darin@google.com981f3552008-08-16 12:09:05 +090036#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +090037
initial.commit3f4a7322008-07-27 06:49:38 +090038// Upon a SEH exception in this thread, it restores the original unhandled
39// exception filter.
40static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
41 ::SetUnhandledExceptionFilter(old_filter);
42 return EXCEPTION_CONTINUE_SEARCH;
43}
44
45// Retrieves a pointer to the current unhandled exception filter. There
46// is no standalone getter method.
47static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
48 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
49 top_filter = ::SetUnhandledExceptionFilter(0);
50 ::SetUnhandledExceptionFilter(top_filter);
51 return top_filter;
52}
53
darin@google.com981f3552008-08-16 12:09:05 +090054#endif // defined(OS_WIN)
55
initial.commit3f4a7322008-07-27 06:49:38 +090056//------------------------------------------------------------------------------
57
darin@google.comd936b5b2008-08-26 14:53:57 +090058MessageLoop::MessageLoop(Type type)
59 : type_(type),
60 ALLOW_THIS_IN_INITIALIZER_LIST(timer_manager_(this)),
darin@google.comee6fa722008-08-13 08:25:43 +090061 nestable_tasks_allowed_(true),
darin@google.com12d40bb2008-08-20 03:36:23 +090062 exception_restoration_(false),
darin@google.com981f3552008-08-16 12:09:05 +090063 state_(NULL) {
darin@google.comd936b5b2008-08-26 14:53:57 +090064 DCHECK(!tls_index_.Get()) << "should only have one message loop per thread";
evanm@google.comf26fd3a2008-08-21 07:54:52 +090065 tls_index_.Set(this);
darin@google.comd936b5b2008-08-26 14:53:57 +090066
darin@google.com132072e2008-08-26 15:52:41 +090067 // TODO(darin): Choose the pump based on the requested type.
darin@google.com981f3552008-08-16 12:09:05 +090068#if defined(OS_WIN)
darin@google.com132072e2008-08-26 15:52:41 +090069 pump_ = new base::MessagePumpWin();
darin@google.com12d40bb2008-08-20 03:36:23 +090070#else
darin@google.com132072e2008-08-26 15:52:41 +090071 pump_ = new base::MessagePumpDefault();
darin@google.com981f3552008-08-16 12:09:05 +090072#endif
initial.commit3f4a7322008-07-27 06:49:38 +090073}
74
75MessageLoop::~MessageLoop() {
76 DCHECK(this == current());
darin@google.com965e5342008-08-06 08:16:41 +090077
78 // Let interested parties have one last shot at accessing this.
79 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
80 WillDestroyCurrentMessageLoop());
81
82 // OK, now make it so that no one can find us.
evanm@google.comf26fd3a2008-08-21 07:54:52 +090083 tls_index_.Set(NULL);
darin@google.com965e5342008-08-06 08:16:41 +090084
darin@google.com981f3552008-08-16 12:09:05 +090085 DCHECK(!state_);
darin@google.com965e5342008-08-06 08:16:41 +090086
initial.commit3f4a7322008-07-27 06:49:38 +090087 // Most tasks that have not been Run() are deleted in the |timer_manager_|
88 // destructor after we remove our tls index. We delete the tasks in our
89 // queues here so their destuction is similar to the tasks in the
90 // |timer_manager_|.
91 DeletePendingTasks();
92 ReloadWorkQueue();
93 DeletePendingTasks();
94}
95
darin@google.com965e5342008-08-06 08:16:41 +090096void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
97 DCHECK(this == current());
98 destruction_observers_.AddObserver(obs);
99}
100
101void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
102 DCHECK(this == current());
103 destruction_observers_.RemoveObserver(obs);
104}
105
darin@google.com6ddeb842008-08-15 16:31:20 +0900106void MessageLoop::Run() {
darin@google.com981f3552008-08-16 12:09:05 +0900107 AutoRunState save_state(this);
108 RunHandler();
darin@google.com6ddeb842008-08-15 16:31:20 +0900109}
110
jar@google.com9239e022008-07-31 22:10:20 +0900111void MessageLoop::RunAllPending() {
darin@google.com981f3552008-08-16 12:09:05 +0900112 AutoRunState save_state(this);
113 state_->quit_received = true; // Means run until we would otherwise block.
114 RunHandler();
initial.commit3f4a7322008-07-27 06:49:38 +0900115}
116
117// Runs the loop in two different SEH modes:
118// enable_SEH_restoration_ = false : any unhandled exception goes to the last
119// one that calls SetUnhandledExceptionFilter().
120// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
121// that was existed before the loop was run.
darin@google.com981f3552008-08-16 12:09:05 +0900122void MessageLoop::RunHandler() {
123#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900124 if (exception_restoration_) {
125 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
126 __try {
darin@google.com981f3552008-08-16 12:09:05 +0900127 RunInternal();
initial.commit3f4a7322008-07-27 06:49:38 +0900128 } __except(SEHFilter(current_filter)) {
129 }
darin@google.com981f3552008-08-16 12:09:05 +0900130 return;
initial.commit3f4a7322008-07-27 06:49:38 +0900131 }
darin@google.com981f3552008-08-16 12:09:05 +0900132#endif
133
134 RunInternal();
initial.commit3f4a7322008-07-27 06:49:38 +0900135}
136
137//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900138
darin@google.com981f3552008-08-16 12:09:05 +0900139void MessageLoop::RunInternal() {
140 DCHECK(this == current());
141
initial.commit3f4a7322008-07-27 06:49:38 +0900142 StartHistogrammer();
143
darin@google.com981f3552008-08-16 12:09:05 +0900144#if defined(OS_WIN)
145 if (state_->dispatcher) {
146 pump_win()->RunWithDispatcher(this, state_->dispatcher);
147 return;
jar@google.com9239e022008-07-31 22:10:20 +0900148 }
darin@google.com981f3552008-08-16 12:09:05 +0900149#endif
150
151 pump_->Run(this);
jar@google.comfbaaf692008-07-30 16:50:53 +0900152}
jar@google.com7ff36e62008-07-30 15:58:56 +0900153
jar@google.comb4d1bff2008-07-31 04:03:59 +0900154//------------------------------------------------------------------------------
155// Wrapper functions for use in above message loop framework.
156
initial.commit3f4a7322008-07-27 06:49:38 +0900157bool MessageLoop::ProcessNextDelayedNonNestableTask() {
darin@google.com981f3552008-08-16 12:09:05 +0900158 if (state_->run_depth != 1)
initial.commit3f4a7322008-07-27 06:49:38 +0900159 return false;
160
161 if (delayed_non_nestable_queue_.Empty())
162 return false;
163
164 RunTask(delayed_non_nestable_queue_.Pop());
165 return true;
166}
167
initial.commit3f4a7322008-07-27 06:49:38 +0900168//------------------------------------------------------------------------------
169
170void MessageLoop::Quit() {
darin@google.com981f3552008-08-16 12:09:05 +0900171 DCHECK(current() == this);
172 if (state_) {
173 state_->quit_received = true;
174 } else {
175 NOTREACHED() << "Must be inside Run to call Quit";
initial.commit3f4a7322008-07-27 06:49:38 +0900176 }
initial.commit3f4a7322008-07-27 06:49:38 +0900177}
178
179// Possibly called on a background thread!
180void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here,
181 Task* task, int delay_ms) {
182 task->SetBirthPlace(from_here);
183 DCHECK(delay_ms >= 0);
184 DCHECK(!task->is_owned_by_message_loop());
185 task->set_posted_task_delay(delay_ms);
186 DCHECK(task->is_owned_by_message_loop());
187 PostTaskInternal(task);
188}
189
190void MessageLoop::PostTaskInternal(Task* task) {
191 // Warning: Don't try to short-circuit, and handle this thread's tasks more
192 // directly, as it could starve handling of foreign threads. Put every task
193 // into this queue.
194
darin@google.com981f3552008-08-16 12:09:05 +0900195 scoped_refptr<base::MessagePump> pump;
initial.commit3f4a7322008-07-27 06:49:38 +0900196 {
darin@google.com981f3552008-08-16 12:09:05 +0900197 AutoLock locked(incoming_queue_lock_);
198
initial.commit3f4a7322008-07-27 06:49:38 +0900199 bool was_empty = incoming_queue_.Empty();
200 incoming_queue_.Push(task);
201 if (!was_empty)
202 return; // Someone else should have started the sub-pump.
203
darin@google.com981f3552008-08-16 12:09:05 +0900204 pump = pump_;
darin@google.com6ddeb842008-08-15 16:31:20 +0900205 }
darin@google.com981f3552008-08-16 12:09:05 +0900206 // Since the incoming_queue_ may contain a task that destroys this message
207 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
208 // We use a stack-based reference to the message pump so that we can call
209 // ScheduleWork outside of incoming_queue_lock_.
darin@google.com6ddeb842008-08-15 16:31:20 +0900210
darin@google.com981f3552008-08-16 12:09:05 +0900211 pump->ScheduleWork();
initial.commit3f4a7322008-07-27 06:49:38 +0900212}
213
214void MessageLoop::SetNestableTasksAllowed(bool allowed) {
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900215 if (nestable_tasks_allowed_ != allowed) {
216 nestable_tasks_allowed_ = allowed;
217 if (!nestable_tasks_allowed_)
218 return;
219 // Start the native pump if we are not already pumping.
darin@google.com981f3552008-08-16 12:09:05 +0900220 pump_->ScheduleWork();
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900221 }
initial.commit3f4a7322008-07-27 06:49:38 +0900222}
223
224bool MessageLoop::NestableTasksAllowed() const {
225 return nestable_tasks_allowed_;
226}
227
initial.commit3f4a7322008-07-27 06:49:38 +0900228//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900229
230bool MessageLoop::RunTimerTask(Timer* timer) {
231 HistogramEvent(kTimerEvent);
darin@google.comee6fa722008-08-13 08:25:43 +0900232
initial.commit3f4a7322008-07-27 06:49:38 +0900233 Task* task = timer->task();
234 if (task->is_owned_by_message_loop()) {
darin@google.comee6fa722008-08-13 08:25:43 +0900235 // We constructed it through PostDelayedTask().
initial.commit3f4a7322008-07-27 06:49:38 +0900236 DCHECK(!timer->repeating());
237 timer->set_task(NULL);
238 delete timer;
jar@google.com09856292008-08-02 06:55:17 +0900239 task->ResetBirthTime();
initial.commit3f4a7322008-07-27 06:49:38 +0900240 return QueueOrRunTask(task);
initial.commit3f4a7322008-07-27 06:49:38 +0900241 }
darin@google.comee6fa722008-08-13 08:25:43 +0900242
243 // This is an unknown timer task, and we *can't* delay running it, as a user
244 // might try to cancel it with TimerManager at any moment.
245 DCHECK(nestable_tasks_allowed_);
246 RunTask(task);
247 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900248}
249
250void MessageLoop::DiscardTimer(Timer* timer) {
251 Task* task = timer->task();
252 if (task->is_owned_by_message_loop()) {
253 DCHECK(!timer->repeating());
254 timer->set_task(NULL);
255 delete timer; // We constructed it through PostDelayedTask().
256 delete task; // We were given ouwnership in PostTask().
257 }
258}
259
260bool MessageLoop::QueueOrRunTask(Task* new_task) {
261 if (!nestable_tasks_allowed_) {
262 // Task can't be executed right now. Add it to the queue.
263 if (new_task)
264 work_queue_.Push(new_task);
265 return false;
266 }
267
268 // Queue new_task first so we execute the task in FIFO order.
269 if (new_task)
270 work_queue_.Push(new_task);
271
272 // Execute oldest task.
273 while (!work_queue_.Empty()) {
274 Task* task = work_queue_.Pop();
darin@google.com981f3552008-08-16 12:09:05 +0900275 if (task->nestable() || state_->run_depth == 1) {
initial.commit3f4a7322008-07-27 06:49:38 +0900276 RunTask(task);
277 // Show that we ran a task (Note: a new one might arrive as a
278 // consequence!).
279 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900280 }
darin@google.com981f3552008-08-16 12:09:05 +0900281 // We couldn't run the task now because we're in a nested message loop
282 // and the task isn't nestable.
283 delayed_non_nestable_queue_.Push(task);
initial.commit3f4a7322008-07-27 06:49:38 +0900284 }
285
286 // Nothing happened.
287 return false;
288}
289
290void MessageLoop::RunTask(Task* task) {
291 BeforeTaskRunSetup();
292 HistogramEvent(kTaskRunEvent);
293 // task may self-delete during Run() if we don't happen to own it.
294 // ...so check *before* we Run, since we can't check after.
295 bool we_own_task = task->is_owned_by_message_loop();
296 task->Run();
297 if (we_own_task)
298 task->RecycleOrDelete(); // Relinquish control, and probably delete.
299 AfterTaskRunRestore();
300}
301
302void MessageLoop::BeforeTaskRunSetup() {
303 DCHECK(nestable_tasks_allowed_);
304 // Execute the task and assume the worst: It is probably not reentrant.
305 nestable_tasks_allowed_ = false;
306}
307
308void MessageLoop::AfterTaskRunRestore() {
309 nestable_tasks_allowed_ = true;
310}
311
initial.commit3f4a7322008-07-27 06:49:38 +0900312void MessageLoop::ReloadWorkQueue() {
313 // We can improve performance of our loading tasks from incoming_queue_ to
darin@google.com981f3552008-08-16 12:09:05 +0900314 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
315 // load. That reduces the number of locks-per-task significantly when our
316 // queues get large. The optimization is disabled on threads that make use
317 // of the priority queue (prioritization requires all our tasks to be in the
initial.commit3f4a7322008-07-27 06:49:38 +0900318 // work_queue_ ASAP).
319 if (!work_queue_.Empty() && !work_queue_.use_priority_queue())
320 return; // Wait till we *really* need to lock and load.
321
322 // Acquire all we can from the inter-thread queue with one lock acquisition.
323 TaskQueue new_task_list; // Null terminated list.
324 {
325 AutoLock lock(incoming_queue_lock_);
326 if (incoming_queue_.Empty())
327 return;
328 std::swap(incoming_queue_, new_task_list);
329 DCHECK(incoming_queue_.Empty());
330 } // Release lock.
331
332 while (!new_task_list.Empty()) {
333 Task* task = new_task_list.Pop();
334 DCHECK(task->is_owned_by_message_loop());
335
336 if (task->posted_task_delay() > 0)
337 timer_manager_.StartTimer(task->posted_task_delay(), task, false);
338 else
339 work_queue_.Push(task);
340 }
341}
342
343void MessageLoop::DeletePendingTasks() {
darin@google.com62b58bc2008-08-27 14:29:40 +0900344 /* Comment this out as it's causing crashes.
initial.commit3f4a7322008-07-27 06:49:38 +0900345 while (!work_queue_.Empty()) {
346 Task* task = work_queue_.Pop();
347 if (task->is_owned_by_message_loop())
348 delete task;
349 }
350
351 while (!delayed_non_nestable_queue_.Empty()) {
352 Task* task = delayed_non_nestable_queue_.Pop();
353 if (task->is_owned_by_message_loop())
354 delete task;
355 }
darin@google.com62b58bc2008-08-27 14:29:40 +0900356 */
initial.commit3f4a7322008-07-27 06:49:38 +0900357}
358
darin@google.comee6fa722008-08-13 08:25:43 +0900359void MessageLoop::DidChangeNextTimerExpiry() {
darin@google.com6393bed2008-08-20 15:30:58 +0900360 Time next_delayed_work_time = timer_manager_.GetNextFireTime();
361 if (next_delayed_work_time.is_null())
darin@google.com981f3552008-08-16 12:09:05 +0900362 return;
363
364 // Simulates malfunctioning, early firing timers. Pending tasks should only
365 // be invoked when the delay they specify has elapsed.
366 if (timer_manager_.use_broken_delay())
darin@google.com6393bed2008-08-20 15:30:58 +0900367 next_delayed_work_time = Time::Now() + TimeDelta::FromMilliseconds(10);
darin@google.com981f3552008-08-16 12:09:05 +0900368
darin@google.com6393bed2008-08-20 15:30:58 +0900369 pump_->ScheduleDelayedWork(next_delayed_work_time);
darin@google.com981f3552008-08-16 12:09:05 +0900370}
371
372bool MessageLoop::DoWork() {
373 ReloadWorkQueue();
374 return QueueOrRunTask(NULL);
375}
376
darin@google.com6393bed2008-08-20 15:30:58 +0900377bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) {
darin@google.com981f3552008-08-16 12:09:05 +0900378 bool did_work = timer_manager_.RunSomePendingTimers();
379
380 // We may not have run any timers, but we may still have future timers to
381 // run, so we need to inform the pump again of pending timers.
darin@google.com6393bed2008-08-20 15:30:58 +0900382 *next_delayed_work_time = timer_manager_.GetNextFireTime();
darin@google.com981f3552008-08-16 12:09:05 +0900383
384 return did_work;
385}
386
387bool MessageLoop::DoIdleWork() {
388 if (ProcessNextDelayedNonNestableTask())
389 return true;
390
391 if (state_->quit_received)
392 pump_->Quit();
393
394 return false;
395}
396
397//------------------------------------------------------------------------------
398// MessageLoop::AutoRunState
399
400MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
401 // Make the loop reference us.
402 previous_state_ = loop_->state_;
403 if (previous_state_) {
404 run_depth = previous_state_->run_depth + 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900405 } else {
darin@google.com981f3552008-08-16 12:09:05 +0900406 run_depth = 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900407 }
darin@google.com981f3552008-08-16 12:09:05 +0900408 loop_->state_ = this;
409
410 // Initialize the other fields:
411 quit_received = false;
412#if defined(OS_WIN)
413 dispatcher = NULL;
414#endif
415}
416
417MessageLoop::AutoRunState::~AutoRunState() {
418 loop_->state_ = previous_state_;
darin@google.comee6fa722008-08-13 08:25:43 +0900419}
420
initial.commit3f4a7322008-07-27 06:49:38 +0900421//------------------------------------------------------------------------------
422// Implementation of the work_queue_ as a ProiritizedTaskQueue
423
424void MessageLoop::PrioritizedTaskQueue::push(Task * task) {
425 queue_.push(PrioritizedTask(task, --next_sequence_number_));
426}
427
428bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < (
429 PrioritizedTask const & right) const {
darin@google.com12d40bb2008-08-20 03:36:23 +0900430 int compare = task_->priority() - right.task_->priority();
initial.commit3f4a7322008-07-27 06:49:38 +0900431 if (compare)
432 return compare < 0;
433 // Don't compare directly, but rather subtract. This handles overflow
434 // as sequence numbers wrap around.
435 compare = sequence_number_ - right.sequence_number_;
436 DCHECK(compare); // Sequence number are unique for a "long time."
437 // Make sure we don't starve anything with a low priority.
438 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping.
439 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping.
440 return compare < 0;
441}
442
443//------------------------------------------------------------------------------
444// Implementation of a TaskQueue as a null terminated list, with end pointers.
445
446void MessageLoop::TaskQueue::Push(Task* task) {
447 if (!first_)
448 first_ = task;
449 else
450 last_->set_next_task(task);
451 last_ = task;
452}
453
454Task* MessageLoop::TaskQueue::Pop() {
455 DCHECK((!first_) == !last_);
456 Task* task = first_;
457 if (first_) {
458 first_ = task->next_task();
459 if (!first_)
460 last_ = NULL;
461 else
462 task->set_next_task(NULL);
463 }
464 return task;
465}
466
467//------------------------------------------------------------------------------
468// Implementation of a Task queue that automatically switches into a priority
469// queue if it observes any non-zero priorities on tasks.
470
471void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) {
472 if (use_priority_queue_) {
473 prioritized_queue_.push(task);
474 } else {
475 queue_.Push(task);
476 if (task->priority()) {
477 use_priority_queue_ = true; // From now on.
478 while (!queue_.Empty())
479 prioritized_queue_.push(queue_.Pop());
480 }
481 }
482}
483
484Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() {
485 if (!use_priority_queue_)
486 return queue_.Pop();
487 Task* task = prioritized_queue_.front();
488 prioritized_queue_.pop();
489 return task;
490}
491
492bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() {
493 if (use_priority_queue_)
494 return prioritized_queue_.empty();
495 return queue_.Empty();
496}
497
498//------------------------------------------------------------------------------
499// Method and data for histogramming events and actions taken by each instance
500// on each thread.
501
502// static
503bool MessageLoop::enable_histogrammer_ = false;
504
505// static
506void MessageLoop::EnableHistogrammer(bool enable) {
507 enable_histogrammer_ = enable;
508}
509
510void MessageLoop::StartHistogrammer() {
511 if (enable_histogrammer_ && !message_histogram_.get()
512 && StatisticsRecorder::WasStarted()) {
darin@google.com981f3552008-08-16 12:09:05 +0900513 DCHECK(!thread_name_.empty());
initial.commit3f4a7322008-07-27 06:49:38 +0900514 message_histogram_.reset(new LinearHistogram(
515 ASCIIToWide("MsgLoop:" + thread_name_).c_str(),
516 kLeastNonZeroMessageId,
517 kMaxMessageId,
518 kNumberOfDistinctMessagesDisplayed));
519 message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag);
520 message_histogram_->SetRangeDescriptions(event_descriptions_);
521 }
522}
523
524void MessageLoop::HistogramEvent(int event) {
525 if (message_histogram_.get())
526 message_histogram_->Add(event);
527}
528
initial.commit3f4a7322008-07-27 06:49:38 +0900529// Provide a macro that takes an expression (such as a constant, or macro
530// constant) and creates a pair to initalize an array of pairs. In this case,
531// our pair consists of the expressions value, and the "stringized" version
532// of the expression (i.e., the exrpression put in quotes). For example, if
533// we have:
534// #define FOO 2
535// #define BAR 5
536// then the following:
537// VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
538// will expand to:
539// {7, "FOO + BAR"}
540// We use the resulting array as an argument to our histogram, which reads the
541// number as a bucket identifier, and proceeds to use the corresponding name
542// in the pair (i.e., the quoted string) when printing out a histogram.
543#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
544
initial.commit3f4a7322008-07-27 06:49:38 +0900545// static
546const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
initial.commit3f4a7322008-07-27 06:49:38 +0900547 // Provide some pretty print capability in our histogram for our internal
548 // messages.
549
initial.commit3f4a7322008-07-27 06:49:38 +0900550 // A few events we handle (kindred to messages), and used to profile actions.
551 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
initial.commit3f4a7322008-07-27 06:49:38 +0900552 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
553
554 {-1, NULL} // The list must be null terminated, per API to histogram.
555};
license.botf003cfe2008-08-24 09:55:55 +0900556
darin@google.comd936b5b2008-08-26 14:53:57 +0900557//------------------------------------------------------------------------------
558// MessageLoopForUI
559
560#if defined(OS_WIN)
561
562void MessageLoopForUI::Run(Dispatcher* dispatcher) {
563 AutoRunState save_state(this);
564 state_->dispatcher = dispatcher;
565 RunHandler();
566}
567
568void MessageLoopForUI::AddObserver(Observer* observer) {
569 pump_win()->AddObserver(observer);
570}
571
572void MessageLoopForUI::RemoveObserver(Observer* observer) {
573 pump_win()->RemoveObserver(observer);
574}
575
576void MessageLoopForUI::WillProcessMessage(const MSG& message) {
577 pump_win()->WillProcessMessage(message);
578}
579void MessageLoopForUI::DidProcessMessage(const MSG& message) {
580 pump_win()->DidProcessMessage(message);
581}
582void MessageLoopForUI::PumpOutPendingPaintMessages() {
583 pump_win()->PumpOutPendingPaintMessages();
584}
585
586#endif // defined(OS_WIN)
587
588//------------------------------------------------------------------------------
589// MessageLoopForIO
590
591#if defined(OS_WIN)
592
593void MessageLoopForIO::WatchObject(HANDLE object, Watcher* watcher) {
594 pump_win()->WatchObject(object, watcher);
595}
596
597#endif // defined(OS_WIN)