Merge m-c to b2g-inbound. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 27 Jul 2015 16:06:40 -0400
changeset 286466 1b168b0cfdf07548fe413a46fc16195e478a111b
parent 286465 4768c0ddb601133f9576ebade7dca1d6fc3e264c (current diff)
parent 286455 c0a3d6f72a63016ab9969aaed1b8cf4d0043ddea (diff)
child 286467 eee282da3fa40e8a5a2c093cd659e4d88d05957d
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b2g-inbound. a=merge
ipc/glue/Neutering.h
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -848,17 +848,16 @@ MessageChannel::Send(Message* aMsg, Mess
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
 
     if (mCurrentTransaction == 0)
         mListener->OnBeginSyncTransaction();
 
 #ifdef OS_WIN
     SyncStackFrame frame(this, false);
-    NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
 #endif
 
     CxxStackFrame f(*this, OUT_MESSAGE, msg);
 
     MonitorAutoLock lock(*mMonitor);
 
     if (mTimedOutMessageSeqno) {
         // Don't bother sending another sync message if a previous one timed out
@@ -990,17 +989,16 @@ MessageChannel::Send(Message* aMsg, Mess
 bool
 MessageChannel::Call(Message* aMsg, Message* aReply)
 {
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
 
 #ifdef OS_WIN
     SyncStackFrame frame(this, true);
-    NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
 #endif
 
     // This must come before MonitorAutoLock, as its destructor acquires the
     // monitor lock.
     CxxStackFrame cxxframe(*this, OUT_MESSAGE, aMsg);
 
     MonitorAutoLock lock(*mMonitor);
     if (!Connected()) {
@@ -1029,22 +1027,16 @@ MessageChannel::Call(Message* aMsg, Mess
         // might have already processed the OnError event. if so,
         // trying another loop iteration will be futile because
         // channel state will have been cleared
         if (!Connected()) {
             ReportConnectionError("MessageChannel::Call");
             return false;
         }
 
-#ifdef OS_WIN
-        /* We should pump messages at this point to ensure that the IPC peer
-           does not become deadlocked on a pending inter-thread SendMessage() */
-        neuteredRgn.PumpOnce();
-#endif
-
         // Now might be the time to process a message deferred because of race
         // resolution.
         MaybeUndeferIncall();
 
         // Wait for an event to occur.
         while (!InterruptEventOccurred()) {
             bool maybeTimedOut = !WaitForInterruptNotify();
 
@@ -1151,17 +1143,16 @@ MessageChannel::Call(Message* aMsg, Mess
     return true;
 }
 
 bool
 MessageChannel::WaitForIncomingMessage()
 {
 #ifdef OS_WIN
     SyncStackFrame frame(this, true);
-    NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION);
 #endif
 
     { // Scope for lock
         MonitorAutoLock lock(*mMonitor);
         AutoEnterWaitForIncoming waitingForIncoming(*this);
         if (mChannelState != ChannelConnected) {
             return false;
         }
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -10,19 +10,16 @@
 
 #include "base/basictypes.h"
 #include "base/message_loop.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/Vector.h"
 #include "mozilla/WeakPtr.h"
-#if defined(OS_WIN)
-#include "mozilla/ipc/Neutering.h"
-#endif // defined(OS_WIN)
 #include "mozilla/ipc/Transport.h"
 #include "MessageLink.h"
 #include "nsAutoPtr.h"
 
 #include <deque>
 #include <stack>
 #include <math.h>
 
deleted file mode 100644
--- a/ipc/glue/Neutering.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_ipc_Neutering_h
-#define mozilla_ipc_Neutering_h
-
-#include "mozilla/GuardObjects.h"
-
-/**
- * This header declares RAII wrappers for Window neutering. See
- * WindowsMessageLoop.cpp for more details.
- */
-
-namespace mozilla {
-namespace ipc {
-
-/**
- * This class is a RAII wrapper around Window neutering. As long as a
- * NeuteredWindowRegion object is instantiated, Win32 windows belonging to the
- * current thread will be neutered. It is safe to nest multiple instances of
- * this class.
- */
-class MOZ_STACK_CLASS NeuteredWindowRegion
-{
-public:
-  explicit NeuteredWindowRegion(bool aDoNeuter MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-  ~NeuteredWindowRegion();
-
-  /**
-   * This function clears any backlog of nonqueued messages that are pending for
-   * the current thread.
-   */
-  void PumpOnce();
-
-private:
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-  bool mNeuteredByThis;
-};
-
-/**
- * This class is analagous to MutexAutoUnlock for Mutex; it is an RAII class
- * that is to be instantiated within a NeuteredWindowRegion, thus temporarily
- * disabling neutering for the remainder of its enclosing block.
- * @see NeuteredWindowRegion
- */
-class MOZ_STACK_CLASS DeneuteredWindowRegion
-{
-public:
-  DeneuteredWindowRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
-  ~DeneuteredWindowRegion();
-
-private:
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-  bool mReneuter;
-};
-
-} // namespace ipc
-} // namespace mozilla
-
-#endif // mozilla_ipc_Neutering_h
-
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -3,17 +3,16 @@
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "WindowsMessageLoop.h"
-#include "Neutering.h"
 #include "MessageChannel.h"
 
 #include "nsAutoPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsIXULAppInfo.h"
 #include "WinUtils.h"
 
@@ -858,95 +857,16 @@ MessageChannel::SpinInternalEventLoop()
 
 static inline bool
 IsTimeoutExpired(PRIntervalTime aStart, PRIntervalTime aTimeout)
 {
   return (aTimeout != PR_INTERVAL_NO_TIMEOUT) &&
     (aTimeout <= (PR_IntervalNow() - aStart));
 }
 
-static HHOOK gWindowHook;
-
-static inline void
-StartNeutering()
-{
-  MOZ_ASSERT(gUIThreadId);
-  MOZ_ASSERT(!gWindowHook);
-  NS_ASSERTION(!MessageChannel::IsPumpingMessages(),
-               "Shouldn't be pumping already!");
-  MessageChannel::SetIsPumpingMessages(true);
-  gWindowHook = ::SetWindowsHookEx(WH_CALLWNDPROC, CallWindowProcedureHook,
-                                   nullptr, gUIThreadId);
-  NS_ASSERTION(gWindowHook, "Failed to set hook!");
-}
-
-static void
-StopNeutering()
-{
-  MOZ_ASSERT(MessageChannel::IsPumpingMessages());
-  ::UnhookWindowsHookEx(gWindowHook);
-  gWindowHook = NULL;
-  ::UnhookNeuteredWindows();
-  // Before returning we need to set a hook to run any deferred messages that
-  // we received during the IPC call. The hook will unset itself as soon as
-  // someone else calls GetMessage, PeekMessage, or runs code that generates
-  // a "nonqueued" message.
-  ::ScheduleDeferredMessageRun();
-  MessageChannel::SetIsPumpingMessages(false);
-}
-
-NeuteredWindowRegion::NeuteredWindowRegion(bool aDoNeuter MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-  : mNeuteredByThis(!gWindowHook)
-{
-  MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-  if (aDoNeuter && mNeuteredByThis) {
-    StartNeutering();
-  }
-}
-
-NeuteredWindowRegion::~NeuteredWindowRegion()
-{
-  if (gWindowHook && mNeuteredByThis) {
-    StopNeutering();
-  }
-}
-
-void
-NeuteredWindowRegion::PumpOnce()
-{
-  MSG msg = {0};
-  if (gCOMWindow) {
-    // Pump any COM messages so that we don't hang due to STA marshaling.
-    // This call will also expunge any nonqueued messages on the current thread
-    if (::PeekMessageW(&msg, gCOMWindow, 0, 0, PM_REMOVE)) {
-      ::TranslateMessage(&msg);
-      ::DispatchMessageW(&msg);
-    }
-  } else {
-    // Expunge any nonqueued messages on the current thread
-    ::PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE);
-  }
-}
-
-DeneuteredWindowRegion::DeneuteredWindowRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
-  : mReneuter(gWindowHook != NULL)
-{
-  MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-  if (mReneuter) {
-    StopNeutering();
-  }
-}
-
-DeneuteredWindowRegion::~DeneuteredWindowRegion()
-{
-  if (mReneuter) {
-    StartNeutering();
-  }
-}
-
 bool
 MessageChannel::WaitForSyncNotify()
 {
   mMonitor->AssertCurrentThreadOwns();
 
   MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!");
 
   // Use a blocking wait if this channel does not require
@@ -991,16 +911,25 @@ MessageChannel::WaitForSyncNotify()
     InitTimeoutData(&timeoutData, mTimeoutMs);
 
     // We only do this to ensure that we won't get stuck in
     // MsgWaitForMultipleObjects below.
     timerId = SetTimer(nullptr, 0, mTimeoutMs, nullptr);
     NS_ASSERTION(timerId, "SetTimer failed!");
   }
 
+  // Setup deferred processing of native events while we wait for a response.
+  NS_ASSERTION(!MessageChannel::IsPumpingMessages(),
+               "Shouldn't be pumping already!");
+
+  MessageChannel::SetIsPumpingMessages(true);
+  HHOOK windowHook = SetWindowsHookEx(WH_CALLWNDPROC, CallWindowProcedureHook,
+                                      nullptr, gUIThreadId);
+  NS_ASSERTION(windowHook, "Failed to set hook!");
+
   {
     while (1) {
       MSG msg = { 0 };
       // Don't get wrapped up in here if the child connection dies.
       {
         MonitorAutoLock lock(*mMonitor);
         if (!Connected()) {
           break;
@@ -1064,21 +993,35 @@ MessageChannel::WaitForSyncNotify()
       if (!PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE) &&
           !haveSentMessagesPending) {
         // Message was for child, we should wait a bit.
         SwitchToThread();
       }
     }
   }
 
+  // Unhook the neutered window procedure hook.
+  UnhookWindowsHookEx(windowHook);
+
+  // Unhook any neutered windows procedures so messages can be delivered
+  // normally.
+  UnhookNeuteredWindows();
+
+  // Before returning we need to set a hook to run any deferred messages that
+  // we received during the IPC call. The hook will unset itself as soon as
+  // someone else calls GetMessage, PeekMessage, or runs code that generates
+  // a "nonqueued" message.
+  ScheduleDeferredMessageRun();
+
   if (timerId) {
     KillTimer(nullptr, timerId);
-    timerId = 0;
   }
 
+  MessageChannel::SetIsPumpingMessages(false);
+
   return WaitResponse(timedout);
 }
 
 bool
 MessageChannel::WaitForInterruptNotify()
 {
   mMonitor->AssertCurrentThreadOwns();
 
@@ -1102,38 +1045,66 @@ MessageChannel::WaitForInterruptNotify()
 
   MonitorAutoUnlock unlock(*mMonitor);
 
   bool timedout = false;
 
   UINT_PTR timerId = 0;
   TimeoutData timeoutData = { 0 };
 
-  // gWindowHook is used as a flag variable for the loop below: if it is set
+  // windowHook is used as a flag variable for the loop below: if it is set
   // and we start to spin a nested event loop, we need to clear the hook and
   // process deferred/pending messages.
+  // If windowHook is nullptr, MessageChannel::IsPumpingMessages should be false.
+  HHOOK windowHook = nullptr;
+
   while (1) {
-    NS_ASSERTION((!!gWindowHook) == MessageChannel::IsPumpingMessages(),
-                 "gWindowHook out of sync with reality");
+    NS_ASSERTION((!!windowHook) == MessageChannel::IsPumpingMessages(),
+                 "windowHook out of sync with reality");
 
     if (mTopFrame->mSpinNestedEvents) {
-      if (gWindowHook && timerId) {
-        KillTimer(nullptr, timerId);
-        timerId = 0;
+      if (windowHook) {
+        UnhookWindowsHookEx(windowHook);
+        windowHook = nullptr;
+
+        if (timerId) {
+          KillTimer(nullptr, timerId);
+          timerId = 0;
+        }
+
+        // Used by widget to assert on incoming native events
+        MessageChannel::SetIsPumpingMessages(false);
+
+        // Unhook any neutered windows procedures so messages can be delievered
+        // normally.
+        UnhookNeuteredWindows();
+
+        // Send all deferred "nonqueued" message to the intended receiver.
+        // We're dropping into SpinInternalEventLoop so we should be fairly
+        // certain these will get delivered soohn.
+        ScheduleDeferredMessageRun();
       }
-      DeneuteredWindowRegion deneuteredRgn;
       SpinInternalEventLoop();
       ResetEvent(mEvent);
       return true;
     }
 
-    if (mTimeoutMs != kNoTimeout && !timerId) {
-      InitTimeoutData(&timeoutData, mTimeoutMs);
-      timerId = SetTimer(nullptr, 0, mTimeoutMs, nullptr);
-      NS_ASSERTION(timerId, "SetTimer failed!");
+    if (!windowHook) {
+      MessageChannel::SetIsPumpingMessages(true);
+      windowHook = SetWindowsHookEx(WH_CALLWNDPROC, CallWindowProcedureHook,
+                                    nullptr, gUIThreadId);
+      NS_ASSERTION(windowHook, "Failed to set hook!");
+
+      NS_ASSERTION(!timerId, "Timer already initialized?");
+
+      if (mTimeoutMs != kNoTimeout) {
+        InitTimeoutData(&timeoutData, mTimeoutMs);
+        timerId = SetTimer(nullptr, 0, mTimeoutMs, nullptr);
+        NS_ASSERTION(timerId, "SetTimer failed!");
+      }
     }
 
     MSG msg = { 0 };
 
     // Don't get wrapped up in here if the child connection dies.
     {
       MonitorAutoLock lock(*mMonitor);
       if (!Connected()) {
@@ -1175,21 +1146,37 @@ MessageChannel::WaitForInterruptNotify()
     // MsgWaitForMultipleObjects every time.
     if (!PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE) &&
         !haveSentMessagesPending) {
       // Message was for child, we should wait a bit.
       SwitchToThread();
     }
   }
 
-  if (timerId) {
-    KillTimer(nullptr, timerId);
-    timerId = 0;
+  if (windowHook) {
+    // Unhook the neutered window procedure hook.
+    UnhookWindowsHookEx(windowHook);
+
+    // Unhook any neutered windows procedures so messages can be delivered
+    // normally.
+    UnhookNeuteredWindows();
+
+    // Before returning we need to set a hook to run any deferred messages that
+    // we received during the IPC call. The hook will unset itself as soon as
+    // someone else calls GetMessage, PeekMessage, or runs code that generates
+    // a "nonqueued" message.
+    ScheduleDeferredMessageRun();
+
+    if (timerId) {
+      KillTimer(nullptr, timerId);
+    }
   }
 
+  MessageChannel::SetIsPumpingMessages(false);
+
   return WaitResponse(timedout);
 }
 
 void
 MessageChannel::NotifyWorkerThread()
 {
   mMonitor->AssertCurrentThreadOwns();
 
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -20,17 +20,16 @@ EXPORTS.mozilla.ipc += [
     'FileDescriptorSetChild.h',
     'FileDescriptorSetParent.h',
     'FileDescriptorUtils.h',
     'GeckoChildProcessHost.h',
     'InputStreamUtils.h',
     'IOThreadChild.h',
     'MessageChannel.h',
     'MessageLink.h',
-    'Neutering.h',
     'ProcessChild.h',
     'ProtocolUtils.h',
     'ScopedXREEmbed.h',
     'SharedMemory.h',
     'SharedMemoryBasic.h',
     'SharedMemorySysV.h',
     'Shmem.h',
     'Transport.h',