Bug 606052: Nested event consumption by nsAppShell::ProcessGeckoEvents breaks processNextEvent semantics. r=smichaud, a=josh
authorAndrew Sutherland <bugmail@asutherland.org>
Mon, 25 Oct 2010 16:34:13 -0700
changeset 56471 6678fab3e784bbc1bda27f9b34a800c77397d4ad
parent 56470 b3e46c883256a95b716a3558f0d08abd5909aaa8
child 56472 9c6f0e66f38517de23f2aa84de67a9db40f8879e
push id16566
push userdtownsend@mozilla.com
push dateMon, 25 Oct 2010 23:38:16 +0000
treeherdermozilla-central@9c6f0e66f385 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmichaud, josh
bugs606052
milestone2.0b8pre
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 606052: Nested event consumption by nsAppShell::ProcessGeckoEvents breaks processNextEvent semantics. r=smichaud, a=josh
widget/src/xpwidgets/nsBaseAppShell.cpp
widget/src/xpwidgets/nsBaseAppShell.h
--- a/widget/src/xpwidgets/nsBaseAppShell.cpp
+++ b/widget/src/xpwidgets/nsBaseAppShell.cpp
@@ -124,16 +124,17 @@ nsBaseAppShell::NativeEventCallback()
     // appshell - instead, we want to get back to the nested native event
     // loop ASAP (bug 420148).
     mBlockNativeEvent = PR_TRUE;
   }
 
   ++mEventloopNestingLevel;
   EventloopNestingState prevVal = mEventloopNestingState;
   NS_ProcessPendingEvents(thread, THREAD_EVENT_STARVATION_LIMIT);
+  mProcessedGeckoEvents = PR_TRUE;
   mEventloopNestingState = prevVal;
   mBlockNativeEvent = prevBlockNativeEvent;
 
   // Continue processing pending events later (we don't want to starve the
   // embedders event loop).
   if (NS_HasPendingEvents(thread))
     OnDispatchedEvent(nsnull);
 
@@ -284,16 +285,19 @@ nsBaseAppShell::OnProcessNextEvent(nsITh
 
   PRBool *oldBlockedWait = mBlockedWait;
   mBlockedWait = &mayWait;
 
   // When mayWait is true, we need to make sure that there is an event in the
   // thread's event queue before we return.  Otherwise, the thread will block
   // on its event queue waiting for an event.
   PRBool needEvent = mayWait;
+  // Reset prior to invoking DoProcessNextNativeEvent which might cause
+  // NativeEventCallback to process gecko events.
+  mProcessedGeckoEvents = PR_FALSE;
 
   if (mFavorPerf <= 0 && start > mSwitchTime + mStarvationDelay) {
     // Favor pending native events
     PRIntervalTime now = start;
     PRBool keepGoing;
     do {
       mLastNativeEventTime = now;
       keepGoing = DoProcessNextNativeEvent(PR_FALSE);
@@ -301,17 +305,17 @@ nsBaseAppShell::OnProcessNextEvent(nsITh
   } else {
     // Avoid starving native events completely when in performance mode
     if (start - mLastNativeEventTime > limit) {
       mLastNativeEventTime = start;
       DoProcessNextNativeEvent(PR_FALSE);
     }
   }
 
-  while (!NS_HasPendingEvents(thr)) {
+  while (!NS_HasPendingEvents(thr) && !mProcessedGeckoEvents) {
     // If we have been asked to exit from Run, then we should not wait for
     // events to process.  Note that an inner nested event loop causes
     // 'mayWait' to become false too, through 'mBlockedWait'.
     if (mExiting)
       mayWait = PR_FALSE;
 
     mLastNativeEventTime = PR_IntervalNow();
     if (!DoProcessNextNativeEvent(mayWait) || !mayWait)
--- a/widget/src/xpwidgets/nsBaseAppShell.h
+++ b/widget/src/xpwidgets/nsBaseAppShell.h
@@ -133,11 +133,27 @@ private:
    * It is set to PR_TRUE while a nested native event loop (eEventloopOther)
    * is processing gecko events in NativeEventCallback(), thus queuing up
    * native events until we return to that loop (bug 420148).
    * We force mBlockNativeEvent to PR_FALSE in case handling one of the gecko
    * events spins up a nested XPCOM event loop (eg. modal window) which would
    * otherwise lead to a "deadlock" where native events aren't processed at all.
    */
   PRPackedBool mBlockNativeEvent;
+  /**
+   * Tracks whether we have processed any gecko events in NativeEventCallback so
+   * that we can avoid erroneously entering a blocking loop waiting for gecko
+   * events to show up during OnProcessNextEvent.  This is required because on
+   * OS X ProcessGeckoEvents may be invoked inside the context of 
+   * ProcessNextNativeEvent and may result in NativeEventCallback being invoked
+   * and in turn invoking NS_ProcessPendingEvents.  Because
+   * ProcessNextNativeEvent may be invoked prior to the NS_HasPendingEvents
+   * waiting loop, this is the only way to make the loop aware that events may
+   * have been processed.
+   *
+   * This variable is set to PR_FALSE in OnProcessNextEvent prior to the first
+   * call to DoProcessNextNativeEvent.  It is set to PR_TRUE by
+   * NativeEventCallback after calling NS_ProcessPendingEvents.
+   */
+  PRPackedBool mProcessedGeckoEvents;
 };
 
 #endif // nsBaseAppShell_h__