LCOV - code coverage report
Current view: top level - ipc/glue - MessageChannel.h (source / functions) Hit Total Coverage
Test: output.info Lines: 19 73 26.0 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: sw=4 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/. */
       7             : 
       8             : #ifndef ipc_glue_MessageChannel_h
       9             : #define ipc_glue_MessageChannel_h 1
      10             : 
      11             : #include "base/basictypes.h"
      12             : #include "base/message_loop.h"
      13             : 
      14             : #include "nsIMemoryReporter.h"
      15             : #include "mozilla/Atomics.h"
      16             : #include "mozilla/DebugOnly.h"
      17             : #include "mozilla/Monitor.h"
      18             : #include "mozilla/MozPromise.h"
      19             : #include "mozilla/Vector.h"
      20             : #if defined(OS_WIN)
      21             : #include "mozilla/ipc/Neutering.h"
      22             : #endif // defined(OS_WIN)
      23             : #include "mozilla/ipc/Transport.h"
      24             : #include "MessageLink.h"
      25             : #include "nsILabelableRunnable.h"
      26             : #include "nsThreadUtils.h"
      27             : 
      28             : #include <deque>
      29             : #include <functional>
      30             : #include <map>
      31             : #include <math.h>
      32             : #include <stack>
      33             : #include <vector>
      34             : 
      35             : class nsIEventTarget;
      36             : 
      37             : namespace mozilla {
      38             : namespace ipc {
      39             : 
      40             : class MessageChannel;
      41             : class IToplevelProtocol;
      42             : 
      43             : class RefCountedMonitor : public Monitor
      44             : {
      45             :   public:
      46           0 :     RefCountedMonitor()
      47           0 :         : Monitor("mozilla.ipc.MessageChannel.mMonitor")
      48           0 :     {}
      49             : 
      50           0 :     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMonitor)
      51             : 
      52             :   private:
      53           0 :     ~RefCountedMonitor() {}
      54             : };
      55             : 
      56             : enum class SyncSendError {
      57             :     SendSuccess,
      58             :     PreviousTimeout,
      59             :     SendingCPOWWhileDispatchingSync,
      60             :     SendingCPOWWhileDispatchingUrgent,
      61             :     NotConnectedBeforeSend,
      62             :     DisconnectedDuringSend,
      63             :     CancelledBeforeSend,
      64             :     CancelledAfterSend,
      65             :     TimedOut,
      66             :     ReplyError,
      67             : };
      68             : 
      69             : enum class ResponseRejectReason {
      70             :     SendError,
      71             :     ChannelClosed,
      72             :     HandlerRejected,
      73             :     ActorDestroyed,
      74             :     EndGuard_,
      75             : };
      76             : 
      77             : template<typename T>
      78             : using ResolveCallback = std::function<void (T&&)>;
      79             : 
      80             : using RejectCallback = std::function<void (ResponseRejectReason)>;
      81             : 
      82             : enum ChannelState {
      83             :     ChannelClosed,
      84             :     ChannelOpening,
      85             :     ChannelConnected,
      86             :     ChannelTimeout,
      87             :     ChannelClosing,
      88             :     ChannelError
      89             : };
      90             : 
      91             : class AutoEnterTransaction;
      92             : 
      93             : class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver
      94             : {
      95             :     friend class ProcessLink;
      96             :     friend class ThreadLink;
      97             : #ifdef FUZZING
      98             :     friend class ProtocolFuzzerHelper;
      99             : #endif
     100             : 
     101             :     class CxxStackFrame;
     102             :     class InterruptFrame;
     103             : 
     104             :     typedef mozilla::Monitor Monitor;
     105             : 
     106             :     // We could templatize the actor type but it would unnecessarily
     107             :     // expand the code size. Using the actor address as the
     108             :     // identifier is already good enough.
     109             :     typedef void* ActorIdType;
     110             : 
     111             : public:
     112             :     struct UntypedCallbackHolder
     113             :     {
     114             :         UntypedCallbackHolder(ActorIdType aActorId,
     115             :                               RejectCallback&& aReject)
     116           0 :             : mActorId(aActorId)
     117           0 :             , mReject(std::move(aReject))
     118             :         {}
     119             : 
     120           0 :         virtual ~UntypedCallbackHolder() {}
     121             : 
     122             :         void Reject(ResponseRejectReason aReason) {
     123           0 :             mReject(aReason);
     124             :         }
     125             : 
     126             :         ActorIdType mActorId;
     127             :         RejectCallback mReject;
     128             :     };
     129             : 
     130             :     template<typename Value>
     131           0 :     struct CallbackHolder : public UntypedCallbackHolder
     132             :     {
     133           0 :         CallbackHolder(ActorIdType aActorId,
     134             :                        ResolveCallback<Value>&& aResolve,
     135             :                        RejectCallback&& aReject)
     136           0 :             : UntypedCallbackHolder(aActorId, std::move(aReject))
     137           0 :             , mResolve(std::move(aResolve))
     138           0 :         {}
     139             : 
     140             :         void Resolve(Value&& aReason) {
     141           0 :             mResolve(std::move(aReason));
     142             :         }
     143             : 
     144             :         ResolveCallback<Value> mResolve;
     145             :     };
     146             : 
     147             : private:
     148             :     static Atomic<size_t> gUnresolvedResponses;
     149             :     friend class PendingResponseReporter;
     150             : 
     151             :   public:
     152             :     static const int32_t kNoTimeout;
     153             : 
     154             :     typedef IPC::Message Message;
     155             :     typedef IPC::MessageInfo MessageInfo;
     156             :     typedef mozilla::ipc::Transport Transport;
     157             : 
     158             :     explicit MessageChannel(const char *aName,
     159             :                             IToplevelProtocol *aListener);
     160             :     ~MessageChannel();
     161             : 
     162             :     IToplevelProtocol *Listener() const {
     163             :         return mListener;
     164             :     }
     165             : 
     166             :     // "Open" from the perspective of the transport layer; the underlying
     167             :     // socketpair/pipe should already be created.
     168             :     //
     169             :     // Returns true if the transport layer was successfully connected,
     170             :     // i.e., mChannelState == ChannelConnected.
     171             :     bool Open(Transport* aTransport, MessageLoop* aIOLoop=0, Side aSide=UnknownSide);
     172             : 
     173             :     // "Open" a connection to another thread in the same process.
     174             :     //
     175             :     // Returns true if the transport layer was successfully connected,
     176             :     // i.e., mChannelState == ChannelConnected.
     177             :     //
     178             :     // For more details on the process of opening a channel between
     179             :     // threads, see the extended comment on this function
     180             :     // in MessageChannel.cpp.
     181             :     bool Open(MessageChannel *aTargetChan, nsIEventTarget *aEventTarget, Side aSide);
     182             : 
     183             :     // Close the underlying transport channel.
     184             :     void Close();
     185             : 
     186             :     // Force the channel to behave as if a channel error occurred. Valid
     187             :     // for process links only, not thread links.
     188             :     void CloseWithError();
     189             : 
     190             :     void CloseWithTimeout();
     191             : 
     192             :     void SetAbortOnError(bool abort)
     193             :     {
     194           0 :         mAbortOnError = abort;
     195             :     }
     196             : 
     197             :     // Call aInvoke for each pending message until it returns false.
     198             :     // XXX: You must get permission from an IPC peer to use this function
     199             :     //      since it requires custom deserialization and re-orders events.
     200             :     void PeekMessages(const std::function<bool(const Message& aMsg)>& aInvoke);
     201             : 
     202             :     // Misc. behavioral traits consumers can request for this channel
     203             :     enum ChannelFlags {
     204             :       REQUIRE_DEFAULT                         = 0,
     205             :       // Windows: if this channel operates on the UI thread, indicates
     206             :       // WindowsMessageLoop code should enable deferred native message
     207             :       // handling to prevent deadlocks. Should only be used for protocols
     208             :       // that manage child processes which might create native UI, like
     209             :       // plugins.
     210             :       REQUIRE_DEFERRED_MESSAGE_PROTECTION     = 1 << 0,
     211             :       // Windows: When this flag is specified, any wait that occurs during
     212             :       // synchronous IPC will be alertable, thus allowing a11y code in the
     213             :       // chrome process to reenter content while content is waiting on a
     214             :       // synchronous call.
     215             :       REQUIRE_A11Y_REENTRY                    = 1 << 1,
     216             :     };
     217           0 :     void SetChannelFlags(ChannelFlags aFlags) { mFlags = aFlags; }
     218             :     ChannelFlags GetChannelFlags() { return mFlags; }
     219             : 
     220             :     // Asynchronously send a message to the other side of the channel
     221             :     bool Send(Message* aMsg);
     222             : 
     223             :     // Asynchronously send a message to the other side of the channel
     224             :     // and wait for asynchronous reply.
     225             :     template<typename Value>
     226           0 :     void Send(Message* aMsg,
     227             :               ActorIdType aActorId,
     228             :               ResolveCallback<Value>&& aResolve,
     229             :               RejectCallback&& aReject) {
     230           0 :         int32_t seqno = NextSeqno();
     231           0 :         aMsg->set_seqno(seqno);
     232           0 :         if (!Send(aMsg)) {
     233           0 :             aReject(ResponseRejectReason::SendError);
     234           0 :             return;
     235             :         }
     236             : 
     237             :         UniquePtr<UntypedCallbackHolder> callback =
     238             :             MakeUnique<CallbackHolder<Value>>(
     239           0 :                 aActorId, std::move(aResolve), std::move(aReject));
     240           0 :         mPendingResponses.insert(std::make_pair(seqno, std::move(callback)));
     241           0 :         gUnresolvedResponses++;
     242             :     }
     243             : 
     244             :     bool SendBuildIDsMatchMessage(const char* aParentBuildI);
     245             :     bool DoBuildIDsMatch() { return mBuildIDsConfirmedMatch; }
     246             : 
     247             :     // Asynchronously deliver a message back to this side of the
     248             :     // channel
     249             :     bool Echo(Message* aMsg);
     250             : 
     251             :     // Synchronously send |msg| (i.e., wait for |reply|)
     252             :     bool Send(Message* aMsg, Message* aReply);
     253             : 
     254             :     // Make an Interrupt call to the other side of the channel
     255             :     bool Call(Message* aMsg, Message* aReply);
     256             : 
     257             :     // Wait until a message is received
     258             :     bool WaitForIncomingMessage();
     259             : 
     260             :     bool CanSend() const;
     261             : 
     262             :     // Remove and return a callback that needs reply
     263             :     UniquePtr<UntypedCallbackHolder> PopCallback(const Message& aMsg);
     264             : 
     265             :     // Used to reject and remove pending responses owned by the given
     266             :     // actor when it's about to be destroyed.
     267             :     void RejectPendingResponsesForActor(ActorIdType aActorId);
     268             : 
     269             :     // If sending a sync message returns an error, this function gives a more
     270             :     // descriptive error message.
     271             :     SyncSendError LastSendError() const {
     272             :         AssertWorkerThread();
     273             :         return mLastSendError;
     274             :     }
     275             : 
     276             :     // Currently only for debugging purposes, doesn't aquire mMonitor.
     277             :     ChannelState GetChannelState__TotallyRacy() const {
     278             :         return mChannelState;
     279             :     }
     280             : 
     281             :     void SetReplyTimeoutMs(int32_t aTimeoutMs);
     282             : 
     283             :     bool IsOnCxxStack() const {
     284         191 :         return !mCxxStackFrames.empty();
     285             :     }
     286             : 
     287             :     bool IsInTransaction() const;
     288             :     void CancelCurrentTransaction();
     289             : 
     290             :     // Force all calls to Send to defer actually sending messages. This will
     291             :     // cause sync messages to block until another thread calls
     292             :     // StopPostponingSends.
     293             :     //
     294             :     // This must be called from the worker thread.
     295             :     void BeginPostponingSends();
     296             : 
     297             :     // Stop postponing sent messages, and immediately flush all postponed
     298             :     // messages to the link. This may be called from any thread.
     299             :     //
     300             :     // Note that there are no ordering guarantees between two different
     301             :     // MessageChannels. If channel B sends a message, then stops postponing
     302             :     // channel A, messages from A may arrive before B. The easiest way to order
     303             :     // this, if needed, is to make B send a sync message.
     304             :     void StopPostponingSends();
     305             : 
     306             :     /**
     307             :      * This function is used by hang annotation code to determine which IPDL
     308             :      * actor is highest in the call stack at the time of the hang. It should
     309             :      * be called from the main thread when a sync or intr message is about to
     310             :      * be sent.
     311             :      */
     312             :     int32_t GetTopmostMessageRoutingId() const;
     313             : 
     314             :     // Unsound_IsClosed and Unsound_NumQueuedMessages are safe to call from any
     315             :     // thread, but they make no guarantees about whether you'll get an
     316             :     // up-to-date value; the values are written on one thread and read without
     317             :     // locking, on potentially different threads.  Thus you should only use
     318             :     // them when you don't particularly care about getting a recent value (e.g.
     319             :     // in a memory report).
     320           0 :     bool Unsound_IsClosed() const {
     321           0 :         return mLink ? mLink->Unsound_IsClosed() : true;
     322             :     }
     323           0 :     uint32_t Unsound_NumQueuedMessages() const {
     324           0 :         return mLink ? mLink->Unsound_NumQueuedMessages() : 0;
     325             :     }
     326             : 
     327             :     static bool IsPumpingMessages() {
     328             :         return sIsPumpingMessages;
     329             :     }
     330             :     static void SetIsPumpingMessages(bool aIsPumping) {
     331             :         sIsPumpingMessages = aIsPumping;
     332             :     }
     333             : 
     334             :     void SetInKillHardShutdown() {
     335           0 :         mInKillHardShutdown = true;
     336             :     }
     337             : 
     338             : #ifdef OS_WIN
     339             :     struct MOZ_STACK_CLASS SyncStackFrame
     340             :     {
     341             :         SyncStackFrame(MessageChannel* channel, bool interrupt);
     342             :         ~SyncStackFrame();
     343             : 
     344             :         bool mInterrupt;
     345             :         bool mSpinNestedEvents;
     346             :         bool mListenerNotified;
     347             :         MessageChannel* mChannel;
     348             : 
     349             :         // The previous stack frame for this channel.
     350             :         SyncStackFrame* mPrev;
     351             : 
     352             :         // The previous stack frame on any channel.
     353             :         SyncStackFrame* mStaticPrev;
     354             :     };
     355             :     friend struct MessageChannel::SyncStackFrame;
     356             : 
     357             :     static bool IsSpinLoopActive() {
     358             :         for (SyncStackFrame* frame = sStaticTopFrame; frame; frame = frame->mPrev) {
     359             :             if (frame->mSpinNestedEvents)
     360             :                 return true;
     361             :         }
     362             :         return false;
     363             :     }
     364             : 
     365             :   protected:
     366             :     // The deepest sync stack frame for this channel.
     367             :     SyncStackFrame* mTopFrame;
     368             : 
     369             :     bool mIsSyncWaitingOnNonMainThread;
     370             : 
     371             :     // The deepest sync stack frame on any channel.
     372             :     static SyncStackFrame* sStaticTopFrame;
     373             : 
     374             :   public:
     375             :     void ProcessNativeEventsInInterruptCall();
     376             :     static void NotifyGeckoEventDispatch();
     377             : 
     378             :   private:
     379             :     void SpinInternalEventLoop();
     380             : #if defined(ACCESSIBILITY)
     381             :     bool WaitForSyncNotifyWithA11yReentry();
     382             : #endif // defined(ACCESSIBILITY)
     383             : #endif // defined(OS_WIN)
     384             : 
     385             :   private:
     386             :     void CommonThreadOpenInit(MessageChannel *aTargetChan, Side aSide);
     387             :     void OnOpenAsSlave(MessageChannel *aTargetChan, Side aSide);
     388             : 
     389             :     void PostErrorNotifyTask();
     390             :     void OnNotifyMaybeChannelError();
     391             :     void ReportConnectionError(const char* aChannelName, Message* aMsg = nullptr) const;
     392             :     void ReportMessageRouteError(const char* channelName) const;
     393             :     bool MaybeHandleError(Result code, const Message& aMsg, const char* channelName);
     394             : 
     395             :     void Clear();
     396             : 
     397             :     // Send OnChannelConnected notification to listeners.
     398             :     void DispatchOnChannelConnected();
     399             : 
     400             :     bool InterruptEventOccurred();
     401             :     bool HasPendingEvents();
     402             : 
     403             :     void ProcessPendingRequests(AutoEnterTransaction& aTransaction);
     404             :     bool ProcessPendingRequest(Message &&aUrgent);
     405             : 
     406             :     void MaybeUndeferIncall();
     407             :     void EnqueuePendingMessages();
     408             : 
     409             :     // Dispatches an incoming message to its appropriate handler.
     410             :     void DispatchMessage(Message &&aMsg);
     411             : 
     412             :     // DispatchMessage will route to one of these functions depending on the
     413             :     // protocol type of the message.
     414             :     void DispatchSyncMessage(const Message &aMsg, Message*& aReply);
     415             :     void DispatchUrgentMessage(const Message &aMsg);
     416             :     void DispatchAsyncMessage(const Message &aMsg);
     417             :     void DispatchRPCMessage(const Message &aMsg);
     418             :     void DispatchInterruptMessage(Message &&aMsg, size_t aStackDepth);
     419             : 
     420             :     // Return true if the wait ended because a notification was received.
     421             :     //
     422             :     // Return false if the time elapsed from when we started the process of
     423             :     // waiting until afterwards exceeded the currently allotted timeout.
     424             :     // That *DOES NOT* mean false => "no event" (== timeout); there are many
     425             :     // circumstances that could cause the measured elapsed time to exceed the
     426             :     // timeout EVEN WHEN we were notified.
     427             :     //
     428             :     // So in sum: true is a meaningful return value; false isn't,
     429             :     // necessarily.
     430             :     bool WaitForSyncNotify(bool aHandleWindowsMessages);
     431             :     bool WaitForInterruptNotify();
     432             : 
     433             :     bool WaitResponse(bool aWaitTimedOut);
     434             : 
     435             :     bool ShouldContinueFromTimeout();
     436             : 
     437             :     void EndTimeout();
     438             :     void CancelTransaction(int transaction);
     439             : 
     440             :     void RepostAllMessages();
     441             : 
     442             :     // The "remote view of stack depth" can be different than the
     443             :     // actual stack depth when there are out-of-turn replies.  When we
     444             :     // receive one, our actual Interrupt stack depth doesn't decrease, but
     445             :     // the other side (that sent the reply) thinks it has.  So, the
     446             :     // "view" returned here is |stackDepth| minus the number of
     447             :     // out-of-turn replies.
     448             :     //
     449             :     // Only called from the worker thread.
     450             :     size_t RemoteViewOfStackDepth(size_t stackDepth) const {
     451           0 :         AssertWorkerThread();
     452           0 :         return stackDepth - mOutOfTurnReplies.size();
     453             :     }
     454             : 
     455           2 :     int32_t NextSeqno() {
     456           2 :         AssertWorkerThread();
     457           2 :         return (mSide == ChildSide) ? --mNextSeqno : ++mNextSeqno;
     458             :     }
     459             : 
     460             :     // This helper class manages mCxxStackDepth on behalf of MessageChannel.
     461             :     // When the stack depth is incremented from zero to non-zero, it invokes
     462             :     // a callback, and similarly for when the depth goes from non-zero to zero.
     463             :     void EnteredCxxStack();
     464             :     void ExitedCxxStack();
     465             : 
     466             :     void EnteredCall();
     467             :     void ExitedCall();
     468             : 
     469             :     void EnteredSyncSend();
     470             :     void ExitedSyncSend();
     471             : 
     472             :     void DebugAbort(const char* file, int line, const char* cond,
     473             :                     const char* why,
     474             :                     bool reply=false);
     475             : 
     476             :     // This method is only safe to call on the worker thread, or in a
     477             :     // debugger with all threads paused.
     478             :     void DumpInterruptStack(const char* const pfx="") const;
     479             : 
     480             :   private:
     481             :     // Called from both threads
     482           0 :     size_t InterruptStackDepth() const {
     483           0 :         mMonitor->AssertCurrentThreadOwns();
     484           0 :         return mInterruptStack.size();
     485             :     }
     486             : 
     487         191 :     bool AwaitingInterruptReply() const {
     488           0 :         mMonitor->AssertCurrentThreadOwns();
     489           0 :         return !mInterruptStack.empty();
     490             :     }
     491         191 :     bool AwaitingIncomingMessage() const {
     492         382 :         mMonitor->AssertCurrentThreadOwns();
     493         191 :         return mIsWaitingForIncoming;
     494             :     }
     495             : 
     496             :     class MOZ_STACK_CLASS AutoEnterWaitForIncoming
     497             :     {
     498             :     public:
     499           0 :         explicit AutoEnterWaitForIncoming(MessageChannel& aChannel)
     500           0 :             : mChannel(aChannel)
     501             :         {
     502           0 :             aChannel.mMonitor->AssertCurrentThreadOwns();
     503           0 :             aChannel.mIsWaitingForIncoming = true;
     504           0 :         }
     505             : 
     506             :         ~AutoEnterWaitForIncoming()
     507           0 :         {
     508           0 :             mChannel.mIsWaitingForIncoming = false;
     509             :         }
     510             : 
     511             :     private:
     512             :         MessageChannel& mChannel;
     513             :     };
     514             :     friend class AutoEnterWaitForIncoming;
     515             : 
     516             :     // Returns true if we're dispatching an async message's callback.
     517             :     bool DispatchingAsyncMessage() const {
     518           0 :         AssertWorkerThread();
     519           0 :         return mDispatchingAsyncMessage;
     520             :     }
     521             : 
     522             :     int DispatchingAsyncMessageNestedLevel() const {
     523           4 :         AssertWorkerThread();
     524           4 :         return mDispatchingAsyncMessageNestedLevel;
     525             :     }
     526             : 
     527             :     bool Connected() const;
     528             : 
     529             :   private:
     530             :     // Executed on the IO thread.
     531             :     void NotifyWorkerThread();
     532             : 
     533             :     // Return true if |aMsg| is a special message targeted at the IO
     534             :     // thread, in which case it shouldn't be delivered to the worker.
     535             :     bool MaybeInterceptSpecialIOMessage(const Message& aMsg);
     536             : 
     537             :     void OnChannelConnected(int32_t peer_id);
     538             : 
     539             :     // Tell the IO thread to close the channel and wait for it to ACK.
     540             :     void SynchronouslyClose();
     541             : 
     542             :     // Returns true if ShouldDeferMessage(aMsg) is guaranteed to return true.
     543             :     // Otherwise, the result of ShouldDeferMessage(aMsg) may be true or false,
     544             :     // depending on context.
     545             :     static bool IsAlwaysDeferred(const Message& aMsg);
     546             : 
     547             :     // Helper for sending a message via the link. This should only be used for
     548             :     // non-special messages that might have to be postponed.
     549             :     void SendMessageToLink(Message* aMsg);
     550             : 
     551             :     bool WasTransactionCanceled(int transaction);
     552             :     bool ShouldDeferMessage(const Message& aMsg);
     553             :     bool ShouldDeferInterruptMessage(const Message& aMsg, size_t aStackDepth);
     554             :     void OnMessageReceivedFromLink(Message&& aMsg);
     555             :     void OnChannelErrorFromLink();
     556             : 
     557             :   private:
     558             :     // Run on the not current thread.
     559             :     void NotifyChannelClosed();
     560             :     void NotifyMaybeChannelError();
     561             : 
     562             :   private:
     563             :     // Can be run on either thread
     564           0 :     void AssertWorkerThread() const
     565             :     {
     566           0 :         MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet");
     567        2238 :         MOZ_RELEASE_ASSERT(mWorkerThread == GetCurrentVirtualThread(),
     568             :                            "not on worker thread!");
     569        2237 :     }
     570             : 
     571             :     // The "link" thread is either the I/O thread (ProcessLink) or the
     572             :     // other actor's work thread (ThreadLink).  In either case, it is
     573             :     // NOT our worker thread.
     574           0 :     void AssertLinkThread() const
     575             :     {
     576           0 :         MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet");
     577         388 :         MOZ_RELEASE_ASSERT(mWorkerThread != GetCurrentVirtualThread(),
     578             :                            "on worker thread but should not be!");
     579         388 :     }
     580             : 
     581             :   private:
     582             :     class MessageTask :
     583             :         public CancelableRunnable,
     584             :         public LinkedListElement<RefPtr<MessageTask>>,
     585             :         public nsIRunnablePriority,
     586             :         public nsILabelableRunnable
     587             :     {
     588             :     public:
     589             :         explicit MessageTask(MessageChannel* aChannel, Message&& aMessage);
     590             : 
     591             :         NS_DECL_ISUPPORTS_INHERITED
     592             : 
     593             :         NS_IMETHOD Run() override;
     594             :         nsresult Cancel() override;
     595             :         NS_IMETHOD GetPriority(uint32_t* aPriority) override;
     596             :         void Post();
     597             :         void Clear();
     598             : 
     599           0 :         bool IsScheduled() const { return mScheduled; }
     600             : 
     601         191 :         Message& Msg() { return mMessage; }
     602             :         const Message& Msg() const { return mMessage; }
     603             : 
     604             :         bool GetAffectedSchedulerGroups(SchedulerGroupSet& aGroups) override;
     605             : 
     606             :     private:
     607             :         MessageTask() = delete;
     608             :         MessageTask(const MessageTask&) = delete;
     609         764 :         ~MessageTask() {}
     610             : 
     611             :         MessageChannel* mChannel;
     612             :         Message mMessage;
     613             :         bool mScheduled : 1;
     614             :     };
     615             : 
     616             :     bool ShouldRunMessage(const Message& aMsg);
     617             :     void RunMessage(MessageTask& aTask);
     618             : 
     619             :     typedef LinkedList<RefPtr<MessageTask>> MessageQueue;
     620             :     typedef std::map<size_t, Message> MessageMap;
     621             :     typedef std::map<size_t, UniquePtr<UntypedCallbackHolder>> CallbackMap;
     622             :     typedef IPC::Message::msgid_t msgid_t;
     623             : 
     624             :     void WillDestroyCurrentMessageLoop() override;
     625             : 
     626             :   private:
     627             :     // This will be a string literal, so lifetime is not an issue.
     628             :     const char* mName;
     629             : 
     630             :     // Based on presumption the listener owns and overlives the channel,
     631             :     // this is never nullified.
     632             :     IToplevelProtocol* mListener;
     633             :     ChannelState mChannelState;
     634             :     RefPtr<RefCountedMonitor> mMonitor;
     635             :     Side mSide;
     636             :     MessageLink* mLink;
     637             :     MessageLoop* mWorkerLoop;           // thread where work is done
     638             :     RefPtr<CancelableRunnable> mChannelErrorTask;  // NotifyMaybeChannelError runnable
     639             : 
     640             :     // Thread we are allowed to send and receive on. This persists even after
     641             :     // mWorkerLoop is cleared during channel shutdown.
     642             :     PRThread* mWorkerThread;
     643             : 
     644             :     // Timeout periods are broken up in two to prevent system suspension from
     645             :     // triggering an abort. This method (called by WaitForEvent with a 'did
     646             :     // timeout' flag) decides if we should wait again for half of mTimeoutMs
     647             :     // or give up.
     648             :     int32_t mTimeoutMs;
     649             :     bool mInTimeoutSecondHalf;
     650             : 
     651             :     // Worker-thread only; sequence numbers for messages that require
     652             :     // replies.
     653             :     int32_t mNextSeqno;
     654             : 
     655             :     static bool sIsPumpingMessages;
     656             : 
     657             :     // If ::Send returns false, this gives a more descriptive error.
     658             :     SyncSendError mLastSendError;
     659             : 
     660             :     template<class T>
     661             :     class AutoSetValue {
     662             :       public:
     663           0 :         explicit AutoSetValue(T &var, const T &newValue)
     664         379 :           : mVar(var), mPrev(var), mNew(newValue)
     665             :         {
     666         379 :             mVar = newValue;
     667             :         }
     668         379 :         ~AutoSetValue() {
     669             :             // The value may have been zeroed if the transaction was
     670             :             // canceled. In that case we shouldn't return it to its previous
     671             :             // value.
     672           0 :             if (mVar == mNew) {
     673             :                 mVar = mPrev;
     674             :             }
     675             :         }
     676             :       private:
     677             :         T& mVar;
     678             :         T mPrev;
     679             :         T mNew;
     680             :     };
     681             : 
     682             :     bool mDispatchingAsyncMessage;
     683             :     int mDispatchingAsyncMessageNestedLevel;
     684             : 
     685             :     // When we send an urgent request from the parent process, we could race
     686             :     // with an RPC message that was issued by the child beforehand. In this
     687             :     // case, if the parent were to wake up while waiting for the urgent reply,
     688             :     // and process the RPC, it could send an additional urgent message. The
     689             :     // child would wake up to process the urgent message (as it always will),
     690             :     // then send a reply, which could be received by the parent out-of-order
     691             :     // with respect to the first urgent reply.
     692             :     //
     693             :     // To address this problem, urgent or RPC requests are associated with a
     694             :     // "transaction". Whenever one side of the channel wishes to start a
     695             :     // chain of RPC/urgent messages, it allocates a new transaction ID. Any
     696             :     // messages the parent receives, not apart of this transaction, are
     697             :     // deferred. When issuing RPC/urgent requests on top of a started
     698             :     // transaction, the initiating transaction ID is used.
     699             :     //
     700             :     // To ensure IDs are unique, we use sequence numbers for transaction IDs,
     701             :     // which grow in opposite directions from child to parent.
     702             : 
     703             :     friend class AutoEnterTransaction;
     704             :     AutoEnterTransaction *mTransactionStack;
     705             : 
     706             :     int32_t CurrentNestedInsideSyncTransaction() const;
     707             : 
     708             :     bool AwaitingSyncReply() const;
     709             :     int AwaitingSyncReplyNestedLevel() const;
     710             : 
     711             :     bool DispatchingSyncMessage() const;
     712             :     int DispatchingSyncMessageNestedLevel() const;
     713             : 
     714             : #ifdef DEBUG
     715             :     void AssertMaybeDeferredCountCorrect();
     716             : #else
     717             :     void AssertMaybeDeferredCountCorrect() {}
     718             : #endif
     719             : 
     720             :     // If a sync message times out, we store its sequence number here. Any
     721             :     // future sync messages will fail immediately. Once the reply for original
     722             :     // sync message is received, we allow sync messages again.
     723             :     //
     724             :     // When a message times out, nothing is done to inform the other side. The
     725             :     // other side will eventually dispatch the message and send a reply. Our
     726             :     // side is responsible for replying to all sync messages sent by the other
     727             :     // side when it dispatches the timed out message. The response is always an
     728             :     // error.
     729             :     //
     730             :     // A message is only timed out if it initiated a transaction. This avoids
     731             :     // hitting a lot of corner cases with message nesting that we don't really
     732             :     // care about.
     733             :     int32_t mTimedOutMessageSeqno;
     734             :     int mTimedOutMessageNestedLevel;
     735             : 
     736             :     // Queue of all incoming messages.
     737             :     //
     738             :     // If both this side and the other side are functioning correctly, the queue
     739             :     // can only be in certain configurations.  Let
     740             :     //
     741             :     //   |A<| be an async in-message,
     742             :     //   |S<| be a sync in-message,
     743             :     //   |C<| be an Interrupt in-call,
     744             :     //   |R<| be an Interrupt reply.
     745             :     //
     746             :     // The queue can only match this configuration
     747             :     //
     748             :     //  A<* (S< | C< | R< (?{mInterruptStack.size() == 1} A<* (S< | C<)))
     749             :     //
     750             :     // The other side can send as many async messages |A<*| as it wants before
     751             :     // sending us a blocking message.
     752             :     //
     753             :     // The first case is |S<|, a sync in-msg.  The other side must be blocked,
     754             :     // and thus can't send us any more messages until we process the sync
     755             :     // in-msg.
     756             :     //
     757             :     // The second case is |C<|, an Interrupt in-call; the other side must be blocked.
     758             :     // (There's a subtlety here: this in-call might have raced with an
     759             :     // out-call, but we detect that with the mechanism below,
     760             :     // |mRemoteStackDepth|, and races don't matter to the queue.)
     761             :     //
     762             :     // Final case, the other side replied to our most recent out-call |R<|.
     763             :     // If that was the *only* out-call on our stack, |?{mInterruptStack.size() == 1}|,
     764             :     // then other side "finished with us," and went back to its own business.
     765             :     // That business might have included sending any number of async message
     766             :     // |A<*| until sending a blocking message |(S< | C<)|.  If we had more than
     767             :     // one Interrupt call on our stack, the other side *better* not have sent us
     768             :     // another blocking message, because it's blocked on a reply from us.
     769             :     //
     770             :     MessageQueue mPending;
     771             : 
     772             :     // The number of messages in mPending for which IsAlwaysDeferred is false
     773             :     // (i.e., the number of messages that might not be deferred, depending on
     774             :     // context).
     775             :     size_t mMaybeDeferredPendingCount;
     776             : 
     777             :     // Stack of all the out-calls on which this channel is awaiting responses.
     778             :     // Each stack refers to a different protocol and the stacks are mutually
     779             :     // exclusive: multiple outcalls of the same kind cannot be initiated while
     780             :     // another is active.
     781             :     std::stack<MessageInfo> mInterruptStack;
     782             : 
     783             :     // This is what we think the Interrupt stack depth is on the "other side" of this
     784             :     // Interrupt channel.  We maintain this variable so that we can detect racy Interrupt
     785             :     // calls.  With each Interrupt out-call sent, we send along what *we* think the
     786             :     // stack depth of the remote side is *before* it will receive the Interrupt call.
     787             :     //
     788             :     // After sending the out-call, our stack depth is "incremented" by pushing
     789             :     // that pending message onto mPending.
     790             :     //
     791             :     // Then when processing an in-call |c|, it must be true that
     792             :     //
     793             :     //   mInterruptStack.size() == c.remoteDepth
     794             :     //
     795             :     // I.e., my depth is actually the same as what the other side thought it
     796             :     // was when it sent in-call |c|.  If this fails to hold, we have detected
     797             :     // racy Interrupt calls.
     798             :     //
     799             :     // We then increment mRemoteStackDepth *just before* processing the
     800             :     // in-call, since we know the other side is waiting on it, and decrement
     801             :     // it *just after* finishing processing that in-call, since our response
     802             :     // will pop the top of the other side's |mPending|.
     803             :     //
     804             :     // One nice aspect of this race detection is that it is symmetric; if one
     805             :     // side detects a race, then the other side must also detect the same race.
     806             :     size_t mRemoteStackDepthGuess;
     807             : 
     808             :     // Approximation of code frames on the C++ stack. It can only be
     809             :     // interpreted as the implication:
     810             :     //
     811             :     //  !mCxxStackFrames.empty() => MessageChannel code on C++ stack
     812             :     //
     813             :     // This member is only accessed on the worker thread, and so is not
     814             :     // protected by mMonitor.  It is managed exclusively by the helper
     815             :     // |class CxxStackFrame|.
     816             :     mozilla::Vector<InterruptFrame> mCxxStackFrames;
     817             : 
     818             :     // Did we process an Interrupt out-call during this stack?  Only meaningful in
     819             :     // ExitedCxxStack(), from which this variable is reset.
     820             :     bool mSawInterruptOutMsg;
     821             : 
     822             :     // Are we waiting on this channel for an incoming message? This is used
     823             :     // to implement WaitForIncomingMessage(). Must only be accessed while owning
     824             :     // mMonitor.
     825             :     bool mIsWaitingForIncoming;
     826             : 
     827             :     // Map of replies received "out of turn", because of Interrupt
     828             :     // in-calls racing with replies to outstanding in-calls.  See
     829             :     // https://bugzilla.mozilla.org/show_bug.cgi?id=521929.
     830             :     MessageMap mOutOfTurnReplies;
     831             : 
     832             :     // Map of async Callbacks that are still waiting replies.
     833             :     CallbackMap mPendingResponses;
     834             : 
     835             :     // Stack of Interrupt in-calls that were deferred because of race
     836             :     // conditions.
     837             :     std::stack<Message> mDeferred;
     838             : 
     839             : #ifdef OS_WIN
     840             :     HANDLE mEvent;
     841             : #endif
     842             : 
     843             :     // Should the channel abort the process from the I/O thread when
     844             :     // a channel error occurs?
     845             :     bool mAbortOnError;
     846             : 
     847             :     // True if the listener has already been notified of a channel close or
     848             :     // error.
     849             :     bool mNotifiedChannelDone;
     850             : 
     851             :     // See SetChannelFlags
     852             :     ChannelFlags mFlags;
     853             : 
     854             :     // Task and state used to asynchronously notify channel has been connected
     855             :     // safely.  This is necessary to be able to cancel notification if we are
     856             :     // closed at the same time.
     857             :     RefPtr<CancelableRunnable> mOnChannelConnectedTask;
     858             :     bool mPeerPidSet;
     859             :     int32_t mPeerPid;
     860             : 
     861             :     // Channels can enter messages are not sent immediately; instead, they are
     862             :     // held in a queue until another thread deems it is safe to send them.
     863             :     bool mIsPostponingSends;
     864             :     std::vector<UniquePtr<Message>> mPostponedSends;
     865             : 
     866             :     bool mInKillHardShutdown;
     867             : 
     868             :     bool mBuildIDsConfirmedMatch;
     869             : };
     870             : 
     871             : void
     872             : CancelCPOWs();
     873             : 
     874             : } // namespace ipc
     875             : } // namespace mozilla
     876             : 
     877             : namespace IPC {
     878             : template <>
     879             : struct ParamTraits<mozilla::ipc::ResponseRejectReason>
     880             :     : public ContiguousEnumSerializer<mozilla::ipc::ResponseRejectReason,
     881             :                                       mozilla::ipc::ResponseRejectReason::SendError,
     882             :                                       mozilla::ipc::ResponseRejectReason::EndGuard_>
     883             : { };
     884             : } // namespace IPC
     885             : 
     886             : #endif  // ifndef ipc_glue_MessageChannel_h

Generated by: LCOV version 1.13-14-ga5dd952