Bug 1559919 - Finish the WorkerHolder cleanup - part 9 - Notification API ported to WorkerRef, r=asuth

Differential Revision: https://phabricator.services.mozilla.com/D35228

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2019-07-12 11:17:52 +00:00
Родитель 1d8a0b716c
Коммит 839b9341d1
3 изменённых файлов: 54 добавлений и 82 удалений

Просмотреть файл

@ -997,7 +997,7 @@ Notification::~Notification() {
mData.setUndefined();
mozilla::DropJSObjects(this);
AssertIsOnTargetThread();
MOZ_ASSERT(!mWorkerHolder);
MOZ_ASSERT(!mWorkerRef);
MOZ_ASSERT(!mTempRef);
}
@ -2054,10 +2054,10 @@ void Notification::InitFromBase64(const nsAString& aData, ErrorResult& aRv) {
bool Notification::AddRefObject() {
AssertIsOnTargetThread();
MOZ_ASSERT_IF(mWorkerPrivate && !mWorkerHolder, mTaskCount == 0);
MOZ_ASSERT_IF(mWorkerPrivate && mWorkerHolder, mTaskCount > 0);
if (mWorkerPrivate && !mWorkerHolder) {
if (!RegisterWorkerHolder()) {
MOZ_ASSERT_IF(mWorkerPrivate && !mWorkerRef, mTaskCount == 0);
MOZ_ASSERT_IF(mWorkerPrivate && mWorkerRef, mTaskCount > 0);
if (mWorkerPrivate && !mWorkerRef) {
if (!CreateWorkerRef()) {
return false;
}
}
@ -2069,21 +2069,16 @@ bool Notification::AddRefObject() {
void Notification::ReleaseObject() {
AssertIsOnTargetThread();
MOZ_ASSERT(mTaskCount > 0);
MOZ_ASSERT_IF(mWorkerPrivate, mWorkerHolder);
MOZ_ASSERT_IF(mWorkerPrivate, mWorkerRef);
--mTaskCount;
if (mWorkerPrivate && mTaskCount == 0) {
UnregisterWorkerHolder();
MOZ_ASSERT(mWorkerRef);
mWorkerRef = nullptr;
}
Release();
}
NotificationWorkerHolder::NotificationWorkerHolder(Notification* aNotification)
: WorkerHolder("NotificationWorkerHolder"), mNotification(aNotification) {
MOZ_ASSERT(mNotification->mWorkerPrivate);
mNotification->mWorkerPrivate->AssertIsOnWorkerThread();
}
/*
* Called from the worker, runs on main thread, blocks worker.
*
@ -2116,66 +2111,57 @@ class CloseNotificationRunnable final : public WorkerMainThreadRunnable {
bool HadObserver() { return mHadObserver; }
};
bool NotificationWorkerHolder::Notify(WorkerStatus aStatus) {
if (aStatus >= Canceling) {
// CloseNotificationRunnable blocks the worker by pushing a sync event loop
// on the stack. Meanwhile, WorkerControlRunnables dispatched to the worker
// can still continue running. One of these is
// ReleaseNotificationControlRunnable that releases the notification,
// invalidating the notification and this feature. We hold this reference to
// keep the notification valid until we are done with it.
//
// An example of when the control runnable could get dispatched to the
// worker is if a Notification is created and the worker is immediately
// closed, but there is no permission to show it so that the main thread
// immediately drops the NotificationRef. In this case, this function blocks
// on the main thread, but the main thread dispatches the control runnable,
// invalidating mNotification.
RefPtr<Notification> kungFuDeathGrip = mNotification;
// Dispatched to main thread, blocks on closing the Notification.
RefPtr<CloseNotificationRunnable> r =
new CloseNotificationRunnable(kungFuDeathGrip);
ErrorResult rv;
r->Dispatch(Killing, rv);
// XXXbz I'm told throwing and returning false from here is pointless (and
// also that doing sync stuff from here is really weird), so I guess we just
// suppress the exception on rv, if any.
rv.SuppressException();
// Only call ReleaseObject() to match the observer's NotificationRef
// ownership (since CloseNotificationRunnable asked the observer to drop the
// reference to the notification).
if (r->HadObserver()) {
kungFuDeathGrip->ReleaseObject();
}
// From this point we cannot touch properties of this feature because
// ReleaseObject() may have led to the notification going away and the
// notification owns this feature!
}
return true;
}
bool Notification::RegisterWorkerHolder() {
bool Notification::CreateWorkerRef() {
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(!mWorkerHolder);
mWorkerHolder = MakeUnique<NotificationWorkerHolder>(this);
if (NS_WARN_IF(!mWorkerHolder->HoldWorker(mWorkerPrivate, Canceling))) {
MOZ_ASSERT(!mWorkerRef);
RefPtr<Notification> self = this;
mWorkerRef =
StrongWorkerRef::Create(mWorkerPrivate, "Notification", [self]() {
// CloseNotificationRunnable blocks the worker by pushing a sync event
// loop on the stack. Meanwhile, WorkerControlRunnables dispatched to
// the worker can still continue running. One of these is
// ReleaseNotificationControlRunnable that releases the notification,
// invalidating the notification and this feature. We hold this
// reference to keep the notification valid until we are done with it.
//
// An example of when the control runnable could get dispatched to the
// worker is if a Notification is created and the worker is immediately
// closed, but there is no permission to show it so that the main thread
// immediately drops the NotificationRef. In this case, this function
// blocks on the main thread, but the main thread dispatches the control
// runnable, invalidating mNotification.
// Dispatched to main thread, blocks on closing the Notification.
RefPtr<CloseNotificationRunnable> r =
new CloseNotificationRunnable(self);
ErrorResult rv;
r->Dispatch(Killing, rv);
// XXXbz I'm told throwing and returning false from here is pointless
// (and also that doing sync stuff from here is really weird), so I
// guess we just suppress the exception on rv, if any.
rv.SuppressException();
// Only call ReleaseObject() to match the observer's NotificationRef
// ownership (since CloseNotificationRunnable asked the observer to drop
// the reference to the notification).
if (r->HadObserver()) {
self->ReleaseObject();
}
// From this point we cannot touch properties of this feature because
// ReleaseObject() may have led to the notification going away and the
// notification owns this feature!
});
if (NS_WARN_IF(!mWorkerRef)) {
return false;
}
return true;
}
void Notification::UnregisterWorkerHolder() {
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(mWorkerHolder);
mWorkerHolder = nullptr;
}
/*
* Checks:
* 1) Is aWorker allowed to show a notification for scope?

Просмотреть файл

@ -10,7 +10,6 @@
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/NotificationBinding.h"
#include "mozilla/dom/WorkerHolder.h"
#include "nsIObserver.h"
#include "nsISupports.h"
@ -32,20 +31,9 @@ namespace dom {
class NotificationRef;
class WorkerNotificationObserver;
class Promise;
class StrongWorkerRef;
class WorkerPrivate;
class Notification;
class NotificationWorkerHolder final : public WorkerHolder {
// Since the feature is strongly held by a Notification, it is ok to hold
// a raw pointer here.
Notification* mNotification;
public:
explicit NotificationWorkerHolder(Notification* aNotification);
bool Notify(WorkerStatus aStatus) override;
};
// Records telemetry probes at application startup, when a notification is
// shown, and when the notification permission is revoked for a site.
class NotificationTelemetryService final : public nsIObserver {
@ -385,13 +373,12 @@ class Notification : public DOMEventTargetHelper,
bool IsTargetThread() const { return NS_IsMainThread() == !mWorkerPrivate; }
bool RegisterWorkerHolder();
void UnregisterWorkerHolder();
bool CreateWorkerRef();
nsresult ResolveIconAndSoundURL(nsString&, nsString&);
// Only used for Notifications on Workers, worker thread only.
UniquePtr<NotificationWorkerHolder> mWorkerHolder;
RefPtr<StrongWorkerRef> mWorkerRef;
// Target thread only.
uint32_t mTaskCount;
};

Просмотреть файл

@ -73,7 +73,6 @@
#include "mozilla/dom/ServiceWorkerManager.h"
#include "mozilla/UniquePtr.h"
#include "Principal.h"
#include "WorkerHolder.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "WorkerScope.h"