commit 7ee10d8ccfdef59729eac166d6f04f291e8c77f8
parent e5f40f033b0ffb2fef0b8edcb83b927484f70423
Author: Jamie Nicol <jnicol@mozilla.com>
Date: Fri, 14 Nov 2025 10:47:37 +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