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