Bug 1845811 remove unused rv variable r=padenot
[gecko.git] / ipc / glue / MessageChannel.h
blob67540b4ac8029e40aabd8402e6a2f1cc4f4a2573
1 /* -*- Mode: C++; tab-width: 4; 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 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"
17 #if defined(XP_WIN)
18 # include "mozilla/ipc/Neutering.h"
19 #endif // defined(XP_WIN)
21 #include <functional>
22 #include <map>
23 #include <stack>
24 #include <vector>
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"
32 #endif
34 class MessageLoop;
36 namespace IPC {
37 template <typename T>
38 struct ParamTraits;
41 namespace mozilla {
42 namespace ipc {
44 class IToplevelProtocol;
45 class ActorLifecycleProxy;
47 class RefCountedMonitor : public Monitor {
48 public:
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)
58 private:
59 ~RefCountedMonitor() = default;
62 enum class MessageDirection {
63 eSending,
64 eReceiving,
67 enum class MessagePhase {
68 Endpoint,
69 TransferStart,
70 TransferEnd,
73 enum class SyncSendError {
74 SendSuccess,
75 PreviousTimeout,
76 SendingCPOWWhileDispatchingSync,
77 SendingCPOWWhileDispatchingUrgent,
78 NotConnectedBeforeSend,
79 DisconnectedDuringSend,
80 CancelledBeforeSend,
81 CancelledAfterSend,
82 TimedOut,
83 ReplyError,
86 enum class ResponseRejectReason {
87 SendError,
88 ChannelClosed,
89 HandlerRejected,
90 ActorDestroyed,
91 ResolverDestroyed,
92 EndGuard_,
95 template <typename T>
96 using ResolveCallback = std::function<void(T&&)>;
98 using RejectCallback = std::function<void(ResponseRejectReason)>;
100 enum ChannelState {
101 ChannelClosed,
102 ChannelConnected,
103 ChannelClosing,
104 ChannelError
107 class AutoEnterTransaction;
109 class MessageChannel : HasResultCodes {
110 friend class PortLink;
112 typedef mozilla::Monitor Monitor;
114 public:
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)); }
128 int32_t mActorId;
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;
145 private:
146 static Atomic<size_t> gUnresolvedResponses;
147 friend class PendingResponseReporter;
149 public:
150 static constexpr int32_t kNoTimeout = INT32_MIN;
152 using ScopedPort = mozilla::ipc::ScopedPort;
154 explicit MessageChannel(const char* aName, IToplevelProtocol* aListener);
155 ~MessageChannel();
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,
180 Side aSide);
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
205 // unexpectedly.
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
226 enum ChannelFlags {
227 REQUIRE_DEFAULT = 0,
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
232 // plugins.
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);
251 return;
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,
276 int32_t aActorId);
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();
327 #endif
329 #ifdef XP_WIN
330 struct MOZ_STACK_CLASS SyncStackFrame {
331 explicit SyncStackFrame(MessageChannel* channel);
332 ~SyncStackFrame();
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;
350 return false;
353 protected:
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;
362 public:
363 void ProcessNativeEventsInInterruptCall();
364 static void NotifyGeckoEventDispatch();
366 private:
367 void SpinInternalEventLoop();
368 #endif // defined(XP_WIN)
370 private:
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,
414 // necessarily.
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);
437 private:
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);
459 private:
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);
487 private:
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);
500 private:
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!");
507 private:
508 class MessageTask : public CancelableRunnable,
509 public LinkedListElement<RefPtr<MessageTask>>,
510 public nsIRunnablePriority,
511 public nsIRunnableIPCMessageType {
512 public:
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();
527 return mScheduled;
530 UniquePtr<Message>& Msg() MOZ_REQUIRES(*mMonitor) {
531 MOZ_DIAGNOSTIC_ASSERT(mMessage, "message was moved");
532 return mMessage;
534 const UniquePtr<Message>& Msg() const MOZ_REQUIRES(*mMonitor) {
535 MOZ_DIAGNOSTIC_ASSERT(mMessage, "message was moved");
536 return mMessage;
539 void AssertMonitorHeld(const RefCountedMonitor& aMonitor)
540 MOZ_REQUIRES(aMonitor) MOZ_ASSERT_CAPABILITY(*mMonitor) {
541 aMonitor.AssertSameMonitor(*mMonitor);
544 private:
545 ~MessageTask();
547 MessageChannel* Channel() MOZ_REQUIRES(*mMonitor) {
548 mMonitor->AssertCurrentThreadOwns();
549 MOZ_RELEASE_ASSERT(isInList());
550 return mChannel;
553 // The connected MessageChannel's monitor. Guards `mChannel` and
554 // `mScheduled`.
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);
565 #endif
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 {
573 public:
574 NS_DECL_THREADSAFE_ISUPPORTS
576 WorkerTargetShutdownTask(nsISerialEventTarget* aTarget,
577 MessageChannel* aChannel);
579 void TargetShutdown() override;
580 void Clear();
582 private:
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 {
591 public:
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();
602 private:
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;
617 private:
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
622 // afterwards.
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
635 // `MessageChannel`.
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
661 // or give up.
662 // only accessed on WorkerThread
663 int32_t mTimeoutMs = kNoTimeout;
664 bool mInTimeoutSecondHalf = false;
666 // Worker-thread only; sequence numbers for messages that require
667 // replies.
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;
675 template <class T>
676 class AutoSetValue {
677 public:
678 explicit AutoSetValue(T& var, const T& newValue)
679 : mVar(var), mPrev(var), mNew(newValue) {
680 mVar = newValue;
682 ~AutoSetValue() {
683 // The value may have been zeroed if the transaction was
684 // canceled. In that case we shouldn't return it to its previous
685 // value.
686 if (mVar == mNew) {
687 mVar = mPrev;
691 private:
692 T& mVar;
693 T mPrev;
694 T mNew;
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);
729 #ifdef DEBUG
730 void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor);
731 #else
732 void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor) {}
733 #endif
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
743 // error.
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
747 // care about.
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
757 // in-msg.
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
763 // context).
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
768 // by mMonitor.
769 bool mOnCxxStack = false;
771 // Map of async Callbacks that are still waiting replies.
772 CallbackMap mPendingResponses;
774 #ifdef XP_WIN
775 HANDLE mEvent;
776 #endif
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
783 // error.
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;
796 void CancelCPOWs();
798 } // namespace ipc
799 } // namespace mozilla
801 namespace IPC {
802 template <>
803 struct ParamTraits<mozilla::ipc::ResponseRejectReason>
804 : public ContiguousEnumSerializer<
805 mozilla::ipc::ResponseRejectReason,
806 mozilla::ipc::ResponseRejectReason::SendError,
807 mozilla::ipc::ResponseRejectReason::EndGuard_> {};
808 } // namespace IPC
810 namespace geckoprofiler::markers {
812 struct IPCMarker {
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(
832 "messageType",
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.
846 aWriter.IntProperty(
847 "threadId",
848 static_cast<int64_t>(aOriginThreadId.ThreadId().ToNumber()));
851 static mozilla::MarkerSchema MarkerTypeDisplay() {
852 return mozilla::MarkerSchema::SpecialFrontendLocation{};
855 private:
856 static mozilla::Span<const char> IPCSideToString(mozilla::ipc::Side aSide) {
857 switch (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");
864 default:
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) {
872 switch (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");
879 default:
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