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"
10 #include "WorkerRunnable.h"
11 #include "WorkerPrivate.h"
13 namespace mozilla::dom
{
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
{
21 ReleaseRefControlRunnable(WorkerPrivate
* aWorkerPrivate
,
22 already_AddRefed
<StrongWorkerRef
> aRef
)
23 : WorkerControlRunnable("ReleaseRefControlRunnable"),
24 mRef(std::move(aRef
)) {
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
{
39 RefPtr
<StrongWorkerRef
> mRef
;
44 // ----------------------------------------------------------------------------
47 WorkerRef::WorkerRef(WorkerPrivate
* aWorkerPrivate
, const char* aName
,
48 bool aIsPreventingShutdown
)
51 mDebugMutex("WorkerRef"),
53 mWorkerPrivate(aWorkerPrivate
),
55 mIsPreventingShutdown(aIsPreventingShutdown
),
57 MOZ_ASSERT(aWorkerPrivate
);
60 aWorkerPrivate
->AssertIsOnWorkerThread();
63 WorkerRef::~WorkerRef() {
64 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
68 void WorkerRef::ReleaseWorker() {
70 MOZ_ASSERT(mWorkerPrivate
);
72 if (mIsPreventingShutdown
) {
73 mWorkerPrivate
->AssertIsNotPotentiallyLastGCCCRunning();
75 mWorkerPrivate
->RemoveWorkerRef(this);
76 mWorkerPrivate
= nullptr;
82 bool WorkerRef::HoldWorker(WorkerStatus aStatus
) {
83 MOZ_ASSERT(mWorkerPrivate
);
84 MOZ_ASSERT(!mHolding
);
86 if (NS_WARN_IF(!mWorkerPrivate
->AddWorkerRef(this, aStatus
))) {
94 void WorkerRef::Notify() {
95 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
101 MoveOnlyFunction
<void()> callback
= std::move(mCallback
);
102 MOZ_ASSERT(!mCallback
);
107 // ----------------------------------------------------------------------------
111 already_AddRefed
<WeakWorkerRef
> WeakWorkerRef::Create(
112 WorkerPrivate
* aWorkerPrivate
, MoveOnlyFunction
<void()>&& aCallback
) {
113 MOZ_ASSERT(aWorkerPrivate
);
114 aWorkerPrivate
->AssertIsOnWorkerThread();
116 RefPtr
<WeakWorkerRef
> ref
= new WeakWorkerRef(aWorkerPrivate
);
117 if (!ref
->HoldWorker(Canceling
)) {
121 ref
->mCallback
= std::move(aCallback
);
126 WeakWorkerRef::WeakWorkerRef(WorkerPrivate
* aWorkerPrivate
)
127 : WorkerRef(aWorkerPrivate
, "WeakWorkerRef", false) {}
129 WeakWorkerRef::~WeakWorkerRef() = default;
131 void WeakWorkerRef::Notify() {
132 MOZ_ASSERT(mHolding
);
133 MOZ_ASSERT(mWorkerPrivate
);
135 // Notify could drop the last reference to this object. We must keep it alive
136 // in order to call ReleaseWorker() immediately after.
137 RefPtr
<WeakWorkerRef
> kungFuGrip
= this;
143 WorkerPrivate
* WeakWorkerRef::GetPrivate() const {
144 NS_ASSERT_OWNINGTHREAD(WeakWorkerRef
);
145 return mWorkerPrivate
;
148 WorkerPrivate
* WeakWorkerRef::GetUnsafePrivate() const {
149 return mWorkerPrivate
;
152 // ----------------------------------------------------------------------------
156 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::Create(
157 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
158 MoveOnlyFunction
<void()>&& aCallback
) {
159 if (RefPtr
<StrongWorkerRef
> ref
=
160 CreateImpl(aWorkerPrivate
, aName
, Canceling
)) {
161 ref
->mCallback
= std::move(aCallback
);
168 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateForcibly(
169 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
) {
170 return CreateImpl(aWorkerPrivate
, aName
, Killing
);
174 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateImpl(
175 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
176 WorkerStatus
const aFailStatus
) {
177 MOZ_ASSERT(aWorkerPrivate
);
180 RefPtr
<StrongWorkerRef
> ref
= new StrongWorkerRef(aWorkerPrivate
, aName
);
181 if (!ref
->HoldWorker(aFailStatus
)) {
188 StrongWorkerRef::StrongWorkerRef(WorkerPrivate
* aWorkerPrivate
,
190 : WorkerRef(aWorkerPrivate
, aName
, true) {}
192 StrongWorkerRef::~StrongWorkerRef() = default;
194 WorkerPrivate
* StrongWorkerRef::Private() const {
195 NS_ASSERT_OWNINGTHREAD(StrongWorkerRef
);
196 return mWorkerPrivate
;
199 // ----------------------------------------------------------------------------
200 // ThreadSafeWorkerRef
202 ThreadSafeWorkerRef::ThreadSafeWorkerRef(StrongWorkerRef
* aRef
) : mRef(aRef
) {
204 aRef
->Private()->AssertIsOnWorkerThread();
207 ThreadSafeWorkerRef::~ThreadSafeWorkerRef() {
208 // Let's release the StrongWorkerRef on the correct thread.
209 if (!mRef
->mWorkerPrivate
->IsOnWorkerThread()) {
210 WorkerPrivate
* workerPrivate
= mRef
->mWorkerPrivate
;
211 RefPtr
<ReleaseRefControlRunnable
> r
=
212 new ReleaseRefControlRunnable(workerPrivate
, mRef
.forget());
213 r
->Dispatch(workerPrivate
);
218 WorkerPrivate
* ThreadSafeWorkerRef::Private() const {
219 return mRef
->mWorkerPrivate
;
222 // ----------------------------------------------------------------------------
226 already_AddRefed
<IPCWorkerRef
> IPCWorkerRef::Create(
227 WorkerPrivate
* aWorkerPrivate
, const char* aName
,
228 MoveOnlyFunction
<void()>&& aCallback
) {
229 MOZ_ASSERT(aWorkerPrivate
);
230 aWorkerPrivate
->AssertIsOnWorkerThread();
232 RefPtr
<IPCWorkerRef
> ref
= new IPCWorkerRef(aWorkerPrivate
, aName
);
233 if (!ref
->HoldWorker(Canceling
)) {
236 ref
->SetActorCount(1);
237 ref
->mCallback
= std::move(aCallback
);
242 IPCWorkerRef::IPCWorkerRef(WorkerPrivate
* aWorkerPrivate
, const char* aName
)
243 : WorkerRef(aWorkerPrivate
, aName
, false), mActorCount(0) {}
245 IPCWorkerRef::~IPCWorkerRef() {
246 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef
);
247 // explicit type convertion to avoid undefined behavior of uint32_t overflow.
248 mWorkerPrivate
->AdjustNonblockingCCBackgroundActorCount(
249 (int32_t)-mActorCount
);
253 WorkerPrivate
* IPCWorkerRef::Private() const {
254 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef
);
255 return mWorkerPrivate
;
258 void IPCWorkerRef::SetActorCount(uint32_t aCount
) {
259 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef
);
260 // explicit type convertion to avoid undefined behavior of uint32_t overflow.
261 mWorkerPrivate
->AdjustNonblockingCCBackgroundActorCount((int32_t)aCount
-
262 (int32_t)mActorCount
);
263 mActorCount
= aCount
;
266 } // namespace mozilla::dom