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