Bug 1879774 [wpt PR 44524] - WebKit export: Implement field-sizing support for input...
[gecko.git] / dom / workers / WorkerRef.cpp
blob9ba9841041226eb28c4e5c207035ea442b1d12fe
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, "ReleaseRefControlRunnable",
24 WorkerThread),
25 mRef(std::move(aRef)) {
26 MOZ_ASSERT(mRef);
29 bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { return true; }
31 void PostDispatch(WorkerPrivate* aWorkerPrivate,
32 bool aDispatchResult) override {}
34 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
35 mRef = nullptr;
36 return true;
39 private:
40 RefPtr<StrongWorkerRef> mRef;
43 } // namespace
45 // ----------------------------------------------------------------------------
46 // WorkerRef
48 WorkerRef::WorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName,
49 bool aIsPreventingShutdown)
51 #ifdef DEBUG
52 mDebugMutex("WorkerRef"),
53 #endif
54 mWorkerPrivate(aWorkerPrivate),
55 mName(aName),
56 mIsPreventingShutdown(aIsPreventingShutdown),
57 mHolding(false) {
58 MOZ_ASSERT(aWorkerPrivate);
59 MOZ_ASSERT(aName);
61 aWorkerPrivate->AssertIsOnWorkerThread();
64 WorkerRef::~WorkerRef() {
65 NS_ASSERT_OWNINGTHREAD(WorkerRef);
66 ReleaseWorker();
69 void WorkerRef::ReleaseWorker() {
70 if (mHolding) {
71 MOZ_ASSERT(mWorkerPrivate);
73 if (mIsPreventingShutdown) {
74 mWorkerPrivate->AssertIsNotPotentiallyLastGCCCRunning();
76 mWorkerPrivate->RemoveWorkerRef(this);
77 mWorkerPrivate = nullptr;
79 mHolding = false;
83 bool WorkerRef::HoldWorker(WorkerStatus aStatus) {
84 MOZ_ASSERT(mWorkerPrivate);
85 MOZ_ASSERT(!mHolding);
87 if (NS_WARN_IF(!mWorkerPrivate->AddWorkerRef(this, aStatus))) {
88 return false;
91 mHolding = true;
92 return true;
95 void WorkerRef::Notify() {
96 NS_ASSERT_OWNINGTHREAD(WorkerRef);
98 if (!mCallback) {
99 return;
102 MoveOnlyFunction<void()> callback = std::move(mCallback);
103 MOZ_ASSERT(!mCallback);
105 callback();
108 // ----------------------------------------------------------------------------
109 // WeakWorkerRef
111 /* static */
112 already_AddRefed<WeakWorkerRef> WeakWorkerRef::Create(
113 WorkerPrivate* aWorkerPrivate, MoveOnlyFunction<void()>&& aCallback) {
114 MOZ_ASSERT(aWorkerPrivate);
115 aWorkerPrivate->AssertIsOnWorkerThread();
117 RefPtr<WeakWorkerRef> ref = new WeakWorkerRef(aWorkerPrivate);
118 if (!ref->HoldWorker(Canceling)) {
119 return nullptr;
122 ref->mCallback = std::move(aCallback);
124 return ref.forget();
127 WeakWorkerRef::WeakWorkerRef(WorkerPrivate* aWorkerPrivate)
128 : WorkerRef(aWorkerPrivate, "WeakWorkerRef", false) {}
130 WeakWorkerRef::~WeakWorkerRef() = default;
132 void WeakWorkerRef::Notify() {
133 MOZ_ASSERT(mHolding);
134 MOZ_ASSERT(mWorkerPrivate);
136 // Notify could drop the last reference to this object. We must keep it alive
137 // in order to call ReleaseWorker() immediately after.
138 RefPtr<WeakWorkerRef> kungFuGrip = this;
140 WorkerRef::Notify();
141 ReleaseWorker();
144 WorkerPrivate* WeakWorkerRef::GetPrivate() const {
145 NS_ASSERT_OWNINGTHREAD(WeakWorkerRef);
146 return mWorkerPrivate;
149 WorkerPrivate* WeakWorkerRef::GetUnsafePrivate() const {
150 return mWorkerPrivate;
153 // ----------------------------------------------------------------------------
154 // StrongWorkerRef
156 /* static */
157 already_AddRefed<StrongWorkerRef> StrongWorkerRef::Create(
158 WorkerPrivate* const aWorkerPrivate, const char* const aName,
159 MoveOnlyFunction<void()>&& aCallback) {
160 if (RefPtr<StrongWorkerRef> ref =
161 CreateImpl(aWorkerPrivate, aName, Canceling)) {
162 ref->mCallback = std::move(aCallback);
163 return ref.forget();
165 return nullptr;
168 /* static */
169 already_AddRefed<StrongWorkerRef> StrongWorkerRef::CreateForcibly(
170 WorkerPrivate* const aWorkerPrivate, const char* const aName) {
171 return CreateImpl(aWorkerPrivate, aName, Killing);
174 /* static */
175 already_AddRefed<StrongWorkerRef> StrongWorkerRef::CreateImpl(
176 WorkerPrivate* const aWorkerPrivate, const char* const aName,
177 WorkerStatus const aFailStatus) {
178 MOZ_ASSERT(aWorkerPrivate);
179 MOZ_ASSERT(aName);
181 RefPtr<StrongWorkerRef> ref = new StrongWorkerRef(aWorkerPrivate, aName);
182 if (!ref->HoldWorker(aFailStatus)) {
183 return nullptr;
186 return ref.forget();
189 StrongWorkerRef::StrongWorkerRef(WorkerPrivate* aWorkerPrivate,
190 const char* aName)
191 : WorkerRef(aWorkerPrivate, aName, true) {}
193 StrongWorkerRef::~StrongWorkerRef() = default;
195 WorkerPrivate* StrongWorkerRef::Private() const {
196 NS_ASSERT_OWNINGTHREAD(StrongWorkerRef);
197 return mWorkerPrivate;
200 // ----------------------------------------------------------------------------
201 // ThreadSafeWorkerRef
203 ThreadSafeWorkerRef::ThreadSafeWorkerRef(StrongWorkerRef* aRef) : mRef(aRef) {
204 MOZ_ASSERT(aRef);
205 aRef->Private()->AssertIsOnWorkerThread();
208 ThreadSafeWorkerRef::~ThreadSafeWorkerRef() {
209 // Let's release the StrongWorkerRef on the correct thread.
210 if (!mRef->mWorkerPrivate->IsOnWorkerThread()) {
211 WorkerPrivate* workerPrivate = mRef->mWorkerPrivate;
212 RefPtr<ReleaseRefControlRunnable> r =
213 new ReleaseRefControlRunnable(workerPrivate, mRef.forget());
214 r->Dispatch();
215 return;
219 WorkerPrivate* ThreadSafeWorkerRef::Private() const {
220 return mRef->mWorkerPrivate;
223 // ----------------------------------------------------------------------------
224 // IPCWorkerRef
226 /* static */
227 already_AddRefed<IPCWorkerRef> IPCWorkerRef::Create(
228 WorkerPrivate* aWorkerPrivate, const char* aName,
229 MoveOnlyFunction<void()>&& aCallback) {
230 MOZ_ASSERT(aWorkerPrivate);
231 aWorkerPrivate->AssertIsOnWorkerThread();
233 RefPtr<IPCWorkerRef> ref = new IPCWorkerRef(aWorkerPrivate, aName);
234 if (!ref->HoldWorker(Canceling)) {
235 return nullptr;
237 ref->SetActorCount(1);
238 ref->mCallback = std::move(aCallback);
240 return ref.forget();
243 IPCWorkerRef::IPCWorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName)
244 : WorkerRef(aWorkerPrivate, aName, false), mActorCount(0) {}
246 IPCWorkerRef::~IPCWorkerRef() {
247 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
248 // explicit type convertion to avoid undefined behavior of uint32_t overflow.
249 mWorkerPrivate->AdjustNonblockingCCBackgroundActorCount(
250 (int32_t)-mActorCount);
251 ReleaseWorker();
254 WorkerPrivate* IPCWorkerRef::Private() const {
255 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
256 return mWorkerPrivate;
259 void IPCWorkerRef::SetActorCount(uint32_t aCount) {
260 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
261 // explicit type convertion to avoid undefined behavior of uint32_t overflow.
262 mWorkerPrivate->AdjustNonblockingCCBackgroundActorCount((int32_t)aCount -
263 (int32_t)mActorCount);
264 mActorCount = aCount;
267 } // namespace mozilla::dom