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
|