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