blob: 78f820c9784080e1995e7b92198f3cf9b108a27c [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
30#include <algorithm>
31
32#include "base/message_loop.h"
33
34#include "base/logging.h"
35#include "base/string_util.h"
36#include "base/thread_local_storage.h"
37#include "base/win_util.h"
38
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
46static 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
58// Logical events for Histogram profiling. Run with -message-loop-histogrammer
59// to get an accounting of messages and actions taken on each thread.
60static 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
65
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
73static LRESULT CALLBACK MessageLoopWndProc(HWND hwnd, UINT message,
74 WPARAM wparam, LPARAM lparam) {
75 switch (message) {
76 case kMsgQuit:
77 case kMsgPumpATask: {
78 UINT_PTR message_loop_id = static_cast<UINT_PTR>(wparam);
79 MessageLoop* current_message_loop =
80 reinterpret_cast<MessageLoop*>(message_loop_id);
81 DCHECK(MessageLoop::current() == current_message_loop);
82 return current_message_loop->MessageWndProc(hwnd, message, wparam,
83 lparam);
84 }
85 }
86 return ::DefWindowProc(hwnd, message, wparam, lparam);
87}
88
89#ifndef NDEBUG
90// Force exercise of polling model.
91#define CHROME_MAXIMUM_WAIT_OBJECTS 8
92#else
93#define CHROME_MAXIMUM_WAIT_OBJECTS MAXIMUM_WAIT_OBJECTS
94#endif
95
96//------------------------------------------------------------------------------
97// A strategy of -1 uses the default case. All strategies are selected as
98// positive integers.
99// static
100int MessageLoop::strategy_selector_ = -1;
101
102// static
103void MessageLoop::SetStrategy(int strategy) {
104 DCHECK(-1 == strategy_selector_);
105 strategy_selector_ = strategy;
106}
107
108//------------------------------------------------------------------------------
109// Upon a SEH exception in this thread, it restores the original unhandled
110// exception filter.
111static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
112 ::SetUnhandledExceptionFilter(old_filter);
113 return EXCEPTION_CONTINUE_SEARCH;
114}
115
116// Retrieves a pointer to the current unhandled exception filter. There
117// is no standalone getter method.
118static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
119 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
120 top_filter = ::SetUnhandledExceptionFilter(0);
121 ::SetUnhandledExceptionFilter(top_filter);
122 return top_filter;
123}
124
125//------------------------------------------------------------------------------
126
127MessageLoop::MessageLoop() : message_hwnd_(NULL),
128 exception_restoration_(false),
129 nestable_tasks_allowed_(true),
130 dispatcher_(NULL),
[email protected]b87b790c2008-08-03 20:26:26131 quit_received_(false),
initial.commitd7cae122008-07-26 21:49:38132 quit_now_(false),
133 task_pump_message_pending_(false),
134 run_depth_(0) {
135 DCHECK(tls_index_) << "static initializer failed";
136 DCHECK(!current()) << "should only have one message loop per thread";
137 ThreadLocalStorage::Set(tls_index_, this);
138 InitMessageWnd();
139}
140
141MessageLoop::~MessageLoop() {
142 DCHECK(this == current());
[email protected]2a127252008-08-05 23:16:41143
144 // Let interested parties have one last shot at accessing this.
145 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
146 WillDestroyCurrentMessageLoop());
147
148 // OK, now make it so that no one can find us.
initial.commitd7cae122008-07-26 21:49:38149 ThreadLocalStorage::Set(tls_index_, NULL);
[email protected]2a127252008-08-05 23:16:41150
initial.commitd7cae122008-07-26 21:49:38151 DCHECK(!dispatcher_);
152 DCHECK(!quit_received_ && !quit_now_);
[email protected]2a127252008-08-05 23:16:41153
initial.commitd7cae122008-07-26 21:49:38154 // Most tasks that have not been Run() are deleted in the |timer_manager_|
155 // destructor after we remove our tls index. We delete the tasks in our
156 // queues here so their destuction is similar to the tasks in the
157 // |timer_manager_|.
158 DeletePendingTasks();
159 ReloadWorkQueue();
160 DeletePendingTasks();
161}
162
163void MessageLoop::SetThreadName(const std::string& thread_name) {
164 DCHECK(thread_name_.empty());
165 thread_name_ = thread_name;
166 StartHistogrammer();
167}
168
[email protected]2a127252008-08-05 23:16:41169void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
170 DCHECK(this == current());
171 destruction_observers_.AddObserver(obs);
172}
173
174void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
175 DCHECK(this == current());
176 destruction_observers_.RemoveObserver(obs);
177}
178
initial.commitd7cae122008-07-26 21:49:38179void MessageLoop::AddObserver(Observer *obs) {
180 DCHECK(this == current());
181 observers_.AddObserver(obs);
182}
183
184void MessageLoop::RemoveObserver(Observer *obs) {
185 DCHECK(this == current());
186 observers_.RemoveObserver(obs);
187}
188
189void MessageLoop::Run() {
[email protected]3882c4332008-07-30 19:03:59190 RunHandler(NULL, false);
191}
192
193void MessageLoop::Run(Dispatcher* dispatcher) {
194 RunHandler(dispatcher, false);
195}
196
[email protected]7e0e8762008-07-31 13:10:20197void MessageLoop::RunAllPending() {
[email protected]3882c4332008-07-30 19:03:59198 RunHandler(NULL, true);
initial.commitd7cae122008-07-26 21:49:38199}
200
201// Runs the loop in two different SEH modes:
202// enable_SEH_restoration_ = false : any unhandled exception goes to the last
203// one that calls SetUnhandledExceptionFilter().
204// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
205// that was existed before the loop was run.
[email protected]7e0e8762008-07-31 13:10:20206void MessageLoop::RunHandler(Dispatcher* dispatcher, bool non_blocking) {
initial.commitd7cae122008-07-26 21:49:38207 if (exception_restoration_) {
208 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
209 __try {
[email protected]7e0e8762008-07-31 13:10:20210 RunInternal(dispatcher, non_blocking);
initial.commitd7cae122008-07-26 21:49:38211 } __except(SEHFilter(current_filter)) {
212 }
213 } else {
[email protected]7e0e8762008-07-31 13:10:20214 RunInternal(dispatcher, non_blocking);
initial.commitd7cae122008-07-26 21:49:38215 }
216}
217
218//------------------------------------------------------------------------------
initial.commitd7cae122008-07-26 21:49:38219// IF this was just a simple PeekMessage() loop (servicing all passible work
220// queues), then Windows would try to achieve the following order according to
221// MSDN documentation about PeekMessage with no filter):
222// * Sent messages
223// * Posted messages
224// * Sent messages (again)
225// * WM_PAINT messages
226// * WM_TIMER messages
227//
228// Summary: none of the above classes is starved, and sent messages has twice
229// the chance of being processed (i.e., reduced service time).
230
[email protected]7e0e8762008-07-31 13:10:20231void MessageLoop::RunInternal(Dispatcher* dispatcher, bool non_blocking) {
initial.commitd7cae122008-07-26 21:49:38232 // Preserve ability to be called recursively.
233 ScopedStateSave save(this); // State is restored on exit.
234 dispatcher_ = dispatcher;
235 StartHistogrammer();
236
237 DCHECK(this == current());
238 //
[email protected]3882c4332008-07-30 19:03:59239 // Process pending messages and signaled objects.
initial.commitd7cae122008-07-26 21:49:38240 //
241 // Flush these queues before exiting due to a kMsgQuit or else we risk not
242 // shutting down properly as some operations may depend on further event
243 // processing. (Note: some tests may use quit_now_ to exit more swiftly,
244 // and leave messages pending, so don't assert the above fact).
[email protected]7e0e8762008-07-31 13:10:20245 RunTraditional(non_blocking);
246 DCHECK(non_blocking || quit_received_ || quit_now_);
initial.commitd7cae122008-07-26 21:49:38247}
248
[email protected]7e0e8762008-07-31 13:10:20249void MessageLoop::RunTraditional(bool non_blocking) {
250 for (;;) {
initial.commitd7cae122008-07-26 21:49:38251 // If we do any work, we may create more messages etc., and more work
[email protected]3882c4332008-07-30 19:03:59252 // may possibly be waiting in another task group. When we (for example)
253 // ProcessNextWindowsMessage(), there is a good chance there are still more
254 // messages waiting (same thing for ProcessNextObject(), which responds to
255 // only one signaled object; etc.). On the other hand, when any of these
256 // methods return having done no work, then it is pretty unlikely that
257 // calling them again quickly will find any work to do.
initial.commitd7cae122008-07-26 21:49:38258 // Finally, if they all say they had no work, then it is a good time to
259 // consider sleeping (waiting) for more work.
[email protected]3882c4332008-07-30 19:03:59260 bool more_work_is_plausible = ProcessNextWindowsMessage();
initial.commitd7cae122008-07-26 21:49:38261 if (quit_now_)
[email protected]3882c4332008-07-30 19:03:59262 return;
initial.commitd7cae122008-07-26 21:49:38263
264 more_work_is_plausible |= ProcessNextDeferredTask();
265 more_work_is_plausible |= ProcessNextObject();
266 if (more_work_is_plausible)
267 continue;
268
269 if (quit_received_)
[email protected]3882c4332008-07-30 19:03:59270 return;
initial.commitd7cae122008-07-26 21:49:38271
272 // Run any timer that is ready to run. It may create messages etc.
273 if (ProcessSomeTimers())
274 continue;
275
[email protected]b87b790c2008-08-03 20:26:26276 // We run delayed non nestable tasks only after all nestable tasks have
277 // run, to preserve FIFO ordering.
278 if (ProcessNextDelayedNonNestableTask())
279 continue;
280
[email protected]7e0e8762008-07-31 13:10:20281 if (non_blocking)
[email protected]3882c4332008-07-30 19:03:59282 return;
283
initial.commitd7cae122008-07-26 21:49:38284 // We service APCs in WaitForWork, without returning.
285 WaitForWork(); // Wait (sleep) until we have work to do again.
[email protected]7e0e8762008-07-31 13:10:20286 }
[email protected]b8f2fe5d2008-07-30 07:50:53287}
[email protected]7622bd02008-07-30 06:58:56288
[email protected]3882c4332008-07-30 19:03:59289//------------------------------------------------------------------------------
290// Wrapper functions for use in above message loop framework.
291
initial.commitd7cae122008-07-26 21:49:38292bool MessageLoop::ProcessNextDelayedNonNestableTask() {
293 if (run_depth_ != 1)
294 return false;
295
296 if (delayed_non_nestable_queue_.Empty())
297 return false;
298
299 RunTask(delayed_non_nestable_queue_.Pop());
300 return true;
301}
302
initial.commitd7cae122008-07-26 21:49:38303bool MessageLoop::ProcessNextDeferredTask() {
304 ReloadWorkQueue();
305 return QueueOrRunTask(NULL);
306}
307
308bool MessageLoop::ProcessSomeTimers() {
309 return timer_manager_.RunSomePendingTimers();
310}
311
312//------------------------------------------------------------------------------
313
314void MessageLoop::Quit() {
315 EnsureMessageGetsPosted(kMsgQuit);
316}
317
318bool MessageLoop::WatchObject(HANDLE object, Watcher* watcher) {
319 DCHECK(this == current());
320 DCHECK(object);
321 DCHECK_NE(object, INVALID_HANDLE_VALUE);
322
323 std::vector<HANDLE>::iterator it = find(objects_.begin(), objects_.end(),
324 object);
325 if (watcher) {
326 if (it == objects_.end()) {
327 static size_t warning_multiple = 1;
328 if (objects_.size() >= warning_multiple * MAXIMUM_WAIT_OBJECTS / 2) {
329 LOG(INFO) << "More than " << warning_multiple * MAXIMUM_WAIT_OBJECTS / 2
330 << " objects being watched";
331 // This DCHECK() is an artificial limitation, meant to warn us if we
332 // start creating too many objects. It can safely be raised to a higher
333 // level, and the program is designed to handle much larger values.
334 // Before raising this limit, make sure that there is a very good reason
335 // (in your debug testing) to be watching this many objects.
336 DCHECK(2 <= warning_multiple);
337 ++warning_multiple;
338 }
339 objects_.push_back(object);
340 watchers_.push_back(watcher);
341 } else {
342 watchers_[it - objects_.begin()] = watcher;
343 }
344 } else if (it != objects_.end()) {
345 std::vector<HANDLE>::difference_type index = it - objects_.begin();
346 objects_.erase(it);
347 watchers_.erase(watchers_.begin() + index);
348 }
349 return true;
350}
351
352// Possibly called on a background thread!
353void MessageLoop::PostDelayedTask(const tracked_objects::Location& from_here,
354 Task* task, int delay_ms) {
355 task->SetBirthPlace(from_here);
356 DCHECK(delay_ms >= 0);
357 DCHECK(!task->is_owned_by_message_loop());
358 task->set_posted_task_delay(delay_ms);
359 DCHECK(task->is_owned_by_message_loop());
360 PostTaskInternal(task);
361}
362
363void MessageLoop::PostTaskInternal(Task* task) {
364 // Warning: Don't try to short-circuit, and handle this thread's tasks more
365 // directly, as it could starve handling of foreign threads. Put every task
366 // into this queue.
367
368 // Local stack variables to use IF we need to process after releasing locks.
369 HWND message_hwnd;
370 {
371 AutoLock lock1(incoming_queue_lock_);
372 bool was_empty = incoming_queue_.Empty();
373 incoming_queue_.Push(task);
374 if (!was_empty)
375 return; // Someone else should have started the sub-pump.
376
377 // We may have to start the sub-pump.
378 AutoLock lock2(task_pump_message_lock_);
379 if (task_pump_message_pending_)
380 return; // Someone else continued the pumping.
381 task_pump_message_pending_ = true; // We'll send one.
382 message_hwnd = message_hwnd_;
383 } // Release both locks.
384 // We may have just posted a kMsgQuit, and so this instance may now destroyed!
385 // Do not invoke non-static methods, or members in any way!
386
387 // PostMessage may fail, as the hwnd may have vanished due to kMsgQuit.
388 PostMessage(message_hwnd, kMsgPumpATask, reinterpret_cast<UINT_PTR>(this), 0);
389}
390
391void MessageLoop::InitMessageWnd() {
392 HINSTANCE hinst = GetModuleHandle(NULL);
393
394 WNDCLASSEX wc = {0};
395 wc.cbSize = sizeof(wc);
396 wc.lpfnWndProc = MessageLoopWndProc;
397 wc.hInstance = hinst;
398 wc.lpszClassName = kWndClass;
399 RegisterClassEx(&wc);
400
401 message_hwnd_ = CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0,
402 hinst, 0);
403 DCHECK(message_hwnd_);
404}
405
406LRESULT MessageLoop::MessageWndProc(HWND hwnd, UINT message,
407 WPARAM wparam, LPARAM lparam) {
408 DCHECK(hwnd == message_hwnd_);
409 switch (message) {
410 case kMsgPumpATask: {
411 ProcessPumpReplacementMessage(); // Avoid starving paint and timer.
412 if (!nestable_tasks_allowed_)
413 return 0;
414 PumpATaskDuringWndProc();
415 return 0;
416 }
417
418 case kMsgQuit: {
[email protected]b87b790c2008-08-03 20:26:26419 // TODO(jar): bug 1300541 The following assert should be used, but
420 // currently too much code actually triggers the assert, especially in
421 // tests :-(.
422 //CHECK(!quit_received_); // Discarding a second quit will cause a hang.
423 quit_received_ = true;
initial.commitd7cae122008-07-26 21:49:38424 return 0;
425 }
426 }
427 return ::DefWindowProc(hwnd, message, wparam, lparam);
428}
429
430void MessageLoop::WillProcessMessage(const MSG& msg) {
431 FOR_EACH_OBSERVER(Observer, observers_, WillProcessMessage(msg));
432}
433
434void MessageLoop::DidProcessMessage(const MSG& msg) {
435 FOR_EACH_OBSERVER(Observer, observers_, DidProcessMessage(msg));
436}
437
438void MessageLoop::SetNestableTasksAllowed(bool allowed) {
439 nestable_tasks_allowed_ = allowed;
440 if (!nestable_tasks_allowed_)
441 return;
442 // Start the native pump if we are not already pumping.
443 EnsurePumpATaskWasPosted();
444}
445
446bool MessageLoop::NestableTasksAllowed() const {
447 return nestable_tasks_allowed_;
448}
449
450
451bool MessageLoop::ProcessNextWindowsMessage() {
452 MSG msg;
453 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
454 return ProcessMessageHelper(msg);
455 }
456 return false;
457}
458
459bool MessageLoop::ProcessMessageHelper(const MSG& msg) {
460 HistogramEvent(msg.message);
461
462 if (WM_QUIT == msg.message) {
463 // Repost the QUIT message so that it will be retrieved by the primary
464 // GetMessage() loop.
465 quit_now_ = true;
466 PostQuitMessage(static_cast<int>(msg.wParam));
467 return false;
468 }
469
470 // While running our main message pump, we discard kMsgPumpATask messages.
471 if (msg.message == kMsgPumpATask && msg.hwnd == message_hwnd_)
472 return ProcessPumpReplacementMessage();
473
474 WillProcessMessage(msg);
475
476 if (dispatcher_) {
477 if (!dispatcher_->Dispatch(msg))
478 quit_now_ = true;
479 } else {
480 TranslateMessage(&msg);
481 DispatchMessage(&msg);
482 }
483
484 DidProcessMessage(msg);
485 return true;
486}
487
488bool MessageLoop::ProcessPumpReplacementMessage() {
489 MSG msg;
490 bool have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
491 DCHECK(!have_message || kMsgPumpATask != msg.message
492 || msg.hwnd != message_hwnd_);
493 {
494 // Since we discarded a kMsgPumpATask message, we must update the flag.
495 AutoLock lock(task_pump_message_lock_);
496 DCHECK(task_pump_message_pending_);
497 task_pump_message_pending_ = false;
498 }
499 return have_message && ProcessMessageHelper(msg);
500}
501
502// Create a mini-message-pump to force immediate processing of only Windows
503// WM_PAINT messages.
504void MessageLoop::PumpOutPendingPaintMessages() {
505 // Don't provide an infinite loop, but do enough peeking to get the job done.
506 // Actual common max is 4 peeks, but we'll be a little safe here.
507 const int kMaxPeekCount = 20;
508 int peek_count;
509 bool win2k(true);
510 if (win_util::GetWinVersion() > win_util::WINVERSION_2000)
511 win2k = false;
512 for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) {
513 MSG msg;
514 if (win2k) {
515 if (!PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE))
516 break;
517 } else {
518 if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT))
519 break;
520 }
521 ProcessMessageHelper(msg);
522 if (quit_now_ ) // Handle WM_QUIT.
523 break;
524 }
525 // Histogram what was really being used, to help to adjust kMaxPeekCount.
526 DHISTOGRAM_COUNTS(L"Loop.PumpOutPendingPaintMessages Peeks", peek_count);
527}
528
529//------------------------------------------------------------------------------
530// If we handle more than the OS limit on the number of objects that can be
531// waited for, we'll need to poll (sequencing through subsets of the objects
532// that can be passed in a single OS wait call). The following is the polling
533// interval used in that (unusual) case. (I don't have a lot of justifcation
534// for the specific value, but it needed to be short enough that it would not
535// add a lot of latency, and long enough that we wouldn't thrash the CPU for no
536// reason... especially considering the silly user probably has a million tabs
537// open, etc.)
538static const int kMultipleWaitPollingInterval = 20;
539
540void MessageLoop::WaitForWork() {
541 bool original_can_run = nestable_tasks_allowed_;
542 int wait_flags = original_can_run ? MWMO_ALERTABLE | MWMO_INPUTAVAILABLE
543 : MWMO_INPUTAVAILABLE;
544
545 bool use_polling = false; // Poll if too many objects for one OS Wait call.
546 for (;;) {
547 // Do initialization here, in case APC modifies object list.
548 size_t total_objs = original_can_run ? objects_.size() : 0;
549
550 int delay;
551 size_t polling_index = 0; // The first unprocessed object index.
552 do {
553 size_t objs_len =
554 (polling_index < total_objs) ? total_objs - polling_index : 0;
555 if (objs_len >= CHROME_MAXIMUM_WAIT_OBJECTS) {
556 objs_len = CHROME_MAXIMUM_WAIT_OBJECTS - 1;
557 use_polling = true;
558 }
559 HANDLE* objs = objs_len ? polling_index + &objects_.front() : NULL;
560
561 // Only wait up to the time needed by the timer manager to fire the next
562 // set of timers.
563 delay = timer_manager_.GetCurrentDelay();
564 if (use_polling && delay > kMultipleWaitPollingInterval)
565 delay = kMultipleWaitPollingInterval;
566 if (delay < 0) // Negative value means no timers waiting.
567 delay = INFINITE;
568
569 DWORD result;
570 result = MsgWaitForMultipleObjectsEx(static_cast<DWORD>(objs_len), objs,
571 delay, QS_ALLINPUT, wait_flags);
572
573 if (WAIT_IO_COMPLETION == result) {
574 HistogramEvent(kSleepingApcEvent);
575 // We'll loop here when we service an APC. At it currently stands,
576 // *ONLY* the IO thread uses *any* APCs, so this should have no impact
577 // on the UI thread.
578 break; // Break to outer loop, and waitforwork() again.
579 }
580
581 // Use unsigned type to simplify range detection;
582 size_t signaled_index = result - WAIT_OBJECT_0;
583 if (signaled_index < objs_len) {
584 SignalWatcher(polling_index + signaled_index);
585 HistogramEvent(kSleepingSignalEvent);
586 return; // We serviced a signaled object.
587 }
588
589 if (objs_len == signaled_index)
590 return; // A WM_* message is available.
591
592 DCHECK_NE(WAIT_FAILED, result) << GetLastError();
593
594 DCHECK(!objs || result == WAIT_TIMEOUT);
595 if (!use_polling)
596 return;
597 polling_index += objs_len;
598 } while (polling_index < total_objs);
599 // For compatibility, we didn't return sooner. This made us do *some* wait
600 // call(s) before returning. This will probably change in next rev.
601 if (!delay || !timer_manager_.GetCurrentDelay())
602 return; // No work done, but timer is ready to fire.
603 }
604}
605
606// Note: MsgWaitMultipleObjects() can't take a nil list, and that is why I had
607// to use SleepEx() to handle APCs when there were no objects.
608bool MessageLoop::ProcessNextObject() {
609 if (!nestable_tasks_allowed_)
610 return false;
611
612 size_t total_objs = objects_.size();
613 if (!total_objs) {
614 return false;
615 }
616
617 size_t polling_index = 0; // The first unprocessed object index.
618 do {
619 DCHECK(polling_index < total_objs);
620 size_t objs_len = total_objs - polling_index;
621 if (objs_len >= CHROME_MAXIMUM_WAIT_OBJECTS)
622 objs_len = CHROME_MAXIMUM_WAIT_OBJECTS - 1;
623 HANDLE* objs = polling_index + &objects_.front();
624
625 // Identify 1 pending object, or allow an IO APC to be completed.
626 DWORD result = WaitForMultipleObjectsEx(static_cast<DWORD>(objs_len), objs,
627 FALSE, // 1 signal is sufficient.
628 0, // Wait 0ms.
629 false); // Not alertable (no APC).
630
631 // Use unsigned type to simplify range detection;
632 size_t signaled_index = result - WAIT_OBJECT_0;
633 if (signaled_index < objs_len) {
634 SignalWatcher(polling_index + signaled_index);
635 HistogramEvent(kPollingSignalEvent);
636 return true; // We serviced a signaled object.
637 }
638
639 // If an handle is invalid, it will be WAIT_FAILED.
640 DCHECK_EQ(WAIT_TIMEOUT, result) << GetLastError();
641 polling_index += objs_len;
642 } while (polling_index < total_objs);
643 return false; // We serviced nothing.
644}
645
646bool MessageLoop::SignalWatcher(size_t object_index) {
647 BeforeTaskRunSetup();
648 DCHECK(objects_.size() > object_index);
649 // On reception of OnObjectSignaled() to a Watcher object, it may call
650 // WatchObject(). watchers_ and objects_ will be modified. This is
651 // expected, so don't be afraid if, while tracing a OnObjectSignaled()
652 // function, the corresponding watchers_[result] is inexistant.
653 watchers_[object_index]->OnObjectSignaled(objects_[object_index]);
654 // Signaled objects tend to be removed from the watch list, and then added
655 // back (appended). As a result, they move to the end of the objects_ array,
656 // and this should make their service "fair" (no HANDLEs should be starved).
657 AfterTaskRunRestore();
658 return true;
659}
660
661bool MessageLoop::RunTimerTask(Timer* timer) {
662 HistogramEvent(kTimerEvent);
663 Task* task = timer->task();
664 if (task->is_owned_by_message_loop()) {
665 // We constructed it through PostTask().
666 DCHECK(!timer->repeating());
667 timer->set_task(NULL);
668 delete timer;
[email protected]ee73678e2008-08-01 21:55:17669 task->ResetBirthTime();
initial.commitd7cae122008-07-26 21:49:38670 return QueueOrRunTask(task);
671 } else {
672 // This is an unknown timer task, and we *can't* delay running it, as a
673 // user might try to cancel it with TimerManager at any moment.
674 DCHECK(nestable_tasks_allowed_);
675 RunTask(task);
676 return true;
677 }
678}
679
680void MessageLoop::DiscardTimer(Timer* timer) {
681 Task* task = timer->task();
682 if (task->is_owned_by_message_loop()) {
683 DCHECK(!timer->repeating());
684 timer->set_task(NULL);
685 delete timer; // We constructed it through PostDelayedTask().
686 delete task; // We were given ouwnership in PostTask().
687 }
688}
689
690bool MessageLoop::QueueOrRunTask(Task* new_task) {
691 if (!nestable_tasks_allowed_) {
692 // Task can't be executed right now. Add it to the queue.
693 if (new_task)
694 work_queue_.Push(new_task);
695 return false;
696 }
697
698 // Queue new_task first so we execute the task in FIFO order.
699 if (new_task)
700 work_queue_.Push(new_task);
701
702 // Execute oldest task.
703 while (!work_queue_.Empty()) {
704 Task* task = work_queue_.Pop();
705 if (task->nestable() || run_depth_ == 1) {
706 RunTask(task);
707 // Show that we ran a task (Note: a new one might arrive as a
708 // consequence!).
709 return true;
710 } else {
711 // We couldn't run the task now because we're in a nested message loop
712 // and the task isn't nestable.
713 delayed_non_nestable_queue_.Push(task);
714 }
715 }
716
717 // Nothing happened.
718 return false;
719}
720
721void MessageLoop::RunTask(Task* task) {
722 BeforeTaskRunSetup();
723 HistogramEvent(kTaskRunEvent);
724 // task may self-delete during Run() if we don't happen to own it.
725 // ...so check *before* we Run, since we can't check after.
726 bool we_own_task = task->is_owned_by_message_loop();
727 task->Run();
728 if (we_own_task)
729 task->RecycleOrDelete(); // Relinquish control, and probably delete.
730 AfterTaskRunRestore();
731}
732
733void MessageLoop::BeforeTaskRunSetup() {
734 DCHECK(nestable_tasks_allowed_);
735 // Execute the task and assume the worst: It is probably not reentrant.
736 nestable_tasks_allowed_ = false;
737}
738
739void MessageLoop::AfterTaskRunRestore() {
740 nestable_tasks_allowed_ = true;
741}
742
743void MessageLoop::PumpATaskDuringWndProc() {
744 // TODO(jar): Perchance we should check on signaled objects here??
745 // Signals are generally starved during a native message loop. Even if we
746 // try to service a signaled object now, we wouldn't automatically get here
747 // (i.e., the native pump would not re-start) when the next object was
748 // signaled. If we really want to avoid starving signaled objects, we need
749 // to translate them into Tasks that can be passed in via PostTask.
750 // If these native message loops (and sub-pumping activities) are short
751 // lived, then the starvation won't be that long :-/.
752
753 if (!ProcessNextDeferredTask())
754 return; // Nothing to do, so lets stop the sub-pump.
755
756 // We ran a task, so make sure we come back and try to run more tasks.
757 EnsurePumpATaskWasPosted();
758}
759
760void MessageLoop::EnsurePumpATaskWasPosted() {
761 {
762 AutoLock lock(task_pump_message_lock_);
763 if (task_pump_message_pending_)
764 return; // Someone else continued the pumping.
765 task_pump_message_pending_ = true; // We'll send one.
766 }
767 EnsureMessageGetsPosted(kMsgPumpATask);
768}
769
770void MessageLoop::EnsureMessageGetsPosted(int message) const {
771 const int kRetryCount = 30;
772 const int kSleepDurationWhenFailing = 100;
773 for (int i = 0; i < kRetryCount; ++i) {
774 // Posting to our own windows should always succeed. If it doesn't we're in
775 // big trouble.
776 if (PostMessage(message_hwnd_, message,
777 reinterpret_cast<UINT_PTR>(this), 0))
778 return;
779 Sleep(kSleepDurationWhenFailing);
780 }
781 LOG(FATAL) << "Crash with last error " << GetLastError();
782 int* p = NULL;
783 *p = 0; // Crash.
784}
785
786void MessageLoop::ReloadWorkQueue() {
787 // We can improve performance of our loading tasks from incoming_queue_ to
788 // work_queue_ by wating until the last minute (work_queue_ is empty) to load.
789 // That reduces the number of locks-per-task significantly when our queues get
790 // large. The optimization is disabled on threads that make use of the
791 // priority queue (prioritization requires all our tasks to be in the
792 // work_queue_ ASAP).
793 if (!work_queue_.Empty() && !work_queue_.use_priority_queue())
794 return; // Wait till we *really* need to lock and load.
795
796 // Acquire all we can from the inter-thread queue with one lock acquisition.
797 TaskQueue new_task_list; // Null terminated list.
798 {
799 AutoLock lock(incoming_queue_lock_);
800 if (incoming_queue_.Empty())
801 return;
802 std::swap(incoming_queue_, new_task_list);
803 DCHECK(incoming_queue_.Empty());
804 } // Release lock.
805
806 while (!new_task_list.Empty()) {
807 Task* task = new_task_list.Pop();
808 DCHECK(task->is_owned_by_message_loop());
809
810 if (task->posted_task_delay() > 0)
811 timer_manager_.StartTimer(task->posted_task_delay(), task, false);
812 else
813 work_queue_.Push(task);
814 }
815}
816
817void MessageLoop::DeletePendingTasks() {
818 /* Comment this out as it's causing crashes.
819 while (!work_queue_.Empty()) {
820 Task* task = work_queue_.Pop();
821 if (task->is_owned_by_message_loop())
822 delete task;
823 }
824
825 while (!delayed_non_nestable_queue_.Empty()) {
826 Task* task = delayed_non_nestable_queue_.Pop();
827 if (task->is_owned_by_message_loop())
828 delete task;
829 }
830 */
831}
832
833//------------------------------------------------------------------------------
834// Implementation of the work_queue_ as a ProiritizedTaskQueue
835
836void MessageLoop::PrioritizedTaskQueue::push(Task * task) {
837 queue_.push(PrioritizedTask(task, --next_sequence_number_));
838}
839
840bool MessageLoop::PrioritizedTaskQueue::PrioritizedTask::operator < (
841 PrioritizedTask const & right) const {
842 int compare = task_->priority_ - right.task_->priority_;
843 if (compare)
844 return compare < 0;
845 // Don't compare directly, but rather subtract. This handles overflow
846 // as sequence numbers wrap around.
847 compare = sequence_number_ - right.sequence_number_;
848 DCHECK(compare); // Sequence number are unique for a "long time."
849 // Make sure we don't starve anything with a low priority.
850 CHECK(INT_MAX/8 > compare); // We don't get close to wrapping.
851 CHECK(INT_MIN/8 < compare); // We don't get close to wrapping.
852 return compare < 0;
853}
854
855//------------------------------------------------------------------------------
856// Implementation of a TaskQueue as a null terminated list, with end pointers.
857
858void MessageLoop::TaskQueue::Push(Task* task) {
859 if (!first_)
860 first_ = task;
861 else
862 last_->set_next_task(task);
863 last_ = task;
864}
865
866Task* MessageLoop::TaskQueue::Pop() {
867 DCHECK((!first_) == !last_);
868 Task* task = first_;
869 if (first_) {
870 first_ = task->next_task();
871 if (!first_)
872 last_ = NULL;
873 else
874 task->set_next_task(NULL);
875 }
876 return task;
877}
878
879//------------------------------------------------------------------------------
880// Implementation of a Task queue that automatically switches into a priority
881// queue if it observes any non-zero priorities on tasks.
882
883void MessageLoop::OptionallyPrioritizedTaskQueue::Push(Task* task) {
884 if (use_priority_queue_) {
885 prioritized_queue_.push(task);
886 } else {
887 queue_.Push(task);
888 if (task->priority()) {
889 use_priority_queue_ = true; // From now on.
890 while (!queue_.Empty())
891 prioritized_queue_.push(queue_.Pop());
892 }
893 }
894}
895
896Task* MessageLoop::OptionallyPrioritizedTaskQueue::Pop() {
897 if (!use_priority_queue_)
898 return queue_.Pop();
899 Task* task = prioritized_queue_.front();
900 prioritized_queue_.pop();
901 return task;
902}
903
904bool MessageLoop::OptionallyPrioritizedTaskQueue::Empty() {
905 if (use_priority_queue_)
906 return prioritized_queue_.empty();
907 return queue_.Empty();
908}
909
910//------------------------------------------------------------------------------
911// Method and data for histogramming events and actions taken by each instance
912// on each thread.
913
914// static
915bool MessageLoop::enable_histogrammer_ = false;
916
917// static
918void MessageLoop::EnableHistogrammer(bool enable) {
919 enable_histogrammer_ = enable;
920}
921
922void MessageLoop::StartHistogrammer() {
923 if (enable_histogrammer_ && !message_histogram_.get()
924 && StatisticsRecorder::WasStarted()) {
925 message_histogram_.reset(new LinearHistogram(
926 ASCIIToWide("MsgLoop:" + thread_name_).c_str(),
927 kLeastNonZeroMessageId,
928 kMaxMessageId,
929 kNumberOfDistinctMessagesDisplayed));
930 message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag);
931 message_histogram_->SetRangeDescriptions(event_descriptions_);
932 }
933}
934
935void MessageLoop::HistogramEvent(int event) {
936 if (message_histogram_.get())
937 message_histogram_->Add(event);
938}
939
940// Add one undocumented windows message to clean up our display.
941#ifndef WM_SYSTIMER
942#define WM_SYSTIMER 0x118
943#endif
944
945// Provide a macro that takes an expression (such as a constant, or macro
946// constant) and creates a pair to initalize an array of pairs. In this case,
947// our pair consists of the expressions value, and the "stringized" version
948// of the expression (i.e., the exrpression put in quotes). For example, if
949// we have:
950// #define FOO 2
951// #define BAR 5
952// then the following:
953// VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
954// will expand to:
955// {7, "FOO + BAR"}
956// We use the resulting array as an argument to our histogram, which reads the
957// number as a bucket identifier, and proceeds to use the corresponding name
958// in the pair (i.e., the quoted string) when printing out a histogram.
959#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
960
961
962// static
963const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
964 // Only provide an extensive list in debug mode. In release mode, we have to
965 // read the octal values.... but we save about 450 strings, each of length
966 // 10 from our binary image.
967#ifndef NDEBUG
968 // Prepare to include a list of names provided in a special header file4.
969#define A_NAMED_MESSAGE_FROM_WINUSER_H VALUE_TO_NUMBER_AND_NAME
970#include "base/windows_message_list.h"
971#undef A_NAMED_MESSAGE_FROM_WINUSER_H
972 // Add an undocumented message that appeared in our list :-/.
973 VALUE_TO_NUMBER_AND_NAME(WM_SYSTIMER)
974#endif // NDEBUG
975
976 // Provide some pretty print capability in our histogram for our internal
977 // messages.
978
979 // Values we use for WM_USER+n
980 VALUE_TO_NUMBER_AND_NAME(kMsgPumpATask)
981 VALUE_TO_NUMBER_AND_NAME(kMsgQuit)
982
983 // A few events we handle (kindred to messages), and used to profile actions.
984 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
985 VALUE_TO_NUMBER_AND_NAME(kSleepingApcEvent)
986 VALUE_TO_NUMBER_AND_NAME(kSleepingSignalEvent)
987 VALUE_TO_NUMBER_AND_NAME(kPollingSignalEvent)
988 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
989
990 {-1, NULL} // The list must be null terminated, per API to histogram.
991};