Backed out changeset 0e250e45603a (bug 1886022) for causing build bustages on CanvasShutdownManager. CLOSED TREE

This commit is contained in:
Cosmin Sabou 2024-03-19 09:42:20 +02:00
parent 2bf53fd12d
commit cb3c42a748
8 changed files with 105 additions and 175 deletions

View File

@ -24,7 +24,7 @@
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/GeneratePlaceholderCanvasData.h"
#include "mozilla/dom/VideoFrame.h"
#include "mozilla/gfx/CanvasShutdownManager.h"
#include "mozilla/gfx/CanvasManagerChild.h"
#include "nsPresContext.h"
#include "nsIInterfaceRequestorUtils.h"
@ -872,6 +872,41 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasGradient, mContext)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasPattern, mContext)
class CanvasShutdownObserver final : public nsIObserver {
public:
explicit CanvasShutdownObserver(CanvasRenderingContext2D* aCanvas)
: mCanvas(aCanvas) {}
void OnShutdown() {
if (!mCanvas) {
return;
}
mCanvas = nullptr;
nsContentUtils::UnregisterShutdownObserver(this);
}
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
private:
~CanvasShutdownObserver() = default;
CanvasRenderingContext2D* mCanvas;
};
NS_IMPL_ISUPPORTS(CanvasShutdownObserver, nsIObserver)
NS_IMETHODIMP
CanvasShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
if (mCanvas && strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
mCanvas->OnShutdown();
OnShutdown();
}
return NS_OK;
}
NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasRenderingContext2D)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasRenderingContext2D)
@ -1208,8 +1243,14 @@ void CanvasRenderingContext2D::OnShutdown() {
}
bool CanvasRenderingContext2D::AddShutdownObserver() {
auto* const canvasManager = CanvasShutdownManager::Get();
auto* const canvasManager = CanvasManagerChild::Get();
if (NS_WARN_IF(!canvasManager)) {
if (NS_IsMainThread()) {
mShutdownObserver = new CanvasShutdownObserver(this);
nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
return true;
}
mHasShutdown = true;
return false;
}
@ -1219,7 +1260,13 @@ bool CanvasRenderingContext2D::AddShutdownObserver() {
}
void CanvasRenderingContext2D::RemoveShutdownObserver() {
auto* const canvasManager = CanvasShutdownManager::MaybeGet();
if (mShutdownObserver) {
mShutdownObserver->OnShutdown();
mShutdownObserver = nullptr;
return;
}
auto* const canvasManager = CanvasManagerChild::MaybeGet();
if (!canvasManager) {
return;
}

View File

@ -846,6 +846,7 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
// Whether or not we have already shutdown.
bool mHasShutdown = false;
RefPtr<CanvasShutdownObserver> mShutdownObserver;
bool AddShutdownObserver();
void RemoveShutdownObserver();
bool AlreadyShutDown() const { return mHasShutdown; }

View File

@ -10,7 +10,6 @@
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/CanvasShutdownManager.h"
#include "mozilla/gfx/Swizzle.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/ActiveResource.h"
@ -31,10 +30,7 @@ MOZ_THREAD_LOCAL(CanvasManagerChild*) CanvasManagerChild::sLocalManager;
Atomic<uint32_t> CanvasManagerChild::sNextId(1);
CanvasManagerChild::CanvasManagerChild(ThreadSafeWorkerRef* aWorkerRef,
uint32_t aId)
: mWorkerRef(aWorkerRef), mId(aId) {}
CanvasManagerChild::CanvasManagerChild(uint32_t aId) : mId(aId) {}
CanvasManagerChild::~CanvasManagerChild() = default;
void CanvasManagerChild::ActorDestroy(ActorDestroyReason aReason) {
@ -46,6 +42,11 @@ void CanvasManagerChild::ActorDestroy(ActorDestroyReason aReason) {
}
void CanvasManagerChild::DestroyInternal() {
std::set<CanvasRenderingContext2D*> activeCanvas = std::move(mActiveCanvas);
for (const auto& i : activeCanvas) {
i->OnShutdown();
}
if (mActiveResourceTracker) {
mActiveResourceTracker->AgeAllGenerations();
mActiveResourceTracker.reset();
@ -66,6 +67,12 @@ void CanvasManagerChild::Destroy() {
}
/* static */ void CanvasManagerChild::Shutdown() {
MOZ_ASSERT(NS_IsMainThread());
// The worker threads should destroy their own CanvasManagerChild instances
// during their shutdown sequence. We just need to take care of the main
// thread. We need to init here because we may have never created a
// CanvasManagerChild for the main thread in the first place.
if (sLocalManager.init()) {
RefPtr<CanvasManagerChild> manager = sLocalManager.get();
if (manager) {
@ -96,11 +103,6 @@ void CanvasManagerChild::Destroy() {
return managerWeak;
}
auto* shutdownManager = CanvasShutdownManager::Get();
if (NS_WARN_IF(!shutdownManager)) {
return nullptr;
}
// We are only used on the main thread, or on worker threads.
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT_IF(!worker, NS_IsMainThread());
@ -119,8 +121,29 @@ void CanvasManagerChild::Destroy() {
return nullptr;
}
auto manager = MakeRefPtr<CanvasManagerChild>(shutdownManager->GetWorkerRef(),
sNextId++);
auto manager = MakeRefPtr<CanvasManagerChild>(sNextId++);
if (worker) {
// The ThreadSafeWorkerRef will let us know when the worker is shutting
// down. This will let us clear our threadlocal reference and close the
// actor. We rely upon an explicit shutdown for the main thread.
RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
worker, "CanvasManager", [manager]() { manager->Destroy(); });
if (NS_WARN_IF(!workerRef)) {
return nullptr;
}
manager->mWorkerRef = new ThreadSafeWorkerRef(workerRef);
} else if (NS_IsMainThread()) {
if (NS_WARN_IF(
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed))) {
return nullptr;
}
} else {
MOZ_ASSERT_UNREACHABLE("Can only be used on main or DOM worker threads!");
return nullptr;
}
if (NS_WARN_IF(!childEndpoint.Bind(manager))) {
return nullptr;
}
@ -152,6 +175,16 @@ void CanvasManagerChild::Destroy() {
return sLocalManager.get();
}
void CanvasManagerChild::AddShutdownObserver(
dom::CanvasRenderingContext2D* aCanvas) {
mActiveCanvas.insert(aCanvas);
}
void CanvasManagerChild::RemoveShutdownObserver(
dom::CanvasRenderingContext2D* aCanvas) {
mActiveCanvas.erase(aCanvas);
}
void CanvasManagerChild::EndCanvasTransaction() {
if (!mCanvasChild) {
return;

View File

@ -10,6 +10,7 @@
#include "mozilla/gfx/PCanvasManagerChild.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/ThreadLocal.h"
#include <set>
namespace mozilla {
namespace dom {
@ -34,8 +35,7 @@ class CanvasManagerChild final : public PCanvasManagerChild {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CanvasManagerChild, override);
explicit CanvasManagerChild(dom::ThreadSafeWorkerRef* aWorkerRef,
uint32_t aId);
explicit CanvasManagerChild(uint32_t aId);
uint32_t Id() const { return mId; }
already_AddRefed<DataSourceSurface> GetSnapshot(
uint32_t aManagerId, int32_t aProtocolId,
@ -49,6 +49,9 @@ class CanvasManagerChild final : public PCanvasManagerChild {
static bool CreateParent(
mozilla::ipc::Endpoint<PCanvasManagerParent>&& aEndpoint);
void AddShutdownObserver(dom::CanvasRenderingContext2D* aCanvas);
void RemoveShutdownObserver(dom::CanvasRenderingContext2D* aCanvas);
bool IsCanvasActive() { return mActive; }
void EndCanvasTransaction();
void ClearCachedResources();
@ -70,6 +73,7 @@ class CanvasManagerChild final : public PCanvasManagerChild {
RefPtr<layers::CanvasChild> mCanvasChild;
RefPtr<webgpu::WebGPUChild> mWebGPUChild;
UniquePtr<layers::ActiveResourceTracker> mActiveResourceTracker;
std::set<dom::CanvasRenderingContext2D*> mActiveCanvas;
const uint32_t mId;
bool mActive = true;
bool mBlocked = false;

View File

@ -1,108 +0,0 @@
/* -*- 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 "CanvasShutdownManager.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/dom/CanvasRenderingContext2D.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/gfx/CanvasManagerChild.h"
using namespace mozilla::dom;
namespace mozilla::gfx {
// The owning thread will tell us to close when it is shutdown, either via
// CanvasShutdownManager::Shutdown for the main thread, or via a shutdown
// callback from ThreadSafeWorkerRef for worker threads.
MOZ_THREAD_LOCAL(CanvasShutdownManager*) CanvasShutdownManager::sLocalManager;
CanvasShutdownManager::CanvasShutdownManager(StrongWorkerRef* aWorkerRef)
: mWorkerRef(new ThreadSafeWorkerRef(aWorkerRef)) {}
CanvasShutdownManager::CanvasShutdownManager() = default;
CanvasShutdownManager::~CanvasShutdownManager() = default;
void CanvasShutdownManager::Destroy() {
std::set<CanvasRenderingContext2D*> activeCanvas = std::move(mActiveCanvas);
for (const auto& i : activeCanvas) {
i->OnShutdown();
}
CanvasManagerChild::Shutdown();
mWorkerRef = nullptr;
}
/* static */ void CanvasShutdownManager::Shutdown() {
auto* manager = MaybeGet();
if (!manager) {
return;
}
sLocalManager.set(nullptr);
manager->Destroy();
delete manager;
}
/* static */ CanvasShutdownManager* CanvasShutdownManager::MaybeGet() {
if (NS_WARN_IF(!sLocalManager.init())) {
return nullptr;
}
return sLocalManager.get();
}
/* static */ CanvasShutdownManager* CanvasShutdownManager::Get() {
if (NS_WARN_IF(!sLocalManager.init())) {
return nullptr;
}
CanvasShutdownManager* managerWeak = sLocalManager.get();
if (managerWeak) {
return managerWeak;
}
if (WorkerPrivate* worker = GetCurrentThreadWorkerPrivate()) {
// The ThreadSafeWorkerRef will let us know when the worker is shutting
// down. This will let us clear our threadlocal reference and close the
// actor. We rely upon an explicit shutdown for the main thread.
RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
worker, "CanvasShutdownManager", []() { Shutdown(); });
if (NS_WARN_IF(!workerRef)) {
return nullptr;
}
CanvasShutdownManager* manager = new CanvasShutdownManager(workerRef);
sLocalManager.set(manager);
return manager;
}
if (NS_IsMainThread()) {
if (NS_WARN_IF(
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed))) {
return nullptr;
}
CanvasShutdownManager* manager = new CanvasShutdownManager();
sLocalManager.set(manager);
return manager;
}
MOZ_ASSERT_UNREACHABLE("Can only be used on main or DOM worker threads!");
return nullptr;
}
void CanvasShutdownManager::AddShutdownObserver(
dom::CanvasRenderingContext2D* aCanvas) {
mActiveCanvas.insert(aCanvas);
}
void CanvasShutdownManager::RemoveShutdownObserver(
dom::CanvasRenderingContext2D* aCanvas) {
mActiveCanvas.erase(aCanvas);
}
} // namespace mozilla::gfx

View File

@ -1,45 +0,0 @@
/* -*- 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/. */
#ifndef _include_gfx_ipc_CanvasShutdownManager_h__
#define _include_gfx_ipc_CanvasShutdownManager_h__
#include "mozilla/ThreadLocal.h"
#include <set>
namespace mozilla {
namespace dom {
class CanvasRenderingContext2D;
class StrongWorkerRef;
class ThreadSafeWorkerRef;
} // namespace dom
namespace gfx {
class CanvasShutdownManager final {
public:
static CanvasShutdownManager* Get();
static CanvasShutdownManager* MaybeGet();
static void Shutdown();
dom::ThreadSafeWorkerRef* GetWorkerRef() const { return mWorkerRef; }
void AddShutdownObserver(dom::CanvasRenderingContext2D* aCanvas);
void RemoveShutdownObserver(dom::CanvasRenderingContext2D* aCanvas);
private:
explicit CanvasShutdownManager(dom::StrongWorkerRef* aWorkerRef);
CanvasShutdownManager();
~CanvasShutdownManager();
void Destroy();
RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef;
std::set<dom::CanvasRenderingContext2D*> mActiveCanvas;
static MOZ_THREAD_LOCAL(CanvasShutdownManager*) sLocalManager;
};
} // namespace gfx
} // namespace mozilla
#endif // _include_gfx_ipc_CanvasShutdownManager_h__

View File

@ -13,7 +13,6 @@ EXPORTS.mozilla.gfx += [
"CanvasManagerChild.h",
"CanvasManagerParent.h",
"CanvasRenderThread.h",
"CanvasShutdownManager.h",
"CrossProcessPaint.h",
"FileHandleWrapper.h",
"GPUChild.h",
@ -43,7 +42,6 @@ UNIFIED_SOURCES += [
"CanvasManagerChild.cpp",
"CanvasManagerParent.cpp",
"CanvasRenderThread.cpp",
"CanvasShutdownManager.cpp",
"CompositorSession.cpp",
"CompositorWidgetVsyncObserver.cpp",
"CrossProcessPaint.cpp",

View File

@ -21,8 +21,8 @@
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/gfx/GraphicsMessages.h"
#include "mozilla/gfx/CanvasManagerChild.h"
#include "mozilla/gfx/CanvasRenderThread.h"
#include "mozilla/gfx/CanvasShutdownManager.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/EnumTypeTraits.h"
@ -1343,7 +1343,7 @@ void gfxPlatform::ShutdownLayersIPC() {
if (XRE_IsContentProcess()) {
gfx::VRManagerChild::ShutDown();
gfx::CanvasShutdownManager::Shutdown();
gfx::CanvasManagerChild::Shutdown();
// cf bug 1215265.
if (StaticPrefs::layers_child_process_shutdown()) {
layers::CompositorManagerChild::Shutdown();
@ -1354,7 +1354,7 @@ void gfxPlatform::ShutdownLayersIPC() {
VideoBridgeParent::Shutdown();
RDDProcessManager::RDDProcessShutdown();
gfx::VRManagerChild::ShutDown();
gfx::CanvasShutdownManager::Shutdown();
gfx::CanvasManagerChild::Shutdown();
layers::CompositorManagerChild::Shutdown();
layers::ImageBridgeChild::ShutDown();
// This could be running on either the Compositor thread, the Renderer