void
GPUProcessHost::Shutdown()
{
  MOZ_ASSERT(!mShutdownRequested);

  mListener = nullptr;

  if (mGPUChild) {
    // OnChannelClosed uses this to check if the shutdown was expected or
    // unexpected.
    mShutdownRequested = true;

#ifdef NS_FREE_PERMANENT_DATA
    // The channel might already be closed if we got here unexpectedly.
    if (!mChannelClosed) {
      mGPUChild->Close();
    }
#else
    // No need to communicate shutdown, the GPU process doesn't need to
    // communicate anything back.
    KillHard("NormalShutdown");
#endif

    // If we're shutting down unexpectedly, we're in the middle of handling an
    // ActorDestroy for PGPUChild, which is still on the stack. We'll return
    // back to OnChannelClosed.
    //
    // Otherwise, we'll wait for OnChannelClose to be called whenever PGPUChild
    // acknowledges shutdown.
    return;
  }

  DestroyProcess();
}
void
GPUProcessManager::OnProcessDeviceReset(GPUProcessHost* aHost)
{
  // Detect whether the device is resetting too quickly or too much
  // indicating that we should give up and use software
  mDeviceResetCount++;

  auto newTime = TimeStamp::Now();
  auto delta = (int32_t)(newTime - mDeviceResetLastTime).ToMilliseconds();
  mDeviceResetLastTime = newTime;

  if (ShouldLimitDeviceResets(mDeviceResetCount, delta)) {
    DestroyProcess();
    DisableGPUProcess("GPU processed experienced too many device resets");

    HandleProcessLost();
    return;
  }

  RebuildRemoteSessions();

  for (const auto& listener : mListeners) {
    listener->OnCompositorDeviceReset();
  }
}
void
GPUProcessHost::OnChannelClosed()
{
  if (!mShutdownRequested) {
    // This is an unclean shutdown. Notify our listener that we're going away.
    mChannelClosed = true;
    if (mListener) {
      mListener->OnProcessUnexpectedShutdown(this);
    }
  }

  // Release the actor.
  GPUChild::Destroy(Move(mGPUChild));
  MOZ_ASSERT(!mGPUChild);

  // If the owner of GPUProcessHost already requested shutdown, we can now
  // schedule destruction. Otherwise we must wait for someone to call
  // Shutdown. Note that GPUProcessManager calls Shutdown within
  // OnProcessUnexpectedShutdown.
  if (mShutdownRequested) {
    DestroyProcess();
  }
}
void
GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost)
{
  MOZ_ASSERT(mProcess && mProcess == aHost);

  DestroyProcess();

  if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestarts())) {
    char disableMessage[64];
    SprintfLiteral(disableMessage, "GPU process disabled after %d attempts",
                   mNumProcessAttempts);
    DisableGPUProcess(disableMessage);
  } else if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestartsWithDecoder()) &&
             mDecodeVideoOnGpuProcess) {
    mDecodeVideoOnGpuProcess = false;
    Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
                                     uint32_t(FallbackType::DECODINGDISABLED));
  } else {
    Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS,
                                     uint32_t(FallbackType::NONE));
  }

  HandleProcessLost();
}
void
GPUProcessManager::CleanShutdown()
{
  DestroyProcess();
  mVsyncIOThread = nullptr;
}