Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/file/ipc/IPCBlobInputStreamThread.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 "IPCBlobInputStreamThread.h"
8
9
#include "mozilla/StaticMutex.h"
10
#include "mozilla/SystemGroup.h"
11
#include "mozilla/TaskCategory.h"
12
#include "mozilla/ipc/BackgroundChild.h"
13
#include "mozilla/ipc/PBackgroundChild.h"
14
#include "nsXPCOMPrivate.h"
15
16
namespace mozilla {
17
18
using namespace ipc;
19
20
namespace dom {
21
22
namespace {
23
24
StaticMutex gIPCBlobThreadMutex;
25
StaticRefPtr<IPCBlobInputStreamThread> gIPCBlobThread;
26
bool gShutdownHasStarted = false;
27
28
class ThreadInitializeRunnable final : public Runnable
29
{
30
public:
31
0
  ThreadInitializeRunnable() : Runnable("dom::ThreadInitializeRunnable") {}
32
33
  NS_IMETHOD
34
  Run() override
35
0
  {
36
0
     mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
37
0
     MOZ_ASSERT(gIPCBlobThread);
38
0
     gIPCBlobThread->InitializeOnMainThread();
39
0
     return NS_OK;
40
0
  }
41
};
42
43
class MigrateActorRunnable final : public Runnable
44
{
45
public:
46
  explicit MigrateActorRunnable(IPCBlobInputStreamChild* aActor)
47
    : Runnable("dom::MigrateActorRunnable")
48
    , mActor(aActor)
49
0
  {
50
0
    MOZ_ASSERT(mActor);
51
0
  }
52
53
  NS_IMETHOD
54
  Run() override
55
0
  {
56
0
    MOZ_ASSERT(mActor->State() == IPCBlobInputStreamChild::eInactiveMigrating);
57
0
58
0
    PBackgroundChild* actorChild =
59
0
      BackgroundChild::GetOrCreateForCurrentThread();
60
0
    if (!actorChild) {
61
0
      return NS_OK;
62
0
    }
63
0
64
0
    if (actorChild->SendPIPCBlobInputStreamConstructor(mActor, mActor->ID(),
65
0
                                                       mActor->Size())) {
66
0
      // We need manually to increase the reference for this actor because the
67
0
      // IPC allocator method is not triggered. The Release() is called by IPDL
68
0
      // when the actor is deleted.
69
0
      mActor.get()->AddRef();
70
0
      mActor->Migrated();
71
0
    }
72
0
73
0
    return NS_OK;
74
0
  }
75
76
private:
77
0
  ~MigrateActorRunnable() = default;
78
79
  RefPtr<IPCBlobInputStreamChild> mActor;
80
};
81
82
} // anonymous
83
84
NS_IMPL_ISUPPORTS(IPCBlobInputStreamThread, nsIObserver, nsIEventTarget)
85
86
/* static */ bool
87
IPCBlobInputStreamThread::IsOnFileEventTarget(nsIEventTarget* aEventTarget)
88
0
{
89
0
  MOZ_ASSERT(aEventTarget);
90
0
91
0
  mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
92
0
  return gIPCBlobThread && aEventTarget == gIPCBlobThread->mThread;
93
0
}
94
95
/* static */ IPCBlobInputStreamThread*
96
IPCBlobInputStreamThread::GetOrCreate()
97
0
{
98
0
  mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
99
0
100
0
  if (gShutdownHasStarted) {
101
0
    return nullptr;
102
0
  }
103
0
104
0
  if (!gIPCBlobThread) {
105
0
    gIPCBlobThread = new IPCBlobInputStreamThread();
106
0
    if (!gIPCBlobThread->Initialize()) {
107
0
      return nullptr;
108
0
    }
109
0
  }
110
0
111
0
  return gIPCBlobThread;
112
0
}
113
114
bool
115
IPCBlobInputStreamThread::Initialize()
116
0
{
117
0
  nsCOMPtr<nsIThread> thread;
118
0
  nsresult rv = NS_NewNamedThread("DOM File", getter_AddRefs(thread));
119
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
120
0
    return false;
121
0
  }
122
0
123
0
  mThread = thread;
124
0
125
0
  if (!mPendingActors.IsEmpty()) {
126
0
    for (uint32_t i = 0; i < mPendingActors.Length(); ++i) {
127
0
      MigrateActorInternal(mPendingActors[i]);
128
0
    }
129
0
130
0
    mPendingActors.Clear();
131
0
  }
132
0
133
0
  if (!NS_IsMainThread()) {
134
0
    RefPtr<Runnable> runnable = new ThreadInitializeRunnable();
135
0
    SystemGroup::Dispatch(TaskCategory::Other, runnable.forget());
136
0
    return true;
137
0
  }
138
0
139
0
  InitializeOnMainThread();
140
0
  return true;
141
0
}
142
143
void
144
IPCBlobInputStreamThread::InitializeOnMainThread()
145
0
{
146
0
  MOZ_ASSERT(NS_IsMainThread());
147
0
148
0
  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
149
0
  if (NS_WARN_IF(!obs)) {
150
0
    return;
151
0
  }
152
0
153
0
  nsresult rv =
154
0
    obs->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
155
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
156
0
    return;
157
0
  }
158
0
}
159
160
NS_IMETHODIMP
161
IPCBlobInputStreamThread::Observe(nsISupports* aSubject,
162
                                  const char* aTopic,
163
                                  const char16_t* aData)
164
0
{
165
0
  MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
166
0
167
0
  mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
168
0
169
0
  if (mThread) {
170
0
    mThread->Shutdown();
171
0
    mThread = nullptr;
172
0
  }
173
0
174
0
  gShutdownHasStarted = true;
175
0
  gIPCBlobThread = nullptr;
176
0
177
0
  return NS_OK;
178
0
}
179
180
void
181
IPCBlobInputStreamThread::MigrateActor(IPCBlobInputStreamChild* aActor)
182
0
{
183
0
  MOZ_ASSERT(aActor->State() == IPCBlobInputStreamChild::eInactiveMigrating);
184
0
185
0
  mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
186
0
187
0
  if (gShutdownHasStarted) {
188
0
    return;
189
0
  }
190
0
191
0
  if (!mThread) {
192
0
    // The thread is not initialized yet.
193
0
    mPendingActors.AppendElement(aActor);
194
0
    return;
195
0
  }
196
0
197
0
  MigrateActorInternal(aActor);
198
0
}
199
200
void
201
IPCBlobInputStreamThread::MigrateActorInternal(IPCBlobInputStreamChild* aActor)
202
0
{
203
0
  RefPtr<Runnable> runnable = new MigrateActorRunnable(aActor);
204
0
  mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
205
0
}
206
207
// nsIEventTarget
208
209
NS_IMETHODIMP_(bool)
210
IPCBlobInputStreamThread::IsOnCurrentThreadInfallible()
211
0
{
212
0
  return mThread->IsOnCurrentThread();
213
0
}
214
215
NS_IMETHODIMP
216
IPCBlobInputStreamThread::IsOnCurrentThread(bool* aRetval)
217
0
{
218
0
  return mThread->IsOnCurrentThread(aRetval);
219
0
}
220
221
NS_IMETHODIMP
222
IPCBlobInputStreamThread::Dispatch(already_AddRefed<nsIRunnable> aRunnable,
223
                                   uint32_t aFlags)
224
0
{
225
0
  nsCOMPtr<nsIRunnable> runnable(aRunnable);
226
0
227
0
  mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
228
0
229
0
  if (gShutdownHasStarted) {
230
0
    return NS_ERROR_NOT_INITIALIZED;
231
0
  }
232
0
233
0
  return mThread->Dispatch(runnable.forget(), aFlags);
234
0
}
235
236
NS_IMETHODIMP
237
IPCBlobInputStreamThread::DispatchFromScript(nsIRunnable* aRunnable,
238
                                             uint32_t aFlags)
239
0
{
240
0
  nsCOMPtr<nsIRunnable> runnable(aRunnable);
241
0
  return Dispatch(runnable.forget(), aFlags);
242
0
}
243
244
NS_IMETHODIMP
245
IPCBlobInputStreamThread::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
246
0
{
247
0
  return NS_ERROR_NOT_IMPLEMENTED;
248
0
}
249
250
} // dom namespace
251
} // mozilla namespace