Bug 1044245 - Don't track Windows IPC stack frames on non-gui threads. r=bsmedberg, a=sledru
authorJim Mathies <jmathies@mozilla.com>
Thu, 07 Aug 2014 22:21:05 -0400
changeset 217447 e8ba5bca8c4ca59413790f575ef0c4baa504c582
parent 217446 bef1ccd4c38d6be2c54fbddae5deb3cc18f7545a
child 217448 6d461156b9450b051bc99923accae87baad6e3c5
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg, sledru
bugs1044245
milestone33.0a2
Bug 1044245 - Don't track Windows IPC stack frames on non-gui threads. r=bsmedberg, a=sledru
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!");