Bug 1842773 - Part 5: Add ArrayBuffer.prototype.{maxByteLength,resizable} getters...
[gecko.git] / dom / media / gmp / GMPPlatform.cpp
blobcacd7936eb8cd7916657fb7376d15949325180f7
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/. */
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"
16 #ifdef XP_WIN
17 # include "mozilla/UntrustedModulesProcessor.h"
18 #endif
20 #include <ctime>
22 namespace mozilla::gmp {
24 static MessageLoop* sMainLoop = nullptr;
25 static GMPChild* sChild = nullptr;
27 static bool IsOnChildMainThread() {
28 return sMainLoop && sMainLoop == MessageLoop::current();
31 // We just need a refcounted wrapper for GMPTask objects.
32 class GMPRunnable final {
33 public:
34 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPRunnable)
36 explicit GMPRunnable(GMPTask* aTask) : mTask(aTask) { MOZ_ASSERT(mTask); }
38 void Run() {
39 mTask->Run();
40 mTask->Destroy();
41 mTask = nullptr;
44 private:
45 ~GMPRunnable() = default;
47 GMPTask* mTask;
50 class GMPSyncRunnable final {
51 public:
52 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPSyncRunnable)
54 GMPSyncRunnable(GMPTask* aTask, MessageLoop* aMessageLoop)
55 : mDone(false),
56 mTask(aTask),
57 mMessageLoop(aMessageLoop),
58 mMonitor("GMPSyncRunnable") {
59 MOZ_ASSERT(mTask);
60 MOZ_ASSERT(mMessageLoop);
63 void Post() {
64 // We assert here for two reasons.
65 // 1) Nobody should be blocking the main thread.
66 // 2) This prevents deadlocks when doing sync calls to main which if the
67 // main thread tries to do a sync call back to the calling thread.
68 MOZ_ASSERT(!IsOnChildMainThread());
70 mMessageLoop->PostTask(NewRunnableMethod("gmp::GMPSyncRunnable::Run", this,
71 &GMPSyncRunnable::Run));
72 MonitorAutoLock lock(mMonitor);
73 while (!mDone) {
74 lock.Wait();
78 void Run() {
79 mTask->Run();
80 mTask->Destroy();
81 mTask = nullptr;
82 MonitorAutoLock lock(mMonitor);
83 mDone = true;
84 lock.Notify();
87 private:
88 ~GMPSyncRunnable() = default;
90 bool mDone MOZ_GUARDED_BY(mMonitor);
91 GMPTask* mTask;
92 MessageLoop* mMessageLoop;
93 Monitor mMonitor;
96 class GMPThreadImpl : public GMPThread {
97 public:
98 GMPThreadImpl();
99 virtual ~GMPThreadImpl();
101 // GMPThread
102 void Post(GMPTask* aTask) override;
103 void Join() override;
105 private:
106 Mutex mMutex MOZ_UNANNOTATED;
107 base::Thread mThread MOZ_GUARDED_BY(mMutex);
110 GMPErr CreateThread(GMPThread** aThread) {
111 if (!aThread) {
112 return GMPGenericErr;
115 *aThread = new GMPThreadImpl();
117 return GMPNoErr;
120 GMPErr RunOnMainThread(GMPTask* aTask) {
121 if (!aTask || !sMainLoop) {
122 return GMPGenericErr;
125 RefPtr<GMPRunnable> r = new GMPRunnable(aTask);
126 sMainLoop->PostTask(
127 NewRunnableMethod("gmp::GMPRunnable::Run", r, &GMPRunnable::Run));
129 return GMPNoErr;
132 GMPErr SyncRunOnMainThread(GMPTask* aTask) {
133 if (!aTask || !sMainLoop || IsOnChildMainThread()) {
134 return GMPGenericErr;
137 RefPtr<GMPSyncRunnable> r = new GMPSyncRunnable(aTask, sMainLoop);
139 r->Post();
141 return GMPNoErr;
144 class MOZ_CAPABILITY("mutex") GMPMutexImpl : public GMPMutex {
145 public:
146 GMPMutexImpl();
147 virtual ~GMPMutexImpl();
149 // GMPMutex
150 void Acquire() override MOZ_CAPABILITY_ACQUIRE();
151 void Release() override MOZ_CAPABILITY_RELEASE();
152 void Destroy() override;
154 private:
155 ReentrantMonitor mMonitor MOZ_UNANNOTATED;
158 GMPErr CreateMutex(GMPMutex** aMutex) {
159 if (!aMutex) {
160 return GMPGenericErr;
163 *aMutex = new GMPMutexImpl();
165 return GMPNoErr;
168 GMPErr CreateRecord(const char* aRecordName, uint32_t aRecordNameSize,
169 GMPRecord** aOutRecord, GMPRecordClient* aClient) {
170 if (aRecordNameSize > GMP_MAX_RECORD_NAME_SIZE || aRecordNameSize == 0) {
171 NS_WARNING("GMP tried to CreateRecord with too long or 0 record name");
172 return GMPGenericErr;
174 GMPStorageChild* storage = sChild->GetGMPStorage();
175 if (!storage) {
176 return GMPGenericErr;
178 MOZ_ASSERT(storage);
179 return storage->CreateRecord(nsDependentCString(aRecordName, aRecordNameSize),
180 aOutRecord, aClient);
183 GMPErr SetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS) {
184 if (!aTask || !sMainLoop || !IsOnChildMainThread()) {
185 return GMPGenericErr;
187 GMPTimerChild* timers = sChild->GetGMPTimers();
188 NS_ENSURE_TRUE(timers, GMPGenericErr);
189 return timers->SetTimer(aTask, aTimeoutMS);
192 GMPErr GetClock(GMPTimestamp* aOutTime) {
193 if (!aOutTime) {
194 return GMPGenericErr;
196 *aOutTime = base::Time::Now().ToDoubleT() * 1000.0;
197 return GMPNoErr;
200 void InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild) {
201 if (!sMainLoop) {
202 sMainLoop = MessageLoop::current();
204 if (!sChild) {
205 sChild = aChild;
208 aPlatformAPI.version = 0;
209 aPlatformAPI.createthread = &CreateThread;
210 aPlatformAPI.runonmainthread = &RunOnMainThread;
211 aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread;
212 aPlatformAPI.createmutex = &CreateMutex;
213 aPlatformAPI.createrecord = &CreateRecord;
214 aPlatformAPI.settimer = &SetTimerOnMainThread;
215 aPlatformAPI.getcurrenttime = &GetClock;
218 void SendFOGData(ipc::ByteBuf&& buf) {
219 if (sChild) {
220 sChild->SendFOGData(std::move(buf));
224 #ifdef XP_WIN
225 RefPtr<PGMPChild::GetModulesTrustPromise> SendGetModulesTrust(
226 ModulePaths&& aModules, bool aRunAtNormalPriority) {
227 if (!sChild) {
228 return PGMPChild::GetModulesTrustPromise::CreateAndReject(
229 ipc::ResponseRejectReason::SendError, __func__);
231 return sChild->SendGetModulesTrust(std::move(aModules), aRunAtNormalPriority);
233 #endif
235 GMPThreadImpl::GMPThreadImpl() : mMutex("GMPThreadImpl"), mThread("GMPThread") {
236 MOZ_COUNT_CTOR(GMPThread);
239 GMPThreadImpl::~GMPThreadImpl() { MOZ_COUNT_DTOR(GMPThread); }
241 void GMPThreadImpl::Post(GMPTask* aTask) {
242 MutexAutoLock lock(mMutex);
244 if (!mThread.IsRunning()) {
245 bool started = mThread.Start();
246 if (!started) {
247 NS_WARNING("Unable to start GMPThread!");
248 return;
252 RefPtr<GMPRunnable> r = new GMPRunnable(aTask);
253 mThread.message_loop()->PostTask(
254 NewRunnableMethod("gmp::GMPRunnable::Run", r.get(), &GMPRunnable::Run));
257 void GMPThreadImpl::Join() {
259 MutexAutoLock lock(mMutex);
260 if (mThread.IsRunning()) {
261 mThread.Stop();
264 delete this;
267 GMPMutexImpl::GMPMutexImpl() : mMonitor("gmp-mutex") {
268 MOZ_COUNT_CTOR(GMPMutexImpl);
271 GMPMutexImpl::~GMPMutexImpl() { MOZ_COUNT_DTOR(GMPMutexImpl); }
273 void GMPMutexImpl::Destroy() { delete this; }
275 MOZ_PUSH_IGNORE_THREAD_SAFETY
276 void GMPMutexImpl::Acquire() { mMonitor.Enter(); }
278 void GMPMutexImpl::Release() { mMonitor.Exit(); }
279 MOZ_POP_THREAD_SAFETY
281 GMPTask* NewGMPTask(std::function<void()>&& aFunction) {
282 class Task : public GMPTask {
283 public:
284 explicit Task(std::function<void()>&& aFunction)
285 : mFunction(std::move(aFunction)) {}
286 void Destroy() override { delete this; }
287 ~Task() override = default;
288 void Run() override { mFunction(); }
290 private:
291 std::function<void()> mFunction;
293 return new Task(std::move(aFunction));
296 } // namespace mozilla::gmp