Commit 6b5b9dcb authored by Robert O'Callahan's avatar Robert O'Callahan
Browse files

Bug 1236789. Avoid creating an unnecessary thread pool thread for...

Bug 1236789. Avoid creating an unnecessary thread pool thread for tail-dispatch in TaskQueue. r=bholley

MozReview-Commit-ID: H1rhQPBU00L

--HG--
extra : rebase_source : beb861cec3c9587bfe466b6fd34abaa95abd9865
parent 2bee0a75
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -55,6 +55,11 @@ public:
  // Forward behaviour to wrapped thread pool implementation.
  NS_FORWARD_SAFE_NSITHREADPOOL(mPool);

  // Call this when dispatching from an event on the same
  // threadpool that is about to complete. We should not create a new thread
  // in that case since a thread is about to become idle.
  nsresult TailDispatch(nsIRunnable *event) { return Dispatch(event, NS_DISPATCH_TAIL); }

  NS_IMETHOD DispatchFromScript(nsIRunnable *event, uint32_t flags) override {
      return Dispatch(event, flags);
  }
+1 −1
Original line number Diff line number Diff line
@@ -193,7 +193,7 @@ TaskQueue::Runner::Run()
  // run in a loop here so that we don't hog the thread pool. This means we may
  // run on another thread next time, but we rely on the memory fences from
  // mQueueMonitor for thread safety of non-threadsafe tasks.
  nsresult rv = mQueue->mPool->Dispatch(this, NS_DISPATCH_NORMAL);
  nsresult rv = mQueue->mPool->TailDispatch(this);
  if (NS_FAILED(rv)) {
    // Failed to dispatch, shutdown!
    MonitorAutoLock mon(mQueue->mQueueMonitor);
+13 −0
Original line number Diff line number Diff line
@@ -40,6 +40,18 @@ interface nsIEventTarget : nsISupports
   */
  const unsigned long DISPATCH_SYNC = 1;

  /**
   * This flag specifies that the dispatch is occurring from a running event
   * that was dispatched to the same event target, and that event is about to
   * finish.
   *
   * A thread pool can use this as an optimization hint to not spin up
   * another thread, since the current thread is about to become idle.
   *
   * These events are always async.
   */
  const unsigned long DISPATCH_TAIL = 2;

  /**
   * Check to see if this event target is associated with the current thread.
   *
@@ -91,4 +103,5 @@ interface nsIEventTarget : nsISupports
// convenient aliases:
#define NS_DISPATCH_NORMAL nsIEventTarget::DISPATCH_NORMAL
#define NS_DISPATCH_SYNC   nsIEventTarget::DISPATCH_SYNC
#define NS_DISPATCH_TAIL   nsIEventTarget::DISPATCH_TAIL
%}
+4 −3
Original line number Diff line number Diff line
@@ -64,11 +64,11 @@ nsresult
nsThreadPool::PutEvent(nsIRunnable* aEvent)
{
  nsCOMPtr<nsIRunnable> event(aEvent);
  return PutEvent(event.forget());
  return PutEvent(event.forget(), 0);
}

nsresult
nsThreadPool::PutEvent(already_AddRefed<nsIRunnable>&& aEvent)
nsThreadPool::PutEvent(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
{
  // Avoid spawning a new thread while holding the event queue lock...

@@ -86,6 +86,7 @@ nsThreadPool::PutEvent(already_AddRefed<nsIRunnable>&& aEvent)

    // Make sure we have a thread to service this event.
    if (mThreads.Count() < (int32_t)mThreadLimit &&
        !(aFlags & NS_DISPATCH_TAIL) &&
        // Spawn a new thread if we don't have enough idle threads to serve
        // pending events immediately.
        mEvents.Count(lock) >= mIdleCount) {
@@ -272,7 +273,7 @@ nsThreadPool::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
    }
  } else {
    NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
    PutEvent(Move(aEvent));
    PutEvent(Move(aEvent), aFlags);
  }
  return NS_OK;
}
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ private:

  void ShutdownThread(nsIThread* aThread);
  nsresult PutEvent(nsIRunnable* aEvent);
  nsresult PutEvent(already_AddRefed<nsIRunnable>&& aEvent);
  nsresult PutEvent(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags);

  nsCOMArray<nsIThread> mThreads;
  mozilla::Mutex        mMutex;