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