gfx/ipc/VsyncBridgeChild.cpp
author Eitan Isaacson <eitan@monotonous.org>
Thu, 20 Dec 2018 16:03:00 -0500
changeset 501491 c58ea2229c337e9981ab9d3650b04fd3d249b141
parent 477586 b54db66223586b4e04f5cb926fccdacf8a176b91
child 508163 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1513912 - Null check return from TextToSpeech.getFeatures(). r=agi, a=jcristau

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "VsyncBridgeChild.h"
#include "VsyncIOThreadHolder.h"
#include "mozilla/dom/ContentChild.h"

namespace mozilla {
namespace gfx {

VsyncBridgeChild::VsyncBridgeChild(RefPtr<VsyncIOThreadHolder> aThread, const uint64_t& aProcessToken)
 : mThread(aThread),
   mLoop(nullptr),
   mProcessToken(aProcessToken)
{
}

VsyncBridgeChild::~VsyncBridgeChild()
{
}

/* static */ RefPtr<VsyncBridgeChild>
VsyncBridgeChild::Create(RefPtr<VsyncIOThreadHolder> aThread,
                         const uint64_t& aProcessToken,
                         Endpoint<PVsyncBridgeChild>&& aEndpoint)
{
  RefPtr<VsyncBridgeChild> child = new VsyncBridgeChild(aThread, aProcessToken);

  RefPtr<nsIRunnable> task = NewRunnableMethod<Endpoint<PVsyncBridgeChild>&&>(
    "gfx::VsyncBridgeChild::Open",
    child,
    &VsyncBridgeChild::Open,
    std::move(aEndpoint));
  aThread->GetThread()->Dispatch(task.forget(), nsIThread::DISPATCH_NORMAL);

  return child;
}

void
VsyncBridgeChild::Open(Endpoint<PVsyncBridgeChild>&& aEndpoint)
{
  if (!aEndpoint.Bind(this)) {
    // The GPU Process Manager might be gone if we receive ActorDestroy very
    // late in shutdown.
    if (GPUProcessManager* gpm = GPUProcessManager::Get())
      gpm->NotifyRemoteActorDestroyed(mProcessToken);
    return;
  }

  mLoop = MessageLoop::current();

  // Last reference is freed in DeallocPVsyncBridgeChild.
  AddRef();
}

class NotifyVsyncTask : public Runnable
{
public:
  NotifyVsyncTask(RefPtr<VsyncBridgeChild> aVsyncBridge,
                  TimeStamp aTimeStamp,
                  const layers::LayersId& aLayersId)
    : Runnable("gfx::NotifyVsyncTask")
    , mVsyncBridge(aVsyncBridge)
    , mTimeStamp(aTimeStamp)
    , mLayersId(aLayersId)
  {}

  NS_IMETHOD Run() override {
    mVsyncBridge->NotifyVsyncImpl(mTimeStamp, mLayersId);
    return NS_OK;
  }

private:
  RefPtr<VsyncBridgeChild> mVsyncBridge;
  TimeStamp mTimeStamp;
  layers::LayersId mLayersId;
};

bool
VsyncBridgeChild::IsOnVsyncIOThread() const
{
  return MessageLoop::current() == mLoop;
}

void
VsyncBridgeChild::NotifyVsync(TimeStamp aTimeStamp, const layers::LayersId& aLayersId)
{
  // This should be on the Vsync thread (not the Vsync I/O thread).
  MOZ_ASSERT(!IsOnVsyncIOThread());

  RefPtr<NotifyVsyncTask> task = new NotifyVsyncTask(this, aTimeStamp, aLayersId);
  mLoop->PostTask(task.forget());
}

void
VsyncBridgeChild::NotifyVsyncImpl(TimeStamp aTimeStamp, const layers::LayersId& aLayersId)
{
  // This should be on the Vsync I/O thread.
  MOZ_ASSERT(IsOnVsyncIOThread());

  if (!mProcessToken) {
    return;
  }
  SendNotifyVsync(aTimeStamp, aLayersId);
}

void
VsyncBridgeChild::Close()
{
  if (!IsOnVsyncIOThread()) {
    mLoop->PostTask(NewRunnableMethod(
      "gfx::VsyncBridgeChild::Close", this, &VsyncBridgeChild::Close));
    return;
  }

  // We clear mProcessToken when the channel is closed.
  if (!mProcessToken) {
    return;
  }

  // Clear the process token so we don't notify the GPUProcessManager. It already
  // knows we're closed since it manually called Close, and in fact the GPM could
  // have already been destroyed during shutdown.
  mProcessToken = 0;

  // Close the underlying IPC channel.
  PVsyncBridgeChild::Close();
}

void
VsyncBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
{
  if (mProcessToken) {
    GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
    mProcessToken = 0;
  }
}

void
VsyncBridgeChild::DeallocPVsyncBridgeChild()
{
  Release();
}

void
VsyncBridgeChild::ProcessingError(Result aCode, const char* aReason)
{
  MOZ_RELEASE_ASSERT(aCode == MsgDropped, "Processing error in VsyncBridgeChild");
}

void
VsyncBridgeChild::HandleFatalError(const char* aMsg) const
{
  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
}

} // namespace gfx
} // namespace mozilla