blob: 4d61b6a4098ee39060234224fe38796a09c432f9 [file] [log] [blame]
initial.commitd7cae122008-07-26 21:49:381// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
[email protected]ea15e982008-08-15 07:31:2030#include "base/message_loop.h"
31
[email protected]fc7fb6e2008-08-16 03:09:0532#include <algorithm>
33
initial.commitd7cae122008-07-26 21:49:3834#include "base/logging.h"
35#include "base/string_util.h"
36#include "base/thread_local_storage.h"
initial.commitd7cae122008-07-26 21:49:3837
38// a TLS index to the message loop for the current thread
39// Note that if we start doing complex stuff in other static initializers
40// this could cause problems.
41/*static*/ TLSSlot MessageLoop::tls_index_ = ThreadLocalStorage::Alloc();
42
43//------------------------------------------------------------------------------
44
initial.commitd7cae122008-07-26 21:49:3845// Logical events for Histogram profiling. Run with -message-loop-histogrammer
46// to get an accounting of messages and actions taken on each thread.
[email protected]fc7fb6e2008-08-16 03:09:0547static const int kTaskRunEvent = 0x1;
48static const int kTimerEvent = 0x2;
initial.commitd7cae122008-07-26 21:49:3849
50// Provide range of message IDs for use in histogramming and debug display.
51static const int kLeastNonZeroMessageId = 1;
52static const int kMaxMessageId = 1099;
53static const int kNumberOfDistinctMessagesDisplayed = 1100;
54
55//------------------------------------------------------------------------------
56
[email protected]fc7fb6e2008-08-16 03:09:0557#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:3858
initial.commitd7cae122008-07-26 21:49:3859// Upon a SEH exception in this thread, it restores the original unhandled
60// exception filter.
61static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
62 ::SetUnhandledExceptionFilter(old_filter);
63 return EXCEPTION_CONTINUE_SEARCH;
64}
65
66// Retrieves a pointer to the current unhandled exception filter. There
67// is no standalone getter method.
68static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
69 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
70 top_filter = ::SetUnhandledExceptionFilter(0);
71 ::SetUnhandledExceptionFilter(top_filter);
72 return top_filter;
73}
74
[email protected]fc7fb6e2008-08-16 03:09:0575#endif // defined(OS_WIN)
76
initial.commitd7cae122008-07-26 21:49:3877//------------------------------------------------------------------------------
78
[email protected]a5b94a92008-08-12 23:25:4379MessageLoop::MessageLoop()
80#pragma warning(suppress: 4355) // OK, to use |this| in the initializer list.
81 : timer_manager_(this),
[email protected]a5b94a92008-08-12 23:25:4382 exception_restoration_(false),
83 nestable_tasks_allowed_(true),
[email protected]fc7fb6e2008-08-16 03:09:0584 state_(NULL) {
initial.commitd7cae122008-07-26 21:49:3885 DCHECK(tls_index_) << "static initializer failed";
86 DCHECK(!current()) << "should only have one message loop per thread";
87 ThreadLocalStorage::Set(tls_index_, this);
[email protected]fc7fb6e2008-08-16 03:09:0588#if defined(OS_WIN)
89 pump_ = new base::MessagePumpWin();
90#endif
initial.commitd7cae122008-07-26 21:49:3891}
92
93MessageLoop::~MessageLoop() {
94 DCHECK(this == current());
[email protected]2a127252008-08-05 23:16:4195
96 // Let interested parties have one last shot at accessing this.
97 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
98 WillDestroyCurrentMessageLoop());
99
100 // OK, now make it so that no one can find us.
initial.commitd7cae122008-07-26 21:49:38101 ThreadLocalStorage::Set(tls_index_, NULL);
[email protected]2a127252008-08-05 23:16:41102
[email protected]fc7fb6e2008-08-16 03:09:05103 DCHECK(!state_);
[email protected]2a127252008-08-05 23:16:41104
initial.commitd7cae122008-07-26 21:49:38105 // Most tasks that have not been Run() are deleted in the |timer_manager_|
106 // destructor after we remove our tls index. We delete the tasks in our
107 // queues here so their destuction is similar to the tasks in the
108 // |timer_manager_|.
109 DeletePendingTasks();
110 ReloadWorkQueue();
111 DeletePendingTasks();
112}
113
[email protected]2a127252008-08-05 23:16:41114void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
115 DCHECK(this == current());
116 destruction_observers_.AddObserver(obs);
117}
118
119void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
120 DCHECK(this == current());
121 destruction_observers_.RemoveObserver(obs);
122}
123
[email protected]ea15e982008-08-15 07:31:20124void MessageLoop::Run() {
[email protected]fc7fb6e2008-08-16 03:09:05125 AutoRunState save_state(this);
126 RunHandler();
[email protected]ea15e982008-08-15 07:31:20127}
128
[email protected]fc7fb6e2008-08-16 03:09:05129#if defined(OS_WIN)
130void MessageLoop::Run(base::MessagePumpWin::Dispatcher* dispatcher) {
131 AutoRunState save_state(this);
132 state_->dispatcher = dispatcher;
133 RunHandler();
[email protected]ea15e982008-08-15 07:31:20134}
[email protected]fc7fb6e2008-08-16 03:09:05135#endif
[email protected]3882c4332008-07-30 19:03:59136
[email protected]7e0e8762008-07-31 13:10:20137void MessageLoop::RunAllPending() {
[email protected]fc7fb6e2008-08-16 03:09:05138 AutoRunState save_state(this);
139 state_->quit_received = true; // Means run until we would otherwise block.
140 RunHandler();
initial.commitd7cae122008-07-26 21:49:38141}
142
143// Runs the loop in two different SEH modes:
144// enable_SEH_restoration_ = false : any unhandled exception goes to the last
145// one that calls SetUnhandledExceptionFilter().
146// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
147// that was existed before the loop was run.
[email protected]fc7fb6e2008-08-16 03:09:05148void MessageLoop::RunHandler() {
149#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38150 if (exception_restoration_) {
151 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
152 __try {
[email protected]fc7fb6e2008-08-16 03:09:05153 RunInternal();
initial.commitd7cae122008-07-26 21:49:38154 } __except(SEHFilter(current_filter)) {
155 }
[email protected]fc7fb6e2008-08-16 03:09:05156 return;
initial.commitd7cae122008-07-26 21:49:38157 }
[email protected]fc7fb6e2008-08-16 03:09:05158#endif
159
160 RunInternal();
initial.commitd7cae122008-07-26 21:49:38161}
162
163//------------------------------------------------------------------------------
initial.commitd7cae122008-07-26 21:49:38164
[email protected]fc7fb6e2008-08-16 03:09:05165void MessageLoop::RunInternal() {
166 DCHECK(this == current());
167
initial.commitd7cae122008-07-26 21:49:38168 StartHistogrammer();
169
[email protected]fc7fb6e2008-08-16 03:09:05170#if defined(OS_WIN)
171 if (state_->dispatcher) {
172 pump_win()->RunWithDispatcher(this, state_->dispatcher);
173 return;
[email protected]7e0e8762008-07-31 13:10:20174 }
[email protected]fc7fb6e2008-08-16 03:09:05175#endif
176
177 pump_->Run(this);
[email protected]b8f2fe5d2008-07-30 07:50:53178}
[email protected]7622bd02008-07-30 06:58:56179
[email protected]3882c4332008-07-30 19:03:59180//------------------------------------------------------------------------------
181// Wrapper functions for use in above message loop framework.
182
initial.commitd7cae122008-07-26 21:49:38183bool MessageLoop::ProcessNextDelayedNonNestableTask() {
[email protected]fc7fb6e2008-08-16 03:09:05184 if (state_->run_depth != 1)
initial.commitd7cae122008-07-26 21:49:38185 return false;
186
187 if (delayed_non_nestable_queue_.Empty())
188 return false;
189
190 RunTask(delayed_non_nestable_queue_.Pop());
191 return true;
192}
193
initial.commitd7cae122008-07-26 21:49:38194//------------------------------------------------------------------------------
195
196void MessageLoop::Quit() {
[email protected]fc7fb6e2008-08-16 03:09:05197 DCHECK(current() == this);
198 if (state_) {
199 state_->quit_received = true;
200 } else {
201 NOTREACHED() << "Must be inside Run to call Quit";
initial.commitd7cae122008-07-26 21:49:38202 }
initial.commitd7cae122008-07-26 21:49:38203}
204
205// Possibly called on a background thread!
206void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here,
207 Task* task, int delay_ms) {
208 task->SetBirthPlace(from_here);
209 DCHECK(delay_ms >= 0);
210 DCHECK(!task->is_owned_by_message_loop());
211 task->set_posted_task_delay(delay_ms);
212 DCHECK(task->is_owned_by_message_loop());
213 PostTaskInternal(task);
214}
215
216void MessageLoop::PostTaskInternal(Task* task) {
217 // Warning: Don't try to short-circuit, and handle this thread's tasks more
218 // directly, as it could starve handling of foreign threads. Put every task
219 // into this queue.
220
[email protected]fc7fb6e2008-08-16 03:09:05221 scoped_refptr<base::MessagePump> pump;
initial.commitd7cae122008-07-26 21:49:38222 {
[email protected]fc7fb6e2008-08-16 03:09:05223 AutoLock locked(incoming_queue_lock_);
224
initial.commitd7cae122008-07-26 21:49:38225 bool was_empty = incoming_queue_.Empty();
226 incoming_queue_.Push(task);
227 if (!was_empty)
228 return; // Someone else should have started the sub-pump.
229
[email protected]fc7fb6e2008-08-16 03:09:05230 pump = pump_;
[email protected]ea15e982008-08-15 07:31:20231 }
[email protected]fc7fb6e2008-08-16 03:09:05232 // Since the incoming_queue_ may contain a task that destroys this message
233 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
234 // We use a stack-based reference to the message pump so that we can call
235 // ScheduleWork outside of incoming_queue_lock_.
[email protected]ea15e982008-08-15 07:31:20236
[email protected]fc7fb6e2008-08-16 03:09:05237 pump->ScheduleWork();
initial.commitd7cae122008-07-26 21:49:38238}
239
240void MessageLoop::SetNestableTasksAllowed(bool allowed) {
[email protected]124a2bdf2008-08-09 00:14:09241 if (nestable_tasks_allowed_ != allowed) {
242 nestable_tasks_allowed_ = allowed;
243 if (!nestable_tasks_allowed_)
244 return;
245 // Start the native pump if we are not already pumping.
[email protected]fc7fb6e2008-08-16 03:09:05246 pump_->ScheduleWork();
[email protected]124a2bdf2008-08-09 00:14:09247 }
initial.commitd7cae122008-07-26 21:49:38248}
249
250bool MessageLoop::NestableTasksAllowed() const {
251 return nestable_tasks_allowed_;
252}
253
initial.commitd7cae122008-07-26 21:49:38254//------------------------------------------------------------------------------
initial.commitd7cae122008-07-26 21:49:38255
256bool MessageLoop::RunTimerTask(Timer* timer) {
257 HistogramEvent(kTimerEvent);
[email protected]a5b94a92008-08-12 23:25:43258
initial.commitd7cae122008-07-26 21:49:38259 Task* task = timer->task();
260 if (task->is_owned_by_message_loop()) {
[email protected]a5b94a92008-08-12 23:25:43261 // We constructed it through PostDelayedTask().
initial.commitd7cae122008-07-26 21:49:38262 DCHECK(!timer->repeating());
263 timer->set_task(NULL);
264 delete timer;
[email protected]ee73678e2008-08-01 21:55:17265 task->ResetBirthTime();
initial.commitd7cae122008-07-26 21:49:38266 return QueueOrRunTask(task);
initial.commitd7cae122008-07-26 21:49:38267 }
[email protected]a5b94a92008-08-12 23:25:43268
269 // This is an unknown timer task, and we *can't* delay running it, as a user
270 // might try to cancel it with TimerManager at any moment.
271 DCHECK(nestable_tasks_allowed_);
272 RunTask(task);
273 return true;
initial.commitd7cae122008-07-26 21:49:38274}
275
276void MessageLoop::DiscardTimer(Timer* timer) {
277 Task* task = timer->task();
278 if (task->is_owned_by_message_loop()) {
279 DCHECK(!timer->repeating());
280 timer->set_task(NULL);
281 delete timer; // We constructed it through PostDelayedTask().
282 delete task; // We were given ouwnership in PostTask().
283 }
284}
285
286bool MessageLoop::QueueOrRunTask(Task* new_task) {
287 if (!nestable_tasks_allowed_) {
288 // Task can't be executed right now. Add it to the queue.
289 if (new_task)
290 work_queue_.Push(new_task);
291 return false;
292 }
293
294 // Queue new_task first so we execute the task in FIFO order.
295 if (new_task)
296 work_queue_.Push(new_task);
297
298 // Execute oldest task.
299 while (!work_queue_.Empty()) {
300 Task* task = work_queue_.Pop();
[email protected]fc7fb6e2008-08-16 03:09:05301 if (task->nestable() || state_->run_depth == 1) {
initial.commitd7cae122008-07-26 21:49:38302 RunTask(task);
303 // Show that we ran a task (Note: a new one might arrive as a
304 // consequence!).
305 return true;
initial.commitd7cae122008-07-26 21:49:38306 }
[email protected]fc7fb6e2008-08-16 03:09:05307 // We couldn't run the task now because we're in a nested message loop
308 // and the task isn't nestable.
309 delayed_non_nestable_queue_.Push(task);
initial.commitd7cae122008-07-26 21:49:38310 }
311
312 // Nothing happened.
313 return false;
314}
315
316void MessageLoop::RunTask(Task* task) {
317 BeforeTaskRunSetup();
318 HistogramEvent(kTaskRunEvent);
319 // task may self-delete during Run() if we don't happen to own it.
320 // ...so check *before* we Run, since we can't check after.
321 bool we_own_task = task->is_owned_by_message_loop();
322 task->Run();
323 if (we_own_task)
324 task->RecycleOrDelete(); // Relinquish control, and probably delete.
325 AfterTaskRunRestore();
326}
327
328void MessageLoop::BeforeTaskRunSetup() {
329 DCHECK(nestable_tasks_allowed_);
330 // Execute the task and assume the worst: It is probably not reentrant.
331 nestable_tasks_allowed_ = false;
332}
333
334void MessageLoop::AfterTaskRunRestore() {
335 nestable_tasks_allowed_ = true;
336}
337
initial.commitd7cae122008-07-26 21:49:38338void MessageLoop::ReloadWorkQueue() {
339 // We can improve performance of our loading tasks from incoming_queue_ to
[email protected]fc7fb6e2008-08-16 03:09:05340 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
341 // load. That reduces the number of locks-per-task significantly when our
342 // queues get large. The optimization is disabled on threads that make use
343 // of the priority queue (prioritization requires all our tasks to be in the
initial.commitd7cae122008-07-26 21:49:38344 // work_queue_ ASAP).
345 if (!work_queue_.Empty() && !work_queue_.use_priority_queue())
346 return; // Wait till we *really* need to lock and load.
347
348 // Acquire all we can from the inter-thread queue with one lock acquisition.
349 TaskQueue new_task_list; // Null terminated list.
350 {
351 AutoLock lock(incoming_queue_lock_);
352 if (incoming_queue_.Empty())
353 return;
354 std::swap(incoming_queue_, new_task_list);
355 DCHECK(incoming_queue_.Empty());
356 } // Release lock.
357
358 while (!new_task_list.Empty()) {
359 Task* task = new_task_list.Pop();
360 DCHECK(task->is_owned_by_message_loop());
361
362 if (task->posted_task_delay() > 0)
363 timer_manager_.StartTimer(task->posted_task_delay(), task, false);
364 else
365 work_queue_.Push(task);
366 }
367}
368
369void MessageLoop::DeletePendingTasks() {
370 /* Comment this out as it's causing crashes.
371 while (!work_queue_.Empty()) {
372 Task* task = work_queue_.Pop();
373 if (task->is_owned_by_message_loop())
374 delete task;
375 }
376
377 while (!delayed_non_nestable_queue_.Empty()) {
378 Task* task = delayed_non_nestable_queue_.Pop();
379 if (task->is_owned_by_message_loop())
380 delete task;
381 }
382 */
383}
384
[email protected]a5b94a92008-08-12 23:25:43385void MessageLoop::DidChangeNextTimerExpiry() {
[email protected]ea15e982008-08-15 07:31:20386 int delay = timer_manager_.GetCurrentDelay();
[email protected]fc7fb6e2008-08-16 03:09:05387 if (delay == -1)
388 return;
389
390 // Simulates malfunctioning, early firing timers. Pending tasks should only
391 // be invoked when the delay they specify has elapsed.
392 if (timer_manager_.use_broken_delay())
393 delay = 10;
394
395 pump_->ScheduleDelayedWork(TimeDelta::FromMilliseconds(delay));
396}
397
398bool MessageLoop::DoWork() {
399 ReloadWorkQueue();
400 return QueueOrRunTask(NULL);
401}
402
403bool MessageLoop::DoDelayedWork(TimeDelta* next_delay) {
404 bool did_work = timer_manager_.RunSomePendingTimers();
405
406 // We may not have run any timers, but we may still have future timers to
407 // run, so we need to inform the pump again of pending timers.
408 *next_delay = TimeDelta::FromMilliseconds(timer_manager_.GetCurrentDelay());
409
410 return did_work;
411}
412
413bool MessageLoop::DoIdleWork() {
414 if (ProcessNextDelayedNonNestableTask())
415 return true;
416
417 if (state_->quit_received)
418 pump_->Quit();
419
420 return false;
421}
422
423//------------------------------------------------------------------------------
424// MessageLoop::AutoRunState
425
426MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
427 // Make the loop reference us.
428 previous_state_ = loop_->state_;
429 if (previous_state_) {
430 run_depth = previous_state_->run_depth + 1;
[email protected]ea15e982008-08-15 07:31:20431 } else {
[email protected]fc7fb6e2008-08-16 03:09:05432 run_depth = 1;
[email protected]ea15e982008-08-15 07:31:20433 }
[email protected]fc7fb6e2008-08-16 03:09:05434 loop_->state_ = this;
435
436 // Initialize the other fields:
437 quit_received = false;
438#if defined(OS_WIN)
439 dispatcher = NULL;
440#endif
441}
442
443MessageLoop::AutoRunState::~AutoRunState() {
444 loop_->state_ = previous_state_;
[email protected]a5b94a92008-08-12 23:25:43445}
446
initial.commitd7cae122008-07-26 21:49:38447//------------------------------------------------------------------------------
448// Implementation of the work_queue_ as a ProiritizedTaskQueue
449
450void MessageLoop::PrioritizedTaskQueue::push(Task * task) {
451 queue_.push(PrioritizedTask(task, --next_sequence_number_));
452}
453
454bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < (
455 PrioritizedTask const & right) const {
456 int compare = task_->priority_ - right.task_->priority_;
457 if (compare)
458 return compare < 0;
459 // Don't compare directly, but rather subtract. This handles overflow
460 // as sequence numbers wrap around.
461 compare = sequence_number_ - right.sequence_number_;
462 DCHECK(compare); // Sequence number are unique for a "long time."
463 // Make sure we don't starve anything with a low priority.
464 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping.
465 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping.
466 return compare < 0;
467}
468
469//------------------------------------------------------------------------------
470// Implementation of a TaskQueue as a null terminated list, with end pointers.
471
472void MessageLoop::TaskQueue::Push(Task* task) {
473 if (!first_)
474 first_ = task;
475 else
476 last_->set_next_task(task);
477 last_ = task;
478}
479
480Task* MessageLoop::TaskQueue::Pop() {
481 DCHECK((!first_) == !last_);
482 Task* task = first_;
483 if (first_) {
484 first_ = task->next_task();
485 if (!first_)
486 last_ = NULL;
487 else
488 task->set_next_task(NULL);
489 }
490 return task;
491}
492
493//------------------------------------------------------------------------------
494// Implementation of a Task queue that automatically switches into a priority
495// queue if it observes any non-zero priorities on tasks.
496
497void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) {
498 if (use_priority_queue_) {
499 prioritized_queue_.push(task);
500 } else {
501 queue_.Push(task);
502 if (task->priority()) {
503 use_priority_queue_ = true; // From now on.
504 while (!queue_.Empty())
505 prioritized_queue_.push(queue_.Pop());
506 }
507 }
508}
509
510Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() {
511 if (!use_priority_queue_)
512 return queue_.Pop();
513 Task* task = prioritized_queue_.front();
514 prioritized_queue_.pop();
515 return task;
516}
517
518bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() {
519 if (use_priority_queue_)
520 return prioritized_queue_.empty();
521 return queue_.Empty();
522}
523
524//------------------------------------------------------------------------------
525// Method and data for histogramming events and actions taken by each instance
526// on each thread.
527
528// static
529bool MessageLoop::enable_histogrammer_ = false;
530
531// static
532void MessageLoop::EnableHistogrammer(bool enable) {
533 enable_histogrammer_ = enable;
534}
535
536void MessageLoop::StartHistogrammer() {
537 if (enable_histogrammer_ && !message_histogram_.get()
538 && StatisticsRecorder::WasStarted()) {
[email protected]fc7fb6e2008-08-16 03:09:05539 DCHECK(!thread_name_.empty());
initial.commitd7cae122008-07-26 21:49:38540 message_histogram_.reset(new LinearHistogram(
541 ASCIIToWide("MsgLoop:" + thread_name_).c_str(),
542 kLeastNonZeroMessageId,
543 kMaxMessageId,
544 kNumberOfDistinctMessagesDisplayed));
545 message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag);
546 message_histogram_->SetRangeDescriptions(event_descriptions_);
547 }
548}
549
550void MessageLoop::HistogramEvent(int event) {
551 if (message_histogram_.get())
552 message_histogram_->Add(event);
553}
554
initial.commitd7cae122008-07-26 21:49:38555// Provide a macro that takes an expression (such as a constant, or macro
556// constant) and creates a pair to initalize an array of pairs. In this case,
557// our pair consists of the expressions value, and the "stringized" version
558// of the expression (i.e., the exrpression put in quotes). For example, if
559// we have:
560// #define FOO 2
561// #define BAR 5
562// then the following:
563// VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
564// will expand to:
565// {7, "FOO + BAR"}
566// We use the resulting array as an argument to our histogram, which reads the
567// number as a bucket identifier, and proceeds to use the corresponding name
568// in the pair (i.e., the quoted string) when printing out a histogram.
569#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
570
initial.commitd7cae122008-07-26 21:49:38571// static
572const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
initial.commitd7cae122008-07-26 21:49:38573 // Provide some pretty print capability in our histogram for our internal
574 // messages.
575
initial.commitd7cae122008-07-26 21:49:38576 // A few events we handle (kindred to messages), and used to profile actions.
577 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
initial.commitd7cae122008-07-26 21:49:38578 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
579
580 {-1, NULL} // The list must be null terminated, per API to histogram.
581};