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