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
, WorkerThreadUnchangedBusyCount
),
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
)
49 : mWorkerPrivate(aWorkerPrivate
),
51 mIsPreventingShutdown(aIsPreventingShutdown
),
53 MOZ_ASSERT(aWorkerPrivate
);
56 aWorkerPrivate
->AssertIsOnWorkerThread();
59 WorkerRef::~WorkerRef() {
60 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
64 void WorkerRef::ReleaseWorker() {
66 MOZ_ASSERT(mWorkerPrivate
);
68 mWorkerPrivate
->RemoveWorkerRef(this);
69 mWorkerPrivate
= nullptr;
75 bool WorkerRef::HoldWorker(WorkerStatus aStatus
) {
76 MOZ_ASSERT(mWorkerPrivate
);
77 MOZ_ASSERT(!mHolding
);
79 if (NS_WARN_IF(!mWorkerPrivate
->AddWorkerRef(this, aStatus
))) {
87 void WorkerRef::Notify() {
88 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
94 MoveOnlyFunction
<void()> callback
= std::move(mCallback
);
95 MOZ_ASSERT(!mCallback
);
100 // ----------------------------------------------------------------------------
104 already_AddRefed
<WeakWorkerRef
> WeakWorkerRef::Create(
105 WorkerPrivate
* aWorkerPrivate
, MoveOnlyFunction
<void()>&& aCallback
) {
106 MOZ_ASSERT(aWorkerPrivate
);
107 aWorkerPrivate
->AssertIsOnWorkerThread();
109 RefPtr
<WeakWorkerRef
> ref
= new WeakWorkerRef(aWorkerPrivate
);
110 if (!ref
->HoldWorker(Canceling
)) {
114 ref
->mCallback
= std::move(aCallback
);
119 WeakWorkerRef::WeakWorkerRef(WorkerPrivate
* aWorkerPrivate
)
120 : WorkerRef(aWorkerPrivate
, "WeakWorkerRef", false) {}
122 WeakWorkerRef::~WeakWorkerRef() = default;
124 void WeakWorkerRef::Notify() {
125 MOZ_ASSERT(mHolding
);
126 MOZ_ASSERT(mWorkerPrivate
);
128 // Notify could drop the last reference to this object. We must keep it alive
129 // in order to call ReleaseWorker() immediately after.
130 RefPtr
<WeakWorkerRef
> kungFuGrip
= this;
136 WorkerPrivate
* WeakWorkerRef::GetPrivate() const {
137 NS_ASSERT_OWNINGTHREAD(WeakWorkerRef
);
138 return mWorkerPrivate
;
141 WorkerPrivate
* WeakWorkerRef::GetUnsafePrivate() const {
142 return mWorkerPrivate
;
145 // ----------------------------------------------------------------------------
149 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::Create(
150 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
151 MoveOnlyFunction
<void()>&& aCallback
) {
152 if (RefPtr
<StrongWorkerRef
> ref
=
153 CreateImpl(aWorkerPrivate
, aName
, Canceling
)) {
154 ref
->mCallback
= std::move(aCallback
);
161 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateForcibly(
162 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
) {
163 return CreateImpl(aWorkerPrivate
, aName
, Killing
);
167 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateImpl(
168 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
169 WorkerStatus
const aFailStatus
) {
170 MOZ_ASSERT(aWorkerPrivate
);
173 RefPtr
<StrongWorkerRef
> ref
= new StrongWorkerRef(aWorkerPrivate
, aName
);
174 if (!ref
->HoldWorker(aFailStatus
)) {
181 StrongWorkerRef::StrongWorkerRef(WorkerPrivate
* aWorkerPrivate
,
183 : WorkerRef(aWorkerPrivate
, aName
, true) {}
185 StrongWorkerRef::~StrongWorkerRef() = default;
187 WorkerPrivate
* StrongWorkerRef::Private() const {
188 NS_ASSERT_OWNINGTHREAD(StrongWorkerRef
);
189 return mWorkerPrivate
;
192 // ----------------------------------------------------------------------------
193 // ThreadSafeWorkerRef
195 ThreadSafeWorkerRef::ThreadSafeWorkerRef(StrongWorkerRef
* aRef
) : mRef(aRef
) {
197 aRef
->Private()->AssertIsOnWorkerThread();
200 ThreadSafeWorkerRef::~ThreadSafeWorkerRef() {
201 // Let's release the StrongWorkerRef on the correct thread.
202 if (!mRef
->mWorkerPrivate
->IsOnWorkerThread()) {
203 WorkerPrivate
* workerPrivate
= mRef
->mWorkerPrivate
;
204 RefPtr
<ReleaseRefControlRunnable
> r
=
205 new ReleaseRefControlRunnable(workerPrivate
, mRef
.forget());
211 WorkerPrivate
* ThreadSafeWorkerRef::Private() const {
212 return mRef
->mWorkerPrivate
;
215 // ----------------------------------------------------------------------------
219 already_AddRefed
<IPCWorkerRef
> IPCWorkerRef::Create(
220 WorkerPrivate
* aWorkerPrivate
, const char* aName
,
221 MoveOnlyFunction
<void()>&& aCallback
) {
222 MOZ_ASSERT(aWorkerPrivate
);
223 aWorkerPrivate
->AssertIsOnWorkerThread();
225 RefPtr
<IPCWorkerRef
> ref
= new IPCWorkerRef(aWorkerPrivate
, aName
);
226 if (!ref
->HoldWorker(Canceling
)) {
230 ref
->mCallback
= std::move(aCallback
);
235 IPCWorkerRef::IPCWorkerRef(WorkerPrivate
* aWorkerPrivate
, const char* aName
)
236 : WorkerRef(aWorkerPrivate
, aName
, false) {}
238 IPCWorkerRef::~IPCWorkerRef() = default;
240 WorkerPrivate
* IPCWorkerRef::Private() const {
241 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef
);
242 return mWorkerPrivate
;
245 } // namespace mozilla::dom