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