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/. */
9 #include "mozilla/Unused.h"
10 #include "WorkerHolder.h"
11 #include "WorkerRunnable.h"
12 #include "WorkerPrivate.h"
19 // This runnable is used to release the StrongWorkerRef on the worker thread
20 // when a ThreadSafeWorkerRef is released.
21 class ReleaseRefControlRunnable final
: public WorkerControlRunnable
{
23 ReleaseRefControlRunnable(WorkerPrivate
* aWorkerPrivate
,
24 already_AddRefed
<StrongWorkerRef
> aRef
)
25 : WorkerControlRunnable(aWorkerPrivate
, WorkerThreadUnchangedBusyCount
),
26 mRef(std::move(aRef
)) {
30 bool PreDispatch(WorkerPrivate
* aWorkerPrivate
) override
{ return true; }
32 void PostDispatch(WorkerPrivate
* aWorkerPrivate
,
33 bool aDispatchResult
) override
{}
35 bool WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
) override
{
41 RefPtr
<StrongWorkerRef
> mRef
;
46 // ----------------------------------------------------------------------------
49 class WorkerRef::Holder final
: public mozilla::dom::WorkerHolder
{
51 Holder(const char* aName
, WorkerRef
* aWorkerRef
, Behavior aBehavior
)
52 : mozilla::dom::WorkerHolder(aName
, aBehavior
), mWorkerRef(aWorkerRef
) {}
54 bool Notify(WorkerStatus aStatus
) override
{
55 MOZ_ASSERT(mWorkerRef
);
57 if (aStatus
< Canceling
) {
61 // Let's keep this object alive for the whole Notify() execution.
62 RefPtr
<WorkerRef
> workerRef
;
63 workerRef
= mWorkerRef
;
70 WorkerRef
* mWorkerRef
;
73 // ----------------------------------------------------------------------------
76 WorkerRef::WorkerRef(WorkerPrivate
* aWorkerPrivate
)
77 : mWorkerPrivate(aWorkerPrivate
) {
78 MOZ_ASSERT(aWorkerPrivate
);
79 aWorkerPrivate
->AssertIsOnWorkerThread();
82 WorkerRef::~WorkerRef() { NS_ASSERT_OWNINGTHREAD(WorkerRef
); }
84 void WorkerRef::Notify() {
86 NS_ASSERT_OWNINGTHREAD(WorkerRef
);
92 std::function
<void()> callback
= std::move(mCallback
);
93 MOZ_ASSERT(!mCallback
);
98 // ----------------------------------------------------------------------------
102 already_AddRefed
<WeakWorkerRef
> WeakWorkerRef::Create(
103 WorkerPrivate
* aWorkerPrivate
, std::function
<void()>&& aCallback
) {
104 MOZ_ASSERT(aWorkerPrivate
);
105 aWorkerPrivate
->AssertIsOnWorkerThread();
107 RefPtr
<WeakWorkerRef
> ref
= new WeakWorkerRef(aWorkerPrivate
);
109 // This holder doesn't keep the worker alive.
110 UniquePtr
<Holder
> holder(new Holder("WeakWorkerRef::Holder", ref
,
111 WorkerHolder::AllowIdleShutdownStart
));
112 if (NS_WARN_IF(!holder
->HoldWorker(aWorkerPrivate
, Canceling
))) {
116 ref
->mHolder
= std::move(holder
);
117 ref
->mCallback
= std::move(aCallback
);
122 WeakWorkerRef::WeakWorkerRef(WorkerPrivate
* aWorkerPrivate
)
123 : WorkerRef(aWorkerPrivate
) {}
125 WeakWorkerRef::~WeakWorkerRef() = default;
127 void WeakWorkerRef::Notify() {
131 mWorkerPrivate
= nullptr;
134 WorkerPrivate
* WeakWorkerRef::GetPrivate() const {
135 NS_ASSERT_OWNINGTHREAD(WeakWorkerRef
);
136 return mWorkerPrivate
;
139 WorkerPrivate
* WeakWorkerRef::GetUnsafePrivate() const {
140 return mWorkerPrivate
;
143 // ----------------------------------------------------------------------------
147 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::Create(
148 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
149 std::function
<void()>&& aCallback
) {
150 if (RefPtr
<StrongWorkerRef
> ref
=
151 CreateImpl(aWorkerPrivate
, aName
, Canceling
)) {
152 ref
->mCallback
= std::move(aCallback
);
159 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateForcibly(
160 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
) {
161 return CreateImpl(aWorkerPrivate
, aName
, Killing
);
165 already_AddRefed
<StrongWorkerRef
> StrongWorkerRef::CreateImpl(
166 WorkerPrivate
* const aWorkerPrivate
, const char* const aName
,
167 WorkerStatus
const aFailStatus
) {
168 MOZ_ASSERT(aWorkerPrivate
);
171 RefPtr
<StrongWorkerRef
> ref
= new StrongWorkerRef(aWorkerPrivate
);
173 // The worker is kept alive by this holder.
174 UniquePtr
<Holder
> holder(
175 new Holder(aName
, ref
, WorkerHolder::PreventIdleShutdownStart
));
176 if (NS_WARN_IF(!holder
->HoldWorker(aWorkerPrivate
, aFailStatus
))) {
180 ref
->mHolder
= std::move(holder
);
185 StrongWorkerRef::StrongWorkerRef(WorkerPrivate
* aWorkerPrivate
)
186 : WorkerRef(aWorkerPrivate
) {}
188 StrongWorkerRef::~StrongWorkerRef() { NS_ASSERT_OWNINGTHREAD(StrongWorkerRef
); }
190 WorkerPrivate
* StrongWorkerRef::Private() const {
192 NS_ASSERT_OWNINGTHREAD(StrongWorkerRef
);
193 return mWorkerPrivate
;
196 // ----------------------------------------------------------------------------
197 // ThreadSafeWorkerRef
199 ThreadSafeWorkerRef::ThreadSafeWorkerRef(StrongWorkerRef
* aRef
) : mRef(aRef
) {
201 aRef
->Private()->AssertIsOnWorkerThread();
204 ThreadSafeWorkerRef::~ThreadSafeWorkerRef() {
205 // Let's release the StrongWorkerRef on the correct thread.
206 if (!mRef
->mWorkerPrivate
->IsOnWorkerThread()) {
207 WorkerPrivate
* workerPrivate
= mRef
->mWorkerPrivate
;
208 RefPtr
<ReleaseRefControlRunnable
> r
=
209 new ReleaseRefControlRunnable(workerPrivate
, mRef
.forget());
215 WorkerPrivate
* ThreadSafeWorkerRef::Private() const {
216 return mRef
->mWorkerPrivate
;
220 } // namespace mozilla