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 if (mIsPreventingShutdown
) {
69 mWorkerPrivate
->AssertIsNotPotentiallyLastGCCCRunning();
71 mWorkerPrivate
->RemoveWorkerRef(this);
72 mWorkerPrivate
= nullptr;
78 bool WorkerRef::HoldWorker(WorkerStatus aStatus
) {
79 MOZ_ASSERT(mWorkerPrivate
);
80 MOZ_ASSERT(!mHolding
);
82 if (NS_WARN_IF(!mWorkerPrivate
->AddWorkerRef(this, aStatus
))) {
90 void WorkerRef::Notify() {
91 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
97 MoveOnlyFunction
<void()> callback
= std::move(mCallback
);
98 MOZ_ASSERT(!mCallback
);
103 // ----------------------------------------------------------------------------
107 already_AddRefed
<WeakWorkerRef
> WeakWorkerRef::Create(
108 WorkerPrivate
* aWorkerPrivate
, MoveOnlyFunction
<void()>&& aCallback
) {
109 MOZ_ASSERT(aWorkerPrivate
);
110 aWorkerPrivate
->AssertIsOnWorkerThread();
112 RefPtr
<WeakWorkerRef
> ref
= new WeakWorkerRef(aWorkerPrivate
);
113 if (!ref
->HoldWorker(Canceling
)) {
117 ref
->mCallback
= std::move(aCallback
);
122 WeakWorkerRef::WeakWorkerRef(WorkerPrivate
* aWorkerPrivate
)
123 : WorkerRef(aWorkerPrivate
, "WeakWorkerRef", false) {}
125 WeakWorkerRef::~WeakWorkerRef() = default;
127 void WeakWorkerRef::Notify() {
128 MOZ_ASSERT(mHolding
);
129 MOZ_ASSERT(mWorkerPrivate
);
131 // Notify could drop the last reference to this object. We must keep it alive
132 // in order to call ReleaseWorker() immediately after.
133 RefPtr
<WeakWorkerRef
> kungFuGrip
= this;
139 WorkerPrivate
* WeakWorkerRef::GetPrivate() const {
140 NS_ASSERT_OWNINGTHREAD(WeakWorkerRef
);
141 return mWorkerPrivate
;
144 WorkerPrivate
* WeakWorkerRef::GetUnsafePrivate() const {
145 return mWorkerPrivate
;
148 // ----------------------------------------------------------------------------
152 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::Create(
153 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
154 MoveOnlyFunction
<void()>&& aCallback
) {
155 if (RefPtr
<StrongWorkerRef
> ref
=
156 CreateImpl(aWorkerPrivate
, aName
, Canceling
)) {
157 ref
->mCallback
= std::move(aCallback
);
164 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateForcibly(
165 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
) {
166 return CreateImpl(aWorkerPrivate
, aName
, Killing
);
170 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateImpl(
171 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
172 WorkerStatus
const aFailStatus
) {
173 MOZ_ASSERT(aWorkerPrivate
);
176 RefPtr
<StrongWorkerRef
> ref
= new StrongWorkerRef(aWorkerPrivate
, aName
);
177 if (!ref
->HoldWorker(aFailStatus
)) {
184 StrongWorkerRef::StrongWorkerRef(WorkerPrivate
* aWorkerPrivate
,
186 : WorkerRef(aWorkerPrivate
, aName
, true) {}
188 StrongWorkerRef::~StrongWorkerRef() = default;
190 WorkerPrivate
* StrongWorkerRef::Private() const {
191 NS_ASSERT_OWNINGTHREAD(StrongWorkerRef
);
192 return mWorkerPrivate
;
195 // ----------------------------------------------------------------------------
196 // ThreadSafeWorkerRef
198 ThreadSafeWorkerRef::ThreadSafeWorkerRef(StrongWorkerRef
* aRef
) : mRef(aRef
) {
200 aRef
->Private()->AssertIsOnWorkerThread();
203 ThreadSafeWorkerRef::~ThreadSafeWorkerRef() {
204 // Let's release the StrongWorkerRef on the correct thread.
205 if (!mRef
->mWorkerPrivate
->IsOnWorkerThread()) {
206 WorkerPrivate
* workerPrivate
= mRef
->mWorkerPrivate
;
207 RefPtr
<ReleaseRefControlRunnable
> r
=
208 new ReleaseRefControlRunnable(workerPrivate
, mRef
.forget());
214 WorkerPrivate
* ThreadSafeWorkerRef::Private() const {
215 return mRef
->mWorkerPrivate
;
218 // ----------------------------------------------------------------------------
222 already_AddRefed
<IPCWorkerRef
> IPCWorkerRef::Create(
223 WorkerPrivate
* aWorkerPrivate
, const char* aName
,
224 MoveOnlyFunction
<void()>&& aCallback
) {
225 MOZ_ASSERT(aWorkerPrivate
);
226 aWorkerPrivate
->AssertIsOnWorkerThread();
228 RefPtr
<IPCWorkerRef
> ref
= new IPCWorkerRef(aWorkerPrivate
, aName
);
229 if (!ref
->HoldWorker(Canceling
)) {
233 ref
->mCallback
= std::move(aCallback
);
238 IPCWorkerRef::IPCWorkerRef(WorkerPrivate
* aWorkerPrivate
, const char* aName
)
239 : WorkerRef(aWorkerPrivate
, aName
, false) {}
241 IPCWorkerRef::~IPCWorkerRef() = default;
243 WorkerPrivate
* IPCWorkerRef::Private() const {
244 NS_ASSERT_OWNINGTHREAD(IPCWorkerRef
);
245 return mWorkerPrivate
;
248 } // namespace mozilla::dom