commit 6d17a0731b52498a4906b8e8a98081f1cbe6d91d
parent 1614dd7ebbd368f0ad9563268c15cbb89bd9fe8e
Author: Jamie Nicol <jnicol@mozilla.com>
Date: Tue, 18 Nov 2025 18:00:35 +0000
Bug 1999645 - Use live token instead of ipc::TaskFactory in GPUProcessHost. r=aosmond
To ensure tasks dispatched between threads in GPUProcessHost do not
run after the GPU process has been destroyed we currently use
ipc::TaskFactory, which allows us to revoke pending tasks on
shutdown.
This patch switches to using a refcounted "live token" and checking
whether the process is still live before doing any work in the
task. This is the same approach used in the RDD and Utility processes.
This should have no functional change, but will allow subsequent
patches to ensure the process is still live when executing promise
callbacks.
Additionally removes the unused OnChannelErrorTask() function.
Differential Revision: https://phabricator.services.mozilla.com/D272307
Diffstat:
2 files changed, 22 insertions(+), 36 deletions(-)
diff --git a/gfx/ipc/GPUProcessHost.cpp b/gfx/ipc/GPUProcessHost.cpp
@@ -34,11 +34,11 @@ using namespace ipc;
GPUProcessHost::GPUProcessHost(Listener* aListener)
: GeckoChildProcessHost(GeckoProcessType_GPU),
mListener(aListener),
- mTaskFactory(this),
mLaunchPhase(LaunchPhase::Unlaunched),
mProcessToken(0),
mShutdownRequested(false),
- mChannelClosed(false) {
+ mChannelClosed(false),
+ mLiveToken(new media::Refcountable<bool>(true)) {
MOZ_COUNT_CTOR(GPUProcessHost);
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX)
@@ -107,27 +107,12 @@ void GPUProcessHost::OnChannelConnected(base::ProcessId peer_pid) {
GeckoChildProcessHost::OnChannelConnected(peer_pid);
- // Post a task to the main thread. Take the lock because mTaskFactory is not
- // thread-safe.
- RefPtr<Runnable> runnable;
- {
- MonitorAutoLock lock(mMonitor);
- runnable =
- mTaskFactory.NewRunnableMethod(&GPUProcessHost::OnChannelConnectedTask);
- }
- NS_DispatchToMainThread(runnable);
-}
-
-void GPUProcessHost::OnChannelConnectedTask() {
- if (mLaunchPhase == LaunchPhase::Waiting) {
- InitAfterConnect(true);
- }
-}
-
-void GPUProcessHost::OnChannelErrorTask() {
- if (mLaunchPhase == LaunchPhase::Waiting) {
- InitAfterConnect(false);
- }
+ NS_DispatchToMainThread(NS_NewRunnableFunction(
+ "GPUProcessHost::OnChannelConnected", [this, liveToken = mLiveToken]() {
+ if (*mLiveToken && mLaunchPhase == LaunchPhase::Waiting) {
+ InitAfterConnect(true);
+ }
+ }));
}
static uint64_t sProcessTokenCounter = 0;
@@ -252,14 +237,12 @@ void GPUProcessHost::KillProcess(bool aGenerateMinidump) {
void GPUProcessHost::CrashProcess() { mGPUChild->SendCrashProcess(); }
void GPUProcessHost::DestroyProcess() {
- // Cancel all tasks. We don't want anything triggering after our caller
- // expects this to go away.
- {
- MonitorAutoLock lock(mMonitor);
- mTaskFactory.RevokeAll();
- }
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // Any pending tasks will be cancelled from now on.
+ *mLiveToken = false;
- GetCurrentSerialEventTarget()->Dispatch(
+ NS_DispatchToMainThread(
NS_NewRunnableFunction("DestroyProcessRunnable", [this] { Destroy(); }));
}
diff --git a/gfx/ipc/GPUProcessHost.h b/gfx/ipc/GPUProcessHost.h
@@ -11,7 +11,7 @@
#include "mozilla/gfx/Types.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/ipc/ProtocolUtils.h"
-#include "mozilla/ipc/TaskFactory.h"
+#include "mozilla/media/MediaUtils.h"
#ifdef MOZ_WIDGET_ANDROID
# include "mozilla/java/CompositorSurfaceManagerWrappers.h"
@@ -124,10 +124,6 @@ class GPUProcessHost final : public mozilla::ipc::GeckoChildProcessHost {
private:
~GPUProcessHost();
- // Called on the main thread.
- void OnChannelConnectedTask();
- void OnChannelErrorTask();
-
// Called on the main thread after a connection has been established.
void InitAfterConnect(bool aSucceeded);
@@ -150,7 +146,6 @@ class GPUProcessHost final : public mozilla::ipc::GeckoChildProcessHost {
DISALLOW_COPY_AND_ASSIGN(GPUProcessHost);
Listener* mListener;
- mozilla::ipc::TaskFactory<GPUProcessHost> mTaskFactory;
enum class LaunchPhase { Unlaunched, Waiting, Complete };
LaunchPhase mLaunchPhase;
@@ -165,6 +160,14 @@ class GPUProcessHost final : public mozilla::ipc::GeckoChildProcessHost {
TimeStamp mLaunchTime;
+ // Set to true on construction and to false just prior deletion.
+ // The GPUProcessHost isn't refcounted; so we can capture this by value in
+ // lambdas along with a strong reference to mLiveToken and check if that value
+ // is true before accessing "this".
+ // While a reference to mLiveToken can be taken on any thread; its value can
+ // only be read on the main thread.
+ const RefPtr<media::Refcountable<bool>> mLiveToken;
+
#ifdef MOZ_WIDGET_ANDROID
// Binder interface used to send compositor surfaces to GPU process. There is
// one instance per GPU process which gets initialized after launch, then