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"
18 // This runnable is used to release the StrongWorkerRef on the worker thread
19 // when a ThreadSafeWorkerRef is released.
20 class ReleaseRefControlRunnable final
: public WorkerControlRunnable
{
22 ReleaseRefControlRunnable(WorkerPrivate
* aWorkerPrivate
,
23 already_AddRefed
<StrongWorkerRef
> aRef
)
24 : WorkerControlRunnable(aWorkerPrivate
, WorkerThreadUnchangedBusyCount
),
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
)
50 : mWorkerPrivate(aWorkerPrivate
),
52 mIsPreventingShutdown(aIsPreventingShutdown
),
54 MOZ_ASSERT(aWorkerPrivate
);
57 aWorkerPrivate
->AssertIsOnWorkerThread();
60 WorkerRef::~WorkerRef() {
61 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
65 void WorkerRef::ReleaseWorker() {
67 MOZ_ASSERT(mWorkerPrivate
);
69 mWorkerPrivate
->RemoveWorkerRef(this);
70 mWorkerPrivate
= nullptr;
76 bool WorkerRef::HoldWorker(WorkerStatus aStatus
) {
77 MOZ_ASSERT(mWorkerPrivate
);
78 MOZ_ASSERT(!mHolding
);
80 if (NS_WARN_IF(!mWorkerPrivate
->AddWorkerRef(this, aStatus
))) {
88 void WorkerRef::Notify() {
89 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
95 std::function
<void()> callback
= std::move(mCallback
);
96 MOZ_ASSERT(!mCallback
);
101 // ----------------------------------------------------------------------------
105 already_AddRefed
<WeakWorkerRef
> WeakWorkerRef::Create(
106 WorkerPrivate
* aWorkerPrivate
, std::function
<void()>&& aCallback
) {
107 MOZ_ASSERT(aWorkerPrivate
);
108 aWorkerPrivate
->AssertIsOnWorkerThread();
110 RefPtr
<WeakWorkerRef
> ref
= new WeakWorkerRef(aWorkerPrivate
);
111 if (!ref
->HoldWorker(Canceling
)) {
115 ref
->mCallback
= std::move(aCallback
);
120 WeakWorkerRef::WeakWorkerRef(WorkerPrivate
* aWorkerPrivate
)
121 : WorkerRef(aWorkerPrivate
, "WeakWorkerRef", false) {}
123 WeakWorkerRef::~WeakWorkerRef() = default;
125 void WeakWorkerRef::Notify() {
126 MOZ_ASSERT(mHolding
);
127 MOZ_ASSERT(mWorkerPrivate
);
129 // Notify could drop the last reference to this object. We must keep it alive
130 // in order to call ReleaseWorker() immediately after.
131 RefPtr
<WeakWorkerRef
> kungFuGrip
= this;
137 WorkerPrivate
* WeakWorkerRef::GetPrivate() const {
138 NS_ASSERT_OWNINGTHREAD(WeakWorkerRef
);
139 return mWorkerPrivate
;
142 WorkerPrivate
* WeakWorkerRef::GetUnsafePrivate() const {
143 return mWorkerPrivate
;
146 // ----------------------------------------------------------------------------
150 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::Create(
151 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
152 std::function
<void()>&& aCallback
) {
153 if (RefPtr
<StrongWorkerRef
> ref
=
154 CreateImpl(aWorkerPrivate
, aName
, Canceling
)) {
155 ref
->mCallback
= std::move(aCallback
);
162 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateForcibly(
163 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
) {
164 return CreateImpl(aWorkerPrivate
, aName
, Killing
);
168 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateImpl(
169 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
170 WorkerStatus
const aFailStatus
) {
171 MOZ_ASSERT(aWorkerPrivate
);
174 RefPtr
<StrongWorkerRef
> ref
= new StrongWorkerRef(aWorkerPrivate
, aName
);
175 if (!ref
->HoldWorker(aFailStatus
)) {
182 StrongWorkerRef::StrongWorkerRef(WorkerPrivate
* aWorkerPrivate
,
184 : WorkerRef(aWorkerPrivate
, aName
, true) {}
186 StrongWorkerRef::~StrongWorkerRef() = default;
188 WorkerPrivate
* StrongWorkerRef::Private() const {
189 NS_ASSERT_OWNINGTHREAD(StrongWorkerRef
);
190 return mWorkerPrivate
;
193 // ----------------------------------------------------------------------------
194 // ThreadSafeWorkerRef
196 ThreadSafeWorkerRef::ThreadSafeWorkerRef(StrongWorkerRef
* aRef
) : mRef(aRef
) {
198 aRef
->Private()->AssertIsOnWorkerThread();
201 ThreadSafeWorkerRef::~ThreadSafeWorkerRef() {
202 // Let's release the StrongWorkerRef on the correct thread.
203 if (!mRef
->mWorkerPrivate
->IsOnWorkerThread()) {
204 WorkerPrivate
* workerPrivate
= mRef
->mWorkerPrivate
;
205 RefPtr
<ReleaseRefControlRunnable
> r
=
206 new ReleaseRefControlRunnable(workerPrivate
, mRef
.forget());
212 WorkerPrivate
* ThreadSafeWorkerRef::Private() const {
213 return mRef
->mWorkerPrivate
;
216 // ----------------------------------------------------------------------------
220 already_AddRefed
<IPCWorkerRef
> IPCWorkerRef::Create(
221 WorkerPrivate
* aWorkerPrivate
, const char* aName
,
222 std::function
<void()>&& aCallback
) {
223 MOZ_ASSERT(aWorkerPrivate
);
224 aWorkerPrivate
->AssertIsOnWorkerThread();
226 RefPtr
<IPCWorkerRef
> ref
= new IPCWorkerRef(aWorkerPrivate
, aName
);
227 if (!ref
->HoldWorker(Canceling
)) {
231 ref
->mCallback
= std::move(aCallback
);
236 IPCWorkerRef::IPCWorkerRef(WorkerPrivate
* aWorkerPrivate
, const char* aName
)
237 : WorkerRef(aWorkerPrivate
, aName
, false) {}
239 IPCWorkerRef::~IPCWorkerRef() = default;
241 WorkerPrivate
* IPCWorkerRef::Private() const {
242 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef
);
243 return mWorkerPrivate
;
247 } // namespace mozilla