Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/gmp/GMPPlatform.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "GMPPlatform.h"
7
#include "GMPStorageChild.h"
8
#include "GMPTimerChild.h"
9
#include "mozilla/Monitor.h"
10
#include "GMPChild.h"
11
#include "mozilla/Mutex.h"
12
#include "base/thread.h"
13
#include "base/time.h"
14
#include "mozilla/ReentrantMonitor.h"
15
16
#include <ctime>
17
18
namespace mozilla {
19
namespace gmp {
20
21
static MessageLoop* sMainLoop = nullptr;
22
static GMPChild* sChild = nullptr;
23
24
static bool
25
IsOnChildMainThread()
26
0
{
27
0
  return sMainLoop && sMainLoop == MessageLoop::current();
28
0
}
29
30
// We just need a refcounted wrapper for GMPTask objects.
31
class GMPRunnable final
32
{
33
public:
34
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPRunnable)
35
36
  explicit GMPRunnable(GMPTask* aTask)
37
  : mTask(aTask)
38
0
  {
39
0
    MOZ_ASSERT(mTask);
40
0
  }
41
42
  void Run()
43
0
  {
44
0
    mTask->Run();
45
0
    mTask->Destroy();
46
0
    mTask = nullptr;
47
0
  }
48
49
private:
50
  ~GMPRunnable()
51
0
  {
52
0
  }
53
54
  GMPTask* mTask;
55
};
56
57
class GMPSyncRunnable final
58
{
59
public:
60
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPSyncRunnable)
61
62
  GMPSyncRunnable(GMPTask* aTask, MessageLoop* aMessageLoop)
63
  : mDone(false)
64
  , mTask(aTask)
65
  , mMessageLoop(aMessageLoop)
66
  , mMonitor("GMPSyncRunnable")
67
0
  {
68
0
    MOZ_ASSERT(mTask);
69
0
    MOZ_ASSERT(mMessageLoop);
70
0
  }
71
72
  void Post()
73
0
  {
74
0
    // We assert here for two reasons.
75
0
    // 1) Nobody should be blocking the main thread.
76
0
    // 2) This prevents deadlocks when doing sync calls to main which if the
77
0
    //    main thread tries to do a sync call back to the calling thread.
78
0
    MOZ_ASSERT(!IsOnChildMainThread());
79
0
80
0
    mMessageLoop->PostTask(NewRunnableMethod(
81
0
      "gmp::GMPSyncRunnable::Run", this, &GMPSyncRunnable::Run));
82
0
    MonitorAutoLock lock(mMonitor);
83
0
    while (!mDone) {
84
0
      lock.Wait();
85
0
    }
86
0
  }
87
88
  void Run()
89
0
  {
90
0
    mTask->Run();
91
0
    mTask->Destroy();
92
0
    mTask = nullptr;
93
0
    MonitorAutoLock lock(mMonitor);
94
0
    mDone = true;
95
0
    lock.Notify();
96
0
  }
97
98
private:
99
  ~GMPSyncRunnable()
100
0
  {
101
0
  }
102
103
  bool mDone;
104
  GMPTask* mTask;
105
  MessageLoop* mMessageLoop;
106
  Monitor mMonitor;
107
};
108
109
class GMPThreadImpl : public GMPThread
110
{
111
public:
112
  GMPThreadImpl();
113
  virtual ~GMPThreadImpl();
114
115
  // GMPThread
116
  void Post(GMPTask* aTask) override;
117
  void Join() override;
118
119
private:
120
  Mutex mMutex;
121
  base::Thread mThread;
122
};
123
124
GMPErr
125
CreateThread(GMPThread** aThread)
126
0
{
127
0
  if (!aThread) {
128
0
    return GMPGenericErr;
129
0
  }
130
0
131
0
  *aThread = new GMPThreadImpl();
132
0
133
0
  return GMPNoErr;
134
0
}
135
136
GMPErr
137
RunOnMainThread(GMPTask* aTask)
138
0
{
139
0
  if (!aTask || !sMainLoop) {
140
0
    return GMPGenericErr;
141
0
  }
142
0
143
0
  RefPtr<GMPRunnable> r = new GMPRunnable(aTask);
144
0
  sMainLoop->PostTask(
145
0
    NewRunnableMethod("gmp::GMPRunnable::Run", r, &GMPRunnable::Run));
146
0
147
0
  return GMPNoErr;
148
0
}
149
150
GMPErr
151
SyncRunOnMainThread(GMPTask* aTask)
152
0
{
153
0
  if (!aTask || !sMainLoop || IsOnChildMainThread()) {
154
0
    return GMPGenericErr;
155
0
  }
156
0
157
0
  RefPtr<GMPSyncRunnable> r = new GMPSyncRunnable(aTask, sMainLoop);
158
0
159
0
  r->Post();
160
0
161
0
  return GMPNoErr;
162
0
}
163
164
class GMPMutexImpl : public GMPMutex
165
{
166
public:
167
  GMPMutexImpl();
168
  virtual ~GMPMutexImpl();
169
170
  // GMPMutex
171
  void Acquire() override;
172
  void Release() override;
173
  void Destroy() override;
174
175
private:
176
  ReentrantMonitor mMonitor;
177
};
178
179
GMPErr
180
CreateMutex(GMPMutex** aMutex)
181
0
{
182
0
  if (!aMutex) {
183
0
    return GMPGenericErr;
184
0
  }
185
0
186
0
  *aMutex = new GMPMutexImpl();
187
0
188
0
  return GMPNoErr;
189
0
}
190
191
GMPErr
192
CreateRecord(const char* aRecordName,
193
             uint32_t aRecordNameSize,
194
             GMPRecord** aOutRecord,
195
             GMPRecordClient* aClient)
196
0
{
197
0
  if (aRecordNameSize > GMP_MAX_RECORD_NAME_SIZE ||
198
0
      aRecordNameSize == 0) {
199
0
    NS_WARNING("GMP tried to CreateRecord with too long or 0 record name");
200
0
    return GMPGenericErr;
201
0
  }
202
0
  GMPStorageChild* storage = sChild->GetGMPStorage();
203
0
  if (!storage) {
204
0
    return GMPGenericErr;
205
0
  }
206
0
  MOZ_ASSERT(storage);
207
0
  return storage->CreateRecord(nsDependentCString(aRecordName, aRecordNameSize),
208
0
                               aOutRecord,
209
0
                               aClient);
210
0
}
211
212
GMPErr
213
SetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS)
214
0
{
215
0
  if (!aTask || !sMainLoop || !IsOnChildMainThread()) {
216
0
    return GMPGenericErr;
217
0
  }
218
0
  GMPTimerChild* timers = sChild->GetGMPTimers();
219
0
  NS_ENSURE_TRUE(timers, GMPGenericErr);
220
0
  return timers->SetTimer(aTask, aTimeoutMS);
221
0
}
222
223
GMPErr
224
GetClock(GMPTimestamp* aOutTime)
225
0
{
226
0
  if (!aOutTime) {
227
0
    return GMPGenericErr;
228
0
  }
229
0
  *aOutTime = base::Time::Now().ToDoubleT() * 1000.0;
230
0
 return GMPNoErr;
231
0
}
232
233
void
234
InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
235
0
{
236
0
  if (!sMainLoop) {
237
0
    sMainLoop = MessageLoop::current();
238
0
  }
239
0
  if (!sChild) {
240
0
    sChild = aChild;
241
0
  }
242
0
243
0
  aPlatformAPI.version = 0;
244
0
  aPlatformAPI.createthread = &CreateThread;
245
0
  aPlatformAPI.runonmainthread = &RunOnMainThread;
246
0
  aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
247
0
  aPlatformAPI.createmutex = &CreateMutex;
248
0
  aPlatformAPI.createrecord = &CreateRecord;
249
0
  aPlatformAPI.settimer = &SetTimerOnMainThread;
250
0
  aPlatformAPI.getcurrenttime = &GetClock;
251
0
}
252
253
GMPThreadImpl::GMPThreadImpl()
254
: mMutex("GMPThreadImpl"),
255
  mThread("GMPThread")
256
0
{
257
0
  MOZ_COUNT_CTOR(GMPThread);
258
0
}
259
260
GMPThreadImpl::~GMPThreadImpl()
261
0
{
262
0
  MOZ_COUNT_DTOR(GMPThread);
263
0
}
264
265
void
266
GMPThreadImpl::Post(GMPTask* aTask)
267
0
{
268
0
  MutexAutoLock lock(mMutex);
269
0
270
0
  if (!mThread.IsRunning()) {
271
0
    bool started = mThread.Start();
272
0
    if (!started) {
273
0
      NS_WARNING("Unable to start GMPThread!");
274
0
      return;
275
0
    }
276
0
  }
277
0
278
0
  RefPtr<GMPRunnable> r = new GMPRunnable(aTask);
279
0
  mThread.message_loop()->PostTask(
280
0
    NewRunnableMethod("gmp::GMPRunnable::Run", r.get(), &GMPRunnable::Run));
281
0
}
282
283
void
284
GMPThreadImpl::Join()
285
0
{
286
0
  {
287
0
    MutexAutoLock lock(mMutex);
288
0
    if (mThread.IsRunning()) {
289
0
      mThread.Stop();
290
0
    }
291
0
  }
292
0
  delete this;
293
0
}
294
295
GMPMutexImpl::GMPMutexImpl()
296
: mMonitor("gmp-mutex")
297
0
{
298
0
  MOZ_COUNT_CTOR(GMPMutexImpl);
299
0
}
300
301
GMPMutexImpl::~GMPMutexImpl()
302
0
{
303
0
  MOZ_COUNT_DTOR(GMPMutexImpl);
304
0
}
305
306
void
307
GMPMutexImpl::Destroy()
308
0
{
309
0
  delete this;
310
0
}
311
312
void
313
GMPMutexImpl::Acquire()
314
0
{
315
0
  mMonitor.Enter();
316
0
}
317
318
void
319
GMPMutexImpl::Release()
320
0
{
321
0
  mMonitor.Exit();
322
0
}
323
324
GMPTask*
325
NewGMPTask(std::function<void()>&& aFunction)
326
0
{
327
0
  class Task : public GMPTask
328
0
  {
329
0
  public:
330
0
    explicit Task(std::function<void()>&& aFunction)
331
0
      : mFunction(std::move(aFunction))
332
0
    {
333
0
    }
334
0
    void Destroy() override
335
0
    {
336
0
      delete this;
337
0
    }
338
0
    ~Task() override
339
0
    {
340
0
    }
341
0
    void Run() override
342
0
    {
343
0
      mFunction();
344
0
    }
345
0
  private:
346
0
    std::function<void()> mFunction;
347
0
  };
348
0
  return new Task(std::move(aFunction));
349
0
}
350
351
} // namespace gmp
352
} // namespace mozilla