commit ecdc16905e250ad631f23e9ec604b8e099f7ad53
parent 6f8fbe841ac3f16980a743e8073b91e0e9ec7741
Author: Eden Chuang <echuang@mozilla.com>
Date: Mon, 3 Nov 2025 10:46:45 +0000
Bug 1968451 - Using ThreadSafeWorkerRef instead of WeakWorkerRef in PermissionStatusSink. r=dom-worker-reviewers,hsingh,permissions-reviewers,asuth,timhuang
Differential Revision: https://phabricator.services.mozilla.com/D268513
Diffstat:
2 files changed, 36 insertions(+), 10 deletions(-)
diff --git a/dom/permission/PermissionStatusSink.cpp b/dom/permission/PermissionStatusSink.cpp
@@ -51,10 +51,26 @@ PermissionStatusSink::Init() {
MutexAutoLock lock(mMutex);
- mWorkerRef = WeakWorkerRef::Create(
- workerPrivate, [self = RefPtr(this)] { self->Disentangle(); });
+ RefPtr<StrongWorkerRef> workerRef = StrongWorkerRef::Create(
+ workerPrivate, "PermissionStatusSink",
+ [self = RefPtr(this)]() { self->Disentangle(); });
+ if (NS_WARN_IF(!workerRef)) {
+ // If WorkerRef creation fails, the Worker has started shutting down. But
+ // we are on the Worker thread, promise handlers in
+ // PermissionStatus::Init()/Permissions::Query() can still be dispatched
+ // to the Worker thread for outer promise rejection.
+ return PermissionStatePromise::CreateAndReject(NS_ERROR_FAILURE,
+ __func__);
+ ;
+ }
+
+ mWorkerRef = new ThreadSafeWorkerRef(workerRef);
}
+ // On the Worker thread, so the below async function must be executed before
+ // WorkerRef callback which should also be on the Worker thread. So the above
+ // created WorkerRef should protect the outer promise handling can be
+ // dispatched on the Worker thread.
return InvokeAsync(GetMainThreadSerialEventTarget(), __func__,
[self = RefPtr(this)] {
MOZ_ASSERT(!self->mObserver);
@@ -102,6 +118,17 @@ bool PermissionStatusSink::MaybeUpdatedByNotifyOnlyOnMainThread(
void PermissionStatusSink::PermissionChangedOnMainThread() {
MOZ_ASSERT(NS_IsMainThread());
+ // Nothing to do if Worker had shutted down.
+ if (!mSerialEventTarget->IsOnCurrentThread()) {
+ MutexAutoLock lock(mMutex);
+ if (!mWorkerRef) {
+ return;
+ }
+ }
+
+ // mWorkerRef is not nullptr, it will protect the promise handling can be
+ // dispatched to the Worker thread, even though the Worker starts shutdown,
+ // because mWorkerRef is nullify on the main thread.
ComputeStateOnMainThread()->Then(
mSerialEventTarget, __func__,
[self = RefPtr(this)](
@@ -117,17 +144,16 @@ void PermissionStatusSink::Disentangle() {
mPermissionStatus = nullptr;
- {
- MutexAutoLock lock(mMutex);
- mWorkerRef = nullptr;
- }
-
NS_DispatchToMainThread(
NS_NewRunnableFunction(__func__, [self = RefPtr(this)] {
if (self->mObserver) {
self->mObserver->RemoveSink(self);
self->mObserver = nullptr;
}
+ {
+ MutexAutoLock lock(self->mMutex);
+ self->mWorkerRef = nullptr;
+ }
}));
}
@@ -167,7 +193,7 @@ PermissionStatusSink::ComputeStateOnMainThread() {
// If we have mWorkerRef, we haven't received the WorkerRef notification
// yet.
- WorkerPrivate* workerPrivate = mWorkerRef->GetUnsafePrivate();
+ WorkerPrivate* workerPrivate = mWorkerRef->Private();
MOZ_ASSERT(workerPrivate);
ancestorWindow = workerPrivate->GetAncestorWindow();
diff --git a/dom/permission/PermissionStatusSink.h b/dom/permission/PermissionStatusSink.h
@@ -19,7 +19,7 @@ namespace mozilla::dom {
class PermissionObserver;
class PermissionStatus;
-class WeakWorkerRef;
+class ThreadSafeWorkerRef;
class PermissionStatusSink {
public:
@@ -70,7 +70,7 @@ class PermissionStatusSink {
// Protected by mutex.
// Created and released on worker-thread. Used also on main-thread.
- RefPtr<WeakWorkerRef> mWorkerRef MOZ_GUARDED_BY(mMutex);
+ RefPtr<ThreadSafeWorkerRef> mWorkerRef MOZ_GUARDED_BY(mMutex);
PermissionName mPermissionName;
nsCString mPermissionType;