blob: 4528b932853f0a53a2e0c395c50af8a69b681346 [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
67 switch (type) {
68 case TYPE_DEFAULT:
69 pump_ = new base::MessagePumpDefault();
70 break;
71 case TYPE_UI:
72 case TYPE_IO:
73 // TODO(darin): Use a special pumps for UI and IO, and figure out what to
74 // do for non-Windows platforms.
darin@google.com981f3552008-08-16 12:09:05 +090075#if defined(OS_WIN)
darin@google.comd936b5b2008-08-26 14:53:57 +090076 pump_ = new base::MessagePumpWin();
darin@google.com12d40bb2008-08-20 03:36:23 +090077#else
darin@google.comd936b5b2008-08-26 14:53:57 +090078 pump_ = new base::MessagePumpDefault();
darin@google.com981f3552008-08-16 12:09:05 +090079#endif
darin@google.comd936b5b2008-08-26 14:53:57 +090080 break;
81 }
initial.commit3f4a7322008-07-27 06:49:38 +090082}
83
84MessageLoop::~MessageLoop() {
85 DCHECK(this == current());
darin@google.com965e5342008-08-06 08:16:41 +090086
87 // Let interested parties have one last shot at accessing this.
88 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
89 WillDestroyCurrentMessageLoop());
90
91 // OK, now make it so that no one can find us.
evanm@google.comf26fd3a2008-08-21 07:54:52 +090092 tls_index_.Set(NULL);
darin@google.com965e5342008-08-06 08:16:41 +090093
darin@google.com981f3552008-08-16 12:09:05 +090094 DCHECK(!state_);
darin@google.com965e5342008-08-06 08:16:41 +090095
initial.commit3f4a7322008-07-27 06:49:38 +090096 // Most tasks that have not been Run() are deleted in the |timer_manager_|
97 // destructor after we remove our tls index. We delete the tasks in our
98 // queues here so their destuction is similar to the tasks in the
99 // |timer_manager_|.
100 DeletePendingTasks();
101 ReloadWorkQueue();
102 DeletePendingTasks();
103}
104
darin@google.com965e5342008-08-06 08:16:41 +0900105void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
106 DCHECK(this == current());
107 destruction_observers_.AddObserver(obs);
108}
109
110void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
111 DCHECK(this == current());
112 destruction_observers_.RemoveObserver(obs);
113}
114
darin@google.com6ddeb842008-08-15 16:31:20 +0900115void MessageLoop::Run() {
darin@google.com981f3552008-08-16 12:09:05 +0900116 AutoRunState save_state(this);
117 RunHandler();
darin@google.com6ddeb842008-08-15 16:31:20 +0900118}
119
jar@google.com9239e022008-07-31 22:10:20 +0900120void MessageLoop::RunAllPending() {
darin@google.com981f3552008-08-16 12:09:05 +0900121 AutoRunState save_state(this);
122 state_->quit_received = true; // Means run until we would otherwise block.
123 RunHandler();
initial.commit3f4a7322008-07-27 06:49:38 +0900124}
125
126// Runs the loop in two different SEH modes:
127// enable_SEH_restoration_ = false : any unhandled exception goes to the last
128// one that calls SetUnhandledExceptionFilter().
129// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
130// that was existed before the loop was run.
darin@google.com981f3552008-08-16 12:09:05 +0900131void MessageLoop::RunHandler() {
132#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900133 if (exception_restoration_) {
134 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
135 __try {
darin@google.com981f3552008-08-16 12:09:05 +0900136 RunInternal();
initial.commit3f4a7322008-07-27 06:49:38 +0900137 } __except(SEHFilter(current_filter)) {
138 }
darin@google.com981f3552008-08-16 12:09:05 +0900139 return;
initial.commit3f4a7322008-07-27 06:49:38 +0900140 }
darin@google.com981f3552008-08-16 12:09:05 +0900141#endif
142
143 RunInternal();
initial.commit3f4a7322008-07-27 06:49:38 +0900144}
145
146//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900147
darin@google.com981f3552008-08-16 12:09:05 +0900148void MessageLoop::RunInternal() {
149 DCHECK(this == current());
150
initial.commit3f4a7322008-07-27 06:49:38 +0900151 StartHistogrammer();
152
darin@google.com981f3552008-08-16 12:09:05 +0900153#if defined(OS_WIN)
154 if (state_->dispatcher) {
155 pump_win()->RunWithDispatcher(this, state_->dispatcher);
156 return;
jar@google.com9239e022008-07-31 22:10:20 +0900157 }
darin@google.com981f3552008-08-16 12:09:05 +0900158#endif
159
160 pump_->Run(this);
jar@google.comfbaaf692008-07-30 16:50:53 +0900161}
jar@google.com7ff36e62008-07-30 15:58:56 +0900162
jar@google.comb4d1bff2008-07-31 04:03:59 +0900163//------------------------------------------------------------------------------
164// Wrapper functions for use in above message loop framework.
165
initial.commit3f4a7322008-07-27 06:49:38 +0900166bool MessageLoop::ProcessNextDelayedNonNestableTask() {
darin@google.com981f3552008-08-16 12:09:05 +0900167 if (state_->run_depth != 1)
initial.commit3f4a7322008-07-27 06:49:38 +0900168 return false;
169
170 if (delayed_non_nestable_queue_.Empty())
171 return false;
172
173 RunTask(delayed_non_nestable_queue_.Pop());
174 return true;
175}
176
initial.commit3f4a7322008-07-27 06:49:38 +0900177//------------------------------------------------------------------------------
178
179void MessageLoop::Quit() {
darin@google.com981f3552008-08-16 12:09:05 +0900180 DCHECK(current() == this);
181 if (state_) {
182 state_->quit_received = true;
183 } else {
184 NOTREACHED() << "Must be inside Run to call Quit";
initial.commit3f4a7322008-07-27 06:49:38 +0900185 }
initial.commit3f4a7322008-07-27 06:49:38 +0900186}
187
188// Possibly called on a background thread!
189void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here,
190 Task* task, int delay_ms) {
191 task->SetBirthPlace(from_here);
192 DCHECK(delay_ms >= 0);
193 DCHECK(!task->is_owned_by_message_loop());
194 task->set_posted_task_delay(delay_ms);
195 DCHECK(task->is_owned_by_message_loop());
196 PostTaskInternal(task);
197}
198
199void MessageLoop::PostTaskInternal(Task* task) {
200 // Warning: Don't try to short-circuit, and handle this thread's tasks more
201 // directly, as it could starve handling of foreign threads. Put every task
202 // into this queue.
203
darin@google.com981f3552008-08-16 12:09:05 +0900204 scoped_refptr<base::MessagePump> pump;
initial.commit3f4a7322008-07-27 06:49:38 +0900205 {
darin@google.com981f3552008-08-16 12:09:05 +0900206 AutoLock locked(incoming_queue_lock_);
207
initial.commit3f4a7322008-07-27 06:49:38 +0900208 bool was_empty = incoming_queue_.Empty();
209 incoming_queue_.Push(task);
210 if (!was_empty)
211 return; // Someone else should have started the sub-pump.
212
darin@google.com981f3552008-08-16 12:09:05 +0900213 pump = pump_;
darin@google.com6ddeb842008-08-15 16:31:20 +0900214 }
darin@google.com981f3552008-08-16 12:09:05 +0900215 // Since the incoming_queue_ may contain a task that destroys this message
216 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
217 // We use a stack-based reference to the message pump so that we can call
218 // ScheduleWork outside of incoming_queue_lock_.
darin@google.com6ddeb842008-08-15 16:31:20 +0900219
darin@google.com981f3552008-08-16 12:09:05 +0900220 pump->ScheduleWork();
initial.commit3f4a7322008-07-27 06:49:38 +0900221}
222
223void MessageLoop::SetNestableTasksAllowed(bool allowed) {
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900224 if (nestable_tasks_allowed_ != allowed) {
225 nestable_tasks_allowed_ = allowed;
226 if (!nestable_tasks_allowed_)
227 return;
228 // Start the native pump if we are not already pumping.
darin@google.com981f3552008-08-16 12:09:05 +0900229 pump_->ScheduleWork();
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900230 }
initial.commit3f4a7322008-07-27 06:49:38 +0900231}
232
233bool MessageLoop::NestableTasksAllowed() const {
234 return nestable_tasks_allowed_;
235}
236
initial.commit3f4a7322008-07-27 06:49:38 +0900237//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900238
239bool MessageLoop::RunTimerTask(Timer* timer) {
240 HistogramEvent(kTimerEvent);
darin@google.comee6fa722008-08-13 08:25:43 +0900241
initial.commit3f4a7322008-07-27 06:49:38 +0900242 Task* task = timer->task();
243 if (task->is_owned_by_message_loop()) {
darin@google.comee6fa722008-08-13 08:25:43 +0900244 // We constructed it through PostDelayedTask().
initial.commit3f4a7322008-07-27 06:49:38 +0900245 DCHECK(!timer->repeating());
246 timer->set_task(NULL);
247 delete timer;
jar@google.com09856292008-08-02 06:55:17 +0900248 task->ResetBirthTime();
initial.commit3f4a7322008-07-27 06:49:38 +0900249 return QueueOrRunTask(task);
initial.commit3f4a7322008-07-27 06:49:38 +0900250 }
darin@google.comee6fa722008-08-13 08:25:43 +0900251
252 // This is an unknown timer task, and we *can't* delay running it, as a user
253 // might try to cancel it with TimerManager at any moment.
254 DCHECK(nestable_tasks_allowed_);
255 RunTask(task);
256 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900257}
258
259void MessageLoop::DiscardTimer(Timer* timer) {
260 Task* task = timer->task();
261 if (task->is_owned_by_message_loop()) {
262 DCHECK(!timer->repeating());
263 timer->set_task(NULL);
264 delete timer; // We constructed it through PostDelayedTask().
265 delete task; // We were given ouwnership in PostTask().
266 }
267}
268
269bool MessageLoop::QueueOrRunTask(Task* new_task) {
270 if (!nestable_tasks_allowed_) {
271 // Task can't be executed right now. Add it to the queue.
272 if (new_task)
273 work_queue_.Push(new_task);
274 return false;
275 }
276
277 // Queue new_task first so we execute the task in FIFO order.
278 if (new_task)
279 work_queue_.Push(new_task);
280
281 // Execute oldest task.
282 while (!work_queue_.Empty()) {
283 Task* task = work_queue_.Pop();
darin@google.com981f3552008-08-16 12:09:05 +0900284 if (task->nestable() || state_->run_depth == 1) {
initial.commit3f4a7322008-07-27 06:49:38 +0900285 RunTask(task);
286 // Show that we ran a task (Note: a new one might arrive as a
287 // consequence!).
288 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900289 }
darin@google.com981f3552008-08-16 12:09:05 +0900290 // We couldn't run the task now because we're in a nested message loop
291 // and the task isn't nestable.
292 delayed_non_nestable_queue_.Push(task);
initial.commit3f4a7322008-07-27 06:49:38 +0900293 }
294
295 // Nothing happened.
296 return false;
297}
298
299void MessageLoop::RunTask(Task* task) {
300 BeforeTaskRunSetup();
301 HistogramEvent(kTaskRunEvent);
302 // task may self-delete during Run() if we don't happen to own it.
303 // ...so check *before* we Run, since we can't check after.
304 bool we_own_task = task->is_owned_by_message_loop();
305 task->Run();
306 if (we_own_task)
307 task->RecycleOrDelete(); // Relinquish control, and probably delete.
308 AfterTaskRunRestore();
309}
310
311void MessageLoop::BeforeTaskRunSetup() {
312 DCHECK(nestable_tasks_allowed_);
313 // Execute the task and assume the worst: It is probably not reentrant.
314 nestable_tasks_allowed_ = false;
315}
316
317void MessageLoop::AfterTaskRunRestore() {
318 nestable_tasks_allowed_ = true;
319}
320
initial.commit3f4a7322008-07-27 06:49:38 +0900321void MessageLoop::ReloadWorkQueue() {
322 // We can improve performance of our loading tasks from incoming_queue_ to
darin@google.com981f3552008-08-16 12:09:05 +0900323 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
324 // load. That reduces the number of locks-per-task significantly when our
325 // queues get large. The optimization is disabled on threads that make use
326 // of the priority queue (prioritization requires all our tasks to be in the
initial.commit3f4a7322008-07-27 06:49:38 +0900327 // work_queue_ ASAP).
328 if (!work_queue_.Empty() && !work_queue_.use_priority_queue())
329 return; // Wait till we *really* need to lock and load.
330
331 // Acquire all we can from the inter-thread queue with one lock acquisition.
332 TaskQueue new_task_list; // Null terminated list.
333 {
334 AutoLock lock(incoming_queue_lock_);
335 if (incoming_queue_.Empty())
336 return;
337 std::swap(incoming_queue_, new_task_list);
338 DCHECK(incoming_queue_.Empty());
339 } // Release lock.
340
341 while (!new_task_list.Empty()) {
342 Task* task = new_task_list.Pop();
343 DCHECK(task->is_owned_by_message_loop());
344
345 if (task->posted_task_delay() > 0)
346 timer_manager_.StartTimer(task->posted_task_delay(), task, false);
347 else
348 work_queue_.Push(task);
349 }
350}
351
352void MessageLoop::DeletePendingTasks() {
353 /* Comment this out as it's causing crashes.
354 while (!work_queue_.Empty()) {
355 Task* task = work_queue_.Pop();
356 if (task->is_owned_by_message_loop())
357 delete task;
358 }
359
360 while (!delayed_non_nestable_queue_.Empty()) {
361 Task* task = delayed_non_nestable_queue_.Pop();
362 if (task->is_owned_by_message_loop())
363 delete task;
364 }
365 */
366}
367
darin@google.comee6fa722008-08-13 08:25:43 +0900368void MessageLoop::DidChangeNextTimerExpiry() {
darin@google.com6393bed2008-08-20 15:30:58 +0900369 Time next_delayed_work_time = timer_manager_.GetNextFireTime();
370 if (next_delayed_work_time.is_null())
darin@google.com981f3552008-08-16 12:09:05 +0900371 return;
372
373 // Simulates malfunctioning, early firing timers. Pending tasks should only
374 // be invoked when the delay they specify has elapsed.
375 if (timer_manager_.use_broken_delay())
darin@google.com6393bed2008-08-20 15:30:58 +0900376 next_delayed_work_time = Time::Now() + TimeDelta::FromMilliseconds(10);
darin@google.com981f3552008-08-16 12:09:05 +0900377
darin@google.com6393bed2008-08-20 15:30:58 +0900378 pump_->ScheduleDelayedWork(next_delayed_work_time);
darin@google.com981f3552008-08-16 12:09:05 +0900379}
380
381bool MessageLoop::DoWork() {
382 ReloadWorkQueue();
383 return QueueOrRunTask(NULL);
384}
385
darin@google.com6393bed2008-08-20 15:30:58 +0900386bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) {
darin@google.com981f3552008-08-16 12:09:05 +0900387 bool did_work = timer_manager_.RunSomePendingTimers();
388
389 // We may not have run any timers, but we may still have future timers to
390 // run, so we need to inform the pump again of pending timers.
darin@google.com6393bed2008-08-20 15:30:58 +0900391 *next_delayed_work_time = timer_manager_.GetNextFireTime();
darin@google.com981f3552008-08-16 12:09:05 +0900392
393 return did_work;
394}
395
396bool MessageLoop::DoIdleWork() {
397 if (ProcessNextDelayedNonNestableTask())
398 return true;
399
400 if (state_->quit_received)
401 pump_->Quit();
402
403 return false;
404}
405
406//------------------------------------------------------------------------------
407// MessageLoop::AutoRunState
408
409MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
410 // Make the loop reference us.
411 previous_state_ = loop_->state_;
412 if (previous_state_) {
413 run_depth = previous_state_->run_depth + 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900414 } else {
darin@google.com981f3552008-08-16 12:09:05 +0900415 run_depth = 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900416 }
darin@google.com981f3552008-08-16 12:09:05 +0900417 loop_->state_ = this;
418
419 // Initialize the other fields:
420 quit_received = false;
421#if defined(OS_WIN)
422 dispatcher = NULL;
423#endif
424}
425
426MessageLoop::AutoRunState::~AutoRunState() {
427 loop_->state_ = previous_state_;
darin@google.comee6fa722008-08-13 08:25:43 +0900428}
429
initial.commit3f4a7322008-07-27 06:49:38 +0900430//------------------------------------------------------------------------------
431// Implementation of the work_queue_ as a ProiritizedTaskQueue
432
433void MessageLoop::PrioritizedTaskQueue::push(Task * task) {
434 queue_.push(PrioritizedTask(task, --next_sequence_number_));
435}
436
437bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < (
438 PrioritizedTask const & right) const {
darin@google.com12d40bb2008-08-20 03:36:23 +0900439 int compare = task_->priority() - right.task_->priority();
initial.commit3f4a7322008-07-27 06:49:38 +0900440 if (compare)
441 return compare < 0;
442 // Don't compare directly, but rather subtract. This handles overflow
443 // as sequence numbers wrap around.
444 compare = sequence_number_ - right.sequence_number_;
445 DCHECK(compare); // Sequence number are unique for a "long time."
446 // Make sure we don't starve anything with a low priority.
447 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping.
448 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping.
449 return compare < 0;
450}
451
452//------------------------------------------------------------------------------
453// Implementation of a TaskQueue as a null terminated list, with end pointers.
454
455void MessageLoop::TaskQueue::Push(Task* task) {
456 if (!first_)
457 first_ = task;
458 else
459 last_->set_next_task(task);
460 last_ = task;
461}
462
463Task* MessageLoop::TaskQueue::Pop() {
464 DCHECK((!first_) == !last_);
465 Task* task = first_;
466 if (first_) {
467 first_ = task->next_task();
468 if (!first_)
469 last_ = NULL;
470 else
471 task->set_next_task(NULL);
472 }
473 return task;
474}
475
476//------------------------------------------------------------------------------
477// Implementation of a Task queue that automatically switches into a priority
478// queue if it observes any non-zero priorities on tasks.
479
480void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) {
481 if (use_priority_queue_) {
482 prioritized_queue_.push(task);
483 } else {
484 queue_.Push(task);
485 if (task->priority()) {
486 use_priority_queue_ = true; // From now on.
487 while (!queue_.Empty())
488 prioritized_queue_.push(queue_.Pop());
489 }
490 }
491}
492
493Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() {
494 if (!use_priority_queue_)
495 return queue_.Pop();
496 Task* task = prioritized_queue_.front();
497 prioritized_queue_.pop();
498 return task;
499}
500
501bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() {
502 if (use_priority_queue_)
503 return prioritized_queue_.empty();
504 return queue_.Empty();
505}
506
507//------------------------------------------------------------------------------
508// Method and data for histogramming events and actions taken by each instance
509// on each thread.
510
511// static
512bool MessageLoop::enable_histogrammer_ = false;
513
514// static
515void MessageLoop::EnableHistogrammer(bool enable) {
516 enable_histogrammer_ = enable;
517}
518
519void MessageLoop::StartHistogrammer() {
520 if (enable_histogrammer_ && !message_histogram_.get()
521 && StatisticsRecorder::WasStarted()) {
darin@google.com981f3552008-08-16 12:09:05 +0900522 DCHECK(!thread_name_.empty());
initial.commit3f4a7322008-07-27 06:49:38 +0900523 message_histogram_.reset(new LinearHistogram(
524 ASCIIToWide("MsgLoop:" + thread_name_).c_str(),
525 kLeastNonZeroMessageId,
526 kMaxMessageId,
527 kNumberOfDistinctMessagesDisplayed));
528 message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag);
529 message_histogram_->SetRangeDescriptions(event_descriptions_);
530 }
531}
532
533void MessageLoop::HistogramEvent(int event) {
534 if (message_histogram_.get())
535 message_histogram_->Add(event);
536}
537
initial.commit3f4a7322008-07-27 06:49:38 +0900538// Provide a macro that takes an expression (such as a constant, or macro
539// constant) and creates a pair to initalize an array of pairs. In this case,
540// our pair consists of the expressions value, and the "stringized" version
541// of the expression (i.e., the exrpression put in quotes). For example, if
542// we have:
543// #define FOO 2
544// #define BAR 5
545// then the following:
546// VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
547// will expand to:
548// {7, "FOO + BAR"}
549// We use the resulting array as an argument to our histogram, which reads the
550// number as a bucket identifier, and proceeds to use the corresponding name
551// in the pair (i.e., the quoted string) when printing out a histogram.
552#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
553
initial.commit3f4a7322008-07-27 06:49:38 +0900554// static
555const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
initial.commit3f4a7322008-07-27 06:49:38 +0900556 // Provide some pretty print capability in our histogram for our internal
557 // messages.
558
initial.commit3f4a7322008-07-27 06:49:38 +0900559 // A few events we handle (kindred to messages), and used to profile actions.
560 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
initial.commit3f4a7322008-07-27 06:49:38 +0900561 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
562
563 {-1, NULL} // The list must be null terminated, per API to histogram.
564};
license.botf003cfe2008-08-24 09:55:55 +0900565
darin@google.comd936b5b2008-08-26 14:53:57 +0900566//------------------------------------------------------------------------------
567// MessageLoopForUI
568
569#if defined(OS_WIN)
570
571void MessageLoopForUI::Run(Dispatcher* dispatcher) {
572 AutoRunState save_state(this);
573 state_->dispatcher = dispatcher;
574 RunHandler();
575}
576
577void MessageLoopForUI::AddObserver(Observer* observer) {
578 pump_win()->AddObserver(observer);
579}
580
581void MessageLoopForUI::RemoveObserver(Observer* observer) {
582 pump_win()->RemoveObserver(observer);
583}
584
585void MessageLoopForUI::WillProcessMessage(const MSG& message) {
586 pump_win()->WillProcessMessage(message);
587}
588void MessageLoopForUI::DidProcessMessage(const MSG& message) {
589 pump_win()->DidProcessMessage(message);
590}
591void MessageLoopForUI::PumpOutPendingPaintMessages() {
592 pump_win()->PumpOutPendingPaintMessages();
593}
594
595#endif // defined(OS_WIN)
596
597//------------------------------------------------------------------------------
598// MessageLoopForIO
599
600#if defined(OS_WIN)
601
602void MessageLoopForIO::WatchObject(HANDLE object, Watcher* watcher) {
603 pump_win()->WatchObject(object, watcher);
604}
605
606#endif // defined(OS_WIN)