Bug 1874684 - Part 17: Fix uninitialised variable warnings from clang-tidy. r=allstarschh
[gecko.git] / ipc / glue / MessageChannel.h
bloba1a5bad9162160743270efda55e56f45b7fa1b10
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 // Return whether the current transaction is complete.
297 // This is intended only for tests.
298 bool TestOnlyIsTransactionComplete() const MOZ_EXCLUDES(*mMonitor);
300 // IsClosed and NumQueuedMessages are safe to call from any thread, but
301 // may provide an out-of-date value.
302 bool IsClosed() MOZ_EXCLUDES(*mMonitor) {
303 MonitorAutoLock lock(*mMonitor);
304 return IsClosedLocked();
306 bool IsClosedLocked() const MOZ_REQUIRES(*mMonitor) {
307 mMonitor->AssertCurrentThreadOwns();
308 return mLink ? mLink->IsClosed() : true;
311 static bool IsPumpingMessages() { return sIsPumpingMessages; }
312 static void SetIsPumpingMessages(bool aIsPumping) {
313 sIsPumpingMessages = aIsPumping;
317 * Does this MessageChannel currently cross process boundaries?
319 bool IsCrossProcess() const MOZ_REQUIRES(*mMonitor);
320 void SetIsCrossProcess(bool aIsCrossProcess) MOZ_REQUIRES(*mMonitor);
322 nsID GetMessageChannelId() const {
323 MonitorAutoLock lock(*mMonitor);
324 return mMessageChannelId;
327 #ifdef FUZZING_SNAPSHOT
328 Maybe<mojo::core::ports::PortName> GetPortName() {
329 MonitorAutoLock lock(*mMonitor);
330 return mLink ? mLink->GetPortName() : Nothing();
332 #endif
334 #ifdef XP_WIN
335 struct MOZ_STACK_CLASS SyncStackFrame {
336 explicit SyncStackFrame(MessageChannel* channel);
337 ~SyncStackFrame();
339 bool mSpinNestedEvents;
340 bool mListenerNotified;
341 MessageChannel* mChannel;
343 // The previous stack frame for this channel.
344 SyncStackFrame* mPrev;
346 // The previous stack frame on any channel.
347 SyncStackFrame* mStaticPrev;
349 friend struct MessageChannel::SyncStackFrame;
351 static bool IsSpinLoopActive() {
352 for (SyncStackFrame* frame = sStaticTopFrame; frame; frame = frame->mPrev) {
353 if (frame->mSpinNestedEvents) return true;
355 return false;
358 protected:
359 // The deepest sync stack frame for this channel.
360 SyncStackFrame* mTopFrame = nullptr;
362 bool mIsSyncWaitingOnNonMainThread = false;
364 // The deepest sync stack frame on any channel.
365 static SyncStackFrame* sStaticTopFrame;
367 public:
368 void ProcessNativeEventsInInterruptCall();
369 static void NotifyGeckoEventDispatch();
371 private:
372 void SpinInternalEventLoop();
373 #endif // defined(XP_WIN)
375 private:
376 void PostErrorNotifyTask() MOZ_REQUIRES(*mMonitor);
377 void OnNotifyMaybeChannelError() MOZ_EXCLUDES(*mMonitor);
378 void ReportConnectionError(const char* aFunctionName,
379 const uint32_t aMsgTyp) const
380 MOZ_REQUIRES(*mMonitor);
381 void ReportMessageRouteError(const char* channelName) const
382 MOZ_EXCLUDES(*mMonitor);
383 bool MaybeHandleError(Result code, const Message& aMsg,
384 const char* channelName) MOZ_EXCLUDES(*mMonitor);
386 void Clear() MOZ_REQUIRES(*mMonitor);
388 bool HasPendingEvents() MOZ_REQUIRES(*mMonitor);
390 void ProcessPendingRequests(ActorLifecycleProxy* aProxy,
391 AutoEnterTransaction& aTransaction)
392 MOZ_REQUIRES(*mMonitor);
393 bool ProcessPendingRequest(ActorLifecycleProxy* aProxy,
394 UniquePtr<Message> aUrgent)
395 MOZ_REQUIRES(*mMonitor);
397 void EnqueuePendingMessages() MOZ_REQUIRES(*mMonitor);
399 // Dispatches an incoming message to its appropriate handler.
400 void DispatchMessage(ActorLifecycleProxy* aProxy, UniquePtr<Message> aMsg)
401 MOZ_REQUIRES(*mMonitor);
403 // DispatchMessage will route to one of these functions depending on the
404 // protocol type of the message.
405 void DispatchSyncMessage(ActorLifecycleProxy* aProxy, const Message& aMsg,
406 UniquePtr<Message>& aReply) MOZ_EXCLUDES(*mMonitor);
407 void DispatchAsyncMessage(ActorLifecycleProxy* aProxy, const Message& aMsg)
408 MOZ_EXCLUDES(*mMonitor);
410 // Return true if the wait ended because a notification was received.
412 // Return false if the time elapsed from when we started the process of
413 // waiting until afterwards exceeded the currently allotted timeout.
414 // That *DOES NOT* mean false => "no event" (== timeout); there are many
415 // circumstances that could cause the measured elapsed time to exceed the
416 // timeout EVEN WHEN we were notified.
418 // So in sum: true is a meaningful return value; false isn't,
419 // necessarily.
420 bool WaitForSyncNotify() MOZ_REQUIRES(*mMonitor);
422 bool WaitResponse(bool aWaitTimedOut);
424 bool ShouldContinueFromTimeout() MOZ_REQUIRES(*mMonitor);
426 void EndTimeout() MOZ_REQUIRES(*mMonitor);
427 void CancelTransaction(int transaction) MOZ_REQUIRES(*mMonitor);
429 void RepostAllMessages() MOZ_REQUIRES(*mMonitor);
431 int32_t NextSeqno() {
432 AssertWorkerThread();
433 return (mSide == ChildSide) ? --mNextSeqno : ++mNextSeqno;
436 void DebugAbort(const char* file, int line, const char* cond, const char* why,
437 bool reply = false) MOZ_REQUIRES(*mMonitor);
439 void AddProfilerMarker(const IPC::Message& aMessage,
440 MessageDirection aDirection) MOZ_REQUIRES(*mMonitor);
442 private:
443 // Returns true if we're dispatching an async message's callback.
444 bool DispatchingAsyncMessage() const {
445 AssertWorkerThread();
446 return mDispatchingAsyncMessage;
449 int DispatchingAsyncMessageNestedLevel() const {
450 AssertWorkerThread();
451 return mDispatchingAsyncMessageNestedLevel;
454 // Check if there is still a live connection to our peer. This may change to
455 // `false` at any time due to the connection to our peer being closed or
456 // dropped (e.g. due to a crash).
457 bool Connected() const MOZ_REQUIRES(*mMonitor);
459 // Check if there is either still a live connection to our peer, or we have
460 // received a `Goodbye` from our peer, and are actively shutting down our
461 // connection with our peer.
462 bool ConnectedOrClosing() const MOZ_REQUIRES(*mMonitor);
464 private:
465 // Executed on the IO thread.
466 void NotifyWorkerThread() MOZ_REQUIRES(*mMonitor);
468 // Return true if |aMsg| is a special message targeted at the IO
469 // thread, in which case it shouldn't be delivered to the worker.
470 bool MaybeInterceptSpecialIOMessage(const Message& aMsg)
471 MOZ_REQUIRES(*mMonitor);
473 // Returns true if ShouldDeferMessage(aMsg) is guaranteed to return true.
474 // Otherwise, the result of ShouldDeferMessage(aMsg) may be true or false,
475 // depending on context.
476 static bool IsAlwaysDeferred(const Message& aMsg);
478 // Helper for sending a message via the link. If the message is [LazySend], it
479 // will be queued, and if the message is not-[LazySend], it will flush any
480 // pending [LazySend] messages.
481 void SendMessageToLink(UniquePtr<Message> aMsg) MOZ_REQUIRES(*mMonitor);
483 // Called to flush [LazySend] messages to the link.
484 void FlushLazySendMessages() MOZ_REQUIRES(*mMonitor);
486 bool WasTransactionCanceled(int transaction);
487 bool ShouldDeferMessage(const Message& aMsg) MOZ_REQUIRES(*mMonitor);
488 void OnMessageReceivedFromLink(UniquePtr<Message> aMsg)
489 MOZ_REQUIRES(*mMonitor);
490 void OnChannelErrorFromLink() MOZ_REQUIRES(*mMonitor);
492 private:
493 // Clear this channel, and notify the listener that the channel has either
494 // closed or errored.
496 // These methods must be called on the worker thread, passing in a
497 // `ReleasableMonitorAutoLock`. This lock guard will be reset before the
498 // listener is called, allowing for the monitor to be unlocked before the
499 // MessageChannel is potentially destroyed.
500 void NotifyChannelClosed(ReleasableMonitorAutoLock& aLock)
501 MOZ_REQUIRES(*mMonitor);
502 void NotifyMaybeChannelError(ReleasableMonitorAutoLock& aLock)
503 MOZ_REQUIRES(*mMonitor);
505 private:
506 void AssertWorkerThread() const {
507 MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet");
508 MOZ_RELEASE_ASSERT(mWorkerThread && mWorkerThread->IsOnCurrentThread(),
509 "not on worker thread!");
512 private:
513 class MessageTask : public CancelableRunnable,
514 public LinkedListElement<RefPtr<MessageTask>>,
515 public nsIRunnablePriority,
516 public nsIRunnableIPCMessageType {
517 public:
518 explicit MessageTask(MessageChannel* aChannel, UniquePtr<Message> aMessage);
519 MessageTask() = delete;
520 MessageTask(const MessageTask&) = delete;
522 NS_DECL_ISUPPORTS_INHERITED
524 NS_IMETHOD Run() override;
525 nsresult Cancel() override;
526 NS_IMETHOD GetPriority(uint32_t* aPriority) override;
527 NS_DECL_NSIRUNNABLEIPCMESSAGETYPE
528 void Post() MOZ_REQUIRES(*mMonitor);
530 bool IsScheduled() const MOZ_REQUIRES(*mMonitor) {
531 mMonitor->AssertCurrentThreadOwns();
532 return mScheduled;
535 UniquePtr<Message>& Msg() MOZ_REQUIRES(*mMonitor) {
536 MOZ_DIAGNOSTIC_ASSERT(mMessage, "message was moved");
537 return mMessage;
539 const UniquePtr<Message>& Msg() const MOZ_REQUIRES(*mMonitor) {
540 MOZ_DIAGNOSTIC_ASSERT(mMessage, "message was moved");
541 return mMessage;
544 void AssertMonitorHeld(const RefCountedMonitor& aMonitor)
545 MOZ_REQUIRES(aMonitor) MOZ_ASSERT_CAPABILITY(*mMonitor) {
546 aMonitor.AssertSameMonitor(*mMonitor);
549 private:
550 ~MessageTask();
552 MessageChannel* Channel() MOZ_REQUIRES(*mMonitor) {
553 mMonitor->AssertCurrentThreadOwns();
554 MOZ_RELEASE_ASSERT(isInList());
555 return mChannel;
558 // The connected MessageChannel's monitor. Guards `mChannel` and
559 // `mScheduled`.
560 RefPtr<RefCountedMonitor> const mMonitor;
561 // The channel which this MessageTask is associated with. Only valid while
562 // `mMonitor` is held, and this MessageTask `isInList()`.
563 MessageChannel* const mChannel;
564 UniquePtr<Message> mMessage MOZ_GUARDED_BY(*mMonitor);
565 uint32_t const mPriority;
566 bool mScheduled : 1 MOZ_GUARDED_BY(*mMonitor);
567 #ifdef FUZZING_SNAPSHOT
568 const bool mIsFuzzMsg;
569 bool mFuzzStopped MOZ_GUARDED_BY(*mMonitor);
570 #endif
573 bool ShouldRunMessage(const Message& aMsg) MOZ_REQUIRES(*mMonitor);
574 void RunMessage(ActorLifecycleProxy* aProxy, MessageTask& aTask)
575 MOZ_REQUIRES(*mMonitor);
577 class WorkerTargetShutdownTask final : public nsITargetShutdownTask {
578 public:
579 NS_DECL_THREADSAFE_ISUPPORTS
581 WorkerTargetShutdownTask(nsISerialEventTarget* aTarget,
582 MessageChannel* aChannel);
584 void TargetShutdown() override;
585 void Clear();
587 private:
588 ~WorkerTargetShutdownTask() = default;
590 const nsCOMPtr<nsISerialEventTarget> mTarget;
591 // Cleared by MessageChannel before it is destroyed.
592 MessageChannel* MOZ_NON_OWNING_REF mChannel;
595 class FlushLazySendMessagesRunnable final : public CancelableRunnable {
596 public:
597 explicit FlushLazySendMessagesRunnable(MessageChannel* aChannel);
599 NS_DECL_ISUPPORTS_INHERITED
601 NS_IMETHOD Run() override;
602 nsresult Cancel() override;
604 void PushMessage(UniquePtr<Message> aMsg);
605 nsTArray<UniquePtr<Message>> TakeMessages();
607 private:
608 ~FlushLazySendMessagesRunnable() = default;
610 // Cleared by MessageChannel before it is destroyed.
611 MessageChannel* MOZ_NON_OWNING_REF mChannel;
613 // LazySend messages which haven't been sent yet, but will be sent as soon
614 // as a non-LazySend message is sent, or this runnable is executed.
615 nsTArray<UniquePtr<Message>> mQueue;
618 typedef LinkedList<RefPtr<MessageTask>> MessageQueue;
619 typedef std::map<size_t, UniquePtr<UntypedCallbackHolder>> CallbackMap;
620 typedef IPC::Message::msgid_t msgid_t;
622 private:
623 // This will be a string literal, so lifetime is not an issue.
624 const char* const mName;
626 // ID for each MessageChannel. Set when it is opened, and never cleared
627 // afterwards.
629 // This ID is only intended for diagnostics, debugging, and reporting
630 // purposes, and shouldn't be used for message routing or permissions checks.
631 nsID mMessageChannelId MOZ_GUARDED_BY(*mMonitor) = {};
633 // Based on presumption the listener owns and overlives the channel,
634 // this is never nullified.
635 IToplevelProtocol* const mListener;
637 // This monitor guards all state in this MessageChannel, except where
638 // otherwise noted. It is refcounted so a reference to it can be shared with
639 // IPC listener objects which need to access weak references to this
640 // `MessageChannel`.
641 RefPtr<RefCountedMonitor> const mMonitor;
643 ChannelState mChannelState MOZ_GUARDED_BY(*mMonitor) = ChannelClosed;
644 Side mSide = UnknownSide;
645 bool mIsCrossProcess MOZ_GUARDED_BY(*mMonitor) = false;
646 UniquePtr<MessageLink> mLink MOZ_GUARDED_BY(*mMonitor);
648 // NotifyMaybeChannelError runnable
649 RefPtr<CancelableRunnable> mChannelErrorTask MOZ_GUARDED_BY(*mMonitor);
651 // Thread we are allowed to send and receive on. Set in Open(); never
652 // changed, and we can only call Open() once. We shouldn't be accessing
653 // from multiple threads before Open().
654 nsCOMPtr<nsISerialEventTarget> mWorkerThread;
656 // Shutdown task to close the channel before mWorkerThread goes away.
657 RefPtr<WorkerTargetShutdownTask> mShutdownTask MOZ_GUARDED_BY(*mMonitor);
659 // Task to force sending lazy messages when mQueuedLazyMessages is non-empty.
660 RefPtr<FlushLazySendMessagesRunnable> mFlushLazySendTask
661 MOZ_GUARDED_BY(*mMonitor);
663 // Timeout periods are broken up in two to prevent system suspension from
664 // triggering an abort. This method (called by WaitForEvent with a 'did
665 // timeout' flag) decides if we should wait again for half of mTimeoutMs
666 // or give up.
667 // only accessed on WorkerThread
668 int32_t mTimeoutMs = kNoTimeout;
669 bool mInTimeoutSecondHalf = false;
671 // Worker-thread only; sequence numbers for messages that require
672 // replies.
673 int32_t mNextSeqno = 0;
675 static bool sIsPumpingMessages;
677 // If ::Send returns false, this gives a more descriptive error.
678 SyncSendError mLastSendError = SyncSendError::SendSuccess;
680 template <class T>
681 class AutoSetValue {
682 public:
683 explicit AutoSetValue(T& var, const T& newValue)
684 : mVar(var), mPrev(var), mNew(newValue) {
685 mVar = newValue;
687 ~AutoSetValue() {
688 // The value may have been zeroed if the transaction was
689 // canceled. In that case we shouldn't return it to its previous
690 // value.
691 if (mVar == mNew) {
692 mVar = mPrev;
696 private:
697 T& mVar;
698 T mPrev;
699 T mNew;
702 bool mDispatchingAsyncMessage = false;
703 int mDispatchingAsyncMessageNestedLevel = 0;
705 // When we send an urgent request from the parent process, we could race
706 // with an RPC message that was issued by the child beforehand. In this
707 // case, if the parent were to wake up while waiting for the urgent reply,
708 // and process the RPC, it could send an additional urgent message. The
709 // child would wake up to process the urgent message (as it always will),
710 // then send a reply, which could be received by the parent out-of-order
711 // with respect to the first urgent reply.
713 // To address this problem, urgent or RPC requests are associated with a
714 // "transaction". Whenever one side of the channel wishes to start a
715 // chain of RPC/urgent messages, it allocates a new transaction ID. Any
716 // messages the parent receives, not apart of this transaction, are
717 // deferred. When issuing RPC/urgent requests on top of a started
718 // transaction, the initiating transaction ID is used.
720 // To ensure IDs are unique, we use sequence numbers for transaction IDs,
721 // which grow in opposite directions from child to parent.
723 friend class AutoEnterTransaction;
724 AutoEnterTransaction* mTransactionStack MOZ_GUARDED_BY(*mMonitor) = nullptr;
726 int32_t CurrentNestedInsideSyncTransaction() const MOZ_REQUIRES(*mMonitor);
728 bool AwaitingSyncReply() const MOZ_REQUIRES(*mMonitor);
729 int AwaitingSyncReplyNestedLevel() const MOZ_REQUIRES(*mMonitor);
731 bool DispatchingSyncMessage() const MOZ_REQUIRES(*mMonitor);
732 int DispatchingSyncMessageNestedLevel() const MOZ_REQUIRES(*mMonitor);
734 #ifdef DEBUG
735 void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor);
736 #else
737 void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor) {}
738 #endif
740 // If a sync message times out, we store its sequence number here. Any
741 // future sync messages will fail immediately. Once the reply for original
742 // sync message is received, we allow sync messages again.
744 // When a message times out, nothing is done to inform the other side. The
745 // other side will eventually dispatch the message and send a reply. Our
746 // side is responsible for replying to all sync messages sent by the other
747 // side when it dispatches the timed out message. The response is always an
748 // error.
750 // A message is only timed out if it initiated a transaction. This avoids
751 // hitting a lot of corner cases with message nesting that we don't really
752 // care about.
753 int32_t mTimedOutMessageSeqno MOZ_GUARDED_BY(*mMonitor) = 0;
754 int mTimedOutMessageNestedLevel MOZ_GUARDED_BY(*mMonitor) = 0;
756 // Queue of all incoming messages.
758 // If both this side and the other side are functioning correctly, the other
759 // side can send as many async messages as it wants before sending us a
760 // blocking message. After sending a blocking message, the other side must be
761 // blocked, and thus can't send us any more messages until we process the sync
762 // in-msg.
764 MessageQueue mPending MOZ_GUARDED_BY(*mMonitor);
766 // The number of messages in mPending for which IsAlwaysDeferred is false
767 // (i.e., the number of messages that might not be deferred, depending on
768 // context).
769 size_t mMaybeDeferredPendingCount MOZ_GUARDED_BY(*mMonitor) = 0;
771 // Is there currently MessageChannel logic for this channel on the C++ stack?
772 // This member is only accessed on the worker thread, and so is not protected
773 // by mMonitor.
774 bool mOnCxxStack = false;
776 // Map of async Callbacks that are still waiting replies.
777 CallbackMap mPendingResponses;
779 #ifdef XP_WIN
780 HANDLE mEvent;
781 #endif
783 // Should the channel abort the process from the I/O thread when
784 // a channel error occurs?
785 bool mAbortOnError MOZ_GUARDED_BY(*mMonitor) = false;
787 // True if the listener has already been notified of a channel close or
788 // error.
789 bool mNotifiedChannelDone MOZ_GUARDED_BY(*mMonitor) = false;
791 // See SetChannelFlags
792 ChannelFlags mFlags = REQUIRE_DEFAULT;
794 bool mBuildIDsConfirmedMatch MOZ_GUARDED_BY(*mMonitor) = false;
796 // If this is true, both ends of this message channel have event targets
797 // on the same thread.
798 bool mIsSameThreadChannel = false;
801 void CancelCPOWs();
803 } // namespace ipc
804 } // namespace mozilla
806 namespace IPC {
807 template <>
808 struct ParamTraits<mozilla::ipc::ResponseRejectReason>
809 : public ContiguousEnumSerializer<
810 mozilla::ipc::ResponseRejectReason,
811 mozilla::ipc::ResponseRejectReason::SendError,
812 mozilla::ipc::ResponseRejectReason::EndGuard_> {};
813 } // namespace IPC
815 namespace geckoprofiler::markers {
817 struct IPCMarker {
818 static constexpr mozilla::Span<const char> MarkerTypeName() {
819 return mozilla::MakeStringSpan("IPC");
821 static void StreamJSONMarkerData(
822 mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
823 mozilla::TimeStamp aStart, mozilla::TimeStamp aEnd, int32_t aOtherPid,
824 int32_t aMessageSeqno, IPC::Message::msgid_t aMessageType,
825 mozilla::ipc::Side aSide, mozilla::ipc::MessageDirection aDirection,
826 mozilla::ipc::MessagePhase aPhase, bool aSync,
827 mozilla::MarkerThreadId aOriginThreadId) {
828 using namespace mozilla::ipc;
829 // This payload still streams a startTime and endTime property because it
830 // made the migration to MarkerTiming on the front-end easier.
831 aWriter.TimeProperty("startTime", aStart);
832 aWriter.TimeProperty("endTime", aEnd);
834 aWriter.IntProperty("otherPid", aOtherPid);
835 aWriter.IntProperty("messageSeqno", aMessageSeqno);
836 aWriter.StringProperty(
837 "messageType",
838 mozilla::MakeStringSpan(IPC::StringFromIPCMessageType(aMessageType)));
839 aWriter.StringProperty("side", IPCSideToString(aSide));
840 aWriter.StringProperty("direction",
841 aDirection == MessageDirection::eSending
842 ? mozilla::MakeStringSpan("sending")
843 : mozilla::MakeStringSpan("receiving"));
844 aWriter.StringProperty("phase", IPCPhaseToString(aPhase));
845 aWriter.BoolProperty("sync", aSync);
846 if (!aOriginThreadId.IsUnspecified()) {
847 // Tech note: If `ToNumber()` returns a uint64_t, the conversion to
848 // int64_t is "implementation-defined" before C++20. This is acceptable
849 // here, because this is a one-way conversion to a unique identifier
850 // that's used to visually separate data by thread on the front-end.
851 aWriter.IntProperty(
852 "threadId",
853 static_cast<int64_t>(aOriginThreadId.ThreadId().ToNumber()));
856 static mozilla::MarkerSchema MarkerTypeDisplay() {
857 return mozilla::MarkerSchema::SpecialFrontendLocation{};
860 private:
861 static mozilla::Span<const char> IPCSideToString(mozilla::ipc::Side aSide) {
862 switch (aSide) {
863 case mozilla::ipc::ParentSide:
864 return mozilla::MakeStringSpan("parent");
865 case mozilla::ipc::ChildSide:
866 return mozilla::MakeStringSpan("child");
867 case mozilla::ipc::UnknownSide:
868 return mozilla::MakeStringSpan("unknown");
869 default:
870 MOZ_ASSERT_UNREACHABLE("Invalid IPC side");
871 return mozilla::MakeStringSpan("<invalid IPC side>");
875 static mozilla::Span<const char> IPCPhaseToString(
876 mozilla::ipc::MessagePhase aPhase) {
877 switch (aPhase) {
878 case mozilla::ipc::MessagePhase::Endpoint:
879 return mozilla::MakeStringSpan("endpoint");
880 case mozilla::ipc::MessagePhase::TransferStart:
881 return mozilla::MakeStringSpan("transferStart");
882 case mozilla::ipc::MessagePhase::TransferEnd:
883 return mozilla::MakeStringSpan("transferEnd");
884 default:
885 MOZ_ASSERT_UNREACHABLE("Invalid IPC phase");
886 return mozilla::MakeStringSpan("<invalid IPC phase>");
891 } // namespace geckoprofiler::markers
893 #endif // ifndef ipc_glue_MessageChannel_h