Bug 1861467 - [wpt-sync] Update web-platform-tests to eedf737ce39c512d0ca3471f988972e...
[gecko.git] / dom / workers / WorkerRef.cpp
blob342d1b0f7cf44a38ef3efec322753d1db857d119
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/WorkerRef.h"
9 #include "nsDebug.h"
10 #include "WorkerRunnable.h"
11 #include "WorkerPrivate.h"
13 namespace mozilla::dom {
15 namespace {
17 // This runnable is used to release the StrongWorkerRef on the worker thread
18 // when a ThreadSafeWorkerRef is released.
19 class ReleaseRefControlRunnable final : public WorkerControlRunnable {
20 public:
21 ReleaseRefControlRunnable(WorkerPrivate* aWorkerPrivate,
22 already_AddRefed<StrongWorkerRef> aRef)
23 : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
24 mRef(std::move(aRef)) {
25 MOZ_ASSERT(mRef);
28 bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { return true; }
30 void PostDispatch(WorkerPrivate* aWorkerPrivate,
31 bool aDispatchResult) override {}
33 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
34 mRef = nullptr;
35 return true;
38 private:
39 RefPtr<StrongWorkerRef> mRef;
42 } // namespace
44 // ----------------------------------------------------------------------------
45 // WorkerRef
47 WorkerRef::WorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName,
48 bool aIsPreventingShutdown)
49 : mWorkerPrivate(aWorkerPrivate),
50 mName(aName),
51 mIsPreventingShutdown(aIsPreventingShutdown),
52 mHolding(false) {
53 MOZ_ASSERT(aWorkerPrivate);
54 MOZ_ASSERT(aName);
56 aWorkerPrivate->AssertIsOnWorkerThread();
59 WorkerRef::~WorkerRef() {
60 NS_ASSERT_OWNINGTHREAD(WorkerRef);
61 ReleaseWorker();
64 void WorkerRef::ReleaseWorker() {
65 if (mHolding) {
66 MOZ_ASSERT(mWorkerPrivate);
68 if (mIsPreventingShutdown) {
69 mWorkerPrivate->AssertIsNotPotentiallyLastGCCCRunning();
71 mWorkerPrivate->RemoveWorkerRef(this);
72 mWorkerPrivate = nullptr;
74 mHolding = false;
78 bool WorkerRef::HoldWorker(WorkerStatus aStatus) {
79 MOZ_ASSERT(mWorkerPrivate);
80 MOZ_ASSERT(!mHolding);
82 if (NS_WARN_IF(!mWorkerPrivate->AddWorkerRef(this, aStatus))) {
83 return false;
86 mHolding = true;
87 return true;
90 void WorkerRef::Notify() {
91 NS_ASSERT_OWNINGTHREAD(WorkerRef);
93 if (!mCallback) {
94 return;
97 MoveOnlyFunction<void()> callback = std::move(mCallback);
98 MOZ_ASSERT(!mCallback);
100 callback();
103 // ----------------------------------------------------------------------------
104 // WeakWorkerRef
106 /* static */
107 already_AddRefed<WeakWorkerRef> WeakWorkerRef::Create(
108 WorkerPrivate* aWorkerPrivate, MoveOnlyFunction<void()>&& aCallback) {
109 MOZ_ASSERT(aWorkerPrivate);
110 aWorkerPrivate->AssertIsOnWorkerThread();
112 RefPtr<WeakWorkerRef> ref = new WeakWorkerRef(aWorkerPrivate);
113 if (!ref->HoldWorker(Canceling)) {
114 return nullptr;
117 ref->mCallback = std::move(aCallback);
119 return ref.forget();
122 WeakWorkerRef::WeakWorkerRef(WorkerPrivate* aWorkerPrivate)
123 : WorkerRef(aWorkerPrivate, "WeakWorkerRef", false) {}
125 WeakWorkerRef::~WeakWorkerRef() = default;
127 void WeakWorkerRef::Notify() {
128 MOZ_ASSERT(mHolding);
129 MOZ_ASSERT(mWorkerPrivate);
131 // Notify could drop the last reference to this object. We must keep it alive
132 // in order to call ReleaseWorker() immediately after.
133 RefPtr<WeakWorkerRef> kungFuGrip = this;
135 WorkerRef::Notify();
136 ReleaseWorker();
139 WorkerPrivate* WeakWorkerRef::GetPrivate() const {
140 NS_ASSERT_OWNINGTHREAD(WeakWorkerRef);
141 return mWorkerPrivate;
144 WorkerPrivate* WeakWorkerRef::GetUnsafePrivate() const {
145 return mWorkerPrivate;
148 // ----------------------------------------------------------------------------
149 // StrongWorkerRef
151 /* static */
152 already_AddRefed<StrongWorkerRef> StrongWorkerRef::Create(
153 WorkerPrivate* const aWorkerPrivate, const char* const aName,
154 MoveOnlyFunction<void()>&& aCallback) {
155 if (RefPtr<StrongWorkerRef> ref =
156 CreateImpl(aWorkerPrivate, aName, Canceling)) {
157 ref->mCallback = std::move(aCallback);
158 return ref.forget();
160 return nullptr;
163 /* static */
164 already_AddRefed<StrongWorkerRef> StrongWorkerRef::CreateForcibly(
165 WorkerPrivate* const aWorkerPrivate, const char* const aName) {
166 return CreateImpl(aWorkerPrivate, aName, Killing);
169 /* static */
170 already_AddRefed<StrongWorkerRef> StrongWorkerRef::CreateImpl(
171 WorkerPrivate* const aWorkerPrivate, const char* const aName,
172 WorkerStatus const aFailStatus) {
173 MOZ_ASSERT(aWorkerPrivate);
174 MOZ_ASSERT(aName);
176 RefPtr<StrongWorkerRef> ref = new StrongWorkerRef(aWorkerPrivate, aName);
177 if (!ref->HoldWorker(aFailStatus)) {
178 return nullptr;
181 return ref.forget();
184 StrongWorkerRef::StrongWorkerRef(WorkerPrivate* aWorkerPrivate,
185 const char* aName)
186 : WorkerRef(aWorkerPrivate, aName, true) {}
188 StrongWorkerRef::~StrongWorkerRef() = default;
190 WorkerPrivate* StrongWorkerRef::Private() const {
191 NS_ASSERT_OWNINGTHREAD(StrongWorkerRef);
192 return mWorkerPrivate;
195 // ----------------------------------------------------------------------------
196 // ThreadSafeWorkerRef
198 ThreadSafeWorkerRef::ThreadSafeWorkerRef(StrongWorkerRef* aRef) : mRef(aRef) {
199 MOZ_ASSERT(aRef);
200 aRef->Private()->AssertIsOnWorkerThread();
203 ThreadSafeWorkerRef::~ThreadSafeWorkerRef() {
204 // Let's release the StrongWorkerRef on the correct thread.
205 if (!mRef->mWorkerPrivate->IsOnWorkerThread()) {
206 WorkerPrivate* workerPrivate = mRef->mWorkerPrivate;
207 RefPtr<ReleaseRefControlRunnable> r =
208 new ReleaseRefControlRunnable(workerPrivate, mRef.forget());
209 r->Dispatch();
210 return;
214 WorkerPrivate* ThreadSafeWorkerRef::Private() const {
215 return mRef->mWorkerPrivate;
218 // ----------------------------------------------------------------------------
219 // IPCWorkerRef
221 /* static */
222 already_AddRefed<IPCWorkerRef> IPCWorkerRef::Create(
223 WorkerPrivate* aWorkerPrivate, const char* aName,
224 MoveOnlyFunction<void()>&& aCallback) {
225 MOZ_ASSERT(aWorkerPrivate);
226 aWorkerPrivate->AssertIsOnWorkerThread();
228 RefPtr<IPCWorkerRef> ref = new IPCWorkerRef(aWorkerPrivate, aName);
229 if (!ref->HoldWorker(Canceling)) {
230 return nullptr;
233 ref->mCallback = std::move(aCallback);
235 return ref.forget();
238 IPCWorkerRef::IPCWorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName)
239 : WorkerRef(aWorkerPrivate, aName, false) {}
241 IPCWorkerRef::~IPCWorkerRef() = default;
243 WorkerPrivate* IPCWorkerRef::Private() const {
244 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
245 return mWorkerPrivate;
248 } // namespace mozilla::dom