1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=4 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef IPDLQUEUE_H_
#define IPDLQUEUE_H_ 1
#include <atomic>
#include <tuple>
#include <vector>
#include <unordered_map>
#include "ipc/IPCMessageUtilsSpecializations.h"
#include "mozilla/dom/QueueParamTraits.h"
#include "mozilla/ipc/SharedMemoryBasic.h"
#include "mozilla/Assertions.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/Logging.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/TypeTraits.h"
#include "nsString.h"
#include "mozilla/WeakPtr.h"
namespace IPC {
template <typename T>
struct ParamTraits;
} // namespace IPC
namespace mozilla {
namespace dom {
using mozilla::webgl::QueueStatus;
extern LazyLogModule gIpdlQueueLog;
#define IPDLQUEUE_LOG_(lvl, ...) \
MOZ_LOG(mozilla::dom::gIpdlQueueLog, lvl, (__VA_ARGS__))
#define IPDLQUEUE_LOGD(...) IPDLQUEUE_LOG_(LogLevel::Debug, __VA_ARGS__)
#define IPDLQUEUE_LOGE(...) IPDLQUEUE_LOG_(LogLevel::Error, __VA_ARGS__)
template <typename ActorP, typename ActorC>
class IpdlQueue;
template <typename Derived>
class SyncConsumerActor;
enum IpdlQueueProtocol {
/**
* Sends the message immediately. Does not wait for a response.
*/
kAsync,
/**
* Sends the message immediately or caches it for a later batch
* send. Messages may be sent at any point in the future but
* will always be processed in order. kSync messages always force
* a flush of the cache but other mechanisms (e.g. periodic tasks)
* can do this as well.
*/
kBufferedAsync,
/**
* Sends the message immediately. Waits for any response message,
* which can immediately be read upon completion of the send.
*/
kSync
};
constexpr uint64_t kIllegalQueueId = 0;
inline uint64_t NewIpdlQueueId() {
static std::atomic<uint64_t> sNextIpdlQueueId = 1;
return sNextIpdlQueueId++;
}
struct IpdlQueueBuffer {
uint64_t id = kIllegalQueueId;
nsTArray<uint8_t> data;
IpdlQueueBuffer() = default;
IpdlQueueBuffer(const IpdlQueueBuffer&) = delete;
IpdlQueueBuffer(IpdlQueueBuffer&&) = default;
IpdlQueueBuffer(uint64_t aId, nsTArray<uint8_t>&& aData)
: id(aId), data(std::move(aData)) {}
};
using IpdlQueueBuffers = nsTArray<IpdlQueueBuffer>;
static constexpr uint32_t kAsyncFlushWaitMs = 4; // 4ms
template <typename Derived>
class AsyncProducerActor {
public:
virtual bool TransmitIpdlQueueData(IpdlQueueProtocol aProtocol,
IpdlQueueBuffer&& aData) {
MOZ_ASSERT((aProtocol == IpdlQueueProtocol::kAsync) ||
(aProtocol == IpdlQueueProtocol::kBufferedAsync));
if (mResponseBuffers || (aProtocol == IpdlQueueProtocol::kBufferedAsync)) {
// Always use response buffer if set.
auto& buffers = mResponseBuffers ? *mResponseBuffers : mAsyncBuffers;
// We are in the middle of a sync transaction. Store the data so
// that we can return it with the response.
const uint64_t id = aData.id;
for (auto& elt : buffers) {
if (elt.id == id) {
elt.data.AppendElements(aData.data);
return true;
}
}
buffers.AppendElement(std::move(aData));
if (!mResponseBuffers) {
PostFlushAsyncCache(kAsyncFlushWaitMs);
}
return true;
}
// We are not inside of a transaction. Send normally, but first send any
// cached messages.
FlushAsyncCache();
Derived* self = static_cast<Derived*>(this);
return self->SendTransmitIpdlQueueData(std::move(aData));
}
// This can be called at any time to flush all queued async messages.
bool FlushAsyncCache() {
Derived* self = static_cast<Derived*>(this);
for (auto& elt : mAsyncBuffers) {
if (!elt.data.IsEmpty()) {
if (!self->SendTransmitIpdlQueueData(std::move(elt))) {
return false;
}
}
}
mAsyncBuffers.Clear();
return true;
}
bool PostFlushAsyncCache(uint32_t aEstWaitTimeMs) {
if (mPostedFlushRunnable) {
// Already scheduled a flush for later.
return true;
}
MOZ_ASSERT(GetCurrentSerialEventTarget(),
"No message loop for IpdlQueue flush task");
Derived* self = static_cast<Derived*>(this);
// IpdlProducer/IpdlConsumer guarantees the actor supports WeakPtr.
auto weak = WeakPtr<Derived>(self);
already_AddRefed<mozilla::Runnable> flushRunnable =
NS_NewRunnableFunction("FlushAsyncCache", [weak] {
auto strong = RefPtr<Derived>(weak);
if (!strong) {
return;
}
strong->FlushAsyncCache();
strong->ClearFlushRunnable();
});
NS_ENSURE_SUCCESS(GetCurrentSerialEventTarget()->DelayedDispatch(
std::move(flushRunnable), aEstWaitTimeMs),
false);
mPostedFlushRunnable = true;
return true;
}
void ClearFlushRunnable() { mPostedFlushRunnable = false; }
template <typename... Args>
IpdlQueueProtocol GetIpdlQueueProtocol(const Args&...) {
return IpdlQueueProtocol::kAsync;
}
protected:
friend SyncConsumerActor<Derived>;
void SetResponseBuffers(IpdlQueueBuffers* aResponse) {
MOZ_ASSERT(!mResponseBuffers);
mResponseBuffers = aResponse;
// Response should include any cached async transmissions.
*mResponseBuffers = std::move(mAsyncBuffers);
}
void ClearResponseBuffers() {
MOZ_ASSERT(mResponseBuffers);
mResponseBuffers = nullptr;
}
// Stores response when inside of a kSync transaction.
IpdlQueueBuffers* mResponseBuffers = nullptr;
// For kBufferedAsync transmissions that occur outside of a response to a
// kSync message.
IpdlQueueBuffers mAsyncBuffers;
bool mPostedFlushRunnable = false;
};
template <typename Derived>
class SyncProducerActor : public AsyncProducerActor<Derived> {
public:
bool TransmitIpdlQueueData(IpdlQueueProtocol aProtocol,
IpdlQueueBuffer&& aData) override {
Derived* self = static_cast<Derived*>(this);
if (mResponseBuffers || (aProtocol != IpdlQueueProtocol::kSync)) {
return AsyncProducerActor<Derived>::TransmitIpdlQueueData(
aProtocol, std::forward<IpdlQueueBuffer>(aData));
}
IpdlQueueBuffers responses;
if (!self->SendExchangeIpdlQueueData(std::forward<IpdlQueueBuffer>(aData),
&responses)) {
return false;
}
for (auto& buf : responses) {
if (!self->StoreIpdlQueueData(std::move(buf))) {
return false;
}
}
return true;
}
protected:
using AsyncProducerActor<Derived>::mResponseBuffers;
};
template <typename Derived>
class AsyncConsumerActor {
public:
// Returns the ipdlQueue contents that were Recv'ed in a prior IPDL
// transmission. No new data is received via IPDL during this operation.
nsTArray<uint8_t> TakeIpdlQueueData(uint64_t aId) {
auto it = mIpdlQueueBuffers.find(aId);
if (it != mIpdlQueueBuffers.end()) {
return std::move(it->second.data);
}
return nsTArray<uint8_t>();
}
protected:
friend SyncProducerActor<Derived>;
// Store data received from the producer, to be read by local IpdlConsumers.
bool StoreIpdlQueueData(IpdlQueueBuffer&& aBuffer) {
auto it = mIpdlQueueBuffers.find(aBuffer.id);
if (it == mIpdlQueueBuffers.end()) {
return mIpdlQueueBuffers.insert({aBuffer.id, std::move(aBuffer)}).second;
}
return it->second.data.AppendElements(aBuffer.data, fallible);
}
mozilla::ipc::IPCResult RecvTransmitIpdlQueueData(IpdlQueueBuffer&& aBuffer) {
if (StoreIpdlQueueData(std::forward<IpdlQueueBuffer>(aBuffer))) {
return IPC_OK();
}
return IPC_FAIL_NO_REASON(static_cast<Derived*>(this));
}
std::unordered_map<uint64_t, IpdlQueueBuffer> mIpdlQueueBuffers;
};
template <typename Derived>
class SyncConsumerActor : public AsyncConsumerActor<Derived> {
protected:
using AsyncConsumerActor<Derived>::StoreIpdlQueueData;
mozilla::ipc::IPCResult RecvExchangeIpdlQueueData(
IpdlQueueBuffer&& aBuffer, IpdlQueueBuffers* aResponse) {
uint64_t id = aBuffer.id;
if (!StoreIpdlQueueData(std::forward<IpdlQueueBuffer>(aBuffer))) {
return IPC_FAIL_NO_REASON(static_cast<Derived*>(this));
}
// Mark the actor as in a sync operation, then calls handler.
// During handler, if actor is used as producer (for ALL queues)
// then instead of immediately sending, it writes the data into
// aResponse. When handler is done, we unmark the actor.
// Note that we must buffer for _all_ queues associated with the
// actor as the intended response queue is indistinguishable from
// the rest from our vantage point.
Derived* actor = static_cast<Derived*>(this);
actor->SetResponseBuffers(aResponse);
auto clearResponseBuffer =
MakeScopeExit([&] { actor->ClearResponseBuffers(); });
#if defined(DEBUG)
// Response now includes any cached async transmissions. It is
// illegal to have a response queue also used for other purposes
// so the cache for that queue must be empty.
DebugOnly<bool> responseBufferIsEmpty = [&] {
for (auto& elt : *aResponse) {
if (elt.id == id) {
return elt.data.IsEmpty();
}
}
return true;
}();
MOZ_ASSERT(responseBufferIsEmpty);
#endif
return actor->RunQueue(id) ? IPC_OK() : IPC_FAIL_NO_REASON(actor);
}
};
template <typename _Actor>
class IpdlProducer final : public SupportsWeakPtr {
nsTArray<uint8_t> mSerializedData;
WeakPtr<_Actor> mActor;
uint64_t mId;
public:
using Actor = _Actor;
using SelfType = IpdlProducer<Actor>;
// For IPDL:
IpdlProducer() : mId(kIllegalQueueId) {}
/**
* Insert aArgs into the queue. If the operation does not succeed then
* the queue is unchanged.
*/
template <typename... Args>
QueueStatus TryInsert(Args&&... aArgs) {
MOZ_ASSERT(mId != kIllegalQueueId);
if (!mActor) {
NS_WARNING("TryInsert with actor that was already freed.");
return QueueStatus::kFatalError;
}
// Fill mSerializedData with the data to send. Clear it when done.
MOZ_ASSERT(mSerializedData.IsEmpty());
auto self = *this;
auto clearData = MakeScopeExit([&] { self.mSerializedData.Clear(); });
const IpdlQueueProtocol protocol = mActor->GetIpdlQueueProtocol(aArgs...);
QueueStatus status = SerializeAllArgs(std::forward<Args>(aArgs)...);
if (status != QueueStatus::kSuccess) {
return status;
}
return mActor->TransmitIpdlQueueData(
protocol, IpdlQueueBuffer(mId, std::move(mSerializedData)))
? QueueStatus::kSuccess
: QueueStatus::kFatalError;
}
/**
* Same as TryInsert. IPDL send failures are considered fatal to the
* IpdlQueue.
*/
template <typename... Args>
QueueStatus TryWaitInsert(const Maybe<TimeDuration>&, Args&&... aArgs) {
return TryInsert(std::forward<Args>(aArgs)...);
}
QueueStatus AllocShmem(mozilla::ipc::Shmem* aShmem, size_t aBufferSize,
const void* aBuffer = nullptr) {
if (!mActor) {
return QueueStatus::kFatalError;
}
if (!mActor->AllocShmem(
aBufferSize,
mozilla::ipc::SharedMemory::SharedMemoryType::TYPE_BASIC, aShmem)) {
return QueueStatus::kOOMError;
}
if (aBuffer) {
memcpy(aShmem->get<uint8_t>(), aBuffer, aBufferSize);
}
return QueueStatus::kSuccess;
}
protected:
template <typename T1, typename T2>
friend class IpdlQueue;
friend struct mozilla::ipc::IPDLParamTraits<SelfType>;
explicit IpdlProducer(uint64_t aId, Actor* aActor = nullptr)
: mActor(aActor), mId(aId) {}
template <typename... Args>
QueueStatus SerializeAllArgs(Args&&... aArgs) {
size_t read = 0;
size_t write = 0;
mozilla::webgl::ProducerView<SelfType> view(this, read, &write);
size_t bytesNeeded = MinSizeofArgs(view, aArgs...);
if (!mSerializedData.SetLength(bytesNeeded, fallible)) {
return QueueStatus::kOOMError;
}
return SerializeArgs(view, aArgs...);
}
QueueStatus SerializeArgs(mozilla::webgl::ProducerView<SelfType>& aView) {
return QueueStatus::kSuccess;
}
template <typename Arg, typename... Args>
QueueStatus SerializeArgs(mozilla::webgl::ProducerView<SelfType>& aView,
const Arg& aArg, const Args&... aArgs) {
QueueStatus status = SerializeArg(aView, aArg);
if (!IsSuccess(status)) {
return status;
}
return SerializeArgs(aView, aArgs...);
}
template <typename Arg>
QueueStatus SerializeArg(mozilla::webgl::ProducerView<SelfType>& aView,
const Arg& aArg) {
return mozilla::webgl::QueueParamTraits<
typename std::remove_volatile<Arg>::type>::Write(aView, aArg);
}
public:
template <typename Arg>
QueueStatus WriteObject(size_t aRead, size_t* aWrite, const Arg& arg,
size_t aArgSize) {
if (mSerializedData.Length() < (*aWrite) + aArgSize) {
// Previous MinSizeOfArgs estimate was insufficient. Resize the
// buffer to accomodate our real needs.
mSerializedData.SetLength(*aWrite + aArgSize);
}
return mozilla::webgl::Marshaller::WriteObject(
mSerializedData.Elements(), mSerializedData.Length() + 1, aRead, aWrite,
arg, aArgSize);
}
base::ProcessId OtherPid() { return mActor ? mActor->OtherPid() : 0; }
protected:
size_t MinSizeofArgs(mozilla::webgl::ProducerView<SelfType>& aView) {
return 0;
}
template <typename Arg, typename... Args>
size_t MinSizeofArgs(mozilla::webgl::ProducerView<SelfType>& aView,
const Arg& aArg, const Args&... aArgs) {
return aView.MinSizeParam(aArg) + MinSizeofArgs(aView, aArgs...);
}
};
template <typename _Actor>
class IpdlConsumer final : public SupportsWeakPtr {
public:
using Actor = _Actor;
using SelfType = IpdlConsumer<Actor>;
// For IPDL
IpdlConsumer() : mId(kIllegalQueueId) {}
/**
* Attempts to copy and remove aArgs from the queue. If the operation does
* not succeed then the queue is unchanged. If the operation returns
* kQueueNotReady then the consumer does not yet have enough data to satisfy
* the request. In this case, the IPDL MessageQueue should be given the
* opportunity to run, at which point TryRemove can be attempted again.
*/
template <typename... Args>
QueueStatus TryRemove(Args&... aArgs) {
MOZ_ASSERT(mId != kIllegalQueueId);
if (!mActor) {
NS_WARNING("TryRemove with actor that was already freed.");
return QueueStatus::kFatalError;
}
mBuf.AppendElements(mActor->TakeIpdlQueueData(mId));
return DeserializeAllArgs(aArgs...);
}
/**
* Equivalent to TryRemove. Duration is ignored as it would need to
* allow the IPDL queue to run to be useful.
*/
template <typename... Args>
QueueStatus TryWaitRemove(const Maybe<TimeDuration>&, Args&... aArgs) {
return TryRemove(aArgs...);
}
mozilla::ipc::Shmem::SharedMemory* LookupSharedMemory(uint32_t aId) {
return mActor ? mActor->LookupSharedMemory(aId) : nullptr;
}
protected:
template <typename T1, typename T2>
friend class IpdlQueue;
friend struct mozilla::ipc::IPDLParamTraits<SelfType>;
explicit IpdlConsumer(uint64_t aId, Actor* aActor = nullptr)
: mActor(aActor), mId(aId) {}
template <typename... Args>
QueueStatus DeserializeAllArgs(Args&... aArgs) {
size_t read = 0;
size_t write = mBuf.Length();
mozilla::webgl::ConsumerView<SelfType> view(this, &read, write);
QueueStatus status = DeserializeArgs(view, aArgs...);
if (IsSuccess(status) && (read > 0)) {
mBuf.RemoveElementsAt(0, read);
}
return status;
}
QueueStatus DeserializeArgs(mozilla::webgl::ConsumerView<SelfType>& aView) {
return QueueStatus::kSuccess;
}
template <typename Arg, typename... Args>
QueueStatus DeserializeArgs(mozilla::webgl::ConsumerView<SelfType>& aView,
Arg& aArg, Args&... aArgs) {
QueueStatus status = DeserializeArg(aView, aArg);
if (!IsSuccess(status)) {
return status;
}
return DeserializeArgs(aView, aArgs...);
}
template <typename Arg>
QueueStatus DeserializeArg(mozilla::webgl::ConsumerView<SelfType>& aView,
Arg& aArg) {
return mozilla::webgl::
QueueParamTraits<typename mozilla::webgl::RemoveCVR<Arg>::Type>::Read(
aView, const_cast<std::remove_cv_t<Arg>*>(&aArg));
}
public:
template <typename Arg>
QueueStatus ReadObject(size_t* aRead, size_t aWrite, Arg* arg,
size_t aArgSize) {
// TODO: Queue needs one extra byte for PCQ (fixme).
return mozilla::webgl::Marshaller::ReadObject(
mBuf.Elements(), mBuf.Length() + 1, aRead, aWrite, arg, aArgSize);
}
base::ProcessId OtherPid() { return mActor ? mActor->OtherPid() : 0; }
protected:
WeakPtr<Actor> mActor;
uint64_t mId;
nsTArray<uint8_t> mBuf;
};
/**
* An IpdlQueue is a queue that uses an actor of type ActorP to send data and
* its reciprocal (i.e. child to its parent or vice-versa) to receive data.
* ActorP must derive from one of:
* AsyncProducerActor, SyncProducerActor
* ActorC must derive from one of:
* AsyncConsumerActor, SyncConsumerActor
*/
template <typename _ActorP, typename _ActorC>
class IpdlQueue final {
public:
using ActorP = _ActorP;
using ActorC = _ActorC;
using Producer = IpdlProducer<ActorP>;
using Consumer = IpdlConsumer<ActorC>;
UniquePtr<Producer> TakeProducer() { return std::move(mProducer); }
UniquePtr<Consumer> TakeConsumer() { return std::move(mConsumer); }
/**
* Create an IpdlQueue where the given actor is a producer and its
* reciprocal is the consumer.
* The reciprocal actor type must be typedefed in ActorC as OtherSideActor.
* For example, WebGLChild::OtherSideActor is WebGLParent.
*/
static UniquePtr<IpdlQueue<ActorP, ActorC>> Create(ActorP* aProducerActor) {
static_assert(std::is_same<typename ActorP::OtherSideActor, ActorC>::value,
"ActorP's reciprocal must be ActorC");
static_assert(std::is_same<typename ActorC::OtherSideActor, ActorP>::value,
"ActorC's reciprocal must be ActorP");
auto id = NewIpdlQueueId();
return WrapUnique(new IpdlQueue<ActorP, ActorC>(
std::move(WrapUnique(new Producer(id, aProducerActor))),
std::move(WrapUnique(new Consumer(id)))));
}
/**
* Create an IpdlQueue where the given actor is a consumer and its
* reciprocal is the producer.
* The reciprocal actor type must be typedefed in ActorC as OtherSideActor.
* For example, WebGLChild::OtherSideActor is WebGLParent.
*/
static UniquePtr<IpdlQueue<ActorP, ActorC>> Create(ActorC* aConsumerActor) {
static_assert(std::is_same<typename ActorP::OtherSideActor, ActorC>::value,
"ActorP's reciprocal must be ActorC");
static_assert(std::is_same<typename ActorC::OtherSideActor, ActorP>::value,
"ActorC's reciprocal must be ActorP");
auto id = NewIpdlQueueId();
return WrapUnique(new IpdlQueue<ActorP, ActorC>(
std::move(WrapUnique(new Producer(id))),
std::move(WrapUnique(new Consumer(id, aConsumerActor)))));
}
private:
IpdlQueue(UniquePtr<Producer>&& aProducer, UniquePtr<Consumer>&& aConsumer)
: mProducer(std::move(aProducer)), mConsumer(std::move(aConsumer)) {}
UniquePtr<Producer> mProducer;
UniquePtr<Consumer> mConsumer;
};
} // namespace dom
namespace ipc {
template <typename Actor>
struct IPDLParamTraits<mozilla::dom::IpdlProducer<Actor>> {
typedef mozilla::dom::IpdlProducer<Actor> paramType;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
MOZ_ASSERT(aParam.mActor == nullptr);
WriteIPDLParam(aMsg, aActor, aParam.mId);
}
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, paramType* aResult) {
aResult->mActor = static_cast<Actor*>(aActor);
return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mId);
}
};
template <typename Actor>
struct IPDLParamTraits<mozilla::dom::IpdlConsumer<Actor>> {
typedef mozilla::dom::IpdlConsumer<Actor> paramType;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
MOZ_ASSERT(aParam.mActor == nullptr);
WriteIPDLParam(aMsg, aActor, aParam.mId);
WriteIPDLParam(aMsg, aActor, aParam.mBuf);
}
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, paramType* aResult) {
aResult->mActor = static_cast<Actor*>(aActor);
return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mId) &&
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mBuf);
}
};
template <>
struct IPDLParamTraits<mozilla::dom::IpdlQueueBuffer> {
typedef mozilla::dom::IpdlQueueBuffer paramType;
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const paramType& aParam) {
WriteParam(aMsg, aParam.id);
WriteParam(aMsg, aParam.data);
}
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, paramType* aResult) {
return ReadParam(aMsg, aIter, &aResult->id) &&
ReadParam(aMsg, aIter, &aResult->data);
}
};
} // namespace ipc
} // namespace mozilla
#endif // IPDLQUEUE_H_
|