diff --git a/dom/workers/WorkerRef.cpp b/dom/workers/WorkerRef.cpp index 255b0ec65e65..55ed43a4d01a 100644 --- a/dom/workers/WorkerRef.cpp +++ b/dom/workers/WorkerRef.cpp @@ -216,5 +216,41 @@ WorkerPrivate* ThreadSafeWorkerRef::Private() const { return mRef->mWorkerPrivate; } +// ---------------------------------------------------------------------------- +// IPCWorkerRef + +/* static */ +already_AddRefed IPCWorkerRef::Create( + WorkerPrivate* aWorkerPrivate, const char* aName, + std::function&& aCallback) { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + RefPtr ref = new IPCWorkerRef(aWorkerPrivate); + + // This holder doesn't keep the worker alive. + UniquePtr holder( + new Holder(aName, ref, WorkerHolder::AllowIdleShutdownStart)); + if (NS_WARN_IF(!holder->HoldWorker(aWorkerPrivate, Canceling))) { + return nullptr; + } + + ref->mHolder = std::move(holder); + ref->mCallback = std::move(aCallback); + + return ref.forget(); +} + +IPCWorkerRef::IPCWorkerRef(WorkerPrivate* aWorkerPrivate) + : WorkerRef(aWorkerPrivate) {} + +IPCWorkerRef::~IPCWorkerRef() = default; + +WorkerPrivate* IPCWorkerRef::Private() const { + MOZ_ASSERT(mHolder); + NS_ASSERT_OWNINGTHREAD(IPCWorkerRef); + return mWorkerPrivate; +} + } // namespace dom } // namespace mozilla diff --git a/dom/workers/WorkerRef.h b/dom/workers/WorkerRef.h index fa42a452962e..4094831bb270 100644 --- a/dom/workers/WorkerRef.h +++ b/dom/workers/WorkerRef.h @@ -79,6 +79,23 @@ namespace dom { * ThreadSafeWorkerRef can be destroyed in any thread. Internally it keeps a * reference to its StrongWorkerRef creator and this ref will be dropped on the * correct thread when the ThreadSafeWorkerRef is deleted. + * + * IPC WorkerRef + * ~~~~~~~~~~~~~ + * + * IPDL protocols require a correct shutdown sequence. Because of this, they + * need a special configuration: + * 1. they need to be informed when the Worker starts the shutting down + * 2. they don't want to prevent the shutdown + * 3. but at the same time, they need to block the shutdown until the WorkerRef + * is not longer alive. + * + * Point 1 is a standard feature of WorkerRef; point 2 is similar to + * WeakWorkerRef; point 3 is similar to StrongWorkerRef. + * + * You can create a special IPC WorkerRef using this static method: + * mozilla::dom::IPCWorkerRef::Create(WorkerPrivate* aWorkerPrivate, + * const char* * aName); */ class WorkerPrivate; @@ -174,6 +191,37 @@ class ThreadSafeWorkerRef final { RefPtr mRef; }; +class IPCWorkerRef final : public WorkerRef { + public: + static already_AddRefed Create( + WorkerPrivate* aWorkerPrivate, const char* aName, + std::function&& aCallback = nullptr); + + WorkerPrivate* Private() const; + + private: + explicit IPCWorkerRef(WorkerPrivate* aWorkerPrivate); + ~IPCWorkerRef(); +}; + +// Template class to keep an Actor pointer, as a raw pointer, in a ref-counted +// way when passed to lambdas. +template +class IPCWorkerRefHelper final { + public: + NS_INLINE_DECL_REFCOUNTING(IPCWorkerRefHelper); + + explicit IPCWorkerRefHelper(ActorPtr* aActor) : mActor(aActor) {} + + ActorPtr* Actor() const { return mActor; } + + private: + ~IPCWorkerRefHelper() = default; + + // Raw pointer + ActorPtr* mActor; +}; + } // namespace dom } // namespace mozilla