blob: 410394f7911db02156db3242b60da89dea7701f8 [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.com0795f572008-08-30 09:22:48 +090069 if (type_ == TYPE_DEFAULT) {
70 pump_ = new base::MessagePumpDefault();
71 } else {
72 pump_ = new base::MessagePumpWin();
73 }
darin@google.com12d40bb2008-08-20 03:36:23 +090074#else
darin@google.com132072e2008-08-26 15:52:41 +090075 pump_ = new base::MessagePumpDefault();
darin@google.com981f3552008-08-16 12:09:05 +090076#endif
initial.commit3f4a7322008-07-27 06:49:38 +090077}
78
79MessageLoop::~MessageLoop() {
80 DCHECK(this == current());
darin@google.com965e5342008-08-06 08:16:41 +090081
82 // Let interested parties have one last shot at accessing this.
83 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
84 WillDestroyCurrentMessageLoop());
85
86 // OK, now make it so that no one can find us.
evanm@google.comf26fd3a2008-08-21 07:54:52 +090087 tls_index_.Set(NULL);
darin@google.com965e5342008-08-06 08:16:41 +090088
darin@google.com981f3552008-08-16 12:09:05 +090089 DCHECK(!state_);
darin@google.com965e5342008-08-06 08:16:41 +090090
initial.commit3f4a7322008-07-27 06:49:38 +090091 // Most tasks that have not been Run() are deleted in the |timer_manager_|
92 // destructor after we remove our tls index. We delete the tasks in our
93 // queues here so their destuction is similar to the tasks in the
94 // |timer_manager_|.
95 DeletePendingTasks();
96 ReloadWorkQueue();
97 DeletePendingTasks();
98}
99
darin@google.com965e5342008-08-06 08:16:41 +0900100void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
101 DCHECK(this == current());
102 destruction_observers_.AddObserver(obs);
103}
104
105void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
106 DCHECK(this == current());
107 destruction_observers_.RemoveObserver(obs);
108}
109
darin@google.com6ddeb842008-08-15 16:31:20 +0900110void MessageLoop::Run() {
darin@google.com981f3552008-08-16 12:09:05 +0900111 AutoRunState save_state(this);
112 RunHandler();
darin@google.com6ddeb842008-08-15 16:31:20 +0900113}
114
jar@google.com9239e022008-07-31 22:10:20 +0900115void MessageLoop::RunAllPending() {
darin@google.com981f3552008-08-16 12:09:05 +0900116 AutoRunState save_state(this);
117 state_->quit_received = true; // Means run until we would otherwise block.
118 RunHandler();
initial.commit3f4a7322008-07-27 06:49:38 +0900119}
120
121// Runs the loop in two different SEH modes:
122// enable_SEH_restoration_ = false : any unhandled exception goes to the last
123// one that calls SetUnhandledExceptionFilter().
124// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
125// that was existed before the loop was run.
darin@google.com981f3552008-08-16 12:09:05 +0900126void MessageLoop::RunHandler() {
127#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900128 if (exception_restoration_) {
129 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
130 __try {
darin@google.com981f3552008-08-16 12:09:05 +0900131 RunInternal();
initial.commit3f4a7322008-07-27 06:49:38 +0900132 } __except(SEHFilter(current_filter)) {
133 }
darin@google.com981f3552008-08-16 12:09:05 +0900134 return;
initial.commit3f4a7322008-07-27 06:49:38 +0900135 }
darin@google.com981f3552008-08-16 12:09:05 +0900136#endif
137
138 RunInternal();
initial.commit3f4a7322008-07-27 06:49:38 +0900139}
140
141//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900142
darin@google.com981f3552008-08-16 12:09:05 +0900143void MessageLoop::RunInternal() {
144 DCHECK(this == current());
145
initial.commit3f4a7322008-07-27 06:49:38 +0900146 StartHistogrammer();
147
darin@google.com981f3552008-08-16 12:09:05 +0900148#if defined(OS_WIN)
149 if (state_->dispatcher) {
150 pump_win()->RunWithDispatcher(this, state_->dispatcher);
151 return;
jar@google.com9239e022008-07-31 22:10:20 +0900152 }
darin@google.com981f3552008-08-16 12:09:05 +0900153#endif
154
155 pump_->Run(this);
jar@google.comfbaaf692008-07-30 16:50:53 +0900156}
jar@google.com7ff36e62008-07-30 15:58:56 +0900157
jar@google.comb4d1bff2008-07-31 04:03:59 +0900158//------------------------------------------------------------------------------
159// Wrapper functions for use in above message loop framework.
160
initial.commit3f4a7322008-07-27 06:49:38 +0900161bool MessageLoop::ProcessNextDelayedNonNestableTask() {
darin@google.com981f3552008-08-16 12:09:05 +0900162 if (state_->run_depth != 1)
initial.commit3f4a7322008-07-27 06:49:38 +0900163 return false;
164
165 if (delayed_non_nestable_queue_.Empty())
166 return false;
167
168 RunTask(delayed_non_nestable_queue_.Pop());
169 return true;
170}
171
initial.commit3f4a7322008-07-27 06:49:38 +0900172//------------------------------------------------------------------------------
173
174void MessageLoop::Quit() {
darin@google.com981f3552008-08-16 12:09:05 +0900175 DCHECK(current() == this);
176 if (state_) {
177 state_->quit_received = true;
178 } else {
179 NOTREACHED() << "Must be inside Run to call Quit";
initial.commit3f4a7322008-07-27 06:49:38 +0900180 }
initial.commit3f4a7322008-07-27 06:49:38 +0900181}
182
183// Possibly called on a background thread!
184void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here,
185 Task* task, int delay_ms) {
186 task->SetBirthPlace(from_here);
darin@google.com0795f572008-08-30 09:22:48 +0900187
188 DCHECK(!task->owned_by_message_loop_);
189 task->owned_by_message_loop_ = true;
190
191 if (delay_ms > 0) {
192 task->delayed_run_time_ =
193 Time::Now() + TimeDelta::FromMilliseconds(delay_ms);
194 } else {
195 DCHECK(delay_ms == 0) << "delay should not be negative";
196 }
197
initial.commit3f4a7322008-07-27 06:49:38 +0900198 PostTaskInternal(task);
199}
200
201void MessageLoop::PostTaskInternal(Task* task) {
202 // Warning: Don't try to short-circuit, and handle this thread's tasks more
203 // directly, as it could starve handling of foreign threads. Put every task
204 // into this queue.
205
darin@google.com981f3552008-08-16 12:09:05 +0900206 scoped_refptr<base::MessagePump> pump;
initial.commit3f4a7322008-07-27 06:49:38 +0900207 {
darin@google.com981f3552008-08-16 12:09:05 +0900208 AutoLock locked(incoming_queue_lock_);
209
initial.commit3f4a7322008-07-27 06:49:38 +0900210 bool was_empty = incoming_queue_.Empty();
211 incoming_queue_.Push(task);
212 if (!was_empty)
213 return; // Someone else should have started the sub-pump.
214
darin@google.com981f3552008-08-16 12:09:05 +0900215 pump = pump_;
darin@google.com6ddeb842008-08-15 16:31:20 +0900216 }
darin@google.com981f3552008-08-16 12:09:05 +0900217 // Since the incoming_queue_ may contain a task that destroys this message
218 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
219 // We use a stack-based reference to the message pump so that we can call
220 // ScheduleWork outside of incoming_queue_lock_.
darin@google.com6ddeb842008-08-15 16:31:20 +0900221
darin@google.com981f3552008-08-16 12:09:05 +0900222 pump->ScheduleWork();
initial.commit3f4a7322008-07-27 06:49:38 +0900223}
224
225void MessageLoop::SetNestableTasksAllowed(bool allowed) {
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900226 if (nestable_tasks_allowed_ != allowed) {
227 nestable_tasks_allowed_ = allowed;
228 if (!nestable_tasks_allowed_)
229 return;
230 // Start the native pump if we are not already pumping.
darin@google.com981f3552008-08-16 12:09:05 +0900231 pump_->ScheduleWork();
mpcomplete@google.com989d5f82008-08-09 09:14:09 +0900232 }
initial.commit3f4a7322008-07-27 06:49:38 +0900233}
234
235bool MessageLoop::NestableTasksAllowed() const {
236 return nestable_tasks_allowed_;
237}
238
initial.commit3f4a7322008-07-27 06:49:38 +0900239//------------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900240
241bool MessageLoop::RunTimerTask(Timer* timer) {
242 HistogramEvent(kTimerEvent);
darin@google.comee6fa722008-08-13 08:25:43 +0900243
initial.commit3f4a7322008-07-27 06:49:38 +0900244 Task* task = timer->task();
darin@google.com0795f572008-08-30 09:22:48 +0900245 if (task->owned_by_message_loop_) {
darin@google.comee6fa722008-08-13 08:25:43 +0900246 // We constructed it through PostDelayedTask().
initial.commit3f4a7322008-07-27 06:49:38 +0900247 DCHECK(!timer->repeating());
248 timer->set_task(NULL);
249 delete timer;
jar@google.com09856292008-08-02 06:55:17 +0900250 task->ResetBirthTime();
initial.commit3f4a7322008-07-27 06:49:38 +0900251 return QueueOrRunTask(task);
initial.commit3f4a7322008-07-27 06:49:38 +0900252 }
darin@google.comee6fa722008-08-13 08:25:43 +0900253
254 // This is an unknown timer task, and we *can't* delay running it, as a user
255 // might try to cancel it with TimerManager at any moment.
256 DCHECK(nestable_tasks_allowed_);
257 RunTask(task);
258 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900259}
260
261void MessageLoop::DiscardTimer(Timer* timer) {
262 Task* task = timer->task();
darin@google.com0795f572008-08-30 09:22:48 +0900263 if (task->owned_by_message_loop_) {
initial.commit3f4a7322008-07-27 06:49:38 +0900264 DCHECK(!timer->repeating());
265 timer->set_task(NULL);
266 delete timer; // We constructed it through PostDelayedTask().
267 delete task; // We were given ouwnership in PostTask().
268 }
269}
270
271bool MessageLoop::QueueOrRunTask(Task* new_task) {
272 if (!nestable_tasks_allowed_) {
273 // Task can't be executed right now. Add it to the queue.
274 if (new_task)
275 work_queue_.Push(new_task);
276 return false;
277 }
278
279 // Queue new_task first so we execute the task in FIFO order.
280 if (new_task)
281 work_queue_.Push(new_task);
282
283 // Execute oldest task.
284 while (!work_queue_.Empty()) {
285 Task* task = work_queue_.Pop();
darin@google.com981f3552008-08-16 12:09:05 +0900286 if (task->nestable() || state_->run_depth == 1) {
initial.commit3f4a7322008-07-27 06:49:38 +0900287 RunTask(task);
288 // Show that we ran a task (Note: a new one might arrive as a
289 // consequence!).
290 return true;
initial.commit3f4a7322008-07-27 06:49:38 +0900291 }
darin@google.com981f3552008-08-16 12:09:05 +0900292 // We couldn't run the task now because we're in a nested message loop
293 // and the task isn't nestable.
294 delayed_non_nestable_queue_.Push(task);
initial.commit3f4a7322008-07-27 06:49:38 +0900295 }
296
297 // Nothing happened.
298 return false;
299}
300
301void MessageLoop::RunTask(Task* task) {
302 BeforeTaskRunSetup();
303 HistogramEvent(kTaskRunEvent);
304 // task may self-delete during Run() if we don't happen to own it.
305 // ...so check *before* we Run, since we can't check after.
darin@google.com0795f572008-08-30 09:22:48 +0900306 bool we_own_task = task->owned_by_message_loop_;
initial.commit3f4a7322008-07-27 06:49:38 +0900307 task->Run();
308 if (we_own_task)
309 task->RecycleOrDelete(); // Relinquish control, and probably delete.
310 AfterTaskRunRestore();
311}
312
313void MessageLoop::BeforeTaskRunSetup() {
314 DCHECK(nestable_tasks_allowed_);
315 // Execute the task and assume the worst: It is probably not reentrant.
316 nestable_tasks_allowed_ = false;
317}
318
319void MessageLoop::AfterTaskRunRestore() {
320 nestable_tasks_allowed_ = true;
321}
322
initial.commit3f4a7322008-07-27 06:49:38 +0900323void MessageLoop::ReloadWorkQueue() {
324 // We can improve performance of our loading tasks from incoming_queue_ to
darin@google.com981f3552008-08-16 12:09:05 +0900325 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
326 // load. That reduces the number of locks-per-task significantly when our
327 // queues get large. The optimization is disabled on threads that make use
328 // of the priority queue (prioritization requires all our tasks to be in the
initial.commit3f4a7322008-07-27 06:49:38 +0900329 // work_queue_ ASAP).
330 if (!work_queue_.Empty() && !work_queue_.use_priority_queue())
331 return; // Wait till we *really* need to lock and load.
332
333 // Acquire all we can from the inter-thread queue with one lock acquisition.
334 TaskQueue new_task_list; // Null terminated list.
335 {
336 AutoLock lock(incoming_queue_lock_);
337 if (incoming_queue_.Empty())
338 return;
339 std::swap(incoming_queue_, new_task_list);
340 DCHECK(incoming_queue_.Empty());
341 } // Release lock.
342
343 while (!new_task_list.Empty()) {
344 Task* task = new_task_list.Pop();
darin@google.com0795f572008-08-30 09:22:48 +0900345 DCHECK(task->owned_by_message_loop_);
initial.commit3f4a7322008-07-27 06:49:38 +0900346
darin@google.com0795f572008-08-30 09:22:48 +0900347 // TODO(darin): We should probably postpone starting the timer until we
348 // process the work queue as starting the timer here breaks the FIFO
349 // ordering of tasks.
350 if (!task->delayed_run_time_.is_null()) {
351 timer_manager_.StartTimer(new Timer(task->delayed_run_time_, task));
352 } else {
initial.commit3f4a7322008-07-27 06:49:38 +0900353 work_queue_.Push(task);
darin@google.com0795f572008-08-30 09:22:48 +0900354 }
initial.commit3f4a7322008-07-27 06:49:38 +0900355 }
356}
357
358void MessageLoop::DeletePendingTasks() {
darin@google.com62b58bc2008-08-27 14:29:40 +0900359 /* Comment this out as it's causing crashes.
initial.commit3f4a7322008-07-27 06:49:38 +0900360 while (!work_queue_.Empty()) {
361 Task* task = work_queue_.Pop();
362 if (task->is_owned_by_message_loop())
363 delete task;
364 }
365
366 while (!delayed_non_nestable_queue_.Empty()) {
367 Task* task = delayed_non_nestable_queue_.Pop();
368 if (task->is_owned_by_message_loop())
369 delete task;
370 }
darin@google.com62b58bc2008-08-27 14:29:40 +0900371 */
initial.commit3f4a7322008-07-27 06:49:38 +0900372}
373
darin@google.comee6fa722008-08-13 08:25:43 +0900374void MessageLoop::DidChangeNextTimerExpiry() {
darin@google.com6393bed2008-08-20 15:30:58 +0900375 Time next_delayed_work_time = timer_manager_.GetNextFireTime();
376 if (next_delayed_work_time.is_null())
darin@google.com981f3552008-08-16 12:09:05 +0900377 return;
378
379 // Simulates malfunctioning, early firing timers. Pending tasks should only
380 // be invoked when the delay they specify has elapsed.
381 if (timer_manager_.use_broken_delay())
darin@google.com6393bed2008-08-20 15:30:58 +0900382 next_delayed_work_time = Time::Now() + TimeDelta::FromMilliseconds(10);
darin@google.com981f3552008-08-16 12:09:05 +0900383
darin@google.com6393bed2008-08-20 15:30:58 +0900384 pump_->ScheduleDelayedWork(next_delayed_work_time);
darin@google.com981f3552008-08-16 12:09:05 +0900385}
386
387bool MessageLoop::DoWork() {
388 ReloadWorkQueue();
389 return QueueOrRunTask(NULL);
390}
391
darin@google.com6393bed2008-08-20 15:30:58 +0900392bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) {
darin@google.com981f3552008-08-16 12:09:05 +0900393 bool did_work = timer_manager_.RunSomePendingTimers();
394
395 // We may not have run any timers, but we may still have future timers to
396 // run, so we need to inform the pump again of pending timers.
darin@google.com6393bed2008-08-20 15:30:58 +0900397 *next_delayed_work_time = timer_manager_.GetNextFireTime();
darin@google.com981f3552008-08-16 12:09:05 +0900398
399 return did_work;
400}
401
402bool MessageLoop::DoIdleWork() {
403 if (ProcessNextDelayedNonNestableTask())
404 return true;
405
406 if (state_->quit_received)
407 pump_->Quit();
408
409 return false;
410}
411
412//------------------------------------------------------------------------------
413// MessageLoop::AutoRunState
414
415MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
416 // Make the loop reference us.
417 previous_state_ = loop_->state_;
418 if (previous_state_) {
419 run_depth = previous_state_->run_depth + 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900420 } else {
darin@google.com981f3552008-08-16 12:09:05 +0900421 run_depth = 1;
darin@google.com6ddeb842008-08-15 16:31:20 +0900422 }
darin@google.com981f3552008-08-16 12:09:05 +0900423 loop_->state_ = this;
424
425 // Initialize the other fields:
426 quit_received = false;
427#if defined(OS_WIN)
428 dispatcher = NULL;
429#endif
430}
431
432MessageLoop::AutoRunState::~AutoRunState() {
433 loop_->state_ = previous_state_;
darin@google.comee6fa722008-08-13 08:25:43 +0900434}
435
initial.commit3f4a7322008-07-27 06:49:38 +0900436//------------------------------------------------------------------------------
437// Implementation of the work_queue_ as a ProiritizedTaskQueue
438
439void MessageLoop::PrioritizedTaskQueue::push(Task * task) {
440 queue_.push(PrioritizedTask(task, --next_sequence_number_));
441}
442
443bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < (
444 PrioritizedTask const & right) const {
darin@google.com12d40bb2008-08-20 03:36:23 +0900445 int compare = task_->priority() - right.task_->priority();
initial.commit3f4a7322008-07-27 06:49:38 +0900446 if (compare)
447 return compare < 0;
448 // Don't compare directly, but rather subtract. This handles overflow
449 // as sequence numbers wrap around.
450 compare = sequence_number_ - right.sequence_number_;
451 DCHECK(compare); // Sequence number are unique for a "long time."
452 // Make sure we don't starve anything with a low priority.
453 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping.
454 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping.
455 return compare < 0;
456}
457
458//------------------------------------------------------------------------------
459// Implementation of a TaskQueue as a null terminated list, with end pointers.
460
461void MessageLoop::TaskQueue::Push(Task* task) {
462 if (!first_)
463 first_ = task;
464 else
465 last_->set_next_task(task);
466 last_ = task;
467}
468
469Task* MessageLoop::TaskQueue::Pop() {
470 DCHECK((!first_) == !last_);
471 Task* task = first_;
472 if (first_) {
473 first_ = task->next_task();
474 if (!first_)
475 last_ = NULL;
476 else
477 task->set_next_task(NULL);
478 }
479 return task;
480}
481
482//------------------------------------------------------------------------------
483// Implementation of a Task queue that automatically switches into a priority
484// queue if it observes any non-zero priorities on tasks.
485
486void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) {
487 if (use_priority_queue_) {
488 prioritized_queue_.push(task);
489 } else {
490 queue_.Push(task);
491 if (task->priority()) {
492 use_priority_queue_ = true; // From now on.
493 while (!queue_.Empty())
494 prioritized_queue_.push(queue_.Pop());
495 }
496 }
497}
498
499Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() {
500 if (!use_priority_queue_)
501 return queue_.Pop();
502 Task* task = prioritized_queue_.front();
503 prioritized_queue_.pop();
504 return task;
505}
506
507bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() {
508 if (use_priority_queue_)
509 return prioritized_queue_.empty();
510 return queue_.Empty();
511}
512
513//------------------------------------------------------------------------------
514// Method and data for histogramming events and actions taken by each instance
515// on each thread.
516
517// static
518bool MessageLoop::enable_histogrammer_ = false;
519
520// static
521void MessageLoop::EnableHistogrammer(bool enable) {
522 enable_histogrammer_ = enable;
523}
524
525void MessageLoop::StartHistogrammer() {
526 if (enable_histogrammer_ && !message_histogram_.get()
527 && StatisticsRecorder::WasStarted()) {
darin@google.com981f3552008-08-16 12:09:05 +0900528 DCHECK(!thread_name_.empty());
initial.commit3f4a7322008-07-27 06:49:38 +0900529 message_histogram_.reset(new LinearHistogram(
530 ASCIIToWide("MsgLoop:" + thread_name_).c_str(),
531 kLeastNonZeroMessageId,
532 kMaxMessageId,
533 kNumberOfDistinctMessagesDisplayed));
534 message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag);
535 message_histogram_->SetRangeDescriptions(event_descriptions_);
536 }
537}
538
539void MessageLoop::HistogramEvent(int event) {
540 if (message_histogram_.get())
541 message_histogram_->Add(event);
542}
543
initial.commit3f4a7322008-07-27 06:49:38 +0900544// Provide a macro that takes an expression (such as a constant, or macro
545// constant) and creates a pair to initalize an array of pairs. In this case,
546// our pair consists of the expressions value, and the "stringized" version
547// of the expression (i.e., the exrpression put in quotes). For example, if
548// we have:
549// #define FOO 2
550// #define BAR 5
551// then the following:
552// VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
553// will expand to:
554// {7, "FOO + BAR"}
555// We use the resulting array as an argument to our histogram, which reads the
556// number as a bucket identifier, and proceeds to use the corresponding name
557// in the pair (i.e., the quoted string) when printing out a histogram.
558#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
559
initial.commit3f4a7322008-07-27 06:49:38 +0900560// static
561const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
initial.commit3f4a7322008-07-27 06:49:38 +0900562 // Provide some pretty print capability in our histogram for our internal
563 // messages.
564
initial.commit3f4a7322008-07-27 06:49:38 +0900565 // A few events we handle (kindred to messages), and used to profile actions.
566 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
initial.commit3f4a7322008-07-27 06:49:38 +0900567 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
568
569 {-1, NULL} // The list must be null terminated, per API to histogram.
570};
license.botf003cfe2008-08-24 09:55:55 +0900571
darin@google.comd936b5b2008-08-26 14:53:57 +0900572//------------------------------------------------------------------------------
573// MessageLoopForUI
574
575#if defined(OS_WIN)
576
577void MessageLoopForUI::Run(Dispatcher* dispatcher) {
578 AutoRunState save_state(this);
579 state_->dispatcher = dispatcher;
580 RunHandler();
581}
582
583void MessageLoopForUI::AddObserver(Observer* observer) {
584 pump_win()->AddObserver(observer);
585}
586
587void MessageLoopForUI::RemoveObserver(Observer* observer) {
588 pump_win()->RemoveObserver(observer);
589}
590
591void MessageLoopForUI::WillProcessMessage(const MSG& message) {
592 pump_win()->WillProcessMessage(message);
593}
594void MessageLoopForUI::DidProcessMessage(const MSG& message) {
595 pump_win()->DidProcessMessage(message);
596}
597void MessageLoopForUI::PumpOutPendingPaintMessages() {
598 pump_win()->PumpOutPendingPaintMessages();
599}
600
601#endif // defined(OS_WIN)
602
603//------------------------------------------------------------------------------
604// MessageLoopForIO
605
606#if defined(OS_WIN)
607
608void MessageLoopForIO::WatchObject(HANDLE object, Watcher* watcher) {
609 pump_win()->WatchObject(object, watcher);
610}
611
612#endif // defined(OS_WIN)