Line data Source code
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 0 : IsOnChildMainThread()
26 : {
27 0 : return sMainLoop && sMainLoop == MessageLoop::current();
28 : }
29 :
30 : // We just need a refcounted wrapper for GMPTask objects.
31 : class GMPRunnable final
32 : {
33 : public:
34 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPRunnable)
35 :
36 0 : explicit GMPRunnable(GMPTask* aTask)
37 0 : : mTask(aTask)
38 : {
39 0 : MOZ_ASSERT(mTask);
40 0 : }
41 :
42 0 : void Run()
43 : {
44 0 : mTask->Run();
45 0 : mTask->Destroy();
46 0 : mTask = nullptr;
47 0 : }
48 :
49 : private:
50 0 : ~GMPRunnable()
51 0 : {
52 0 : }
53 :
54 : GMPTask* mTask;
55 : };
56 :
57 : class GMPSyncRunnable final
58 : {
59 : public:
60 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPSyncRunnable)
61 :
62 0 : GMPSyncRunnable(GMPTask* aTask, MessageLoop* aMessageLoop)
63 0 : : mDone(false)
64 : , mTask(aTask)
65 : , mMessageLoop(aMessageLoop)
66 0 : , mMonitor("GMPSyncRunnable")
67 : {
68 0 : MOZ_ASSERT(mTask);
69 0 : MOZ_ASSERT(mMessageLoop);
70 0 : }
71 :
72 0 : void Post()
73 : {
74 : // We assert here for two reasons.
75 : // 1) Nobody should be blocking the main thread.
76 : // 2) This prevents deadlocks when doing sync calls to main which if the
77 : // main thread tries to do a sync call back to the calling thread.
78 0 : MOZ_ASSERT(!IsOnChildMainThread());
79 :
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 : }
86 0 : }
87 :
88 0 : void Run()
89 : {
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 0 : ~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 0 : CreateThread(GMPThread** aThread)
126 : {
127 0 : if (!aThread) {
128 0 : return GMPGenericErr;
129 : }
130 :
131 0 : *aThread = new GMPThreadImpl();
132 :
133 0 : return GMPNoErr;
134 : }
135 :
136 : GMPErr
137 0 : RunOnMainThread(GMPTask* aTask)
138 : {
139 0 : if (!aTask || !sMainLoop) {
140 0 : return GMPGenericErr;
141 : }
142 :
143 0 : RefPtr<GMPRunnable> r = new GMPRunnable(aTask);
144 0 : sMainLoop->PostTask(
145 0 : NewRunnableMethod("gmp::GMPRunnable::Run", r, &GMPRunnable::Run));
146 :
147 0 : return GMPNoErr;
148 : }
149 :
150 : GMPErr
151 0 : SyncRunOnMainThread(GMPTask* aTask)
152 : {
153 0 : if (!aTask || !sMainLoop || IsOnChildMainThread()) {
154 0 : return GMPGenericErr;
155 : }
156 :
157 0 : RefPtr<GMPSyncRunnable> r = new GMPSyncRunnable(aTask, sMainLoop);
158 :
159 0 : r->Post();
160 :
161 0 : return GMPNoErr;
162 : }
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 0 : CreateMutex(GMPMutex** aMutex)
181 : {
182 0 : if (!aMutex) {
183 0 : return GMPGenericErr;
184 : }
185 :
186 0 : *aMutex = new GMPMutexImpl();
187 :
188 0 : return GMPNoErr;
189 : }
190 :
191 : GMPErr
192 0 : CreateRecord(const char* aRecordName,
193 : uint32_t aRecordNameSize,
194 : GMPRecord** aOutRecord,
195 : GMPRecordClient* aClient)
196 : {
197 0 : if (aRecordNameSize > GMP_MAX_RECORD_NAME_SIZE ||
198 : aRecordNameSize == 0) {
199 0 : NS_WARNING("GMP tried to CreateRecord with too long or 0 record name");
200 0 : return GMPGenericErr;
201 : }
202 0 : GMPStorageChild* storage = sChild->GetGMPStorage();
203 0 : if (!storage) {
204 0 : return GMPGenericErr;
205 : }
206 0 : MOZ_ASSERT(storage);
207 0 : return storage->CreateRecord(nsDependentCString(aRecordName, aRecordNameSize),
208 : aOutRecord,
209 0 : aClient);
210 : }
211 :
212 : GMPErr
213 0 : SetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS)
214 : {
215 0 : if (!aTask || !sMainLoop || !IsOnChildMainThread()) {
216 0 : return GMPGenericErr;
217 : }
218 0 : GMPTimerChild* timers = sChild->GetGMPTimers();
219 0 : NS_ENSURE_TRUE(timers, GMPGenericErr);
220 0 : return timers->SetTimer(aTask, aTimeoutMS);
221 : }
222 :
223 : GMPErr
224 0 : GetClock(GMPTimestamp* aOutTime)
225 : {
226 0 : if (!aOutTime) {
227 0 : return GMPGenericErr;
228 : }
229 0 : *aOutTime = base::Time::Now().ToDoubleT() * 1000.0;
230 0 : return GMPNoErr;
231 : }
232 :
233 : void
234 0 : InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild)
235 : {
236 0 : if (!sMainLoop) {
237 0 : sMainLoop = MessageLoop::current();
238 : }
239 0 : if (!sChild) {
240 0 : sChild = aChild;
241 : }
242 :
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 0 : GMPThreadImpl::GMPThreadImpl()
254 : : mMutex("GMPThreadImpl"),
255 0 : mThread("GMPThread")
256 : {
257 0 : MOZ_COUNT_CTOR(GMPThread);
258 0 : }
259 :
260 0 : GMPThreadImpl::~GMPThreadImpl()
261 : {
262 0 : MOZ_COUNT_DTOR(GMPThread);
263 0 : }
264 :
265 : void
266 0 : GMPThreadImpl::Post(GMPTask* aTask)
267 : {
268 0 : MutexAutoLock lock(mMutex);
269 :
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 : }
276 : }
277 :
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 : }
282 :
283 : void
284 0 : GMPThreadImpl::Join()
285 : {
286 : {
287 0 : MutexAutoLock lock(mMutex);
288 0 : if (mThread.IsRunning()) {
289 0 : mThread.Stop();
290 : }
291 : }
292 0 : delete this;
293 0 : }
294 :
295 0 : GMPMutexImpl::GMPMutexImpl()
296 0 : : mMonitor("gmp-mutex")
297 : {
298 0 : MOZ_COUNT_CTOR(GMPMutexImpl);
299 0 : }
300 :
301 0 : GMPMutexImpl::~GMPMutexImpl()
302 : {
303 0 : MOZ_COUNT_DTOR(GMPMutexImpl);
304 0 : }
305 :
306 : void
307 0 : GMPMutexImpl::Destroy()
308 : {
309 0 : delete this;
310 0 : }
311 :
312 : void
313 0 : GMPMutexImpl::Acquire()
314 : {
315 0 : mMonitor.Enter();
316 0 : }
317 :
318 : void
319 0 : GMPMutexImpl::Release()
320 : {
321 0 : mMonitor.Exit();
322 0 : }
323 :
324 : GMPTask*
325 0 : NewGMPTask(std::function<void()>&& aFunction)
326 : {
327 : class Task : public GMPTask
328 : {
329 : public:
330 0 : explicit Task(std::function<void()>&& aFunction)
331 0 : : mFunction(Move(aFunction))
332 : {
333 0 : }
334 0 : void Destroy() override
335 : {
336 0 : delete this;
337 0 : }
338 0 : ~Task() override
339 0 : {
340 0 : }
341 0 : void Run() override
342 : {
343 0 : mFunction();
344 0 : }
345 : private:
346 : std::function<void()> mFunction;
347 : };
348 0 : return new Task(Move(aFunction));
349 : }
350 :
351 : } // namespace gmp
352 : } // namespace mozilla
|