void
nsBaseAppShell::ScheduleSyncSection(already_AddRefed<nsIRunnable> aRunnable,
                                    bool aStable)
{
  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");

  nsIThread* thread = NS_GetCurrentThread();

  // Add this runnable to our list of synchronous sections.
  SyncSection* section = mSyncSections.AppendElement();
  section->mStable = aStable;
  section->mRunnable = aRunnable;

  // If aStable is false then this synchronous section is supposed to run before
  // the next event at the current nesting level. Record the event loop nesting
  // level and the thread recursion level so that the synchronous section will
  // run at the proper time.
  if (!aStable) {
    section->mEventloopNestingLevel = mEventloopNestingLevel;

    nsCOMPtr<nsIThreadInternal> threadInternal = do_QueryInterface(thread);
    NS_ASSERTION(threadInternal, "This should never fail!");

    uint32_t recursionLevel;
    if (NS_FAILED(threadInternal->GetRecursionDepth(&recursionLevel))) {
      NS_ERROR("This should never fail!");
    }

    // Due to the weird way that the thread recursion counter is implemented we
    // subtract one from the recursion level if we have one.
    section->mThreadRecursionLevel = recursionLevel ? recursionLevel - 1 : 0;
  }

  // Ensure we've got a pending event, else the callbacks will never run.
  if (!NS_HasPendingEvents(thread) && !DispatchDummyEvent(thread)) {
    RunSyncSections(true, 0);
  }
}
// Called from the main thread
NS_IMETHODIMP
nsBaseAppShell::OnProcessNextEvent(nsIThreadInternal *thr, bool mayWait,
                                   uint32_t recursionDepth)
{
    if (mBlockNativeEvent) {
        if (!mayWait)
            return NS_OK;
        // Hmm, we're in a nested native event loop and would like to get
        // back to it ASAP, but it seems a gecko event has caused us to
        // spin up a nested XPCOM event loop (eg. modal window), so we
        // really must start processing native events here again.
        mBlockNativeEvent = false;
        if (NS_HasPendingEvents(thr))
            OnDispatchedEvent(thr); // in case we blocked it earlier
    }

    PRIntervalTime start = PR_IntervalNow();
    PRIntervalTime limit = THREAD_EVENT_STARVATION_LIMIT;

    // Unblock outer nested wait loop (below).
    if (mBlockedWait)
        *mBlockedWait = false;

    bool *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.
    bool needEvent = mayWait;
    // Reset prior to invoking DoProcessNextNativeEvent which might cause
    // NativeEventCallback to process gecko events.
    mProcessedGeckoEvents = false;

    if (mFavorPerf <= 0 && start > mSwitchTime + mStarvationDelay) {
        // Favor pending native events
        PRIntervalTime now = start;
        bool keepGoing;
        do {
            mLastNativeEventTime = now;
            keepGoing = DoProcessNextNativeEvent(false, recursionDepth);
        } while (keepGoing && ((now = PR_IntervalNow()) - start) < limit);
    } else {
        // Avoid starving native events completely when in performance mode
        if (start - mLastNativeEventTime > limit) {
            mLastNativeEventTime = start;
            DoProcessNextNativeEvent(false, recursionDepth);
        }
    }

    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 = false;

        mLastNativeEventTime = PR_IntervalNow();
        if (!DoProcessNextNativeEvent(mayWait, recursionDepth) || !mayWait)
            break;
    }

    mBlockedWait = oldBlockedWait;

    // Make sure that the thread event queue does not block on its monitor, as
    // it normally would do if it did not have any pending events.  To avoid
    // that, we simply insert a dummy event into its queue during shutdown.
    if (needEvent && !mExiting && !NS_HasPendingEvents(thr)) {
        DispatchDummyEvent(thr);
    }

    // We're about to run an event, so we're in a stable state.
    RunSyncSections(true, recursionDepth);

    return NS_OK;
}