Exemplo n.º 1
0
// Main thread via OnProcessNextEvent below
bool
nsBaseAppShell::DoProcessNextNativeEvent(bool mayWait, uint32_t recursionDepth)
{
    // The next native event to be processed may trigger our NativeEventCallback,
    // in which case we do not want it to process any thread events since we'll
    // do that when this function returns.
    //
    // If the next native event is not our NativeEventCallback, then we may end
    // up recursing into this function.
    //
    // However, if the next native event is not our NativeEventCallback, but it
    // results in another native event loop, then our NativeEventCallback could
    // fire and it will see mEventloopNestingState as eEventloopOther.
    //
    EventloopNestingState prevVal = mEventloopNestingState;
    mEventloopNestingState = eEventloopXPCOM;

    ++mEventloopNestingLevel;

    bool result = ProcessNextNativeEvent(mayWait);

    // Make sure that any sync sections registered during this most recent event
    // are run now. This is not considered a stable state because we're not back
    // to the event loop yet.
    RunSyncSections(false, recursionDepth);

    --mEventloopNestingLevel;

    mEventloopNestingState = prevVal;
    return result;
}
Exemplo n.º 2
0
// Called from the main thread
NS_IMETHODIMP
nsBaseAppShell::AfterProcessNextEvent(nsIThreadInternal *thr,
                                      uint32_t recursionDepth)
{
    // We've just finished running an event, so we're in a stable state.
    RunSyncSections(true, recursionDepth);
    return NS_OK;
}
Exemplo n.º 3
0
NS_IMETHODIMP
nsBaseAppShell::RunInStableState(nsIRunnable* aRunnable)
{
  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
  // Record the synchronous section, and run it with any others once
  // we reach a stable state.
  mSyncSections.AppendObject(aRunnable);

  // Ensure we've got a pending event, else the callbacks will never run.
  nsIThread* thread = NS_GetCurrentThread(); 
  if (!NS_HasPendingEvents(thread) &&
       NS_FAILED(thread->Dispatch(new nsRunnable(), NS_DISPATCH_NORMAL)))
  {
    // Failed to dispatch dummy event to cause sync sections to run, thread
    // is probably done processing events, just run the sync sections now.
    RunSyncSections();
  }
  return NS_OK;
}
Exemplo n.º 4
0
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);
  }
}
Exemplo n.º 5
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;
}