blob: a84b3b5921f704663f64182382cc6c58c36c7245 [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.comee6fa722008-08-13 08:25:43 +090058MessageLoop::MessageLoop()
mmentovai@google.comfa5f9932008-08-22 07:26:06 +090059 : ALLOW_THIS_IN_INITIALIZER_LIST(timer_manager_(this)),
darin@google.comee6fa722008-08-13 08:25:43 +090060 nestable_tasks_allowed_(true),
darin@google.com12d40bb2008-08-20 03:36:23 +090061 exception_restoration_(false),
darin@google.com981f3552008-08-16 12:09:05 +090062 state_(NULL) {
initial.commit3f4a7322008-07-27 06:49:38 +090063 DCHECK(!current()) << "should only have one message loop per thread";
evanm@google.comf26fd3a2008-08-21 07:54:52 +090064 tls_index_.Set(this);
darin@google.com12d40bb2008-08-20 03:36:23 +090065 // TODO(darin): Generalize this to support instantiating different pumps.
darin@google.com981f3552008-08-16 12:09:05 +090066#if defined(OS_WIN)
67 pump_ = new base::MessagePumpWin();
darin@google.com12d40bb2008-08-20 03:36:23 +090068#else
69 pump_ = new base::MessagePumpDefault();
darin@google.com981f3552008-08-16 12:09:05 +090070#endif
initial.commit3f4a7322008-07-27 06:49:38 +090071}
72
73MessageLoop::~MessageLoop() {
74 DCHECK(this == current());
darin@google.com965e5342008-08-06 08:16:41 +090075
76 // Let interested parties have one last shot at accessing this.
77 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
78 WillDestroyCurrentMessageLoop());
79
80 // OK, now make it so that no one can find us.
evanm@google.comf26fd3a2008-08-21 07:54:52 +090081 tls_index_.Set(NULL);
darin@google.com965e5342008-08-06 08:16:41 +090082
darin@google.com981f3552008-08-16 12:09:05 +090083 DCHECK(!state_);
darin@google.com965e5342008-08-06 08:16:41 +090084
initial.commit3f4a7322008-07-27 06:49:38 +090085 // Most tasks that have not been Run() are deleted in the |timer_manager_|
86 // destructor after we remove our tls index. We delete the tasks in our
87 // queues here so their destuction is similar to the tasks in the
88 // |timer_manager_|.
89 DeletePendingTasks();
90 ReloadWorkQueue();
91 DeletePendingTasks();
92}
93
darin@google.com965e5342008-08-06 08:16:41 +090094void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
95 DCHECK(this == current());
96 destruction_observers_.AddObserver(obs);
97}
98
99void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
100 DCHECK(this == current());
101 destruction_observers_.RemoveObserver(obs);
102}
103
darin@google.com6ddeb842008-08-15 16:31:20 +0900104void MessageLoop::Run() {
darin@google.com981f3552008-08-16 12:09:05 +0900105 AutoRunState save_state(this);
106 RunHandler();
darin@google.com6ddeb842008-08-15 16:31:20 +0900107}
108
darin@google.com981f3552008-08-16 12:09:05 +0900109#if defined(OS_WIN)
110void MessageLoop::Run(base::MessagePumpWin::Dispatcher* dispatcher) {
111 AutoRunState save_state(this);
112 state_->dispatcher = dispatcher;
113 RunHandler();
darin@google.com6ddeb842008-08-15 16:31:20 +0900114}
darin@google.com981f3552008-08-16 12:09:05 +0900115#endif
jar@google.comb4d1bff2008-07-31 04:03:59 +0900116
jar@google.com9239e022008-07-31 22:10:20 +0900117void MessageLoop::RunAllPending() {
darin@google.com981f3552008-08-16 12:09:05 +0900118 AutoRunState save_state(this);
119 state_->quit_received = true; // Means run until we would otherwise block.
120 RunHandler();
initial.commit3f4a7322008-07-27 06:49:38 +0900121}
122
123// Runs the loop in two different SEH modes:
124// enable_SEH_restoration_ = false : any unhandled exception goes to the last
125// one that calls SetUnhandledExceptionFilter().
126// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
127// that was existed before the loop was run.
darin@google.com981f3552008-08-16 12:09:05 +0900128void MessageLoop::RunHandler() {
129#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900130 if (exception_restoration_) {
131 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
132 __try {
darin@google.com981f3552008-08-16 12:09:05 +0900133 RunInternal();
initial.commit3f4a7322008-07-27 06:49:38 +0900134 } __except(SEHFilter(current_filter)) {
135 }
darin@google.com981f3552008-08-16 12:09:05 +0900136 return;
initial.commit3f4a7322008-07-27 06:49:38 +0900137 }
darin@google.com981f3552008-08-16 12:09:05 +0900138#endif
139
140 RunInternal();
initial.commit3f4a7322008-07-27 06:49:38 +0900141}
142
143//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900144
darin@google.com981f3552008-08-16 12:09:05 +0900145void MessageLoop::RunInternal() {
146 DCHECK(this == current());
147
initial.commit3f4a7322008-07-27 06:49:38 +0900148 StartHistogrammer();
149
darin@google.com981f3552008-08-16 12:09:05 +0900150#if defined(OS_WIN)
151 if (state_->dispatcher) {
152 pump_win()->RunWithDispatcher(this, state_->dispatcher);
153 return;
jar@google.com9239e022008-07-31 22:10:20 +0900154 }
darin@google.com981f3552008-08-16 12:09:05 +0900155#endif
156
157 pump_->Run(this);
jar@google.comfbaaf692008-07-30 16:50:53 +0900158}
jar@google.com7ff36e62008-07-30 15:58:56 +0900159
jar@google.comb4d1bff2008-07-31 04:03:59 +0900160//------------------------------------------------------------------------------
161// Wrapper functions for use in above message loop framework.
162
initial.commit3f4a7322008-07-27 06:49:38 +0900163bool MessageLoop::ProcessNextDelayedNonNestableTask() {
darin@google.com981f3552008-08-16 12:09:05 +0900164 if (state_->run_depth != 1)
initial.commit3f4a7322008-07-27 06:49:38 +0900165 return false;
166
167 if (delayed_non_nestable_queue_.Empty())
168 return false;
169
170 RunTask(delayed_non_nestable_queue_.Pop());
171 return true;
172}
173
initial.commit3f4a7322008-07-27 06:49:38 +0900174//------------------------------------------------------------------------------
175
176void MessageLoop::Quit() {
darin@google.com981f3552008-08-16 12:09:05 +0900177 DCHECK(current() == this);
178 if (state_) {
179 state_->quit_received = true;
180 } else {
181 NOTREACHED() << "Must be inside Run to call Quit";
initial.commit3f4a7322008-07-27 06:49:38 +0900182 }
initial.commit3f4a7322008-07-27 06:49:38 +0900183}
184
185// Possibly called on a background thread!
186void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here,
187 Task* task, int delay_ms) {
188 task->SetBirthPlace(from_here);
189 DCHECK(delay_ms >= 0);
190 DCHECK(!task->is_owned_by_message_loop());
191 task->set_posted_task_delay(delay_ms);
192 DCHECK(task->is_owned_by_message_loop());
193 PostTaskInternal(task);
194}
195
196void MessageLoop::PostTaskInternal(Task* task) {
197 // Warning: Don't try to short-circuit, and handle this thread's tasks more
198 // directly, as it could starve handling of foreign threads. Put every task
199 // into this queue.
200
darin@google.com981f3552008-08-16 12:09:05 +0900201 scoped_refptr<base::MessagePump> pump;
initial.commit3f4a7322008-07-27 06:49:38 +0900202 {
darin@google.com981f3552008-08-16 12:09:05 +0900203 AutoLock locked(incoming_queue_lock_);
204
initial.commit3f4a7322008-07-27 06:49:38 +0900205 bool was_empty = incoming_queue_.Empty();
206 incoming_queue_.Push(task);
207 if (!was_empty)
208 return; // Someone else should have started the sub-pump.
209
darin@google.com981f3552008-08-16 12:09:05 +0900210 pump = pump_;
darin@google.com6ddeb842008-08-15 16:31:20 +0900211 }
darin@google.com981f3552008-08-16 12:09:05 +0900212 // Since the incoming_queue_ may contain a task that destroys this message
213 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
214 // We use a stack-based reference to the message pump so that we can call
215 // ScheduleWork outside of incoming_queue_lock_.
darin@google.com6ddeb842008-08-15 16:31:20 +0900216
darin@google.com981f3552008-08-16 12:09:05 +0900217 pump->ScheduleWork();
initial.commit3f4a7322008-07-27 06:49:38 +0900218}
219
220void MessageLoop::SetNestableTasksAllowed(bool allowed) {
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900221 if (nestable_tasks_allowed_ != allowed) {
222 nestable_tasks_allowed_ = allowed;
223 if (!nestable_tasks_allowed_)
224 return;
225 // Start the native pump if we are not already pumping.
darin@google.com981f3552008-08-16 12:09:05 +0900226 pump_->ScheduleWork();
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900227 }
initial.commit3f4a7322008-07-27 06:49:38 +0900228}
229
230bool MessageLoop::NestableTasksAllowed() const {
231 return nestable_tasks_allowed_;
232}
233
initial.commit3f4a7322008-07-27 06:49:38 +0900234//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900235
236bool MessageLoop::RunTimerTask(Timer* timer) {
237 HistogramEvent(kTimerEvent);
darin@google.comee6fa722008-08-13 08:25:43 +0900238
initial.commit3f4a7322008-07-27 06:49:38 +0900239 Task* task = timer->task();
240 if (task->is_owned_by_message_loop()) {
darin@google.comee6fa722008-08-13 08:25:43 +0900241 // We constructed it through PostDelayedTask().
initial.commit3f4a7322008-07-27 06:49:38 +0900242 DCHECK(!timer->repeating());
243 timer->set_task(NULL);
244 delete timer;
jar@google.com09856292008-08-02 06:55:17 +0900245 task->ResetBirthTime();
initial.commit3f4a7322008-07-27 06:49:38 +0900246 return QueueOrRunTask(task);
initial.commit3f4a7322008-07-27 06:49:38 +0900247 }
darin@google.comee6fa722008-08-13 08:25:43 +0900248
249 // This is an unknown timer task, and we *can't* delay running it, as a user
250 // might try to cancel it with TimerManager at any moment.
251 DCHECK(nestable_tasks_allowed_);
252 RunTask(task);
253 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900254}
255
256void MessageLoop::DiscardTimer(Timer* timer) {
257 Task* task = timer->task();
258 if (task->is_owned_by_message_loop()) {
259 DCHECK(!timer->repeating());
260 timer->set_task(NULL);
261 delete timer; // We constructed it through PostDelayedTask().
262 delete task; // We were given ouwnership in PostTask().
263 }
264}
265
266bool MessageLoop::QueueOrRunTask(Task* new_task) {
267 if (!nestable_tasks_allowed_) {
268 // Task can't be executed right now. Add it to the queue.
269 if (new_task)
270 work_queue_.Push(new_task);
271 return false;
272 }
273
274 // Queue new_task first so we execute the task in FIFO order.
275 if (new_task)
276 work_queue_.Push(new_task);
277
278 // Execute oldest task.
279 while (!work_queue_.Empty()) {
280 Task* task = work_queue_.Pop();
darin@google.com981f3552008-08-16 12:09:05 +0900281 if (task->nestable() || state_->run_depth == 1) {
initial.commit3f4a7322008-07-27 06:49:38 +0900282 RunTask(task);
283 // Show that we ran a task (Note: a new one might arrive as a
284 // consequence!).
285 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900286 }
darin@google.com981f3552008-08-16 12:09:05 +0900287 // We couldn't run the task now because we're in a nested message loop
288 // and the task isn't nestable.
289 delayed_non_nestable_queue_.Push(task);
initial.commit3f4a7322008-07-27 06:49:38 +0900290 }
291
292 // Nothing happened.
293 return false;
294}
295
296void MessageLoop::RunTask(Task* task) {
297 BeforeTaskRunSetup();
298 HistogramEvent(kTaskRunEvent);
299 // task may self-delete during Run() if we don't happen to own it.
300 // ...so check *before* we Run, since we can't check after.
301 bool we_own_task = task->is_owned_by_message_loop();
302 task->Run();
303 if (we_own_task)
304 task->RecycleOrDelete(); // Relinquish control, and probably delete.
305 AfterTaskRunRestore();
306}
307
308void MessageLoop::BeforeTaskRunSetup() {
309 DCHECK(nestable_tasks_allowed_);
310 // Execute the task and assume the worst: It is probably not reentrant.
311 nestable_tasks_allowed_ = false;
312}
313
314void MessageLoop::AfterTaskRunRestore() {
315 nestable_tasks_allowed_ = true;
316}
317
initial.commit3f4a7322008-07-27 06:49:38 +0900318void MessageLoop::ReloadWorkQueue() {
319 // We can improve performance of our loading tasks from incoming_queue_ to
darin@google.com981f3552008-08-16 12:09:05 +0900320 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
321 // load. That reduces the number of locks-per-task significantly when our
322 // queues get large. The optimization is disabled on threads that make use
323 // of the priority queue (prioritization requires all our tasks to be in the
initial.commit3f4a7322008-07-27 06:49:38 +0900324 // work_queue_ ASAP).
325 if (!work_queue_.Empty() && !work_queue_.use_priority_queue())
326 return; // Wait till we *really* need to lock and load.
327
328 // Acquire all we can from the inter-thread queue with one lock acquisition.
329 TaskQueue new_task_list; // Null terminated list.
330 {
331 AutoLock lock(incoming_queue_lock_);
332 if (incoming_queue_.Empty())
333 return;
334 std::swap(incoming_queue_, new_task_list);
335 DCHECK(incoming_queue_.Empty());
336 } // Release lock.
337
338 while (!new_task_list.Empty()) {
339 Task* task = new_task_list.Pop();
340 DCHECK(task->is_owned_by_message_loop());
341
342 if (task->posted_task_delay() > 0)
343 timer_manager_.StartTimer(task->posted_task_delay(), task, false);
344 else
345 work_queue_.Push(task);
346 }
347}
348
349void MessageLoop::DeletePendingTasks() {
350 /* Comment this out as it's causing crashes.
351 while (!work_queue_.Empty()) {
352 Task* task = work_queue_.Pop();
353 if (task->is_owned_by_message_loop())
354 delete task;
355 }
356
357 while (!delayed_non_nestable_queue_.Empty()) {
358 Task* task = delayed_non_nestable_queue_.Pop();
359 if (task->is_owned_by_message_loop())
360 delete task;
361 }
362 */
363}
364
darin@google.comee6fa722008-08-13 08:25:43 +0900365void MessageLoop::DidChangeNextTimerExpiry() {
darin@google.com6393bed2008-08-20 15:30:58 +0900366 Time next_delayed_work_time = timer_manager_.GetNextFireTime();
367 if (next_delayed_work_time.is_null())
darin@google.com981f3552008-08-16 12:09:05 +0900368 return;
369
370 // Simulates malfunctioning, early firing timers. Pending tasks should only
371 // be invoked when the delay they specify has elapsed.
372 if (timer_manager_.use_broken_delay())
darin@google.com6393bed2008-08-20 15:30:58 +0900373 next_delayed_work_time = Time::Now() + TimeDelta::FromMilliseconds(10);
darin@google.com981f3552008-08-16 12:09:05 +0900374
darin@google.com6393bed2008-08-20 15:30:58 +0900375 pump_->ScheduleDelayedWork(next_delayed_work_time);
darin@google.com981f3552008-08-16 12:09:05 +0900376}
377
378bool MessageLoop::DoWork() {
379 ReloadWorkQueue();
380 return QueueOrRunTask(NULL);
381}
382
darin@google.com6393bed2008-08-20 15:30:58 +0900383bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) {
darin@google.com981f3552008-08-16 12:09:05 +0900384 bool did_work = timer_manager_.RunSomePendingTimers();
385
386 // We may not have run any timers, but we may still have future timers to
387 // run, so we need to inform the pump again of pending timers.
darin@google.com6393bed2008-08-20 15:30:58 +0900388 *next_delayed_work_time = timer_manager_.GetNextFireTime();
darin@google.com981f3552008-08-16 12:09:05 +0900389
390 return did_work;
391}
392
393bool MessageLoop::DoIdleWork() {
394 if (ProcessNextDelayedNonNestableTask())
395 return true;
396
397 if (state_->quit_received)
398 pump_->Quit();
399
400 return false;
401}
402
403//------------------------------------------------------------------------------
404// MessageLoop::AutoRunState
405
406MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
407 // Make the loop reference us.
408 previous_state_ = loop_->state_;
409 if (previous_state_) {
410 run_depth = previous_state_->run_depth + 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900411 } else {
darin@google.com981f3552008-08-16 12:09:05 +0900412 run_depth = 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900413 }
darin@google.com981f3552008-08-16 12:09:05 +0900414 loop_->state_ = this;
415
416 // Initialize the other fields:
417 quit_received = false;
418#if defined(OS_WIN)
419 dispatcher = NULL;
420#endif
421}
422
423MessageLoop::AutoRunState::~AutoRunState() {
424 loop_->state_ = previous_state_;
darin@google.comee6fa722008-08-13 08:25:43 +0900425}
426
initial.commit3f4a7322008-07-27 06:49:38 +0900427//------------------------------------------------------------------------------
428// Implementation of the work_queue_ as a ProiritizedTaskQueue
429
430void MessageLoop::PrioritizedTaskQueue::push(Task * task) {
431 queue_.push(PrioritizedTask(task, --next_sequence_number_));
432}
433
434bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < (
435 PrioritizedTask const & right) const {
darin@google.com12d40bb2008-08-20 03:36:23 +0900436 int compare = task_->priority() - right.task_->priority();
initial.commit3f4a7322008-07-27 06:49:38 +0900437 if (compare)
438 return compare < 0;
439 // Don't compare directly, but rather subtract. This handles overflow
440 // as sequence numbers wrap around.
441 compare = sequence_number_ - right.sequence_number_;
442 DCHECK(compare); // Sequence number are unique for a "long time."
443 // Make sure we don't starve anything with a low priority.
444 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping.
445 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping.
446 return compare < 0;
447}
448
449//------------------------------------------------------------------------------
450// Implementation of a TaskQueue as a null terminated list, with end pointers.
451
452void MessageLoop::TaskQueue::Push(Task* task) {
453 if (!first_)
454 first_ = task;
455 else
456 last_->set_next_task(task);
457 last_ = task;
458}
459
460Task* MessageLoop::TaskQueue::Pop() {
461 DCHECK((!first_) == !last_);
462 Task* task = first_;
463 if (first_) {
464 first_ = task->next_task();
465 if (!first_)
466 last_ = NULL;
467 else
468 task->set_next_task(NULL);
469 }
470 return task;
471}
472
473//------------------------------------------------------------------------------
474// Implementation of a Task queue that automatically switches into a priority
475// queue if it observes any non-zero priorities on tasks.
476
477void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) {
478 if (use_priority_queue_) {
479 prioritized_queue_.push(task);
480 } else {
481 queue_.Push(task);
482 if (task->priority()) {
483 use_priority_queue_ = true; // From now on.
484 while (!queue_.Empty())
485 prioritized_queue_.push(queue_.Pop());
486 }
487 }
488}
489
490Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() {
491 if (!use_priority_queue_)
492 return queue_.Pop();
493 Task* task = prioritized_queue_.front();
494 prioritized_queue_.pop();
495 return task;
496}
497
498bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() {
499 if (use_priority_queue_)
500 return prioritized_queue_.empty();
501 return queue_.Empty();
502}
503
504//------------------------------------------------------------------------------
505// Method and data for histogramming events and actions taken by each instance
506// on each thread.
507
508// static
509bool MessageLoop::enable_histogrammer_ = false;
510
511// static
512void MessageLoop::EnableHistogrammer(bool enable) {
513 enable_histogrammer_ = enable;
514}
515
516void MessageLoop::StartHistogrammer() {
517 if (enable_histogrammer_ && !message_histogram_.get()
518 && StatisticsRecorder::WasStarted()) {
darin@google.com981f3552008-08-16 12:09:05 +0900519 DCHECK(!thread_name_.empty());
initial.commit3f4a7322008-07-27 06:49:38 +0900520 message_histogram_.reset(new LinearHistogram(
521 ASCIIToWide("MsgLoop:" + thread_name_).c_str(),
522 kLeastNonZeroMessageId,
523 kMaxMessageId,
524 kNumberOfDistinctMessagesDisplayed));
525 message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag);
526 message_histogram_->SetRangeDescriptions(event_descriptions_);
527 }
528}
529
530void MessageLoop::HistogramEvent(int event) {
531 if (message_histogram_.get())
532 message_histogram_->Add(event);
533}
534
initial.commit3f4a7322008-07-27 06:49:38 +0900535// Provide a macro that takes an expression (such as a constant, or macro
536// constant) and creates a pair to initalize an array of pairs. In this case,
537// our pair consists of the expressions value, and the "stringized" version
538// of the expression (i.e., the exrpression put in quotes). For example, if
539// we have:
540// #define FOO 2
541// #define BAR 5
542// then the following:
543// VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
544// will expand to:
545// {7, "FOO + BAR"}
546// We use the resulting array as an argument to our histogram, which reads the
547// number as a bucket identifier, and proceeds to use the corresponding name
548// in the pair (i.e., the quoted string) when printing out a histogram.
549#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
550
initial.commit3f4a7322008-07-27 06:49:38 +0900551// static
552const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
initial.commit3f4a7322008-07-27 06:49:38 +0900553 // Provide some pretty print capability in our histogram for our internal
554 // messages.
555
initial.commit3f4a7322008-07-27 06:49:38 +0900556 // A few events we handle (kindred to messages), and used to profile actions.
557 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
initial.commit3f4a7322008-07-27 06:49:38 +0900558 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
559
560 {-1, NULL} // The list must be null terminated, per API to histogram.
561};
license.botf003cfe2008-08-24 09:55:55 +0900562