Bug 1072752 - Make Chromium UI message loops for Windows call into WinUtils::WaitForMessage. r=jimm, a=sledru
authorAaron Klotz <aklotz@mozilla.com>
Thu, 25 Sep 2014 12:39:15 -0600
changeset 216877 737fbc0e3df4
parent 216876 4020480a6741
child 216878 3ff9831143fd
push id3951
push userryanvm@gmail.com
push date2014-09-29 18:48 +0000
treeherdermozilla-beta@19338c25065c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, sledru
bugs1072752
milestone33.0
Bug 1072752 - Make Chromium UI message loops for Windows call into WinUtils::WaitForMessage. r=jimm, a=sledru
ipc/chromium/src/base/message_pump_win.cc
widget/windows/WinUtils.cpp
widget/windows/WinUtils.h
--- a/ipc/chromium/src/base/message_pump_win.cc
+++ b/ipc/chromium/src/base/message_pump_win.cc
@@ -4,16 +4,17 @@
 
 #include "base/message_pump_win.h"
 
 #include <math.h>
 
 #include "base/message_loop.h"
 #include "base/histogram.h"
 #include "base/win_util.h"
+#include "WinUtils.h"
 
 using base::Time;
 
 namespace base {
 
 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow";
 
 // Message sent to get an additional time slice for pumping (processing) another
@@ -258,41 +259,17 @@ void MessagePumpForUI::InitMessageWnd() 
 
 void MessagePumpForUI::WaitForWork() {
   // Wait until a message is available, up to the time needed by the timer
   // manager to fire the next set of timers.
   int delay = GetCurrentDelay();
   if (delay < 0)  // Negative value means no timers waiting.
     delay = INFINITE;
 
-  DWORD result;
-  result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
-                                       MWMO_INPUTAVAILABLE);
-
-  if (WAIT_OBJECT_0 == result) {
-    // A WM_* message is available.
-    // If a parent child relationship exists between windows across threads
-    // then their thread inputs are implicitly attached.
-    // This causes the MsgWaitForMultipleObjectsEx API to return indicating
-    // that messages are ready for processing (specifically mouse messages
-    // intended for the child window. Occurs if the child window has capture)
-    // The subsequent PeekMessages call fails to return any messages thus
-    // causing us to enter a tight loop at times.
-    // The WaitMessage call below is a workaround to give the child window
-    // sometime to process its input messages.
-    MSG msg = {0};
-    DWORD queue_status = GetQueueStatus(QS_MOUSE);
-    if (HIWORD(queue_status) & QS_MOUSE &&
-       !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {
-      WaitMessage();
-    }
-    return;
-  }
-
-  DCHECK_NE(WAIT_FAILED, result) << GetLastError();
+  mozilla::widget::WinUtils::WaitForMessage(delay);
 }
 
 void MessagePumpForUI::HandleWorkMessage() {
   // If we are being called outside of the context of Run, then don't try to do
   // any work.  This could correspond to a MessageBox call or something of that
   // sort.
   if (!state_) {
     // Since we handled a kMsgHaveWork message, we must still update this flag.
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -276,23 +276,34 @@ WinUtils::GetMessage(LPMSG aMsg, HWND aW
     return ret;
   }
 #endif // #ifdef NS_ENABLE_TSF
   return ::GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage);
 }
 
 /* static */
 void
-WinUtils::WaitForMessage()
+WinUtils::WaitForMessage(DWORD aTimeoutMs)
 {
+  const DWORD waitStart = ::GetTickCount();
+  DWORD elapsed = 0;
   while (true) {
-    DWORD result = ::MsgWaitForMultipleObjectsEx(0, NULL, INFINITE,
+    if (aTimeoutMs != INFINITE) {
+      elapsed = ::GetTickCount() - waitStart;
+    }
+    if (elapsed >= aTimeoutMs) {
+      break;
+    }
+    DWORD result = ::MsgWaitForMultipleObjectsEx(0, NULL, aTimeoutMs - elapsed,
                                                  MOZ_QS_ALLEVENT,
                                                  MWMO_INPUTAVAILABLE);
     NS_WARN_IF_FALSE(result != WAIT_FAILED, "Wait failed");
+    if (result == WAIT_TIMEOUT) {
+      break;
+    }
 
     // Sent messages (via SendMessage and friends) are processed differently
     // than queued messages (via PostMessage); the destination window procedure
     // of the sent message is called during (Get|Peek)Message. Since PeekMessage
     // does not tell us whether it processed any sent messages, we need to query
     // this ahead of time.
     bool haveSentMessagesPending =
       (HIWORD(::GetQueueStatus(QS_SENDMESSAGE)) & QS_SENDMESSAGE) != 0;
--- a/widget/windows/WinUtils.h
+++ b/widget/windows/WinUtils.h
@@ -141,18 +141,19 @@ public:
    * Wait until a message is ready to be processed.
    * Prefer using this method to directly calling ::WaitMessage since
    * ::WaitMessage will wait if there is an unread message in the queue.
    * That can cause freezes until another message enters the queue if the
    * message is marked read by a call to PeekMessage which the caller is
    * not aware of (e.g., from a different thread).
    * Note that this method may cause sync dispatch of sent (as opposed to
    * posted) messages.
+   * @param aTimeoutMs Timeout for waiting in ms, defaults to INFINITE
    */
-  static void WaitForMessage();
+  static void WaitForMessage(DWORD aTimeoutMs = INFINITE);
 
   /**
    * Gets the value of a string-typed registry value.
    *
    * @param aRoot The registry root to search in.
    * @param aKeyName The name of the registry key to open.
    * @param aValueName The name of the registry value in the specified key whose
    *   value is to be retrieved.  Can be null, to retrieve the key's unnamed/