Bug 1044245: don't track Windows IPC stack frames on non-gui threads r=bsmedberg
authorJim Mathies <jmathies@mozilla.com>
Thu, 07 Aug 2014 22:21:05 -0400
changeset 220098 5a9241e29c61509b85c9e39271a601e5379f8bb9
parent 220097 d1865a8e16d3c27c672498837d9ef369812cfa3c
child 220099 f478a95ef92d27bb4f05eee3ad92483fecd51ffb
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs1044245
milestone34.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
Bug 1044245: don't track Windows IPC stack frames on non-gui threads r=bsmedberg
ipc/glue/WindowsMessageLoop.cpp
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -637,28 +637,37 @@ InitUIThread()
 MessageChannel::SyncStackFrame::SyncStackFrame(MessageChannel* channel, bool interrupt)
   : mInterrupt(interrupt)
   , mSpinNestedEvents(false)
   , mListenerNotified(false)
   , mChannel(channel)
   , mPrev(mChannel->mTopFrame)
   , mStaticPrev(sStaticTopFrame)
 {
+  // Only track stack frames when we are on the gui thread.
+  if (GetCurrentThreadId() != gUIThreadId) {
+    return;
+  }
+
   mChannel->mTopFrame = this;
   sStaticTopFrame = this;
 
   if (!mStaticPrev) {
     NS_ASSERTION(!gNeuteredWindows, "Should only set this once!");
     gNeuteredWindows = new nsAutoTArray<HWND, 20>();
     NS_ASSERTION(gNeuteredWindows, "Out of memory!");
   }
 }
 
 MessageChannel::SyncStackFrame::~SyncStackFrame()
 {
+  if (GetCurrentThreadId() != gUIThreadId) {
+    return;
+  }
+
   NS_ASSERTION(this == mChannel->mTopFrame,
                "Mismatched interrupt stack frames");
   NS_ASSERTION(this == sStaticTopFrame,
                "Mismatched static Interrupt stack frames");
 
   mChannel->mTopFrame = mPrev;
   sStaticTopFrame = mStaticPrev;
 
@@ -687,16 +696,18 @@ MessageChannel::NotifyGeckoEventDispatch
   channel->Listener()->ProcessRemoteNativeEventsInInterruptCall();
 }
 
 // invoked by the module that receives the spin event loop
 // message.
 void
 MessageChannel::ProcessNativeEventsInInterruptCall()
 {
+  NS_ASSERTION(GetCurrentThreadId() == gUIThreadId,
+               "Shouldn't be on a non-main thread in here!");
   if (!mTopFrame) {
     NS_ERROR("Spin logic error: no Interrupt frame");
     return;
   }
 
   mTopFrame->mSpinNestedEvents = true;
 }
 
@@ -770,16 +781,20 @@ IsTimeoutExpired(PRIntervalTime aStart, 
 
 bool
 MessageChannel::WaitForSyncNotify()
 {
   mMonitor->AssertCurrentThreadOwns();
 
   MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!");
 
+  // We jump through a lot of unique hoops in dealing with Windows message
+  // trapping to prevent re-entrancy when we are blocked waiting on a sync
+  // reply or new rpc in-call. However none of this overhead is needed when
+  // we aren't on the main (gui) thread. 
   if (GetCurrentThreadId() != gUIThreadId) {
     PRIntervalTime timeout = (kNoTimeout == mTimeoutMs) ?
                              PR_INTERVAL_NO_TIMEOUT :
                              PR_MillisecondsToInterval(mTimeoutMs);
     PRIntervalTime waitStart = 0;
 
     if (timeout != PR_INTERVAL_NO_TIMEOUT) {
       waitStart = PR_IntervalNow();
@@ -790,19 +805,23 @@ MessageChannel::WaitForSyncNotify()
 
     mMonitor->Wait(timeout);
 
     MOZ_ASSERT(mIsSyncWaitingOnNonMainThread);
     mIsSyncWaitingOnNonMainThread = false;
 
     // If the timeout didn't expire, we know we received an event. The
     // converse is not true.
-    return WaitResponse(timeout == PR_INTERVAL_NO_TIMEOUT ? false : IsTimeoutExpired(waitStart, timeout));
+    return WaitResponse(timeout == PR_INTERVAL_NO_TIMEOUT ?
+                        false : IsTimeoutExpired(waitStart, timeout));
   }
 
+  NS_ASSERTION(GetCurrentThreadId() == gUIThreadId,
+               "Shouldn't be on a non-main thread in here!");
+
   NS_ASSERTION(mTopFrame && !mTopFrame->mInterrupt,
                "Top frame is not a sync frame!");
 
   MonitorAutoUnlock unlock(*mMonitor);
 
   bool timedout = false;
 
   UINT_PTR timerId = 0;
@@ -914,20 +933,26 @@ MessageChannel::WaitForSyncNotify()
 
 bool
 MessageChannel::WaitForInterruptNotify()
 {
   mMonitor->AssertCurrentThreadOwns();
 
   MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!");
 
+  // Re-use sync notification wait code when we aren't on the
+  // gui thread, which bypasses the gui thread hoops we jump
+  // through in dealing with Windows messaging.
   if (GetCurrentThreadId() != gUIThreadId) {
     return WaitForSyncNotify();
   }
 
+  NS_ASSERTION(GetCurrentThreadId() == gUIThreadId,
+               "Shouldn't be on a non-main thread in here!");
+
   if (!InterruptStackDepth()) {
     // There is currently no way to recover from this condition.
     NS_RUNTIMEABORT("StackDepth() is 0 in call to MessageChannel::WaitForNotify!");
   }
 
   NS_ASSERTION(mTopFrame && mTopFrame->mInterrupt,
                "Top frame is not a sync frame!");