1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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 ipc_glue_MessageChannel_h
9 #define ipc_glue_MessageChannel_h
11 #include "ipc/EnumSerializer.h"
12 #include "mozilla/Atomics.h"
13 #include "mozilla/BaseProfilerMarkers.h"
14 #include "mozilla/LinkedList.h"
15 #include "mozilla/Monitor.h"
16 #include "mozilla/Vector.h"
18 # include "mozilla/ipc/Neutering.h"
19 #endif // defined(XP_WIN)
26 #include "MessageLink.h" // for HasResultCodes
27 #include "mozilla/ipc/ScopedPort.h"
28 #include "nsITargetShutdownTask.h"
30 #ifdef FUZZING_SNAPSHOT
31 # include "mozilla/fuzzing/IPCFuzzController.h"
44 class IToplevelProtocol
;
45 class ActorLifecycleProxy
;
47 class RefCountedMonitor
: public Monitor
{
49 RefCountedMonitor() : Monitor("mozilla.ipc.MessageChannel.mMonitor") {}
51 void AssertSameMonitor(const RefCountedMonitor
& aOther
) const
52 MOZ_REQUIRES(*this) MOZ_ASSERT_CAPABILITY(aOther
) {
53 MOZ_ASSERT(this == &aOther
);
56 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMonitor
)
59 ~RefCountedMonitor() = default;
62 enum class MessageDirection
{
67 enum class MessagePhase
{
73 enum class SyncSendError
{
76 SendingCPOWWhileDispatchingSync
,
77 SendingCPOWWhileDispatchingUrgent
,
78 NotConnectedBeforeSend
,
79 DisconnectedDuringSend
,
86 enum class ResponseRejectReason
{
96 using ResolveCallback
= std::function
<void(T
&&)>;
98 using RejectCallback
= std::function
<void(ResponseRejectReason
)>;
107 class AutoEnterTransaction
;
109 class MessageChannel
: HasResultCodes
{
110 friend class PortLink
;
112 typedef mozilla::Monitor Monitor
;
115 using Message
= IPC::Message
;
117 struct UntypedCallbackHolder
{
118 UntypedCallbackHolder(int32_t aActorId
, Message::msgid_t aReplyMsgId
,
119 RejectCallback
&& aReject
)
120 : mActorId(aActorId
),
121 mReplyMsgId(aReplyMsgId
),
122 mReject(std::move(aReject
)) {}
124 virtual ~UntypedCallbackHolder() = default;
126 void Reject(ResponseRejectReason
&& aReason
) { mReject(std::move(aReason
)); }
129 Message::msgid_t mReplyMsgId
;
130 RejectCallback mReject
;
133 template <typename Value
>
134 struct CallbackHolder
: public UntypedCallbackHolder
{
135 CallbackHolder(int32_t aActorId
, Message::msgid_t aReplyMsgId
,
136 ResolveCallback
<Value
>&& aResolve
, RejectCallback
&& aReject
)
137 : UntypedCallbackHolder(aActorId
, aReplyMsgId
, std::move(aReject
)),
138 mResolve(std::move(aResolve
)) {}
140 void Resolve(Value
&& aReason
) { mResolve(std::move(aReason
)); }
142 ResolveCallback
<Value
> mResolve
;
146 static Atomic
<size_t> gUnresolvedResponses
;
147 friend class PendingResponseReporter
;
150 static constexpr int32_t kNoTimeout
= INT32_MIN
;
152 using ScopedPort
= mozilla::ipc::ScopedPort
;
154 explicit MessageChannel(const char* aName
, IToplevelProtocol
* aListener
);
157 IToplevelProtocol
* Listener() const { return mListener
; }
159 // Returns the event target which the worker lives on and must be used for
160 // operations on the current thread. Only safe to access after the
161 // MessageChannel has been opened.
162 nsISerialEventTarget
* GetWorkerEventTarget() const { return mWorkerThread
; }
164 // "Open" a connection using an existing ScopedPort. The ScopedPort must be
165 // valid and connected to a remote.
167 // The `aEventTarget` parameter must be on the current thread.
168 bool Open(ScopedPort aPort
, Side aSide
, const nsID
& aMessageChannelId
,
169 nsISerialEventTarget
* aEventTarget
= nullptr);
171 // "Open" a connection to another thread in the same process.
173 // Returns true if the transport layer was successfully connected,
174 // i.e., mChannelState == ChannelConnected.
176 // For more details on the process of opening a channel between
177 // threads, see the extended comment on this function
178 // in MessageChannel.cpp.
179 bool Open(MessageChannel
* aTargetChan
, nsISerialEventTarget
* aEventTarget
,
182 // "Open" a connection to an actor on the current thread.
184 // Returns true if the transport layer was successfully connected,
185 // i.e., mChannelState == ChannelConnected.
187 // Same-thread channels may not perform synchronous or blocking message
188 // sends, to avoid deadlocks.
189 bool OpenOnSameThread(MessageChannel
* aTargetChan
, Side aSide
);
192 * This sends a special message that is processed on the IO thread, so that
193 * other actors can know that the process will soon shutdown.
195 void NotifyImpendingShutdown() MOZ_EXCLUDES(*mMonitor
);
197 // Close the underlying transport channel.
198 void Close() MOZ_EXCLUDES(*mMonitor
);
200 // Induce an error in this MessageChannel's connection.
202 // After this method is called, no more message notifications will be
203 // delivered to the listener, and the channel will be unable to send or
204 // receive future messages, as if the peer dropped the connection
207 // The OnChannelError notification will be delivered either asynchronously or
208 // during an explicit call to Close(), whichever happens first.
210 // NOTE: If SetAbortOnError(true) has been called on this MessageChannel,
211 // calling this function will immediately exit the current process.
212 void InduceConnectionError() MOZ_EXCLUDES(*mMonitor
);
214 void SetAbortOnError(bool abort
) MOZ_EXCLUDES(*mMonitor
) {
215 MonitorAutoLock
lock(*mMonitor
);
216 mAbortOnError
= abort
;
219 // Call aInvoke for each pending message until it returns false.
220 // XXX: You must get permission from an IPC peer to use this function
221 // since it requires custom deserialization and re-orders events.
222 void PeekMessages(const std::function
<bool(const Message
& aMsg
)>& aInvoke
)
223 MOZ_EXCLUDES(*mMonitor
);
225 // Misc. behavioral traits consumers can request for this channel
228 // Windows: if this channel operates on the UI thread, indicates
229 // WindowsMessageLoop code should enable deferred native message
230 // handling to prevent deadlocks. Should only be used for protocols
231 // that manage child processes which might create native UI, like
233 REQUIRE_DEFERRED_MESSAGE_PROTECTION
= 1 << 0,
235 void SetChannelFlags(ChannelFlags aFlags
) { mFlags
= aFlags
; }
236 ChannelFlags
GetChannelFlags() { return mFlags
; }
238 // Asynchronously send a message to the other side of the channel
239 bool Send(UniquePtr
<Message
> aMsg
) MOZ_EXCLUDES(*mMonitor
);
241 // Asynchronously send a message to the other side of the channel
242 // and wait for asynchronous reply.
243 template <typename Value
>
244 void Send(UniquePtr
<Message
> aMsg
, int32_t aActorId
,
245 Message::msgid_t aReplyMsgId
, ResolveCallback
<Value
>&& aResolve
,
246 RejectCallback
&& aReject
) MOZ_EXCLUDES(*mMonitor
) {
247 int32_t seqno
= NextSeqno();
248 aMsg
->set_seqno(seqno
);
249 if (!Send(std::move(aMsg
))) {
250 aReject(ResponseRejectReason::SendError
);
254 UniquePtr
<UntypedCallbackHolder
> callback
=
255 MakeUnique
<CallbackHolder
<Value
>>(
256 aActorId
, aReplyMsgId
, std::move(aResolve
), std::move(aReject
));
257 mPendingResponses
.insert(std::make_pair(seqno
, std::move(callback
)));
258 gUnresolvedResponses
++;
261 bool SendBuildIDsMatchMessage(const char* aParentBuildID
)
262 MOZ_EXCLUDES(*mMonitor
);
263 bool DoBuildIDsMatch() MOZ_EXCLUDES(*mMonitor
) {
264 MonitorAutoLock
lock(*mMonitor
);
265 return mBuildIDsConfirmedMatch
;
268 // Synchronously send |aMsg| (i.e., wait for |aReply|)
269 bool Send(UniquePtr
<Message
> aMsg
, UniquePtr
<Message
>* aReply
)
270 MOZ_EXCLUDES(*mMonitor
);
272 bool CanSend() const MOZ_EXCLUDES(*mMonitor
);
274 // Remove and return a callback that needs reply
275 UniquePtr
<UntypedCallbackHolder
> PopCallback(const Message
& aMsg
,
278 // Used to reject and remove pending responses owned by the given
279 // actor when it's about to be destroyed.
280 void RejectPendingResponsesForActor(int32_t aActorId
);
282 // If sending a sync message returns an error, this function gives a more
283 // descriptive error message.
284 SyncSendError
LastSendError() const {
285 AssertWorkerThread();
286 return mLastSendError
;
289 void SetReplyTimeoutMs(int32_t aTimeoutMs
);
291 bool IsOnCxxStack() const { return mOnCxxStack
; }
293 void CancelCurrentTransaction() MOZ_EXCLUDES(*mMonitor
);
295 // IsClosed and NumQueuedMessages are safe to call from any thread, but
296 // may provide an out-of-date value.
297 bool IsClosed() MOZ_EXCLUDES(*mMonitor
) {
298 MonitorAutoLock
lock(*mMonitor
);
299 return IsClosedLocked();
301 bool IsClosedLocked() const MOZ_REQUIRES(*mMonitor
) {
302 mMonitor
->AssertCurrentThreadOwns();
303 return mLink
? mLink
->IsClosed() : true;
306 static bool IsPumpingMessages() { return sIsPumpingMessages
; }
307 static void SetIsPumpingMessages(bool aIsPumping
) {
308 sIsPumpingMessages
= aIsPumping
;
312 * Does this MessageChannel currently cross process boundaries?
314 bool IsCrossProcess() const MOZ_REQUIRES(*mMonitor
);
315 void SetIsCrossProcess(bool aIsCrossProcess
) MOZ_REQUIRES(*mMonitor
);
317 nsID
GetMessageChannelId() const {
318 MonitorAutoLock
lock(*mMonitor
);
319 return mMessageChannelId
;
322 #ifdef FUZZING_SNAPSHOT
323 Maybe
<mojo::core::ports::PortName
> GetPortName() {
324 MonitorAutoLock
lock(*mMonitor
);
325 return mLink
? mLink
->GetPortName() : Nothing();
330 struct MOZ_STACK_CLASS SyncStackFrame
{
331 explicit SyncStackFrame(MessageChannel
* channel
);
334 bool mSpinNestedEvents
;
335 bool mListenerNotified
;
336 MessageChannel
* mChannel
;
338 // The previous stack frame for this channel.
339 SyncStackFrame
* mPrev
;
341 // The previous stack frame on any channel.
342 SyncStackFrame
* mStaticPrev
;
344 friend struct MessageChannel::SyncStackFrame
;
346 static bool IsSpinLoopActive() {
347 for (SyncStackFrame
* frame
= sStaticTopFrame
; frame
; frame
= frame
->mPrev
) {
348 if (frame
->mSpinNestedEvents
) return true;
354 // The deepest sync stack frame for this channel.
355 SyncStackFrame
* mTopFrame
= nullptr;
357 bool mIsSyncWaitingOnNonMainThread
= false;
359 // The deepest sync stack frame on any channel.
360 static SyncStackFrame
* sStaticTopFrame
;
363 void ProcessNativeEventsInInterruptCall();
364 static void NotifyGeckoEventDispatch();
367 void SpinInternalEventLoop();
368 #endif // defined(XP_WIN)
371 void PostErrorNotifyTask() MOZ_REQUIRES(*mMonitor
);
372 void OnNotifyMaybeChannelError() MOZ_EXCLUDES(*mMonitor
);
373 void ReportConnectionError(const char* aFunctionName
,
374 const uint32_t aMsgTyp
) const
375 MOZ_REQUIRES(*mMonitor
);
376 void ReportMessageRouteError(const char* channelName
) const
377 MOZ_EXCLUDES(*mMonitor
);
378 bool MaybeHandleError(Result code
, const Message
& aMsg
,
379 const char* channelName
) MOZ_EXCLUDES(*mMonitor
);
381 void Clear() MOZ_REQUIRES(*mMonitor
);
383 bool HasPendingEvents() MOZ_REQUIRES(*mMonitor
);
385 void ProcessPendingRequests(ActorLifecycleProxy
* aProxy
,
386 AutoEnterTransaction
& aTransaction
)
387 MOZ_REQUIRES(*mMonitor
);
388 bool ProcessPendingRequest(ActorLifecycleProxy
* aProxy
,
389 UniquePtr
<Message
> aUrgent
)
390 MOZ_REQUIRES(*mMonitor
);
392 void EnqueuePendingMessages() MOZ_REQUIRES(*mMonitor
);
394 // Dispatches an incoming message to its appropriate handler.
395 void DispatchMessage(ActorLifecycleProxy
* aProxy
, UniquePtr
<Message
> aMsg
)
396 MOZ_REQUIRES(*mMonitor
);
398 // DispatchMessage will route to one of these functions depending on the
399 // protocol type of the message.
400 void DispatchSyncMessage(ActorLifecycleProxy
* aProxy
, const Message
& aMsg
,
401 UniquePtr
<Message
>& aReply
) MOZ_EXCLUDES(*mMonitor
);
402 void DispatchAsyncMessage(ActorLifecycleProxy
* aProxy
, const Message
& aMsg
)
403 MOZ_EXCLUDES(*mMonitor
);
405 // Return true if the wait ended because a notification was received.
407 // Return false if the time elapsed from when we started the process of
408 // waiting until afterwards exceeded the currently allotted timeout.
409 // That *DOES NOT* mean false => "no event" (== timeout); there are many
410 // circumstances that could cause the measured elapsed time to exceed the
411 // timeout EVEN WHEN we were notified.
413 // So in sum: true is a meaningful return value; false isn't,
415 bool WaitForSyncNotify() MOZ_REQUIRES(*mMonitor
);
417 bool WaitResponse(bool aWaitTimedOut
);
419 bool ShouldContinueFromTimeout() MOZ_REQUIRES(*mMonitor
);
421 void EndTimeout() MOZ_REQUIRES(*mMonitor
);
422 void CancelTransaction(int transaction
) MOZ_REQUIRES(*mMonitor
);
424 void RepostAllMessages() MOZ_REQUIRES(*mMonitor
);
426 int32_t NextSeqno() {
427 AssertWorkerThread();
428 return (mSide
== ChildSide
) ? --mNextSeqno
: ++mNextSeqno
;
431 void DebugAbort(const char* file
, int line
, const char* cond
, const char* why
,
432 bool reply
= false) MOZ_REQUIRES(*mMonitor
);
434 void AddProfilerMarker(const IPC::Message
& aMessage
,
435 MessageDirection aDirection
) MOZ_REQUIRES(*mMonitor
);
438 // Returns true if we're dispatching an async message's callback.
439 bool DispatchingAsyncMessage() const {
440 AssertWorkerThread();
441 return mDispatchingAsyncMessage
;
444 int DispatchingAsyncMessageNestedLevel() const {
445 AssertWorkerThread();
446 return mDispatchingAsyncMessageNestedLevel
;
449 // Check if there is still a live connection to our peer. This may change to
450 // `false` at any time due to the connection to our peer being closed or
451 // dropped (e.g. due to a crash).
452 bool Connected() const MOZ_REQUIRES(*mMonitor
);
454 // Check if there is either still a live connection to our peer, or we have
455 // received a `Goodbye` from our peer, and are actively shutting down our
456 // connection with our peer.
457 bool ConnectedOrClosing() const MOZ_REQUIRES(*mMonitor
);
460 // Executed on the IO thread.
461 void NotifyWorkerThread() MOZ_REQUIRES(*mMonitor
);
463 // Return true if |aMsg| is a special message targeted at the IO
464 // thread, in which case it shouldn't be delivered to the worker.
465 bool MaybeInterceptSpecialIOMessage(const Message
& aMsg
)
466 MOZ_REQUIRES(*mMonitor
);
468 // Returns true if ShouldDeferMessage(aMsg) is guaranteed to return true.
469 // Otherwise, the result of ShouldDeferMessage(aMsg) may be true or false,
470 // depending on context.
471 static bool IsAlwaysDeferred(const Message
& aMsg
);
473 // Helper for sending a message via the link. If the message is [LazySend], it
474 // will be queued, and if the message is not-[LazySend], it will flush any
475 // pending [LazySend] messages.
476 void SendMessageToLink(UniquePtr
<Message
> aMsg
) MOZ_REQUIRES(*mMonitor
);
478 // Called to flush [LazySend] messages to the link.
479 void FlushLazySendMessages() MOZ_REQUIRES(*mMonitor
);
481 bool WasTransactionCanceled(int transaction
);
482 bool ShouldDeferMessage(const Message
& aMsg
) MOZ_REQUIRES(*mMonitor
);
483 void OnMessageReceivedFromLink(UniquePtr
<Message
> aMsg
)
484 MOZ_REQUIRES(*mMonitor
);
485 void OnChannelErrorFromLink() MOZ_REQUIRES(*mMonitor
);
488 // Clear this channel, and notify the listener that the channel has either
489 // closed or errored.
491 // These methods must be called on the worker thread, passing in a
492 // `ReleasableMonitorAutoLock`. This lock guard will be reset before the
493 // listener is called, allowing for the monitor to be unlocked before the
494 // MessageChannel is potentially destroyed.
495 void NotifyChannelClosed(ReleasableMonitorAutoLock
& aLock
)
496 MOZ_REQUIRES(*mMonitor
);
497 void NotifyMaybeChannelError(ReleasableMonitorAutoLock
& aLock
)
498 MOZ_REQUIRES(*mMonitor
);
501 void AssertWorkerThread() const {
502 MOZ_ASSERT(mWorkerThread
, "Channel hasn't been opened yet");
503 MOZ_RELEASE_ASSERT(mWorkerThread
&& mWorkerThread
->IsOnCurrentThread(),
504 "not on worker thread!");
508 class MessageTask
: public CancelableRunnable
,
509 public LinkedListElement
<RefPtr
<MessageTask
>>,
510 public nsIRunnablePriority
,
511 public nsIRunnableIPCMessageType
{
513 explicit MessageTask(MessageChannel
* aChannel
, UniquePtr
<Message
> aMessage
);
514 MessageTask() = delete;
515 MessageTask(const MessageTask
&) = delete;
517 NS_DECL_ISUPPORTS_INHERITED
519 NS_IMETHOD
Run() override
;
520 nsresult
Cancel() override
;
521 NS_IMETHOD
GetPriority(uint32_t* aPriority
) override
;
522 NS_DECL_NSIRUNNABLEIPCMESSAGETYPE
523 void Post() MOZ_REQUIRES(*mMonitor
);
525 bool IsScheduled() const MOZ_REQUIRES(*mMonitor
) {
526 mMonitor
->AssertCurrentThreadOwns();
530 UniquePtr
<Message
>& Msg() MOZ_REQUIRES(*mMonitor
) {
531 MOZ_DIAGNOSTIC_ASSERT(mMessage
, "message was moved");
534 const UniquePtr
<Message
>& Msg() const MOZ_REQUIRES(*mMonitor
) {
535 MOZ_DIAGNOSTIC_ASSERT(mMessage
, "message was moved");
539 void AssertMonitorHeld(const RefCountedMonitor
& aMonitor
)
540 MOZ_REQUIRES(aMonitor
) MOZ_ASSERT_CAPABILITY(*mMonitor
) {
541 aMonitor
.AssertSameMonitor(*mMonitor
);
547 MessageChannel
* Channel() MOZ_REQUIRES(*mMonitor
) {
548 mMonitor
->AssertCurrentThreadOwns();
549 MOZ_RELEASE_ASSERT(isInList());
553 // The connected MessageChannel's monitor. Guards `mChannel` and
555 RefPtr
<RefCountedMonitor
> const mMonitor
;
556 // The channel which this MessageTask is associated with. Only valid while
557 // `mMonitor` is held, and this MessageTask `isInList()`.
558 MessageChannel
* const mChannel
;
559 UniquePtr
<Message
> mMessage
MOZ_GUARDED_BY(*mMonitor
);
560 uint32_t const mPriority
;
561 bool mScheduled
: 1 MOZ_GUARDED_BY(*mMonitor
);
562 #ifdef FUZZING_SNAPSHOT
563 const bool mIsFuzzMsg
;
564 bool mFuzzStopped
MOZ_GUARDED_BY(*mMonitor
);
568 bool ShouldRunMessage(const Message
& aMsg
) MOZ_REQUIRES(*mMonitor
);
569 void RunMessage(ActorLifecycleProxy
* aProxy
, MessageTask
& aTask
)
570 MOZ_REQUIRES(*mMonitor
);
572 class WorkerTargetShutdownTask final
: public nsITargetShutdownTask
{
574 NS_DECL_THREADSAFE_ISUPPORTS
576 WorkerTargetShutdownTask(nsISerialEventTarget
* aTarget
,
577 MessageChannel
* aChannel
);
579 void TargetShutdown() override
;
583 ~WorkerTargetShutdownTask() = default;
585 const nsCOMPtr
<nsISerialEventTarget
> mTarget
;
586 // Cleared by MessageChannel before it is destroyed.
587 MessageChannel
* MOZ_NON_OWNING_REF mChannel
;
590 class FlushLazySendMessagesRunnable final
: public CancelableRunnable
{
592 explicit FlushLazySendMessagesRunnable(MessageChannel
* aChannel
);
594 NS_DECL_ISUPPORTS_INHERITED
596 NS_IMETHOD
Run() override
;
597 nsresult
Cancel() override
;
599 void PushMessage(UniquePtr
<Message
> aMsg
);
600 nsTArray
<UniquePtr
<Message
>> TakeMessages();
603 ~FlushLazySendMessagesRunnable() = default;
605 // Cleared by MessageChannel before it is destroyed.
606 MessageChannel
* MOZ_NON_OWNING_REF mChannel
;
608 // LazySend messages which haven't been sent yet, but will be sent as soon
609 // as a non-LazySend message is sent, or this runnable is executed.
610 nsTArray
<UniquePtr
<Message
>> mQueue
;
613 typedef LinkedList
<RefPtr
<MessageTask
>> MessageQueue
;
614 typedef std::map
<size_t, UniquePtr
<UntypedCallbackHolder
>> CallbackMap
;
615 typedef IPC::Message::msgid_t msgid_t
;
618 // This will be a string literal, so lifetime is not an issue.
619 const char* const mName
;
621 // ID for each MessageChannel. Set when it is opened, and never cleared
624 // This ID is only intended for diagnostics, debugging, and reporting
625 // purposes, and shouldn't be used for message routing or permissions checks.
626 nsID mMessageChannelId
MOZ_GUARDED_BY(*mMonitor
) = {};
628 // Based on presumption the listener owns and overlives the channel,
629 // this is never nullified.
630 IToplevelProtocol
* const mListener
;
632 // This monitor guards all state in this MessageChannel, except where
633 // otherwise noted. It is refcounted so a reference to it can be shared with
634 // IPC listener objects which need to access weak references to this
636 RefPtr
<RefCountedMonitor
> const mMonitor
;
638 ChannelState mChannelState
MOZ_GUARDED_BY(*mMonitor
) = ChannelClosed
;
639 Side mSide
= UnknownSide
;
640 bool mIsCrossProcess
MOZ_GUARDED_BY(*mMonitor
) = false;
641 UniquePtr
<MessageLink
> mLink
MOZ_GUARDED_BY(*mMonitor
);
643 // NotifyMaybeChannelError runnable
644 RefPtr
<CancelableRunnable
> mChannelErrorTask
MOZ_GUARDED_BY(*mMonitor
);
646 // Thread we are allowed to send and receive on. Set in Open(); never
647 // changed, and we can only call Open() once. We shouldn't be accessing
648 // from multiple threads before Open().
649 nsCOMPtr
<nsISerialEventTarget
> mWorkerThread
;
651 // Shutdown task to close the channel before mWorkerThread goes away.
652 RefPtr
<WorkerTargetShutdownTask
> mShutdownTask
MOZ_GUARDED_BY(*mMonitor
);
654 // Task to force sending lazy messages when mQueuedLazyMessages is non-empty.
655 RefPtr
<FlushLazySendMessagesRunnable
> mFlushLazySendTask
656 MOZ_GUARDED_BY(*mMonitor
);
658 // Timeout periods are broken up in two to prevent system suspension from
659 // triggering an abort. This method (called by WaitForEvent with a 'did
660 // timeout' flag) decides if we should wait again for half of mTimeoutMs
662 // only accessed on WorkerThread
663 int32_t mTimeoutMs
= kNoTimeout
;
664 bool mInTimeoutSecondHalf
= false;
666 // Worker-thread only; sequence numbers for messages that require
668 int32_t mNextSeqno
= 0;
670 static bool sIsPumpingMessages
;
672 // If ::Send returns false, this gives a more descriptive error.
673 SyncSendError mLastSendError
= SyncSendError::SendSuccess
;
678 explicit AutoSetValue(T
& var
, const T
& newValue
)
679 : mVar(var
), mPrev(var
), mNew(newValue
) {
683 // The value may have been zeroed if the transaction was
684 // canceled. In that case we shouldn't return it to its previous
697 bool mDispatchingAsyncMessage
= false;
698 int mDispatchingAsyncMessageNestedLevel
= 0;
700 // When we send an urgent request from the parent process, we could race
701 // with an RPC message that was issued by the child beforehand. In this
702 // case, if the parent were to wake up while waiting for the urgent reply,
703 // and process the RPC, it could send an additional urgent message. The
704 // child would wake up to process the urgent message (as it always will),
705 // then send a reply, which could be received by the parent out-of-order
706 // with respect to the first urgent reply.
708 // To address this problem, urgent or RPC requests are associated with a
709 // "transaction". Whenever one side of the channel wishes to start a
710 // chain of RPC/urgent messages, it allocates a new transaction ID. Any
711 // messages the parent receives, not apart of this transaction, are
712 // deferred. When issuing RPC/urgent requests on top of a started
713 // transaction, the initiating transaction ID is used.
715 // To ensure IDs are unique, we use sequence numbers for transaction IDs,
716 // which grow in opposite directions from child to parent.
718 friend class AutoEnterTransaction
;
719 AutoEnterTransaction
* mTransactionStack
MOZ_GUARDED_BY(*mMonitor
) = nullptr;
721 int32_t CurrentNestedInsideSyncTransaction() const MOZ_REQUIRES(*mMonitor
);
723 bool AwaitingSyncReply() const MOZ_REQUIRES(*mMonitor
);
724 int AwaitingSyncReplyNestedLevel() const MOZ_REQUIRES(*mMonitor
);
726 bool DispatchingSyncMessage() const MOZ_REQUIRES(*mMonitor
);
727 int DispatchingSyncMessageNestedLevel() const MOZ_REQUIRES(*mMonitor
);
730 void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor
);
732 void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor
) {}
735 // If a sync message times out, we store its sequence number here. Any
736 // future sync messages will fail immediately. Once the reply for original
737 // sync message is received, we allow sync messages again.
739 // When a message times out, nothing is done to inform the other side. The
740 // other side will eventually dispatch the message and send a reply. Our
741 // side is responsible for replying to all sync messages sent by the other
742 // side when it dispatches the timed out message. The response is always an
745 // A message is only timed out if it initiated a transaction. This avoids
746 // hitting a lot of corner cases with message nesting that we don't really
748 int32_t mTimedOutMessageSeqno
MOZ_GUARDED_BY(*mMonitor
) = 0;
749 int mTimedOutMessageNestedLevel
MOZ_GUARDED_BY(*mMonitor
) = 0;
751 // Queue of all incoming messages.
753 // If both this side and the other side are functioning correctly, the other
754 // side can send as many async messages as it wants before sending us a
755 // blocking message. After sending a blocking message, the other side must be
756 // blocked, and thus can't send us any more messages until we process the sync
759 MessageQueue mPending
MOZ_GUARDED_BY(*mMonitor
);
761 // The number of messages in mPending for which IsAlwaysDeferred is false
762 // (i.e., the number of messages that might not be deferred, depending on
764 size_t mMaybeDeferredPendingCount
MOZ_GUARDED_BY(*mMonitor
) = 0;
766 // Is there currently MessageChannel logic for this channel on the C++ stack?
767 // This member is only accessed on the worker thread, and so is not protected
769 bool mOnCxxStack
= false;
771 // Map of async Callbacks that are still waiting replies.
772 CallbackMap mPendingResponses
;
778 // Should the channel abort the process from the I/O thread when
779 // a channel error occurs?
780 bool mAbortOnError
MOZ_GUARDED_BY(*mMonitor
) = false;
782 // True if the listener has already been notified of a channel close or
784 bool mNotifiedChannelDone
MOZ_GUARDED_BY(*mMonitor
) = false;
786 // See SetChannelFlags
787 ChannelFlags mFlags
= REQUIRE_DEFAULT
;
789 bool mBuildIDsConfirmedMatch
MOZ_GUARDED_BY(*mMonitor
) = false;
791 // If this is true, both ends of this message channel have event targets
792 // on the same thread.
793 bool mIsSameThreadChannel
= false;
799 } // namespace mozilla
803 struct ParamTraits
<mozilla::ipc::ResponseRejectReason
>
804 : public ContiguousEnumSerializer
<
805 mozilla::ipc::ResponseRejectReason
,
806 mozilla::ipc::ResponseRejectReason::SendError
,
807 mozilla::ipc::ResponseRejectReason::EndGuard_
> {};
810 namespace geckoprofiler::markers
{
813 static constexpr mozilla::Span
<const char> MarkerTypeName() {
814 return mozilla::MakeStringSpan("IPC");
816 static void StreamJSONMarkerData(
817 mozilla::baseprofiler::SpliceableJSONWriter
& aWriter
,
818 mozilla::TimeStamp aStart
, mozilla::TimeStamp aEnd
, int32_t aOtherPid
,
819 int32_t aMessageSeqno
, IPC::Message::msgid_t aMessageType
,
820 mozilla::ipc::Side aSide
, mozilla::ipc::MessageDirection aDirection
,
821 mozilla::ipc::MessagePhase aPhase
, bool aSync
,
822 mozilla::MarkerThreadId aOriginThreadId
) {
823 using namespace mozilla::ipc
;
824 // This payload still streams a startTime and endTime property because it
825 // made the migration to MarkerTiming on the front-end easier.
826 aWriter
.TimeProperty("startTime", aStart
);
827 aWriter
.TimeProperty("endTime", aEnd
);
829 aWriter
.IntProperty("otherPid", aOtherPid
);
830 aWriter
.IntProperty("messageSeqno", aMessageSeqno
);
831 aWriter
.StringProperty(
833 mozilla::MakeStringSpan(IPC::StringFromIPCMessageType(aMessageType
)));
834 aWriter
.StringProperty("side", IPCSideToString(aSide
));
835 aWriter
.StringProperty("direction",
836 aDirection
== MessageDirection::eSending
837 ? mozilla::MakeStringSpan("sending")
838 : mozilla::MakeStringSpan("receiving"));
839 aWriter
.StringProperty("phase", IPCPhaseToString(aPhase
));
840 aWriter
.BoolProperty("sync", aSync
);
841 if (!aOriginThreadId
.IsUnspecified()) {
842 // Tech note: If `ToNumber()` returns a uint64_t, the conversion to
843 // int64_t is "implementation-defined" before C++20. This is acceptable
844 // here, because this is a one-way conversion to a unique identifier
845 // that's used to visually separate data by thread on the front-end.
848 static_cast<int64_t>(aOriginThreadId
.ThreadId().ToNumber()));
851 static mozilla::MarkerSchema
MarkerTypeDisplay() {
852 return mozilla::MarkerSchema::SpecialFrontendLocation
{};
856 static mozilla::Span
<const char> IPCSideToString(mozilla::ipc::Side aSide
) {
858 case mozilla::ipc::ParentSide
:
859 return mozilla::MakeStringSpan("parent");
860 case mozilla::ipc::ChildSide
:
861 return mozilla::MakeStringSpan("child");
862 case mozilla::ipc::UnknownSide
:
863 return mozilla::MakeStringSpan("unknown");
865 MOZ_ASSERT_UNREACHABLE("Invalid IPC side");
866 return mozilla::MakeStringSpan("<invalid IPC side>");
870 static mozilla::Span
<const char> IPCPhaseToString(
871 mozilla::ipc::MessagePhase aPhase
) {
873 case mozilla::ipc::MessagePhase::Endpoint
:
874 return mozilla::MakeStringSpan("endpoint");
875 case mozilla::ipc::MessagePhase::TransferStart
:
876 return mozilla::MakeStringSpan("transferStart");
877 case mozilla::ipc::MessagePhase::TransferEnd
:
878 return mozilla::MakeStringSpan("transferEnd");
880 MOZ_ASSERT_UNREACHABLE("Invalid IPC phase");
881 return mozilla::MakeStringSpan("<invalid IPC phase>");
886 } // namespace geckoprofiler::markers
888 #endif // ifndef ipc_glue_MessageChannel_h