1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6 
7 #include "base/message_pump_win.h"
8 
9 #include <math.h>
10 
11 #include "base/message_loop.h"
12 #include "base/histogram.h"
13 #include "base/win_util.h"
14 #include "mozilla/ProfilerLabels.h"
15 #include "WinUtils.h"
16 
17 using base::Time;
18 
19 namespace base {
20 
21 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow";
22 
23 // Message sent to get an additional time slice for pumping (processing) another
24 // task (a series of such messages creates a continuous task pump).
25 static const int kMsgHaveWork = WM_USER + 1;
26 
27 //-----------------------------------------------------------------------------
28 // MessagePumpWin public:
29 
AddObserver(Observer * observer)30 void MessagePumpWin::AddObserver(Observer* observer) {
31   observers_.AddObserver(observer);
32 }
33 
RemoveObserver(Observer * observer)34 void MessagePumpWin::RemoveObserver(Observer* observer) {
35   observers_.RemoveObserver(observer);
36 }
37 
WillProcessMessage(const MSG & msg)38 void MessagePumpWin::WillProcessMessage(const MSG& msg) {
39   FOR_EACH_OBSERVER(Observer, observers_, WillProcessMessage(msg));
40 }
41 
DidProcessMessage(const MSG & msg)42 void MessagePumpWin::DidProcessMessage(const MSG& msg) {
43   FOR_EACH_OBSERVER(Observer, observers_, DidProcessMessage(msg));
44 }
45 
RunWithDispatcher(Delegate * delegate,Dispatcher * dispatcher)46 void MessagePumpWin::RunWithDispatcher(Delegate* delegate,
47                                        Dispatcher* dispatcher) {
48   RunState s;
49   s.delegate = delegate;
50   s.dispatcher = dispatcher;
51   s.should_quit = false;
52   s.run_depth = state_ ? state_->run_depth + 1 : 1;
53 
54   RunState* previous_state = state_;
55   state_ = &s;
56 
57   DoRunLoop();
58 
59   state_ = previous_state;
60 }
61 
Quit()62 void MessagePumpWin::Quit() {
63   DCHECK(state_);
64   state_->should_quit = true;
65 }
66 
67 //-----------------------------------------------------------------------------
68 // MessagePumpWin protected:
69 
GetCurrentDelay() const70 int MessagePumpWin::GetCurrentDelay() const {
71   if (delayed_work_time_.is_null()) return -1;
72 
73   // Be careful here.  TimeDelta has a precision of microseconds, but we want a
74   // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
75   // 6?  It should be 6 to avoid executing delayed work too early.
76   double timeout =
77       ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF());
78 
79   // If this value is negative, then we need to run delayed work soon.
80   int delay = static_cast<int>(timeout);
81   if (delay < 0) delay = 0;
82 
83   return delay;
84 }
85 
86 //-----------------------------------------------------------------------------
87 // MessagePumpForUI public:
88 
MessagePumpForUI()89 MessagePumpForUI::MessagePumpForUI() { InitMessageWnd(); }
90 
~MessagePumpForUI()91 MessagePumpForUI::~MessagePumpForUI() {
92   DestroyWindow(message_hwnd_);
93   UnregisterClass(kWndClass, GetModuleHandle(NULL));
94 }
95 
ScheduleWork()96 void MessagePumpForUI::ScheduleWork() {
97   if (InterlockedExchange(&have_work_, 1))
98     return;  // Someone else continued the pumping.
99 
100   // Make sure the MessagePump does some work for us.
101   PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), 0);
102 
103   // In order to wake up any cross-process COM calls which may currently be
104   // pending on the main thread, we also have to post a UI message.
105   PostMessage(message_hwnd_, WM_NULL, 0, 0);
106 }
107 
ScheduleDelayedWork(const TimeTicks & delayed_work_time)108 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
109   //
110   // We would *like* to provide high resolution timers.  Windows timers using
111   // SetTimer() have a 10ms granularity.  We have to use WM_TIMER as a wakeup
112   // mechanism because the application can enter modal windows loops where it
113   // is not running our MessageLoop; the only way to have our timers fire in
114   // these cases is to post messages there.
115   //
116   // To provide sub-10ms timers, we process timers directly from our run loop.
117   // For the common case, timers will be processed there as the run loop does
118   // its normal work.  However, we *also* set the system timer so that WM_TIMER
119   // events fire.  This mops up the case of timers not being able to work in
120   // modal message loops.  It is possible for the SetTimer to pop and have no
121   // pending timers, because they could have already been processed by the
122   // run loop itself.
123   //
124   // We use a single SetTimer corresponding to the timer that will expire
125   // soonest.  As new timers are created and destroyed, we update SetTimer.
126   // Getting a spurrious SetTimer event firing is benign, as we'll just be
127   // processing an empty timer queue.
128   //
129   delayed_work_time_ = delayed_work_time;
130 
131   int delay_msec = GetCurrentDelay();
132   DCHECK(delay_msec >= 0);
133   if (delay_msec < USER_TIMER_MINIMUM) delay_msec = USER_TIMER_MINIMUM;
134 
135   // Create a WM_TIMER event that will wake us up to check for any pending
136   // timers (in case we are running within a nested, external sub-pump).
137   SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay_msec, NULL);
138 }
139 
PumpOutPendingPaintMessages()140 void MessagePumpForUI::PumpOutPendingPaintMessages() {
141   // If we are being called outside of the context of Run, then don't try to do
142   // any work.
143   if (!state_) return;
144 
145   // Create a mini-message-pump to force immediate processing of only Windows
146   // WM_PAINT messages.  Don't provide an infinite loop, but do enough peeking
147   // to get the job done.  Actual common max is 4 peeks, but we'll be a little
148   // safe here.
149   const int kMaxPeekCount = 20;
150   int peek_count;
151   for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) {
152     MSG msg;
153     if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) break;
154     ProcessMessageHelper(msg);
155     if (state_->should_quit)  // Handle WM_QUIT.
156       break;
157   }
158 }
159 
160 //-----------------------------------------------------------------------------
161 // MessagePumpForUI private:
162 
163 // static
WndProcThunk(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)164 LRESULT CALLBACK MessagePumpForUI::WndProcThunk(HWND hwnd, UINT message,
165                                                 WPARAM wparam, LPARAM lparam) {
166   switch (message) {
167     case kMsgHaveWork:
168       reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage();
169       break;
170     case WM_TIMER:
171       reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage();
172       break;
173   }
174   return DefWindowProc(hwnd, message, wparam, lparam);
175 }
176 
DoRunLoop()177 void MessagePumpForUI::DoRunLoop() {
178   // IF this was just a simple PeekMessage() loop (servicing all possible work
179   // queues), then Windows would try to achieve the following order according
180   // to MSDN documentation about PeekMessage with no filter):
181   //    * Sent messages
182   //    * Posted messages
183   //    * Sent messages (again)
184   //    * WM_PAINT messages
185   //    * WM_TIMER messages
186   //
187   // Summary: none of the above classes is starved, and sent messages has twice
188   // the chance of being processed (i.e., reduced service time).
189 
190   for (;;) {
191     // If we do any work, we may create more messages etc., and more work may
192     // possibly be waiting in another task group.  When we (for example)
193     // ProcessNextWindowsMessage(), there is a good chance there are still more
194     // messages waiting.  On the other hand, when any of these methods return
195     // having done no work, then it is pretty unlikely that calling them again
196     // quickly will find any work to do.  Finally, if they all say they had no
197     // work, then it is a good time to consider sleeping (waiting) for more
198     // work.
199 
200     bool more_work_is_plausible = ProcessNextWindowsMessage();
201     if (state_->should_quit) break;
202 
203     more_work_is_plausible |= state_->delegate->DoWork();
204     if (state_->should_quit) break;
205 
206     more_work_is_plausible |=
207         state_->delegate->DoDelayedWork(&delayed_work_time_);
208     // If we did not process any delayed work, then we can assume that our
209     // existing WM_TIMER if any will fire when delayed work should run.  We
210     // don't want to disturb that timer if it is already in flight.  However,
211     // if we did do all remaining delayed work, then lets kill the WM_TIMER.
212     if (more_work_is_plausible && delayed_work_time_.is_null())
213       KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
214     if (state_->should_quit) break;
215 
216     if (more_work_is_plausible) continue;
217 
218     more_work_is_plausible = state_->delegate->DoIdleWork();
219     if (state_->should_quit) break;
220 
221     if (more_work_is_plausible) continue;
222 
223     WaitForWork();  // Wait (sleep) until we have work to do again.
224   }
225 }
226 
InitMessageWnd()227 void MessagePumpForUI::InitMessageWnd() {
228   HINSTANCE hinst = GetModuleHandle(NULL);
229 
230   WNDCLASSEX wc = {0};
231   wc.cbSize = sizeof(wc);
232   wc.lpfnWndProc = WndProcThunk;
233   wc.hInstance = hinst;
234   wc.lpszClassName = kWndClass;
235   RegisterClassEx(&wc);
236 
237   message_hwnd_ =
238       CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, 0);
239   DCHECK(message_hwnd_);
240 }
241 
WaitForWork()242 void MessagePumpForUI::WaitForWork() {
243   AUTO_PROFILER_LABEL("MessagePumpForUI::WaitForWork", IDLE);
244 
245   // Wait until a message is available, up to the time needed by the timer
246   // manager to fire the next set of timers.
247   int delay = GetCurrentDelay();
248   if (delay < 0)  // Negative value means no timers waiting.
249     delay = INFINITE;
250 
251   mozilla::widget::WinUtils::WaitForMessage(delay);
252 }
253 
HandleWorkMessage()254 void MessagePumpForUI::HandleWorkMessage() {
255   // If we are being called outside of the context of Run, then don't try to do
256   // any work.  This could correspond to a MessageBox call or something of that
257   // sort.
258   if (!state_) {
259     // Since we handled a kMsgHaveWork message, we must still update this flag.
260     InterlockedExchange(&have_work_, 0);
261     return;
262   }
263 
264   // Let whatever would have run had we not been putting messages in the queue
265   // run now.  This is an attempt to make our dummy message not starve other
266   // messages that may be in the Windows message queue.
267   ProcessPumpReplacementMessage();
268 
269   // Now give the delegate a chance to do some work.  He'll let us know if he
270   // needs to do more work.
271   if (state_->delegate->DoWork()) ScheduleWork();
272 }
273 
HandleTimerMessage()274 void MessagePumpForUI::HandleTimerMessage() {
275   KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
276 
277   // If we are being called outside of the context of Run, then don't do
278   // anything.  This could correspond to a MessageBox call or something of
279   // that sort.
280   if (!state_) return;
281 
282   state_->delegate->DoDelayedWork(&delayed_work_time_);
283   if (!delayed_work_time_.is_null()) {
284     // A bit gratuitous to set delayed_work_time_ again, but oh well.
285     ScheduleDelayedWork(delayed_work_time_);
286   }
287 }
288 
ProcessNextWindowsMessage()289 bool MessagePumpForUI::ProcessNextWindowsMessage() {
290   // If there are sent messages in the queue then PeekMessage internally
291   // dispatches the message and returns false. We return true in this
292   // case to ensure that the message loop peeks again instead of calling
293   // MsgWaitForMultipleObjectsEx again.
294   bool sent_messages_in_queue = false;
295   DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);
296   if (HIWORD(queue_status) & QS_SENDMESSAGE) sent_messages_in_queue = true;
297 
298   MSG msg;
299   if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
300     return ProcessMessageHelper(msg);
301 
302   return sent_messages_in_queue;
303 }
304 
ProcessMessageHelper(const MSG & msg)305 bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
306   if (WM_QUIT == msg.message) {
307     // Repost the QUIT message so that it will be retrieved by the primary
308     // GetMessage() loop.
309     state_->should_quit = true;
310     PostQuitMessage(static_cast<int>(msg.wParam));
311     return false;
312   }
313 
314   // While running our main message pump, we discard kMsgHaveWork messages.
315   if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_)
316     return ProcessPumpReplacementMessage();
317 
318   WillProcessMessage(msg);
319 
320   if (state_->dispatcher) {
321     if (!state_->dispatcher->Dispatch(msg)) state_->should_quit = true;
322   } else {
323     TranslateMessage(&msg);
324     DispatchMessage(&msg);
325   }
326 
327   DidProcessMessage(msg);
328   return true;
329 }
330 
ProcessPumpReplacementMessage()331 bool MessagePumpForUI::ProcessPumpReplacementMessage() {
332   // When we encounter a kMsgHaveWork message, this method is called to peek
333   // and process a replacement message, such as a WM_PAINT or WM_TIMER.  The
334   // goal is to make the kMsgHaveWork as non-intrusive as possible, even though
335   // a continuous stream of such messages are posted.  This method carefully
336   // peeks a message while there is no chance for a kMsgHaveWork to be pending,
337   // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to
338   // possibly be posted), and finally dispatches that peeked replacement.  Note
339   // that the re-post of kMsgHaveWork may be asynchronous to this thread!!
340 
341   MSG msg;
342   bool have_message = false;
343   if (MessageLoop::current()->os_modal_loop()) {
344     // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
345     have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
346                    PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
347   } else {
348     have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
349 
350     if (have_message && msg.message == WM_NULL)
351       have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
352   }
353 
354   DCHECK(!have_message || kMsgHaveWork != msg.message ||
355          msg.hwnd != message_hwnd_);
356 
357   // Since we discarded a kMsgHaveWork message, we must update the flag.
358   int old_have_work = InterlockedExchange(&have_work_, 0);
359   DCHECK(old_have_work);
360 
361   // We don't need a special time slice if we didn't have_message to process.
362   if (!have_message) return false;
363 
364   // Guarantee we'll get another time slice in the case where we go into native
365   // windows code.   This ScheduleWork() may hurt performance a tiny bit when
366   // tasks appear very infrequently, but when the event queue is busy, the
367   // kMsgHaveWork events get (percentage wise) rarer and rarer.
368   ScheduleWork();
369   return ProcessMessageHelper(msg);
370 }
371 
372 //-----------------------------------------------------------------------------
373 // MessagePumpForIO public:
374 
MessagePumpForIO()375 MessagePumpForIO::MessagePumpForIO() {
376   port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1));
377   DCHECK(port_.IsValid());
378 }
379 
ScheduleWork()380 void MessagePumpForIO::ScheduleWork() {
381   if (InterlockedExchange(&have_work_, 1))
382     return;  // Someone else continued the pumping.
383 
384   // Make sure the MessagePump does some work for us.
385   BOOL ret =
386       PostQueuedCompletionStatus(port_, 0, reinterpret_cast<ULONG_PTR>(this),
387                                  reinterpret_cast<OVERLAPPED*>(this));
388   DCHECK(ret);
389 }
390 
ScheduleDelayedWork(const TimeTicks & delayed_work_time)391 void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
392   // We know that we can't be blocked right now since this method can only be
393   // called on the same thread as Run, so we only need to update our record of
394   // how long to sleep when we do sleep.
395   delayed_work_time_ = delayed_work_time;
396 }
397 
RegisterIOHandler(HANDLE file_handle,IOHandler * handler)398 void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle,
399                                          IOHandler* handler) {
400   ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler);
401   HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1);
402   DCHECK(port == port_.Get());
403 }
404 
405 //-----------------------------------------------------------------------------
406 // MessagePumpForIO private:
407 
DoRunLoop()408 void MessagePumpForIO::DoRunLoop() {
409   for (;;) {
410     // If we do any work, we may create more messages etc., and more work may
411     // possibly be waiting in another task group.  When we (for example)
412     // WaitForIOCompletion(), there is a good chance there are still more
413     // messages waiting.  On the other hand, when any of these methods return
414     // having done no work, then it is pretty unlikely that calling them
415     // again quickly will find any work to do.  Finally, if they all say they
416     // had no work, then it is a good time to consider sleeping (waiting) for
417     // more work.
418 
419     bool more_work_is_plausible = state_->delegate->DoWork();
420     if (state_->should_quit) break;
421 
422     more_work_is_plausible |= WaitForIOCompletion(0, NULL);
423     if (state_->should_quit) break;
424 
425     more_work_is_plausible |=
426         state_->delegate->DoDelayedWork(&delayed_work_time_);
427     if (state_->should_quit) break;
428 
429     if (more_work_is_plausible) continue;
430 
431     more_work_is_plausible = state_->delegate->DoIdleWork();
432     if (state_->should_quit) break;
433 
434     if (more_work_is_plausible) continue;
435 
436     WaitForWork();  // Wait (sleep) until we have work to do again.
437   }
438 }
439 
440 // Wait until IO completes, up to the time needed by the timer manager to fire
441 // the next set of timers.
WaitForWork()442 void MessagePumpForIO::WaitForWork() {
443   // We do not support nested IO message loops. This is to avoid messy
444   // recursion problems.
445   DCHECK(state_->run_depth == 1) << "Cannot nest an IO message loop!";
446 
447   int timeout = GetCurrentDelay();
448   if (timeout < 0)  // Negative value means no timers waiting.
449     timeout = INFINITE;
450 
451   WaitForIOCompletion(timeout, NULL);
452 }
453 
WaitForIOCompletion(DWORD timeout,IOHandler * filter)454 bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
455   IOItem item;
456   if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) {
457     // We have to ask the system for another IO completion.
458     if (!GetIOItem(timeout, &item)) return false;
459 
460     if (ProcessInternalIOItem(item)) return true;
461   }
462 
463   if (item.context->handler) {
464     if (filter && item.handler != filter) {
465       // Save this item for later
466       completed_io_.push_back(item);
467     } else {
468       DCHECK(item.context->handler == item.handler);
469       item.handler->OnIOCompleted(item.context, item.bytes_transfered,
470                                   item.error);
471     }
472   } else {
473     // The handler must be gone by now, just cleanup the mess.
474     delete item.context;
475   }
476   return true;
477 }
478 
479 // Asks the OS for another IO completion result.
GetIOItem(DWORD timeout,IOItem * item)480 bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) {
481   memset(item, 0, sizeof(*item));
482   ULONG_PTR key = 0;
483   OVERLAPPED* overlapped = NULL;
484   AUTO_PROFILER_LABEL("MessagePumpForIO::GetIOItem::Wait", IDLE);
485   if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key,
486                                  &overlapped, timeout)) {
487     if (!overlapped) return false;  // Nothing in the queue.
488     item->error = GetLastError();
489     item->bytes_transfered = 0;
490   }
491 
492   item->handler = reinterpret_cast<IOHandler*>(key);
493   item->context = reinterpret_cast<IOContext*>(overlapped);
494   return true;
495 }
496 
ProcessInternalIOItem(const IOItem & item)497 bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
498   if (this == reinterpret_cast<MessagePumpForIO*>(item.context) &&
499       this == reinterpret_cast<MessagePumpForIO*>(item.handler)) {
500     // This is our internal completion.
501     DCHECK(!item.bytes_transfered);
502     InterlockedExchange(&have_work_, 0);
503     return true;
504   }
505   return false;
506 }
507 
508 // Returns a completion item that was previously received.
MatchCompletedIOItem(IOHandler * filter,IOItem * item)509 bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) {
510   DCHECK(!completed_io_.empty());
511   for (std::list<IOItem>::iterator it = completed_io_.begin();
512        it != completed_io_.end(); ++it) {
513     if (!filter || it->handler == filter) {
514       *item = *it;
515       completed_io_.erase(it);
516       return true;
517     }
518   }
519   return false;
520 }
521 
522 }  // namespace base
523