Ejemplo n.º 1
0
void
LazyIdleThread::ScheduleTimer()
{
  ASSERT_OWNING_THREAD();

  bool shouldSchedule;
  {
    MutexAutoLock lock(mMutex);

    MOZ_ASSERT(mIdleNotificationCount, "Should have at least one!");
    --mIdleNotificationCount;

    shouldSchedule = !mIdleNotificationCount && !mPendingEventCount;
  }

  if (NS_FAILED(mIdleTimer->Cancel())) {
    NS_WARNING("Failed to cancel timer!");
  }

  if (shouldSchedule &&
      NS_FAILED(mIdleTimer->InitWithCallback(this, mIdleTimeoutMS,
                                             nsITimer::TYPE_ONE_SHOT))) {
    NS_WARNING("Failed to schedule timer!");
  }
}
Ejemplo n.º 2
0
NS_IMETHODIMP
LazyIdleThread::Dispatch(already_AddRefed<nsIRunnable> aEvent,
                         uint32_t aFlags)
{
  ASSERT_OWNING_THREAD();
  nsCOMPtr<nsIRunnable> event(aEvent); // avoid leaks

  // LazyIdleThread can't always support synchronous dispatch currently.
  if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
    return NS_ERROR_NOT_IMPLEMENTED;
  }

  if (NS_WARN_IF(mShutdown)) {
    return NS_ERROR_UNEXPECTED;
  }

  // If our thread is shutting down then we can't actually dispatch right now.
  // Queue this runnable for later.
  if (UseRunnableQueue()) {
    mQueuedRunnables->AppendElement(event);
    return NS_OK;
  }

  nsresult rv = EnsureThread();
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  PreDispatch();

  return mThread->Dispatch(event.forget(), aFlags);
}
Ejemplo n.º 3
0
NS_IMETHODIMP
LazyIdleThread::Dispatch(nsIRunnable* aEvent,
                         uint32_t aFlags)
{
    ASSERT_OWNING_THREAD();

    // LazyIdleThread can't always support synchronous dispatch currently.
    if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL))
        return NS_ERROR_NOT_IMPLEMENTED;

    // If our thread is shutting down then we can't actually dispatch right now.
    // Queue this runnable for later.
    if (UseRunnableQueue()) {
        mQueuedRunnables->AppendElement(aEvent);
        return NS_OK;
    }

    nsresult rv = EnsureThread();
    if (NS_WARN_IF(NS_FAILED(rv)))
        return rv;

    PreDispatch();

    return mThread->Dispatch(aEvent, aFlags);
}
Ejemplo n.º 4
0
nsresult
LazyIdleThread::EnsureThread()
{
  ASSERT_OWNING_THREAD();

  if (mShutdown) {
    return NS_ERROR_UNEXPECTED;
  }

  if (mThread) {
    return NS_OK;
  }

  MOZ_ASSERT(!mPendingEventCount, "Shouldn't have events yet!");
  MOZ_ASSERT(!mIdleNotificationCount, "Shouldn't have idle events yet!");
  MOZ_ASSERT(!mIdleTimer, "Should have killed this long ago!");
  MOZ_ASSERT(!mThreadIsShuttingDown, "Should have cleared that!");

  nsresult rv;

  if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) {
    nsCOMPtr<nsIObserverService> obs =
      do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }

    rv = obs->AddObserver(this, "xpcom-shutdown-threads", false);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
  }

  mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
  if (NS_WARN_IF(!mIdleTimer)) {
    return NS_ERROR_UNEXPECTED;
  }

  nsCOMPtr<nsIRunnable> runnable =
    NewRunnableMethod(this, &LazyIdleThread::InitThread);
  if (NS_WARN_IF(!runnable)) {
    return NS_ERROR_UNEXPECTED;
  }

  rv = NS_NewThread(getter_AddRefs(mThread), runnable);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }

  return NS_OK;
}
Ejemplo n.º 5
0
NS_IMETHODIMP
LazyIdleThread::Shutdown()
{
  ASSERT_OWNING_THREAD();

  mShutdown = true;

  nsresult rv = ShutdownThread();
  MOZ_ASSERT(!mThread, "Should have destroyed this by now!");

  mIdleObserver = nullptr;

  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}
Ejemplo n.º 6
0
NS_IMETHODIMP
LazyIdleThread::Shutdown()
{
    ASSERT_OWNING_THREAD();

    mShutdown = true;

    nsresult rv = ShutdownThread();
    MOZ_ASSERT(!mThread, "Should have destroyed this by now!");

    mIdleObserver = nullptr;

    if (NS_WARN_IF(NS_FAILED(rv)))
        return rv;

    return NS_OK;
}
Ejemplo n.º 7
0
void
LazyIdleThread::DisableIdleTimeout()
{
  ASSERT_OWNING_THREAD();
  if (!mIdleTimeoutEnabled) {
    return;
  }
  mIdleTimeoutEnabled = false;

  if (mIdleTimer && NS_FAILED(mIdleTimer->Cancel())) {
    NS_WARNING("Failed to cancel timer!");
  }

  MutexAutoLock lock(mMutex);

  // Pretend we have a pending event to keep the idle timer from firing.
  MOZ_ASSERT(mPendingEventCount < UINT32_MAX, "Way too many!");
  mPendingEventCount++;
}
Ejemplo n.º 8
0
NS_IMETHODIMP
LazyIdleThread::Notify(nsITimer* aTimer)
{
  ASSERT_OWNING_THREAD();

  {
    MutexAutoLock lock(mMutex);

    if (mPendingEventCount || mIdleNotificationCount) {
      // Another event was scheduled since this timer was set. Don't do
      // anything and wait for the timer to fire again.
      return NS_OK;
    }
  }

  nsresult rv = ShutdownThread();
  NS_ENSURE_SUCCESS(rv, rv);

  return NS_OK;
}
Ejemplo n.º 9
0
void
LazyIdleThread::EnableIdleTimeout()
{
  ASSERT_OWNING_THREAD();
  if (mIdleTimeoutEnabled) {
    return;
  }
  mIdleTimeoutEnabled = true;

  {
    MutexAutoLock lock(mMutex);

    MOZ_ASSERT(mPendingEventCount, "Mismatched calls to observer methods!");
    --mPendingEventCount;
  }

  if (mThread) {
    nsCOMPtr<nsIRunnable> runnable(new nsRunnable());
    if (NS_FAILED(Dispatch(runnable, NS_DISPATCH_NORMAL))) {
      NS_WARNING("Failed to dispatch!");
    }
  }
}
Ejemplo n.º 10
0
nsresult
LazyIdleThread::ShutdownThread()
{
  ASSERT_OWNING_THREAD();

  // Before calling Shutdown() on the real thread we need to put a queue in
  // place in case a runnable is posted to the thread while it's in the
  // process of shutting down. This will be our queue.
  nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queuedRunnables;

  nsresult rv;

  if (mThread) {
    if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) {
      nsCOMPtr<nsIObserverService> obs =
        mozilla::services::GetObserverService();
      NS_WARN_IF_FALSE(obs, "Failed to get observer service!");

      if (obs &&
          NS_FAILED(obs->RemoveObserver(this, "xpcom-shutdown-threads"))) {
        NS_WARNING("Failed to remove observer!");
      }
    }

    if (mIdleObserver) {
      mIdleObserver->Observe(static_cast<nsIThread*>(this), IDLE_THREAD_TOPIC,
                             nullptr);
    }

#ifdef DEBUG
    {
      MutexAutoLock lock(mMutex);
      MOZ_ASSERT(!mThreadIsShuttingDown, "Huh?!");
    }
#endif

    nsCOMPtr<nsIRunnable> runnable =
      NS_NewRunnableMethod(this, &LazyIdleThread::CleanupThread);
    NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE);

    PreDispatch();

    rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
    NS_ENSURE_SUCCESS(rv, rv);

    // Put the temporary queue in place before calling Shutdown().
    mQueuedRunnables = &queuedRunnables;

    if (NS_FAILED(mThread->Shutdown())) {
      NS_ERROR("Failed to shutdown the thread!");
    }

    // Now unset the queue.
    mQueuedRunnables = nullptr;

    mThread = nullptr;

    {
      MutexAutoLock lock(mMutex);

      MOZ_ASSERT(!mPendingEventCount, "Huh?!");
      MOZ_ASSERT(!mIdleNotificationCount, "Huh?!");
      MOZ_ASSERT(mThreadIsShuttingDown, "Huh?!");
      mThreadIsShuttingDown = false;
    }
  }

  if (mIdleTimer) {
    rv = mIdleTimer->Cancel();
    NS_ENSURE_SUCCESS(rv, rv);

    mIdleTimer = nullptr;
  }

  // If our temporary queue has any runnables then we need to dispatch them.
  if (queuedRunnables.Length()) {
    // If the thread manager has gone away then these runnables will never run.
    if (mShutdown) {
      NS_ERROR("Runnables dispatched to LazyIdleThread will never run!");
      return NS_OK;
    }

    // Re-dispatch the queued runnables.
    for (uint32_t index = 0; index < queuedRunnables.Length(); index++) {
      nsCOMPtr<nsIRunnable> runnable;
      runnable.swap(queuedRunnables[index]);
      MOZ_ASSERT(runnable, "Null runnable?!");

      if (NS_FAILED(Dispatch(runnable, NS_DISPATCH_NORMAL))) {
        NS_ERROR("Failed to re-dispatch queued runnable!");
      }
    }
  }

  return NS_OK;
}
Ejemplo n.º 11
0
NS_IMETHODIMP
LazyIdleThread::AsyncShutdown()
{
  ASSERT_OWNING_THREAD();
  return NS_ERROR_NOT_IMPLEMENTED;
}