blob: 18f4448fca916b4a7c52161cd9c64619cace3d0e [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]295039bd2008-08-15 04:32:5730#include <algorithm>
31
[email protected]ea15e982008-08-15 07:31:2032#include "base/message_loop.h"
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"
[email protected]ea15e982008-08-15 07:31:2037#include "base/win_util.h"
initial.commitd7cae122008-07-26 21:49:3838
39// a TLS index to the message loop for the current thread
40// Note that if we start doing complex stuff in other static initializers
41// this could cause problems.
42/*static*/ TLSSlot MessageLoop::tls_index_ = ThreadLocalStorage::Alloc();
43
44//------------------------------------------------------------------------------
45
[email protected]ea15e982008-08-15 07:31:2046static const wchar_t kWndClass[] = L"Chrome_MessageLoopWindow";
47
48// Windows Message numbers handled by WindowMessageProc.
49
50// Message sent to get an additional time slice for pumping (processing) another
51// task (a series of such messages creates a continuous task pump).
52static const int kMsgPumpATask = WM_USER + 1;
53
54// Message sent by Quit() to cause our main message pump to terminate as soon as
55// all pending task and message queues have been emptied.
56static const int kMsgQuit = WM_USER + 2;
57
initial.commitd7cae122008-07-26 21:49:3858// Logical events for Histogram profiling. Run with -message-loop-histogrammer
59// to get an accounting of messages and actions taken on each thread.
[email protected]ea15e982008-08-15 07:31:2060static const int kTaskRunEvent = WM_USER + 16; // 0x411
61static const int kSleepingApcEvent = WM_USER + 17; // 0x411
62static const int kPollingSignalEvent = WM_USER + 18; // 0x412
63static const int kSleepingSignalEvent = WM_USER + 19; // 0x413
64static const int kTimerEvent = WM_USER + 20; // 0x414
initial.commitd7cae122008-07-26 21:49:3865
66// Provide range of message IDs for use in histogramming and debug display.
67static const int kLeastNonZeroMessageId = 1;
68static const int kMaxMessageId = 1099;
69static const int kNumberOfDistinctMessagesDisplayed = 1100;
70
71//------------------------------------------------------------------------------
72
[email protected]ea15e982008-08-15 07:31:2073#ifndef NDEBUG
74// Force exercise of polling model.
75#define CHROME_MAXIMUM_WAIT_OBJECTS 8
76#else
77#define CHROME_MAXIMUM_WAIT_OBJECTS MAXIMUM_WAIT_OBJECTS
78#endif
initial.commitd7cae122008-07-26 21:49:3879
[email protected]ea15e982008-08-15 07:31:2080//------------------------------------------------------------------------------
81// A strategy of -1 uses the default case. All strategies are selected as
82// positive integers.
83// static
84int MessageLoop::strategy_selector_ = -1;
85
86// static
87void MessageLoop::SetStrategy(int strategy) {
88 DCHECK(-1 == strategy_selector_);
89 strategy_selector_ = strategy;
90}
91
92//------------------------------------------------------------------------------
initial.commitd7cae122008-07-26 21:49:3893// Upon a SEH exception in this thread, it restores the original unhandled
94// exception filter.
95static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
96 ::SetUnhandledExceptionFilter(old_filter);
97 return EXCEPTION_CONTINUE_SEARCH;
98}
99
100// Retrieves a pointer to the current unhandled exception filter. There
101// is no standalone getter method.
102static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
103 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
104 top_filter = ::SetUnhandledExceptionFilter(0);
105 ::SetUnhandledExceptionFilter(top_filter);
106 return top_filter;
107}
108
initial.commitd7cae122008-07-26 21:49:38109//------------------------------------------------------------------------------
110
[email protected]a5b94a92008-08-12 23:25:43111MessageLoop::MessageLoop()
112#pragma warning(suppress: 4355) // OK, to use |this| in the initializer list.
113 : timer_manager_(this),
[email protected]ea15e982008-08-15 07:31:20114 message_hwnd_(NULL),
[email protected]a5b94a92008-08-12 23:25:43115 exception_restoration_(false),
116 nestable_tasks_allowed_(true),
[email protected]ea15e982008-08-15 07:31:20117 dispatcher_(NULL),
118 quit_received_(false),
119 quit_now_(false),
120 task_pump_message_pending_(false),
121 run_depth_(0) {
initial.commitd7cae122008-07-26 21:49:38122 DCHECK(tls_index_) << "static initializer failed";
123 DCHECK(!current()) << "should only have one message loop per thread";
124 ThreadLocalStorage::Set(tls_index_, this);
[email protected]ea15e982008-08-15 07:31:20125 InitMessageWnd();
initial.commitd7cae122008-07-26 21:49:38126}
127
128MessageLoop::~MessageLoop() {
129 DCHECK(this == current());
[email protected]2a127252008-08-05 23:16:41130
131 // Let interested parties have one last shot at accessing this.
132 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
133 WillDestroyCurrentMessageLoop());
134
135 // OK, now make it so that no one can find us.
initial.commitd7cae122008-07-26 21:49:38136 ThreadLocalStorage::Set(tls_index_, NULL);
[email protected]2a127252008-08-05 23:16:41137
[email protected]ea15e982008-08-15 07:31:20138 DCHECK(!dispatcher_);
139 DCHECK(!quit_received_ && !quit_now_);
[email protected]2a127252008-08-05 23:16:41140
initial.commitd7cae122008-07-26 21:49:38141 // Most tasks that have not been Run() are deleted in the |timer_manager_|
142 // destructor after we remove our tls index. We delete the tasks in our
143 // queues here so their destuction is similar to the tasks in the
144 // |timer_manager_|.
145 DeletePendingTasks();
146 ReloadWorkQueue();
147 DeletePendingTasks();
148}
149
[email protected]ea15e982008-08-15 07:31:20150void MessageLoop::SetThreadName(const std::string& thread_name) {
151 DCHECK(thread_name_.empty());
152 thread_name_ = thread_name;
153 StartHistogrammer();
154}
155
[email protected]2a127252008-08-05 23:16:41156void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
157 DCHECK(this == current());
158 destruction_observers_.AddObserver(obs);
159}
160
161void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
162 DCHECK(this == current());
163 destruction_observers_.RemoveObserver(obs);
164}
165
[email protected]ea15e982008-08-15 07:31:20166void MessageLoop::AddObserver(Observer *obs) {
167 DCHECK(this == current());
168 observers_.AddObserver(obs);
[email protected]3882c4332008-07-30 19:03:59169}
170
[email protected]ea15e982008-08-15 07:31:20171void MessageLoop::RemoveObserver(Observer *obs) {
172 DCHECK(this == current());
173 observers_.RemoveObserver(obs);
[email protected]3882c4332008-07-30 19:03:59174}
[email protected]ea15e982008-08-15 07:31:20175
176void MessageLoop::Run() {
177 RunHandler(NULL, false);
178}
179
180void MessageLoop::Run(Dispatcher* dispatcher) {
181 RunHandler(dispatcher, false);
182}
[email protected]3882c4332008-07-30 19:03:59183
[email protected]7e0e8762008-07-31 13:10:20184void MessageLoop::RunAllPending() {
[email protected]ea15e982008-08-15 07:31:20185 RunHandler(NULL, true);
initial.commitd7cae122008-07-26 21:49:38186}
187
188// Runs the loop in two different SEH modes:
189// enable_SEH_restoration_ = false : any unhandled exception goes to the last
190// one that calls SetUnhandledExceptionFilter().
191// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
192// that was existed before the loop was run.
[email protected]ea15e982008-08-15 07:31:20193void MessageLoop::RunHandler(Dispatcher* dispatcher, bool non_blocking) {
initial.commitd7cae122008-07-26 21:49:38194 if (exception_restoration_) {
195 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
196 __try {
[email protected]ea15e982008-08-15 07:31:20197 RunInternal(dispatcher, non_blocking);
initial.commitd7cae122008-07-26 21:49:38198 } __except(SEHFilter(current_filter)) {
199 }
[email protected]ea15e982008-08-15 07:31:20200 } else {
201 RunInternal(dispatcher, non_blocking);
initial.commitd7cae122008-07-26 21:49:38202 }
initial.commitd7cae122008-07-26 21:49:38203}
204
205//------------------------------------------------------------------------------
[email protected]ea15e982008-08-15 07:31:20206// IF this was just a simple PeekMessage() loop (servicing all passible work
207// queues), then Windows would try to achieve the following order according to
208// MSDN documentation about PeekMessage with no filter):
209// * Sent messages
210// * Posted messages
211// * Sent messages (again)
212// * WM_PAINT messages
213// * WM_TIMER messages
214//
215// Summary: none of the above classes is starved, and sent messages has twice
216// the chance of being processed (i.e., reduced service time).
initial.commitd7cae122008-07-26 21:49:38217
[email protected]ea15e982008-08-15 07:31:20218void MessageLoop::RunInternal(Dispatcher* dispatcher, bool non_blocking) {
219 // Preserve ability to be called recursively.
220 ScopedStateSave save(this); // State is restored on exit.
221 dispatcher_ = dispatcher;
initial.commitd7cae122008-07-26 21:49:38222 StartHistogrammer();
223
[email protected]ea15e982008-08-15 07:31:20224 DCHECK(this == current());
225 //
226 // Process pending messages and signaled objects.
227 //
228 // Flush these queues before exiting due to a kMsgQuit or else we risk not
229 // shutting down properly as some operations may depend on further event
230 // processing. (Note: some tests may use quit_now_ to exit more swiftly,
231 // and leave messages pending, so don't assert the above fact).
232 RunTraditional(non_blocking);
233 DCHECK(non_blocking || quit_received_ || quit_now_);
234}
235
236void MessageLoop::RunTraditional(bool non_blocking) {
237 for (;;) {
238 // If we do any work, we may create more messages etc., and more work
239 // may possibly be waiting in another task group. When we (for example)
240 // ProcessNextWindowsMessage(), there is a good chance there are still more
241 // messages waiting (same thing for ProcessNextObject(), which responds to
242 // only one signaled object; etc.). On the other hand, when any of these
243 // methods return having done no work, then it is pretty unlikely that
244 // calling them again quickly will find any work to do.
245 // Finally, if they all say they had no work, then it is a good time to
246 // consider sleeping (waiting) for more work.
247 bool more_work_is_plausible = ProcessNextWindowsMessage();
248 if (quit_now_)
249 return;
250
251 more_work_is_plausible |= ProcessNextDeferredTask();
252 more_work_is_plausible |= ProcessNextObject();
253 if (more_work_is_plausible)
254 continue;
255
256 if (quit_received_)
257 return;
258
259 // Run any timer that is ready to run. It may create messages etc.
260 if (ProcessSomeTimers())
261 continue;
262
263 // We run delayed non nestable tasks only after all nestable tasks have
264 // run, to preserve FIFO ordering.
265 if (ProcessNextDelayedNonNestableTask())
266 continue;
267
268 if (non_blocking)
269 return;
270
271 // We service APCs in WaitForWork, without returning.
272 WaitForWork(); // Wait (sleep) until we have work to do again.
[email protected]7e0e8762008-07-31 13:10:20273 }
[email protected]b8f2fe5d2008-07-30 07:50:53274}
[email protected]7622bd02008-07-30 06:58:56275
[email protected]3882c4332008-07-30 19:03:59276//------------------------------------------------------------------------------
277// Wrapper functions for use in above message loop framework.
278
initial.commitd7cae122008-07-26 21:49:38279bool MessageLoop::ProcessNextDelayedNonNestableTask() {
[email protected]ea15e982008-08-15 07:31:20280 if (run_depth_ != 1)
initial.commitd7cae122008-07-26 21:49:38281 return false;
282
283 if (delayed_non_nestable_queue_.Empty())
284 return false;
285
286 RunTask(delayed_non_nestable_queue_.Pop());
287 return true;
288}
289
initial.commitd7cae122008-07-26 21:49:38290bool MessageLoop::ProcessNextDeferredTask() {
291 ReloadWorkQueue();
292 return QueueOrRunTask(NULL);
293}
294
295bool MessageLoop::ProcessSomeTimers() {
296 return timer_manager_.RunSomePendingTimers();
297}
298
299//------------------------------------------------------------------------------
300
301void MessageLoop::Quit() {
[email protected]ea15e982008-08-15 07:31:20302 EnsureMessageGetsPosted(kMsgQuit);
303}
304
305bool MessageLoop::WatchObject(HANDLE object, Watcher* watcher) {
306 DCHECK(this == current());
307 DCHECK(object);
308 DCHECK_NE(object, INVALID_HANDLE_VALUE);
309
310 std::vector<HANDLE>::iterator it = find(objects_.begin(), objects_.end(),
311 object);
312 if (watcher) {
313 if (it == objects_.end()) {
314 static size_t warning_multiple = 1;
315 if (objects_.size() >= warning_multiple * MAXIMUM_WAIT_OBJECTS / 2) {
316 LOG(INFO) << "More than " << warning_multiple * MAXIMUM_WAIT_OBJECTS / 2
317 << " objects being watched";
318 // This DCHECK() is an artificial limitation, meant to warn us if we
319 // start creating too many objects. It can safely be raised to a higher
320 // level, and the program is designed to handle much larger values.
321 // Before raising this limit, make sure that there is a very good reason
322 // (in your debug testing) to be watching this many objects.
323 DCHECK(2 <= warning_multiple);
324 ++warning_multiple;
325 }
326 objects_.push_back(object);
327 watchers_.push_back(watcher);
328 } else {
329 watchers_[it - objects_.begin()] = watcher;
330 }
331 } else if (it != objects_.end()) {
332 std::vector<HANDLE>::difference_type index = it - objects_.begin();
333 objects_.erase(it);
334 watchers_.erase(watchers_.begin() + index);
initial.commitd7cae122008-07-26 21:49:38335 }
[email protected]ea15e982008-08-15 07:31:20336 return true;
initial.commitd7cae122008-07-26 21:49:38337}
338
339// Possibly called on a background thread!
340void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here,
341 Task* task, int delay_ms) {
342 task->SetBirthPlace(from_here);
343 DCHECK(delay_ms >= 0);
344 DCHECK(!task->is_owned_by_message_loop());
345 task->set_posted_task_delay(delay_ms);
346 DCHECK(task->is_owned_by_message_loop());
347 PostTaskInternal(task);
348}
349
350void MessageLoop::PostTaskInternal(Task* task) {
351 // Warning: Don't try to short-circuit, and handle this thread's tasks more
352 // directly, as it could starve handling of foreign threads. Put every task
353 // into this queue.
354
[email protected]ea15e982008-08-15 07:31:20355 // Local stack variables to use IF we need to process after releasing locks.
356 HWND message_hwnd;
initial.commitd7cae122008-07-26 21:49:38357 {
[email protected]ea15e982008-08-15 07:31:20358 AutoLock lock1(incoming_queue_lock_);
initial.commitd7cae122008-07-26 21:49:38359 bool was_empty = incoming_queue_.Empty();
360 incoming_queue_.Push(task);
361 if (!was_empty)
362 return; // Someone else should have started the sub-pump.
363
[email protected]ea15e982008-08-15 07:31:20364 // We may have to start the sub-pump.
365 AutoLock lock2(task_pump_message_lock_);
366 if (task_pump_message_pending_)
367 return; // Someone else continued the pumping.
368 task_pump_message_pending_ = true; // We'll send one.
369 message_hwnd = message_hwnd_;
370 } // Release both locks.
371 // We may have just posted a kMsgQuit, and so this instance may now destroyed!
372 // Do not invoke non-static methods, or members in any way!
initial.commitd7cae122008-07-26 21:49:38373
[email protected]ea15e982008-08-15 07:31:20374 // PostMessage may fail, as the hwnd may have vanished due to kMsgQuit.
375 PostMessage(message_hwnd, kMsgPumpATask, 0, 0);
376}
377
378void MessageLoop::InitMessageWnd() {
379 HINSTANCE hinst = GetModuleHandle(NULL);
380
381 WNDCLASSEX wc = {0};
382 wc.cbSize = sizeof(wc);
383 wc.lpfnWndProc = WndProcThunk;
384 wc.hInstance = hinst;
385 wc.lpszClassName = kWndClass;
386 RegisterClassEx(&wc);
387
388 message_hwnd_ = CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0,
389 hinst, 0);
390 DCHECK(message_hwnd_);
391}
392
393// static
394LRESULT CALLBACK MessageLoop::WndProcThunk(
395 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
396 DCHECK(MessageLoop::current());
397 return MessageLoop::current()->WndProc(hwnd, message, wparam, lparam);
398}
399
400LRESULT MessageLoop::WndProc(
401 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
402 if (hwnd == message_hwnd_) {
403 switch (message) {
404 case kMsgPumpATask: {
405 ProcessPumpReplacementMessage(); // Avoid starving paint and timer.
406 if (!nestable_tasks_allowed_)
407 return 0;
408 PumpATaskDuringWndProc();
409 return 0;
410 }
411
412 case WM_TIMER:
413 ProcessSomeTimers(); // Give the TimerManager a tickle.
414 DidChangeNextTimerExpiry(); // Maybe generate another WM_TIMER.
415 return 0;
416
417 case kMsgQuit: {
418 // TODO(jar): bug 1300541 The following assert should be used, but
419 // currently too much code actually triggers the assert, especially in
420 // tests :-(.
421 // Discarding a second quit will cause a hang.
422 //CHECK(!quit_received_);
423 quit_received_ = true;
424 return 0;
425 }
426 }
427 }
428 return ::DefWindowProc(hwnd, message, wparam, lparam);
429}
430
431void MessageLoop::WillProcessMessage(const MSG& msg) {
432 FOR_EACH_OBSERVER(Observer, observers_, WillProcessMessage(msg));
433}
434
435void MessageLoop::DidProcessMessage(const MSG& msg) {
436 FOR_EACH_OBSERVER(Observer, observers_, DidProcessMessage(msg));
initial.commitd7cae122008-07-26 21:49:38437}
438
439void MessageLoop::SetNestableTasksAllowed(bool allowed) {
[email protected]124a2bdf2008-08-09 00:14:09440 if (nestable_tasks_allowed_ != allowed) {
441 nestable_tasks_allowed_ = allowed;
442 if (!nestable_tasks_allowed_)
443 return;
444 // Start the native pump if we are not already pumping.
[email protected]ea15e982008-08-15 07:31:20445 EnsurePumpATaskWasPosted();
[email protected]124a2bdf2008-08-09 00:14:09446 }
initial.commitd7cae122008-07-26 21:49:38447}
448
449bool MessageLoop::NestableTasksAllowed() const {
450 return nestable_tasks_allowed_;
451}
452
[email protected]ea15e982008-08-15 07:31:20453bool MessageLoop::ProcessNextWindowsMessage() {
454 MSG msg;
455 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
456 return ProcessMessageHelper(msg);
457 }
458 return false;
459}
460
461bool MessageLoop::ProcessMessageHelper(const MSG& msg) {
462 HistogramEvent(msg.message);
463
464 if (WM_QUIT == msg.message) {
465 // Repost the QUIT message so that it will be retrieved by the primary
466 // GetMessage() loop.
467 quit_now_ = true;
468 PostQuitMessage(static_cast<int>(msg.wParam));
469 return false;
470 }
471
472 // While running our main message pump, we discard kMsgPumpATask messages.
473 if (msg.message == kMsgPumpATask && msg.hwnd == message_hwnd_)
474 return ProcessPumpReplacementMessage();
475
476 WillProcessMessage(msg);
477
478 if (dispatcher_) {
479 if (!dispatcher_->Dispatch(msg))
480 quit_now_ = true;
481 } else {
482 TranslateMessage(&msg);
483 DispatchMessage(&msg);
484 }
485
486 DidProcessMessage(msg);
487 return true;
488}
489
490bool MessageLoop::ProcessPumpReplacementMessage() {
491 MSG msg;
492 bool have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
493 DCHECK(!have_message || kMsgPumpATask != msg.message
494 || msg.hwnd != message_hwnd_);
495 {
496 // Since we discarded a kMsgPumpATask message, we must update the flag.
497 AutoLock lock(task_pump_message_lock_);
498 DCHECK(task_pump_message_pending_);
499 task_pump_message_pending_ = false;
500 }
501 return have_message && ProcessMessageHelper(msg);
502}
503
504// Create a mini-message-pump to force immediate processing of only Windows
505// WM_PAINT messages.
506void MessageLoop::PumpOutPendingPaintMessages() {
507 // Don't provide an infinite loop, but do enough peeking to get the job done.
508 // Actual common max is 4 peeks, but we'll be a little safe here.
509 const int kMaxPeekCount = 20;
510 int peek_count;
511 bool win2k(true);
512 if (win_util::GetWinVersion() > win_util::WINVERSION_2000)
513 win2k = false;
514 for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) {
515 MSG msg;
516 if (win2k) {
517 if (!PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE))
518 break;
519 } else {
520 if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT))
521 break;
522 }
523 ProcessMessageHelper(msg);
524 if (quit_now_ ) // Handle WM_QUIT.
525 break;
526 }
527 // Histogram what was really being used, to help to adjust kMaxPeekCount.
528 DHISTOGRAM_COUNTS(L"Loop.PumpOutPendingPaintMessages Peeks", peek_count);
529}
530
initial.commitd7cae122008-07-26 21:49:38531//------------------------------------------------------------------------------
[email protected]ea15e982008-08-15 07:31:20532// If we handle more than the OS limit on the number of objects that can be
533// waited for, we'll need to poll (sequencing through subsets of the objects
534// that can be passed in a single OS wait call). The following is the polling
535// interval used in that (unusual) case. (I don't have a lot of justifcation
536// for the specific value, but it needed to be short enough that it would not
537// add a lot of latency, and long enough that we wouldn't thrash the CPU for no
538// reason... especially considering the silly user probably has a million tabs
539// open, etc.)
540static const int kMultipleWaitPollingInterval = 20;
541
542void MessageLoop::WaitForWork() {
543 bool original_can_run = nestable_tasks_allowed_;
544 int wait_flags = original_can_run ? MWMO_ALERTABLE | MWMO_INPUTAVAILABLE
545 : MWMO_INPUTAVAILABLE;
546
547 bool use_polling = false; // Poll if too many objects for one OS Wait call.
548 for (;;) {
549 // Do initialization here, in case APC modifies object list.
550 size_t total_objs = original_can_run ? objects_.size() : 0;
551
552 int delay;
553 size_t polling_index = 0; // The first unprocessed object index.
554 do {
555 size_t objs_len =
556 (polling_index < total_objs) ? total_objs - polling_index : 0;
557 if (objs_len >= CHROME_MAXIMUM_WAIT_OBJECTS) {
558 objs_len = CHROME_MAXIMUM_WAIT_OBJECTS - 1;
559 use_polling = true;
560 }
561 HANDLE* objs = objs_len ? polling_index + &objects_.front() : NULL;
562
563 // Only wait up to the time needed by the timer manager to fire the next
564 // set of timers.
565 delay = timer_manager_.GetCurrentDelay();
566 if (use_polling && delay > kMultipleWaitPollingInterval)
567 delay = kMultipleWaitPollingInterval;
568 if (delay < 0) // Negative value means no timers waiting.
569 delay = INFINITE;
570
571 DWORD result;
572 result = MsgWaitForMultipleObjectsEx(static_cast<DWORD>(objs_len), objs,
573 delay, QS_ALLINPUT, wait_flags);
574
575 if (WAIT_IO_COMPLETION == result) {
576 HistogramEvent(kSleepingApcEvent);
577 // We'll loop here when we service an APC. At it currently stands,
578 // *ONLY* the IO thread uses *any* APCs, so this should have no impact
579 // on the UI thread.
580 break; // Break to outer loop, and waitforwork() again.
581 }
582
583 // Use unsigned type to simplify range detection;
584 size_t signaled_index = result - WAIT_OBJECT_0;
585 if (signaled_index < objs_len) {
586 SignalWatcher(polling_index + signaled_index);
587 HistogramEvent(kSleepingSignalEvent);
588 return; // We serviced a signaled object.
589 }
590
591 if (objs_len == signaled_index)
592 return; // A WM_* message is available.
593
594 DCHECK_NE(WAIT_FAILED, result) << GetLastError();
595
596 DCHECK(!objs || result == WAIT_TIMEOUT);
597 if (!use_polling)
598 return;
599 polling_index += objs_len;
600 } while (polling_index < total_objs);
601 // For compatibility, we didn't return sooner. This made us do *some* wait
602 // call(s) before returning. This will probably change in next rev.
603 if (!delay || !timer_manager_.GetCurrentDelay())
604 return; // No work done, but timer is ready to fire.
605 }
606}
607
608// Note: MsgWaitMultipleObjects() can't take a nil list, and that is why I had
609// to use SleepEx() to handle APCs when there were no objects.
610bool MessageLoop::ProcessNextObject() {
611 if (!nestable_tasks_allowed_)
612 return false;
613
614 size_t total_objs = objects_.size();
615 if (!total_objs) {
616 return false;
617 }
618
619 size_t polling_index = 0; // The first unprocessed object index.
620 do {
621 DCHECK(polling_index < total_objs);
622 size_t objs_len = total_objs - polling_index;
623 if (objs_len >= CHROME_MAXIMUM_WAIT_OBJECTS)
624 objs_len = CHROME_MAXIMUM_WAIT_OBJECTS - 1;
625 HANDLE* objs = polling_index + &objects_.front();
626
627 // Identify 1 pending object, or allow an IO APC to be completed.
628 DWORD result = WaitForMultipleObjectsEx(static_cast<DWORD>(objs_len), objs,
629 FALSE, // 1 signal is sufficient.
630 0, // Wait 0ms.
631 false); // Not alertable (no APC).
632
633 // Use unsigned type to simplify range detection;
634 size_t signaled_index = result - WAIT_OBJECT_0;
635 if (signaled_index < objs_len) {
636 SignalWatcher(polling_index + signaled_index);
637 HistogramEvent(kPollingSignalEvent);
638 return true; // We serviced a signaled object.
639 }
640
641 // If an handle is invalid, it will be WAIT_FAILED.
642 DCHECK_EQ(WAIT_TIMEOUT, result) << GetLastError();
643 polling_index += objs_len;
644 } while (polling_index < total_objs);
645 return false; // We serviced nothing.
646}
647
648bool MessageLoop::SignalWatcher(size_t object_index) {
649 BeforeTaskRunSetup();
650 DCHECK(objects_.size() > object_index);
651 // On reception of OnObjectSignaled() to a Watcher object, it may call
652 // WatchObject(). watchers_ and objects_ will be modified. This is
653 // expected, so don't be afraid if, while tracing a OnObjectSignaled()
654 // function, the corresponding watchers_[result] is inexistant.
655 watchers_[object_index]->OnObjectSignaled(objects_[object_index]);
656 // Signaled objects tend to be removed from the watch list, and then added
657 // back (appended). As a result, they move to the end of the objects_ array,
658 // and this should make their service "fair" (no HANDLEs should be starved).
659 AfterTaskRunRestore();
660 return true;
661}
initial.commitd7cae122008-07-26 21:49:38662
663bool MessageLoop::RunTimerTask(Timer* timer) {
664 HistogramEvent(kTimerEvent);
[email protected]a5b94a92008-08-12 23:25:43665
initial.commitd7cae122008-07-26 21:49:38666 Task* task = timer->task();
667 if (task->is_owned_by_message_loop()) {
[email protected]a5b94a92008-08-12 23:25:43668 // We constructed it through PostDelayedTask().
initial.commitd7cae122008-07-26 21:49:38669 DCHECK(!timer->repeating());
670 timer->set_task(NULL);
671 delete timer;
[email protected]ee73678e2008-08-01 21:55:17672 task->ResetBirthTime();
initial.commitd7cae122008-07-26 21:49:38673 return QueueOrRunTask(task);
initial.commitd7cae122008-07-26 21:49:38674 }
[email protected]a5b94a92008-08-12 23:25:43675
676 // This is an unknown timer task, and we *can't* delay running it, as a user
677 // might try to cancel it with TimerManager at any moment.
678 DCHECK(nestable_tasks_allowed_);
679 RunTask(task);
680 return true;
initial.commitd7cae122008-07-26 21:49:38681}
682
683void MessageLoop::DiscardTimer(Timer* timer) {
684 Task* task = timer->task();
685 if (task->is_owned_by_message_loop()) {
686 DCHECK(!timer->repeating());
687 timer->set_task(NULL);
688 delete timer; // We constructed it through PostDelayedTask().
689 delete task; // We were given ouwnership in PostTask().
690 }
691}
692
693bool MessageLoop::QueueOrRunTask(Task* new_task) {
694 if (!nestable_tasks_allowed_) {
695 // Task can't be executed right now. Add it to the queue.
696 if (new_task)
697 work_queue_.Push(new_task);
698 return false;
699 }
700
701 // Queue new_task first so we execute the task in FIFO order.
702 if (new_task)
703 work_queue_.Push(new_task);
704
705 // Execute oldest task.
706 while (!work_queue_.Empty()) {
707 Task* task = work_queue_.Pop();
[email protected]ea15e982008-08-15 07:31:20708 if (task->nestable() || run_depth_ == 1) {
initial.commitd7cae122008-07-26 21:49:38709 RunTask(task);
710 // Show that we ran a task (Note: a new one might arrive as a
711 // consequence!).
712 return true;
[email protected]ea15e982008-08-15 07:31:20713 } else {
714 // We couldn't run the task now because we're in a nested message loop
715 // and the task isn't nestable.
716 delayed_non_nestable_queue_.Push(task);
initial.commitd7cae122008-07-26 21:49:38717 }
initial.commitd7cae122008-07-26 21:49:38718 }
719
720 // Nothing happened.
721 return false;
722}
723
724void MessageLoop::RunTask(Task* task) {
725 BeforeTaskRunSetup();
726 HistogramEvent(kTaskRunEvent);
727 // task may self-delete during Run() if we don't happen to own it.
728 // ...so check *before* we Run, since we can't check after.
729 bool we_own_task = task->is_owned_by_message_loop();
730 task->Run();
731 if (we_own_task)
732 task->RecycleOrDelete(); // Relinquish control, and probably delete.
733 AfterTaskRunRestore();
734}
735
736void MessageLoop::BeforeTaskRunSetup() {
737 DCHECK(nestable_tasks_allowed_);
738 // Execute the task and assume the worst: It is probably not reentrant.
739 nestable_tasks_allowed_ = false;
740}
741
742void MessageLoop::AfterTaskRunRestore() {
743 nestable_tasks_allowed_ = true;
744}
745
[email protected]ea15e982008-08-15 07:31:20746void MessageLoop::PumpATaskDuringWndProc() {
747 // TODO(jar): Perchance we should check on signaled objects here??
748 // Signals are generally starved during a native message loop. Even if we
749 // try to service a signaled object now, we wouldn't automatically get here
750 // (i.e., the native pump would not re-start) when the next object was
751 // signaled. If we really want to avoid starving signaled objects, we need
752 // to translate them into Tasks that can be passed in via PostTask.
753 // If these native message loops (and sub-pumping activities) are short
754 // lived, then the starvation won't be that long :-/.
755
756 if (!ProcessNextDeferredTask())
757 return; // Nothing to do, so lets stop the sub-pump.
758
759 // We ran a task, so make sure we come back and try to run more tasks.
760 EnsurePumpATaskWasPosted();
761}
762
763void MessageLoop::EnsurePumpATaskWasPosted() {
764 {
765 AutoLock lock(task_pump_message_lock_);
766 if (task_pump_message_pending_)
767 return; // Someone else continued the pumping.
768 task_pump_message_pending_ = true; // We'll send one.
769 }
770 EnsureMessageGetsPosted(kMsgPumpATask);
771}
772
773void MessageLoop::EnsureMessageGetsPosted(int message) const {
774 const int kRetryCount = 30;
775 const int kSleepDurationWhenFailing = 100;
776 for (int i = 0; i < kRetryCount; ++i) {
777 // Posting to our own windows should always succeed. If it doesn't we're in
778 // big trouble.
779 if (PostMessage(message_hwnd_, message, 0, 0))
780 return;
781 Sleep(kSleepDurationWhenFailing);
782 }
783 LOG(FATAL) << "Crash with last error " << GetLastError();
784 int* p = NULL;
785 *p = 0; // Crash.
786}
787
initial.commitd7cae122008-07-26 21:49:38788void MessageLoop::ReloadWorkQueue() {
789 // We can improve performance of our loading tasks from incoming_queue_ to
[email protected]ea15e982008-08-15 07:31:20790 // work_queue_ by wating until the last minute (work_queue_ is empty) to load.
791 // That reduces the number of locks-per-task significantly when our queues get
792 // large. The optimization is disabled on threads that make use of the
793 // priority queue (prioritization requires all our tasks to be in the
initial.commitd7cae122008-07-26 21:49:38794 // work_queue_ ASAP).
795 if (!work_queue_.Empty() && !work_queue_.use_priority_queue())
796 return; // Wait till we *really* need to lock and load.
797
798 // Acquire all we can from the inter-thread queue with one lock acquisition.
799 TaskQueue new_task_list; // Null terminated list.
800 {
801 AutoLock lock(incoming_queue_lock_);
802 if (incoming_queue_.Empty())
803 return;
804 std::swap(incoming_queue_, new_task_list);
805 DCHECK(incoming_queue_.Empty());
806 } // Release lock.
807
808 while (!new_task_list.Empty()) {
809 Task* task = new_task_list.Pop();
810 DCHECK(task->is_owned_by_message_loop());
811
812 if (task->posted_task_delay() > 0)
813 timer_manager_.StartTimer(task->posted_task_delay(), task, false);
814 else
815 work_queue_.Push(task);
816 }
817}
818
819void MessageLoop::DeletePendingTasks() {
820 /* Comment this out as it's causing crashes.
821 while (!work_queue_.Empty()) {
822 Task* task = work_queue_.Pop();
823 if (task->is_owned_by_message_loop())
824 delete task;
825 }
826
827 while (!delayed_non_nestable_queue_.Empty()) {
828 Task* task = delayed_non_nestable_queue_.Pop();
829 if (task->is_owned_by_message_loop())
830 delete task;
831 }
832 */
833}
834
[email protected]a5b94a92008-08-12 23:25:43835void MessageLoop::DidChangeNextTimerExpiry() {
[email protected]295039bd2008-08-15 04:32:57836#if defined(OS_WIN)
[email protected]ea15e982008-08-15 07:31:20837 //
838 // We would *like* to provide high resolution timers. Windows timers using
839 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup
840 // mechanism because the application can enter modal windows loops where it
841 // is not running our MessageLoop; the only way to have our timers fire in
842 // these cases is to post messages there.
843 //
844 // To provide sub-10ms timers, we process timers directly from our run loop.
845 // For the common case, timers will be processed there as the run loop does
846 // its normal work. However, we *also* set the system timer so that WM_TIMER
847 // events fire. This mops up the case of timers not being able to work in
848 // modal message loops. It is possible for the SetTimer to pop and have no
849 // pending timers, because they could have already been processed by the
850 // run loop itself.
851 //
852 // We use a single SetTimer corresponding to the timer that will expire
853 // soonest. As new timers are created and destroyed, we update SetTimer.
854 // Getting a spurrious SetTimer event firing is benign, as we'll just be
855 // processing an empty timer queue.
856 //
857 int delay = timer_manager_.GetCurrentDelay();
858 if (delay == -1) {
859 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
860 } else {
861 if (delay < USER_TIMER_MINIMUM)
862 delay = USER_TIMER_MINIMUM;
863 // Simulates malfunctioning, early firing timers. Pending tasks should only
864 // be invoked when the delay they specify has elapsed.
865 if (timer_manager_.use_broken_delay())
866 delay = 10;
867 // Create a WM_TIMER event that will wake us up to check for any pending
868 // timers (in case we are running within a nested, external sub-pump).
869 SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay, NULL);
870 }
871#endif // defined(OS_WIN)
[email protected]a5b94a92008-08-12 23:25:43872}
873
initial.commitd7cae122008-07-26 21:49:38874//------------------------------------------------------------------------------
875// Implementation of the work_queue_ as a ProiritizedTaskQueue
876
877void MessageLoop::PrioritizedTaskQueue::push(Task * task) {
878 queue_.push(PrioritizedTask(task, --next_sequence_number_));
879}
880
881bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < (
882 PrioritizedTask const & right) const {
883 int compare = task_->priority_ - right.task_->priority_;
884 if (compare)
885 return compare < 0;
886 // Don't compare directly, but rather subtract. This handles overflow
887 // as sequence numbers wrap around.
888 compare = sequence_number_ - right.sequence_number_;
889 DCHECK(compare); // Sequence number are unique for a "long time."
890 // Make sure we don't starve anything with a low priority.
891 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping.
892 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping.
893 return compare < 0;
894}
895
896//------------------------------------------------------------------------------
897// Implementation of a TaskQueue as a null terminated list, with end pointers.
898
899void MessageLoop::TaskQueue::Push(Task* task) {
900 if (!first_)
901 first_ = task;
902 else
903 last_->set_next_task(task);
904 last_ = task;
905}
906
907Task* MessageLoop::TaskQueue::Pop() {
908 DCHECK((!first_) == !last_);
909 Task* task = first_;
910 if (first_) {
911 first_ = task->next_task();
912 if (!first_)
913 last_ = NULL;
914 else
915 task->set_next_task(NULL);
916 }
917 return task;
918}
919
920//------------------------------------------------------------------------------
921// Implementation of a Task queue that automatically switches into a priority
922// queue if it observes any non-zero priorities on tasks.
923
924void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) {
925 if (use_priority_queue_) {
926 prioritized_queue_.push(task);
927 } else {
928 queue_.Push(task);
929 if (task->priority()) {
930 use_priority_queue_ = true; // From now on.
931 while (!queue_.Empty())
932 prioritized_queue_.push(queue_.Pop());
933 }
934 }
935}
936
937Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() {
938 if (!use_priority_queue_)
939 return queue_.Pop();
940 Task* task = prioritized_queue_.front();
941 prioritized_queue_.pop();
942 return task;
943}
944
945bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() {
946 if (use_priority_queue_)
947 return prioritized_queue_.empty();
948 return queue_.Empty();
949}
950
951//------------------------------------------------------------------------------
952// Method and data for histogramming events and actions taken by each instance
953// on each thread.
954
955// static
956bool MessageLoop::enable_histogrammer_ = false;
957
958// static
959void MessageLoop::EnableHistogrammer(bool enable) {
960 enable_histogrammer_ = enable;
961}
962
963void MessageLoop::StartHistogrammer() {
964 if (enable_histogrammer_ && !message_histogram_.get()
965 && StatisticsRecorder::WasStarted()) {
initial.commitd7cae122008-07-26 21:49:38966 message_histogram_.reset(new LinearHistogram(
967 ASCIIToWide("MsgLoop:" + thread_name_).c_str(),
968 kLeastNonZeroMessageId,
969 kMaxMessageId,
970 kNumberOfDistinctMessagesDisplayed));
971 message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag);
972 message_histogram_->SetRangeDescriptions(event_descriptions_);
973 }
974}
975
976void MessageLoop::HistogramEvent(int event) {
977 if (message_histogram_.get())
978 message_histogram_->Add(event);
979}
980
[email protected]ea15e982008-08-15 07:31:20981// Add one undocumented windows message to clean up our display.
982#ifndef WM_SYSTIMER
983#define WM_SYSTIMER 0x118
984#endif
985
initial.commitd7cae122008-07-26 21:49:38986// Provide a macro that takes an expression (such as a constant, or macro
987// constant) and creates a pair to initalize an array of pairs. In this case,
988// our pair consists of the expressions value, and the "stringized" version
989// of the expression (i.e., the exrpression put in quotes). For example, if
990// we have:
991// #define FOO 2
992// #define BAR 5
993// then the following:
994// VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
995// will expand to:
996// {7, "FOO + BAR"}
997// We use the resulting array as an argument to our histogram, which reads the
998// number as a bucket identifier, and proceeds to use the corresponding name
999// in the pair (i.e., the quoted string) when printing out a histogram.
1000#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
1001
[email protected]ea15e982008-08-15 07:31:201002
initial.commitd7cae122008-07-26 21:49:381003// static
1004const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
[email protected]ea15e982008-08-15 07:31:201005 // Only provide an extensive list in debug mode. In release mode, we have to
1006 // read the octal values.... but we save about 450 strings, each of length
1007 // 10 from our binary image.
1008#ifndef NDEBUG
1009 // Prepare to include a list of names provided in a special header file4.
1010#define A_NAMED_MESSAGE_FROM_WINUSER_H VALUE_TO_NUMBER_AND_NAME
1011#include "base/windows_message_list.h"
1012#undef A_NAMED_MESSAGE_FROM_WINUSER_H
1013 // Add an undocumented message that appeared in our list :-/.
1014 VALUE_TO_NUMBER_AND_NAME(WM_SYSTIMER)
1015#endif // NDEBUG
1016
initial.commitd7cae122008-07-26 21:49:381017 // Provide some pretty print capability in our histogram for our internal
1018 // messages.
1019
[email protected]ea15e982008-08-15 07:31:201020 // Values we use for WM_USER+n
1021 VALUE_TO_NUMBER_AND_NAME(kMsgPumpATask)
1022 VALUE_TO_NUMBER_AND_NAME(kMsgQuit)
1023
initial.commitd7cae122008-07-26 21:49:381024 // A few events we handle (kindred to messages), and used to profile actions.
1025 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
[email protected]ea15e982008-08-15 07:31:201026 VALUE_TO_NUMBER_AND_NAME(kSleepingApcEvent)
1027 VALUE_TO_NUMBER_AND_NAME(kSleepingSignalEvent)
1028 VALUE_TO_NUMBER_AND_NAME(kPollingSignalEvent)
initial.commitd7cae122008-07-26 21:49:381029 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
1030
1031 {-1, NULL} // The list must be null terminated, per API to histogram.
1032};