blob: 28a1866b1a0a609fdcf9e4e210c086996b170382 [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() {
initial.commit3f4a7322008-07-27 06:49:38 +0900344 while (!work_queue_.Empty()) {
345 Task* task = work_queue_.Pop();
346 if (task->is_owned_by_message_loop())
347 delete task;
348 }
349
350 while (!delayed_non_nestable_queue_.Empty()) {
351 Task* task = delayed_non_nestable_queue_.Pop();
352 if (task->is_owned_by_message_loop())
353 delete task;
354 }
initial.commit3f4a7322008-07-27 06:49:38 +0900355}
356
darin@google.comee6fa722008-08-13 08:25:43 +0900357void MessageLoop::DidChangeNextTimerExpiry() {
darin@google.com6393bed2008-08-20 15:30:58 +0900358 Time next_delayed_work_time = timer_manager_.GetNextFireTime();
359 if (next_delayed_work_time.is_null())
darin@google.com981f3552008-08-16 12:09:05 +0900360 return;
361
362 // Simulates malfunctioning, early firing timers. Pending tasks should only
363 // be invoked when the delay they specify has elapsed.
364 if (timer_manager_.use_broken_delay())
darin@google.com6393bed2008-08-20 15:30:58 +0900365 next_delayed_work_time = Time::Now() + TimeDelta::FromMilliseconds(10);
darin@google.com981f3552008-08-16 12:09:05 +0900366
darin@google.com6393bed2008-08-20 15:30:58 +0900367 pump_->ScheduleDelayedWork(next_delayed_work_time);
darin@google.com981f3552008-08-16 12:09:05 +0900368}
369
370bool MessageLoop::DoWork() {
371 ReloadWorkQueue();
372 return QueueOrRunTask(NULL);
373}
374
darin@google.com6393bed2008-08-20 15:30:58 +0900375bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) {
darin@google.com981f3552008-08-16 12:09:05 +0900376 bool did_work = timer_manager_.RunSomePendingTimers();
377
378 // We may not have run any timers, but we may still have future timers to
379 // run, so we need to inform the pump again of pending timers.
darin@google.com6393bed2008-08-20 15:30:58 +0900380 *next_delayed_work_time = timer_manager_.GetNextFireTime();
darin@google.com981f3552008-08-16 12:09:05 +0900381
382 return did_work;
383}
384
385bool MessageLoop::DoIdleWork() {
386 if (ProcessNextDelayedNonNestableTask())
387 return true;
388
389 if (state_->quit_received)
390 pump_->Quit();
391
392 return false;
393}
394
395//------------------------------------------------------------------------------
396// MessageLoop::AutoRunState
397
398MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
399 // Make the loop reference us.
400 previous_state_ = loop_->state_;
401 if (previous_state_) {
402 run_depth = previous_state_->run_depth + 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900403 } else {
darin@google.com981f3552008-08-16 12:09:05 +0900404 run_depth = 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900405 }
darin@google.com981f3552008-08-16 12:09:05 +0900406 loop_->state_ = this;
407
408 // Initialize the other fields:
409 quit_received = false;
410#if defined(OS_WIN)
411 dispatcher = NULL;
412#endif
413}
414
415MessageLoop::AutoRunState::~AutoRunState() {
416 loop_->state_ = previous_state_;
darin@google.comee6fa722008-08-13 08:25:43 +0900417}
418
initial.commit3f4a7322008-07-27 06:49:38 +0900419//------------------------------------------------------------------------------
420// Implementation of the work_queue_ as a ProiritizedTaskQueue
421
422void MessageLoop::PrioritizedTaskQueue::push(Task * task) {
423 queue_.push(PrioritizedTask(task, --next_sequence_number_));
424}
425
426bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < (
427 PrioritizedTask const & right) const {
darin@google.com12d40bb2008-08-20 03:36:23 +0900428 int compare = task_->priority() - right.task_->priority();
initial.commit3f4a7322008-07-27 06:49:38 +0900429 if (compare)
430 return compare < 0;
431 // Don't compare directly, but rather subtract. This handles overflow
432 // as sequence numbers wrap around.
433 compare = sequence_number_ - right.sequence_number_;
434 DCHECK(compare); // Sequence number are unique for a "long time."
435 // Make sure we don't starve anything with a low priority.
436 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping.
437 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping.
438 return compare < 0;
439}
440
441//------------------------------------------------------------------------------
442// Implementation of a TaskQueue as a null terminated list, with end pointers.
443
444void MessageLoop::TaskQueue::Push(Task* task) {
445 if (!first_)
446 first_ = task;
447 else
448 last_->set_next_task(task);
449 last_ = task;
450}
451
452Task* MessageLoop::TaskQueue::Pop() {
453 DCHECK((!first_) == !last_);
454 Task* task = first_;
455 if (first_) {
456 first_ = task->next_task();
457 if (!first_)
458 last_ = NULL;
459 else
460 task->set_next_task(NULL);
461 }
462 return task;
463}
464
465//------------------------------------------------------------------------------
466// Implementation of a Task queue that automatically switches into a priority
467// queue if it observes any non-zero priorities on tasks.
468
469void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) {
470 if (use_priority_queue_) {
471 prioritized_queue_.push(task);
472 } else {
473 queue_.Push(task);
474 if (task->priority()) {
475 use_priority_queue_ = true; // From now on.
476 while (!queue_.Empty())
477 prioritized_queue_.push(queue_.Pop());
478 }
479 }
480}
481
482Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() {
483 if (!use_priority_queue_)
484 return queue_.Pop();
485 Task* task = prioritized_queue_.front();
486 prioritized_queue_.pop();
487 return task;
488}
489
490bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() {
491 if (use_priority_queue_)
492 return prioritized_queue_.empty();
493 return queue_.Empty();
494}
495
496//------------------------------------------------------------------------------
497// Method and data for histogramming events and actions taken by each instance
498// on each thread.
499
500// static
501bool MessageLoop::enable_histogrammer_ = false;
502
503// static
504void MessageLoop::EnableHistogrammer(bool enable) {
505 enable_histogrammer_ = enable;
506}
507
508void MessageLoop::StartHistogrammer() {
509 if (enable_histogrammer_ && !message_histogram_.get()
510 && StatisticsRecorder::WasStarted()) {
darin@google.com981f3552008-08-16 12:09:05 +0900511 DCHECK(!thread_name_.empty());
initial.commit3f4a7322008-07-27 06:49:38 +0900512 message_histogram_.reset(new LinearHistogram(
513 ASCIIToWide("MsgLoop:" + thread_name_).c_str(),
514 kLeastNonZeroMessageId,
515 kMaxMessageId,
516 kNumberOfDistinctMessagesDisplayed));
517 message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag);
518 message_histogram_->SetRangeDescriptions(event_descriptions_);
519 }
520}
521
522void MessageLoop::HistogramEvent(int event) {
523 if (message_histogram_.get())
524 message_histogram_->Add(event);
525}
526
initial.commit3f4a7322008-07-27 06:49:38 +0900527// Provide a macro that takes an expression (such as a constant, or macro
528// constant) and creates a pair to initalize an array of pairs. In this case,
529// our pair consists of the expressions value, and the "stringized" version
530// of the expression (i.e., the exrpression put in quotes). For example, if
531// we have:
532// #define FOO 2
533// #define BAR 5
534// then the following:
535// VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
536// will expand to:
537// {7, "FOO + BAR"}
538// We use the resulting array as an argument to our histogram, which reads the
539// number as a bucket identifier, and proceeds to use the corresponding name
540// in the pair (i.e., the quoted string) when printing out a histogram.
541#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
542
initial.commit3f4a7322008-07-27 06:49:38 +0900543// static
544const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
initial.commit3f4a7322008-07-27 06:49:38 +0900545 // Provide some pretty print capability in our histogram for our internal
546 // messages.
547
initial.commit3f4a7322008-07-27 06:49:38 +0900548 // A few events we handle (kindred to messages), and used to profile actions.
549 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
initial.commit3f4a7322008-07-27 06:49:38 +0900550 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
551
552 {-1, NULL} // The list must be null terminated, per API to histogram.
553};
license.botf003cfe2008-08-24 09:55:55 +0900554
darin@google.comd936b5b2008-08-26 14:53:57 +0900555//------------------------------------------------------------------------------
556// MessageLoopForUI
557
558#if defined(OS_WIN)
559
560void MessageLoopForUI::Run(Dispatcher* dispatcher) {
561 AutoRunState save_state(this);
562 state_->dispatcher = dispatcher;
563 RunHandler();
564}
565
566void MessageLoopForUI::AddObserver(Observer* observer) {
567 pump_win()->AddObserver(observer);
568}
569
570void MessageLoopForUI::RemoveObserver(Observer* observer) {
571 pump_win()->RemoveObserver(observer);
572}
573
574void MessageLoopForUI::WillProcessMessage(const MSG& message) {
575 pump_win()->WillProcessMessage(message);
576}
577void MessageLoopForUI::DidProcessMessage(const MSG& message) {
578 pump_win()->DidProcessMessage(message);
579}
580void MessageLoopForUI::PumpOutPendingPaintMessages() {
581 pump_win()->PumpOutPendingPaintMessages();
582}
583
584#endif // defined(OS_WIN)
585
586//------------------------------------------------------------------------------
587// MessageLoopForIO
588
589#if defined(OS_WIN)
590
591void MessageLoopForIO::WatchObject(HANDLE object, Watcher* watcher) {
592 pump_win()->WatchObject(object, watcher);
593}
594
595#endif // defined(OS_WIN)