Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/workers/WorkerRef.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#include "WorkerRef.h"
8
9
#include "mozilla/Unused.h"
10
#include "WorkerHolder.h"
11
#include "WorkerRunnable.h"
12
#include "WorkerPrivate.h"
13
14
namespace mozilla {
15
namespace dom {
16
17
namespace {
18
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
22
{
23
public:
24
  ReleaseRefControlRunnable(WorkerPrivate* aWorkerPrivate,
25
                            already_AddRefed<StrongWorkerRef> aRef)
26
    : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
27
    , mRef(std::move(aRef))
28
0
  {
29
0
    MOZ_ASSERT(mRef);
30
0
  }
31
32
  bool
33
  PreDispatch(WorkerPrivate* aWorkerPrivate) override
34
0
  {
35
0
    return true;
36
0
  }
37
38
  void
39
  PostDispatch(WorkerPrivate* aWorkerPrivate,
40
               bool aDispatchResult) override
41
0
  {
42
0
  }
43
44
  bool
45
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
46
0
  {
47
0
    mRef = nullptr;
48
0
    return true;
49
0
  }
50
51
private:
52
  RefPtr<StrongWorkerRef> mRef;
53
};
54
55
} // anonymous
56
57
// ----------------------------------------------------------------------------
58
// WorkerRef::Holder
59
60
class WorkerRef::Holder final : public mozilla::dom::WorkerHolder
61
{
62
public:
63
  Holder(const char* aName, WorkerRef* aWorkerRef, Behavior aBehavior)
64
    : mozilla::dom::WorkerHolder(aName, aBehavior)
65
    , mWorkerRef(aWorkerRef)
66
0
  {}
67
68
  bool
69
  Notify(WorkerStatus aStatus) override
70
0
  {
71
0
    MOZ_ASSERT(mWorkerRef);
72
0
73
0
    if (aStatus < Canceling) {
74
0
      return true;
75
0
    }
76
0
77
0
    // Let's keep this object alive for the whole Notify() execution.
78
0
    RefPtr<WorkerRef> workerRef;
79
0
    workerRef = mWorkerRef;
80
0
81
0
    workerRef->Notify();
82
0
    return true;
83
0
  }
84
85
public:
86
  WorkerRef* mWorkerRef;
87
};
88
89
// ----------------------------------------------------------------------------
90
// WorkerRef
91
92
WorkerRef::WorkerRef(WorkerPrivate* aWorkerPrivate)
93
  : mWorkerPrivate(aWorkerPrivate)
94
0
{
95
0
  MOZ_ASSERT(aWorkerPrivate);
96
0
  aWorkerPrivate->AssertIsOnWorkerThread();
97
0
}
98
99
WorkerRef::~WorkerRef()
100
0
{
101
0
  NS_ASSERT_OWNINGTHREAD(WorkerRef);
102
0
}
103
104
void
105
WorkerRef::Notify()
106
0
{
107
0
  MOZ_ASSERT(mHolder);
108
0
  NS_ASSERT_OWNINGTHREAD(WorkerRef);
109
0
110
0
  if (!mCallback) {
111
0
    return;
112
0
  }
113
0
114
0
  std::function<void()> callback = mCallback;
115
0
  mCallback = nullptr;
116
0
117
0
  callback();
118
0
}
119
120
// ----------------------------------------------------------------------------
121
// WeakWorkerRef
122
123
/* static */ already_AddRefed<WeakWorkerRef>
124
WeakWorkerRef::Create(WorkerPrivate* aWorkerPrivate,
125
                      const std::function<void()>& aCallback)
126
0
{
127
0
  MOZ_ASSERT(aWorkerPrivate);
128
0
  aWorkerPrivate->AssertIsOnWorkerThread();
129
0
130
0
  RefPtr<WeakWorkerRef> ref = new WeakWorkerRef(aWorkerPrivate);
131
0
132
0
  // This holder doesn't keep the worker alive.
133
0
  UniquePtr<Holder> holder(new Holder("WeakWorkerRef::Holder", ref,
134
0
                                      WorkerHolder::AllowIdleShutdownStart));
135
0
  if (NS_WARN_IF(!holder->HoldWorker(aWorkerPrivate, Canceling))) {
136
0
    return nullptr;
137
0
  }
138
0
139
0
  ref->mHolder = std::move(holder);
140
0
  ref->mCallback = aCallback;
141
0
142
0
  return ref.forget();
143
0
}
144
145
WeakWorkerRef::WeakWorkerRef(WorkerPrivate* aWorkerPrivate)
146
  : WorkerRef(aWorkerPrivate)
147
0
{}
148
149
WeakWorkerRef::~WeakWorkerRef() = default;
150
151
void
152
WeakWorkerRef::Notify()
153
0
{
154
0
  WorkerRef::Notify();
155
0
156
0
  mHolder = nullptr;
157
0
  mWorkerPrivate = nullptr;
158
0
}
159
160
WorkerPrivate*
161
WeakWorkerRef::GetPrivate() const
162
0
{
163
0
  NS_ASSERT_OWNINGTHREAD(WeakWorkerRef);
164
0
  return mWorkerPrivate;
165
0
}
166
167
WorkerPrivate*
168
WeakWorkerRef::GetUnsafePrivate() const
169
0
{
170
0
  return mWorkerPrivate;
171
0
}
172
173
// ----------------------------------------------------------------------------
174
// StrongWorkerRef
175
176
/* static */ already_AddRefed<StrongWorkerRef>
177
StrongWorkerRef::Create(WorkerPrivate* aWorkerPrivate,
178
                        const char* aName,
179
                        const std::function<void()>& aCallback)
180
0
{
181
0
  MOZ_ASSERT(aWorkerPrivate);
182
0
  MOZ_ASSERT(aName);
183
0
184
0
  RefPtr<StrongWorkerRef> ref = new StrongWorkerRef(aWorkerPrivate);
185
0
186
0
  // The worker is kept alive by this holder.
187
0
  UniquePtr<Holder> holder(new Holder(aName, ref,
188
0
                                      WorkerHolder::PreventIdleShutdownStart));
189
0
  if (NS_WARN_IF(!holder->HoldWorker(aWorkerPrivate, Canceling))) {
190
0
    return nullptr;
191
0
  }
192
0
193
0
  ref->mHolder = std::move(holder);
194
0
  ref->mCallback = aCallback;
195
0
196
0
  return ref.forget();
197
0
}
198
199
StrongWorkerRef::StrongWorkerRef(WorkerPrivate* aWorkerPrivate)
200
  : WorkerRef(aWorkerPrivate)
201
0
{}
202
203
StrongWorkerRef::~StrongWorkerRef()
204
0
{
205
0
  NS_ASSERT_OWNINGTHREAD(StrongWorkerRef);
206
0
}
207
208
WorkerPrivate*
209
StrongWorkerRef::Private() const
210
0
{
211
0
  MOZ_ASSERT(mHolder);
212
0
  NS_ASSERT_OWNINGTHREAD(StrongWorkerRef);
213
0
  return mWorkerPrivate;
214
0
}
215
216
// ----------------------------------------------------------------------------
217
// ThreadSafeWorkerRef
218
219
ThreadSafeWorkerRef::ThreadSafeWorkerRef(StrongWorkerRef* aRef)
220
  : mRef(aRef)
221
0
{
222
0
  MOZ_ASSERT(aRef);
223
0
  aRef->Private()->AssertIsOnWorkerThread();
224
0
}
225
226
ThreadSafeWorkerRef::~ThreadSafeWorkerRef()
227
0
{
228
0
  // Let's release the StrongWorkerRef on the correct thread.
229
0
  if (!mRef->mWorkerPrivate->IsOnWorkerThread()) {
230
0
    WorkerPrivate* workerPrivate = mRef->mWorkerPrivate;
231
0
    RefPtr<ReleaseRefControlRunnable> r =
232
0
      new ReleaseRefControlRunnable(workerPrivate, mRef.forget());
233
0
    r->Dispatch();
234
0
    return;
235
0
  }
236
0
}
237
238
WorkerPrivate*
239
ThreadSafeWorkerRef::Private() const
240
0
{
241
0
  return mRef->mWorkerPrivate;
242
0
}
243
244
} // dom namespace
245
} // mozilla namespace