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