Bug 937306 - Improvements to WinUtils::WaitForMessage. r=jimm, a=sylvestre
authorAaron Klotz <aklotz@mozilla.com>
Sun, 14 Sep 2014 16:15:52 -0600
changeset 216759 60aecc9d11ab
parent 216758 abf1c1e6b222
child 216760 cea1db6ec4ac
push id3904
push userryanvm@gmail.com
push date2014-09-16 12:09 +0000
treeherdermozilla-beta@cea1db6ec4ac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, sylvestre
bugs937306
milestone33.0
Bug 937306 - Improvements to WinUtils::WaitForMessage. r=jimm, a=sylvestre
widget/windows/WinUtils.cpp
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -278,31 +278,40 @@ WinUtils::GetMessage(LPMSG aMsg, HWND aW
 #endif // #ifdef NS_ENABLE_TSF
   return ::GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage);
 }
 
 /* static */
 void
 WinUtils::WaitForMessage()
 {
-  DWORD result = ::MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT,
-                                               MWMO_INPUTAVAILABLE);
-  NS_WARN_IF_FALSE(result != WAIT_FAILED, "Wait failed");
+  while (true) {
+    DWORD result = ::MsgWaitForMultipleObjectsEx(0, NULL, INFINITE,
+                                                 MOZ_QS_ALLEVENT,
+                                                 MWMO_INPUTAVAILABLE);
+    NS_WARN_IF_FALSE(result != WAIT_FAILED, "Wait failed");
 
-  // This idiom is taken from the Chromium ipc code, see
-  // ipc/chromium/src/base/message+puimp_win.cpp:270.
-  // The intent is to avoid a busy wait when MsgWaitForMultipleObjectsEx
-  // returns quickly but PeekMessage would not return a message.
-  if (result == WAIT_OBJECT_0) {
+    // 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;
+
     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();
+    if (haveSentMessagesPending ||
+        ::PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE)) {
+      break;
     }
+    // The message is intended for another thread that has been synchronized
+    // with our input queue; yield to give other threads an opportunity to
+    // process the message. This should prevent busy waiting if resumed due
+    // to another thread's message.
+    ::SwitchToThread();
   }
 }
 
 /* static */
 bool
 WinUtils::GetRegistryKey(HKEY aRoot,
                          char16ptr_t aKeyName,
                          char16ptr_t aValueName,