ipc/chromium/src/base/message_pump_win.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial