void
VsyncSource::Display::UpdateVsyncStatus()
{
  MOZ_ASSERT(NS_IsMainThread());
  // WARNING: This function SHOULD NOT BE CALLED WHILE HOLDING LOCKS
  // NotifyVsync grabs a lock to dispatch vsync events
  // When disabling vsync, we wait for the underlying thread to stop on some platforms
  // We can deadlock if we wait for the underlying vsync thread to stop
  // while the vsync thread is in NotifyVsync.
  bool enableVsync = false;
  { // scope lock
    MutexAutoLock lock(mDispatcherLock);
    enableVsync = !mCompositorVsyncDispatchers.IsEmpty() || mRefreshTimerNeedsVsync;
  }

  if (enableVsync) {
    EnableVsync();
  } else {
    DisableVsync();
  }

  if (IsVsyncEnabled() != enableVsync) {
    NS_WARNING("Vsync status did not change.");
  }
}
void
SoftwareDisplay::DisableVsync()
{
  MOZ_ASSERT(NS_IsMainThread());
  if (!IsVsyncEnabled()) {
    return;
  }

  MOZ_ASSERT(mVsyncThread->IsRunning());
  { // scope lock
    mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
    mVsyncEnabled = false;
    if (mCurrentVsyncTask) {
      mCurrentVsyncTask->Cancel();
      mCurrentVsyncTask = nullptr;
    }
  }
  mVsyncThread->Stop();
}
void
SoftwareDisplay::EnableVsync()
{
  MOZ_ASSERT(NS_IsMainThread());
  if (IsVsyncEnabled()) {
    return;
  }

  { // scope lock
    mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
    mVsyncEnabled = true;
    MOZ_ASSERT(!mVsyncThread->IsRunning());
    MOZ_RELEASE_ASSERT(mVsyncThread->Start(), "Could not start software vsync thread");
    mCurrentVsyncTask = NewRunnableMethod(this,
        &SoftwareDisplay::NotifyVsync,
        mozilla::TimeStamp::Now());
    mVsyncThread->message_loop()->PostTask(FROM_HERE, mCurrentVsyncTask);
  }
}