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(aWorkerPrivate
, "ReleaseRefControlRunnable",
25 mRef(std::move(aRef
)) {
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
{
40 RefPtr
<StrongWorkerRef
> mRef
;
45 // ----------------------------------------------------------------------------
48 WorkerRef::WorkerRef(WorkerPrivate
* aWorkerPrivate
, const char* aName
,
49 bool aIsPreventingShutdown
)
52 mDebugMutex("WorkerRef"),
54 mWorkerPrivate(aWorkerPrivate
),
56 mIsPreventingShutdown(aIsPreventingShutdown
),
58 MOZ_ASSERT(aWorkerPrivate
);
61 aWorkerPrivate
->AssertIsOnWorkerThread();
64 WorkerRef::~WorkerRef() {
65 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
69 void WorkerRef::ReleaseWorker() {
71 MOZ_ASSERT(mWorkerPrivate
);
73 if (mIsPreventingShutdown
) {
74 mWorkerPrivate
->AssertIsNotPotentiallyLastGCCCRunning();
76 mWorkerPrivate
->RemoveWorkerRef(this);
77 mWorkerPrivate
= nullptr;
83 bool WorkerRef::HoldWorker(WorkerStatus aStatus
) {
84 MOZ_ASSERT(mWorkerPrivate
);
85 MOZ_ASSERT(!mHolding
);
87 if (NS_WARN_IF(!mWorkerPrivate
->AddWorkerRef(this, aStatus
))) {
95 void WorkerRef::Notify() {
96 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
102 MoveOnlyFunction
<void()> callback
= std::move(mCallback
);
103 MOZ_ASSERT(!mCallback
);
108 // ----------------------------------------------------------------------------
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
)) {
122 ref
->mCallback
= std::move(aCallback
);
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;
144 WorkerPrivate
* WeakWorkerRef::GetPrivate() const {
145 NS_ASSERT_OWNINGTHREAD(WeakWorkerRef
);
146 return mWorkerPrivate
;
149 WorkerPrivate
* WeakWorkerRef::GetUnsafePrivate() const {
150 return mWorkerPrivate
;
153 // ----------------------------------------------------------------------------
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
);
169 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateForcibly(
170 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
) {
171 return CreateImpl(aWorkerPrivate
, aName
, Killing
);
175 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateImpl(
176 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
177 WorkerStatus
const aFailStatus
) {
178 MOZ_ASSERT(aWorkerPrivate
);
181 RefPtr
<StrongWorkerRef
> ref
= new StrongWorkerRef(aWorkerPrivate
, aName
);
182 if (!ref
->HoldWorker(aFailStatus
)) {
189 StrongWorkerRef::StrongWorkerRef(WorkerPrivate
* aWorkerPrivate
,
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
) {
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());
219 WorkerPrivate
* ThreadSafeWorkerRef::Private() const {
220 return mRef
->mWorkerPrivate
;
223 // ----------------------------------------------------------------------------
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
)) {
237 ref
->SetActorCount(1);
238 ref
->mCallback
= std::move(aCallback
);
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
);
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