Home | History | Annotate | Download | only in base
      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 
     12 using base::Time;
     13 
     14 namespace base {
     15 
     16 static 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).
     20 static const int kMsgHaveWork = WM_USER + 1;
     21 
     22 //-----------------------------------------------------------------------------
     23 // MessagePumpWin public:
     24 
     25 void MessagePumpWin::AddObserver(Observer* observer) {
     26   observers_.AddObserver(observer);
     27 }
     28 
     29 void MessagePumpWin::RemoveObserver(Observer* observer) {
     30   observers_.RemoveObserver(observer);
     31 }
     32 
     33 void MessagePumpWin::WillProcessMessage(const MSG& msg) {
     34   FOR_EACH_OBSERVER(Observer, observers_, WillProcessMessage(msg));
     35 }
     36 
     37 void MessagePumpWin::DidProcessMessage(const MSG& msg) {
     38   FOR_EACH_OBSERVER(Observer, observers_, DidProcessMessage(msg));
     39 }
     40 
     41 void 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 
     57 void MessagePumpWin::Quit() {
     58   DCHECK(state_);
     59   state_->should_quit = true;
     60 }
     61 
     62 //-----------------------------------------------------------------------------
     63 // MessagePumpWin protected:
     64 
     65 int 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 
     85 MessagePumpForUI::MessagePumpForUI() {
     86   InitMessageWnd();
     87 }
     88 
     89 MessagePumpForUI::~MessagePumpForUI() {
     90   DestroyWindow(message_hwnd_);
     91   UnregisterClass(kWndClass, GetModuleHandle(NULL));
     92 }
     93 
     94 void 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 
    102 void 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 
    135 void 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
    169 LRESULT 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 
    182 void 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 
    238 void 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 
    253 void 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 
    287 void 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 
    308 void 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 
    324 bool 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 
    341 bool 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 
    371 bool 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 
    405 MessagePumpForIO::MessagePumpForIO() {
    406   port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1));
    407   DCHECK(port_.IsValid());
    408 }
    409 
    410 void 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 
    421 void 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 
    428 void 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 
    438 void 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.
    478 void 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 
    490 bool 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.
    518 bool 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 
    535 bool 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.
    547 bool 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