MessageChannel.h (28851B)
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 10 11 #include "ipc/EnumSerializer.h" 12 #include "mozilla/BaseProfilerMarkers.h" 13 #include "mozilla/LinkedList.h" 14 #include "mozilla/Monitor.h" 15 #include "mozilla/MoveOnlyFunction.h" 16 #if defined(XP_WIN) 17 # include "mozilla/ipc/Neutering.h" 18 #endif // defined(XP_WIN) 19 20 #include <functional> 21 #include <stack> 22 23 #include "MessageLink.h" // for HasResultCodes 24 #include "mozilla/ipc/ScopedPort.h" 25 #include "nsITargetShutdownTask.h" 26 27 #ifdef FUZZING_SNAPSHOT 28 # include "mozilla/fuzzing/IPCFuzzController.h" 29 #endif 30 31 class MessageLoop; 32 33 namespace IPC { 34 template <typename T> 35 struct ParamTraits; 36 } 37 38 namespace mozilla { 39 namespace ipc { 40 41 class IToplevelProtocol; 42 class ActorLifecycleProxy; 43 44 class RefCountedMonitor : public Monitor { 45 public: 46 RefCountedMonitor() : Monitor("mozilla.ipc.MessageChannel.mMonitor") {} 47 48 void AssertSameMonitor(const RefCountedMonitor& aOther) const 49 MOZ_REQUIRES(*this) MOZ_ASSERT_CAPABILITY(aOther) { 50 MOZ_ASSERT(this == &aOther); 51 } 52 53 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMonitor) 54 55 private: 56 ~RefCountedMonitor() = default; 57 }; 58 59 enum class MessageDirection { 60 eSending, 61 eReceiving, 62 }; 63 64 enum class MessagePhase { 65 Endpoint, 66 TransferStart, 67 TransferEnd, 68 }; 69 70 enum class SyncSendError { 71 SendSuccess, 72 PreviousTimeout, 73 SendingCPOWWhileDispatchingSync, 74 SendingCPOWWhileDispatchingUrgent, 75 NotConnectedBeforeSend, 76 DisconnectedDuringSend, 77 CancelledBeforeSend, 78 CancelledAfterSend, 79 TimedOut, 80 ReplyError, 81 }; 82 83 enum class ResponseRejectReason { 84 SendError, 85 ChannelClosed, 86 HandlerRejected, 87 ActorDestroyed, 88 ResolverDestroyed, 89 EndGuard_, 90 }; 91 92 template <typename T> 93 using ResolveCallback = MoveOnlyFunction<void(T&&)>; 94 95 using RejectCallback = MoveOnlyFunction<void(ResponseRejectReason)>; 96 97 enum ChannelState { 98 ChannelClosed, 99 ChannelConnected, 100 ChannelClosing, 101 ChannelError 102 }; 103 104 class AutoEnterTransaction; 105 106 class MessageChannel : HasResultCodes { 107 friend class PortLink; 108 109 typedef mozilla::Monitor Monitor; 110 111 public: 112 using Message = IPC::Message; 113 using seqno_t = Message::seqno_t; 114 115 static constexpr int32_t kNoTimeout = INT32_MIN; 116 117 using ScopedPort = mozilla::ipc::ScopedPort; 118 119 explicit MessageChannel(const char* aName, IToplevelProtocol* aListener); 120 ~MessageChannel(); 121 122 IToplevelProtocol* Listener() const { return mListener; } 123 124 // Returns the event target which the worker lives on and must be used for 125 // operations on the current thread. Only safe to access after the 126 // MessageChannel has been opened. 127 nsISerialEventTarget* GetWorkerEventTarget() const { return mWorkerThread; } 128 129 // "Open" a connection using an existing ScopedPort. The ScopedPort must be 130 // valid and connected to a remote. 131 // 132 // The `aEventTarget` parameter must be on the current thread. 133 bool Open(ScopedPort aPort, Side aSide, const nsID& aMessageChannelId, 134 nsISerialEventTarget* aEventTarget = nullptr); 135 136 // "Open" a connection to another thread in the same process. 137 // 138 // Returns true if the transport layer was successfully connected, 139 // i.e., mChannelState == ChannelConnected. 140 // 141 // For more details on the process of opening a channel between 142 // threads, see the extended comment on this function 143 // in MessageChannel.cpp. 144 bool Open(MessageChannel* aTargetChan, nsISerialEventTarget* aEventTarget, 145 Side aSide); 146 147 // "Open" a connection to an actor on the current thread. 148 // 149 // Returns true if the transport layer was successfully connected, 150 // i.e., mChannelState == ChannelConnected. 151 // 152 // Same-thread channels may not perform synchronous or blocking message 153 // sends, to avoid deadlocks. 154 bool OpenOnSameThread(MessageChannel* aTargetChan, Side aSide); 155 156 /** 157 * This sends a special message that is processed on the IO thread, so that 158 * other actors can know that the process will soon shutdown. 159 */ 160 void NotifyImpendingShutdown() MOZ_EXCLUDES(*mMonitor); 161 162 // Close the underlying transport channel. 163 void Close() MOZ_EXCLUDES(*mMonitor); 164 165 // Induce an error in this MessageChannel's connection. 166 // 167 // After this method is called, no more message notifications will be 168 // delivered to the listener, and the channel will be unable to send or 169 // receive future messages, as if the peer dropped the connection 170 // unexpectedly. 171 // 172 // The OnChannelError notification will be delivered either asynchronously or 173 // during an explicit call to Close(), whichever happens first. 174 // 175 // NOTE: If SetAbortOnError(true) has been called on this MessageChannel, 176 // calling this function will immediately exit the current process. 177 void InduceConnectionError() MOZ_EXCLUDES(*mMonitor); 178 179 void SetAbortOnError(bool abort) MOZ_EXCLUDES(*mMonitor) { 180 MonitorAutoLock lock(*mMonitor); 181 mAbortOnError = abort; 182 } 183 184 // Call aInvoke for each pending message until it returns false. 185 // XXX: You must get permission from an IPC peer to use this function 186 // since it requires custom deserialization and re-orders events. 187 void PeekMessages(const std::function<bool(const Message& aMsg)>& aInvoke) 188 MOZ_EXCLUDES(*mMonitor); 189 190 // Misc. behavioral traits consumers can request for this channel 191 enum ChannelFlags { 192 REQUIRE_DEFAULT = 0, 193 // Windows: if this channel operates on the UI thread, indicates 194 // WindowsMessageLoop code should enable deferred native message 195 // handling to prevent deadlocks. Should only be used for protocols 196 // that manage child processes which might create native UI, like 197 // plugins. 198 REQUIRE_DEFERRED_MESSAGE_PROTECTION = 1 << 0, 199 }; 200 void SetChannelFlags(ChannelFlags aFlags) { mFlags = aFlags; } 201 ChannelFlags GetChannelFlags() { return mFlags; } 202 203 // Asynchronously send a message to the other side of the channel. 204 // If aSeqno is non-null, it will be set to the seqno of the sent message. 205 bool Send(UniquePtr<Message> aMsg, seqno_t* aSeqno = nullptr) 206 MOZ_EXCLUDES(*mMonitor); 207 208 bool SendBuildIDsMatchMessage(const char* aParentBuildID) 209 MOZ_EXCLUDES(*mMonitor); 210 bool DoBuildIDsMatch() MOZ_EXCLUDES(*mMonitor) { 211 MonitorAutoLock lock(*mMonitor); 212 return mBuildIDsConfirmedMatch; 213 } 214 215 // Synchronously send |aMsg| (i.e., wait for |aReply|) 216 bool Send(UniquePtr<Message> aMsg, UniquePtr<Message>* aReply) 217 MOZ_EXCLUDES(*mMonitor); 218 219 bool CanSend() const MOZ_EXCLUDES(*mMonitor); 220 221 // If sending a sync message returns an error, this function gives a more 222 // descriptive error message. 223 SyncSendError LastSendError() const { 224 AssertWorkerThread(); 225 return mLastSendError; 226 } 227 228 void SetReplyTimeoutMs(int32_t aTimeoutMs); 229 230 bool IsOnCxxStack() const { return mOnCxxStack; } 231 232 void CancelCurrentTransaction() MOZ_EXCLUDES(*mMonitor); 233 234 // Return whether the current transaction is complete. 235 // 236 // This is intended only for tests. 237 bool TestOnlyIsTransactionComplete() const MOZ_EXCLUDES(*mMonitor); 238 239 // IsClosed and NumQueuedMessages are safe to call from any thread, but 240 // may provide an out-of-date value. 241 bool IsClosed() MOZ_EXCLUDES(*mMonitor) { 242 MonitorAutoLock lock(*mMonitor); 243 return IsClosedLocked(); 244 } 245 bool IsClosedLocked() const MOZ_REQUIRES(*mMonitor) { 246 mMonitor->AssertCurrentThreadOwns(); 247 return mLink ? mLink->IsClosed() : true; 248 } 249 250 static bool IsPumpingMessages() { return sIsPumpingMessages; } 251 static void SetIsPumpingMessages(bool aIsPumping) { 252 sIsPumpingMessages = aIsPumping; 253 } 254 255 /** 256 * Does this MessageChannel currently cross process boundaries? 257 */ 258 bool IsCrossProcess() const MOZ_REQUIRES(*mMonitor); 259 void SetIsCrossProcess(bool aIsCrossProcess) MOZ_REQUIRES(*mMonitor); 260 261 nsID GetMessageChannelId() const { 262 MonitorAutoLock lock(*mMonitor); 263 return mMessageChannelId; 264 } 265 266 #ifdef FUZZING_SNAPSHOT 267 Maybe<mojo::core::ports::PortName> GetPortName() { 268 MonitorAutoLock lock(*mMonitor); 269 return mLink ? mLink->GetPortName() : Nothing(); 270 } 271 #endif 272 273 #ifdef XP_WIN 274 struct MOZ_STACK_CLASS SyncStackFrame { 275 explicit SyncStackFrame(MessageChannel* channel); 276 ~SyncStackFrame(); 277 278 bool mSpinNestedEvents; 279 bool mListenerNotified; 280 MessageChannel* mChannel; 281 282 // The previous stack frame for this channel. 283 SyncStackFrame* mPrev; 284 285 // The previous stack frame on any channel. 286 SyncStackFrame* mStaticPrev; 287 }; 288 friend struct MessageChannel::SyncStackFrame; 289 290 static bool IsSpinLoopActive() { 291 for (SyncStackFrame* frame = sStaticTopFrame; frame; frame = frame->mPrev) { 292 if (frame->mSpinNestedEvents) return true; 293 } 294 return false; 295 } 296 297 protected: 298 // The deepest sync stack frame for this channel. 299 SyncStackFrame* mTopFrame = nullptr; 300 301 bool mIsSyncWaitingOnNonMainThread = false; 302 303 // The deepest sync stack frame on any channel. 304 static SyncStackFrame* sStaticTopFrame; 305 306 public: 307 void ProcessNativeEventsInInterruptCall(); 308 static void NotifyGeckoEventDispatch(); 309 #endif // defined(XP_WIN) 310 311 private: 312 void PostErrorNotifyTask() MOZ_REQUIRES(*mMonitor); 313 void OnNotifyMaybeChannelError() MOZ_EXCLUDES(*mMonitor); 314 void ReportConnectionError(const char* aFunctionName, 315 const uint32_t aMsgTyp) const 316 MOZ_REQUIRES(*mMonitor); 317 bool MaybeHandleError(Result code, const Message& aMsg, 318 const char* channelName) MOZ_EXCLUDES(*mMonitor); 319 320 void Clear() MOZ_REQUIRES(*mMonitor); 321 322 bool HasPendingEvents() MOZ_REQUIRES(*mMonitor); 323 324 void ProcessPendingRequests(ActorLifecycleProxy* aProxy, 325 AutoEnterTransaction& aTransaction) 326 MOZ_REQUIRES(*mMonitor); 327 bool ProcessPendingRequest(ActorLifecycleProxy* aProxy, 328 UniquePtr<Message> aUrgent) 329 MOZ_REQUIRES(*mMonitor); 330 331 void EnqueuePendingMessages() MOZ_REQUIRES(*mMonitor); 332 333 // Dispatches an incoming message to its appropriate handler. 334 void DispatchMessage(ActorLifecycleProxy* aProxy, UniquePtr<Message> aMsg) 335 MOZ_REQUIRES(*mMonitor); 336 337 // DispatchMessage will route to one of these functions depending on the 338 // protocol type of the message. 339 void DispatchSyncMessage(ActorLifecycleProxy* aProxy, const Message& aMsg, 340 UniquePtr<Message>& aReply) MOZ_EXCLUDES(*mMonitor); 341 void DispatchAsyncMessage(ActorLifecycleProxy* aProxy, const Message& aMsg) 342 MOZ_EXCLUDES(*mMonitor); 343 344 // Return true if the wait ended because a notification was received. 345 // 346 // Return false if the time elapsed from when we started the process of 347 // waiting until afterwards exceeded the currently allotted timeout. 348 // That *DOES NOT* mean false => "no event" (== timeout); there are many 349 // circumstances that could cause the measured elapsed time to exceed the 350 // timeout EVEN WHEN we were notified. 351 // 352 // So in sum: true is a meaningful return value; false isn't, 353 // necessarily. 354 bool WaitForSyncNotify() MOZ_REQUIRES(*mMonitor); 355 356 bool WaitResponse(bool aWaitTimedOut); 357 358 bool ShouldContinueFromTimeout() MOZ_REQUIRES(*mMonitor); 359 360 void EndTimeout() MOZ_REQUIRES(*mMonitor); 361 void CancelTransaction(seqno_t transaction) MOZ_REQUIRES(*mMonitor); 362 363 void RepostAllMessages() MOZ_REQUIRES(*mMonitor); 364 365 seqno_t NextSeqno() { 366 AssertWorkerThread(); 367 MOZ_RELEASE_ASSERT(mozilla::Abs(mNextSeqno) < INT64_MAX, "seqno overflow"); 368 return (mSide == ChildSide) ? --mNextSeqno : ++mNextSeqno; 369 } 370 371 void DebugAbort(const char* file, int line, const char* cond, const char* why, 372 bool reply = false) MOZ_REQUIRES(*mMonitor); 373 374 void AddProfilerMarker(const IPC::Message& aMessage, 375 MessageDirection aDirection) MOZ_REQUIRES(*mMonitor); 376 377 private: 378 // Returns true if we're dispatching an async message's callback. 379 bool DispatchingAsyncMessage() const { 380 AssertWorkerThread(); 381 return mDispatchingAsyncMessage; 382 } 383 384 int DispatchingAsyncMessageNestedLevel() const { 385 AssertWorkerThread(); 386 return mDispatchingAsyncMessageNestedLevel; 387 } 388 389 // Check if there is still a live connection to our peer. This may change to 390 // `false` at any time due to the connection to our peer being closed or 391 // dropped (e.g. due to a crash). 392 bool Connected() const MOZ_REQUIRES(*mMonitor); 393 394 // Check if there is either still a live connection to our peer, or we have 395 // received a `Goodbye` from our peer, and are actively shutting down our 396 // connection with our peer. 397 bool ConnectedOrClosing() const MOZ_REQUIRES(*mMonitor); 398 399 private: 400 // Executed on the IO thread. 401 void NotifyWorkerThread() MOZ_REQUIRES(*mMonitor); 402 403 // Return true if |aMsg| is a special message targeted at the IO 404 // thread, in which case it shouldn't be delivered to the worker. 405 bool MaybeInterceptSpecialIOMessage(const Message& aMsg) 406 MOZ_REQUIRES(*mMonitor); 407 408 // Returns true if ShouldDeferMessage(aMsg) is guaranteed to return true. 409 // Otherwise, the result of ShouldDeferMessage(aMsg) may be true or false, 410 // depending on context. 411 static bool IsAlwaysDeferred(const Message& aMsg); 412 413 // Helper for sending a message via the link. If the message is [LazySend], it 414 // will be queued, and if the message is not-[LazySend], it will flush any 415 // pending [LazySend] messages. 416 void SendMessageToLink(UniquePtr<Message> aMsg) MOZ_REQUIRES(*mMonitor); 417 418 // Called to flush [LazySend] messages to the link. 419 void FlushLazySendMessages() MOZ_REQUIRES(*mMonitor); 420 421 bool ShouldDeferMessage(const Message& aMsg) MOZ_REQUIRES(*mMonitor); 422 void OnMessageReceivedFromLink(UniquePtr<Message> aMsg) 423 MOZ_REQUIRES(*mMonitor); 424 void OnChannelErrorFromLink() MOZ_REQUIRES(*mMonitor); 425 426 private: 427 // Clear this channel, and notify the listener that the channel has either 428 // closed or errored. 429 // 430 // These methods must be called on the worker thread, passing in a 431 // `ReleasableMonitorAutoLock`. This lock guard will be reset before the 432 // listener is called, allowing for the monitor to be unlocked before the 433 // MessageChannel is potentially destroyed. 434 void NotifyChannelClosed(ReleasableMonitorAutoLock& aLock) 435 MOZ_REQUIRES(*mMonitor); 436 void NotifyMaybeChannelError(ReleasableMonitorAutoLock& aLock) 437 MOZ_REQUIRES(*mMonitor); 438 439 private: 440 void AssertWorkerThread() const { 441 MOZ_ASSERT(mWorkerThread, "Channel hasn't been opened yet"); 442 MOZ_RELEASE_ASSERT(mWorkerThread && mWorkerThread->IsOnCurrentThread(), 443 "not on worker thread!"); 444 } 445 446 private: 447 class MessageTask : public CancelableRunnable, 448 public LinkedListElement<RefPtr<MessageTask>>, 449 public nsIRunnablePriority, 450 public nsIRunnableIPCMessageType { 451 public: 452 explicit MessageTask(MessageChannel* aChannel, UniquePtr<Message> aMessage); 453 MessageTask() = delete; 454 MessageTask(const MessageTask&) = delete; 455 456 NS_DECL_ISUPPORTS_INHERITED 457 458 NS_IMETHOD Run() override; 459 nsresult Cancel() override; 460 NS_IMETHOD GetPriority(uint32_t* aPriority) override; 461 NS_DECL_NSIRUNNABLEIPCMESSAGETYPE 462 void Post() MOZ_REQUIRES(*mMonitor); 463 464 bool IsScheduled() const MOZ_REQUIRES(*mMonitor) { 465 mMonitor->AssertCurrentThreadOwns(); 466 return mScheduled; 467 } 468 469 UniquePtr<Message>& Msg() MOZ_REQUIRES(*mMonitor) { 470 MOZ_DIAGNOSTIC_ASSERT(mMessage, "message was moved"); 471 return mMessage; 472 } 473 const UniquePtr<Message>& Msg() const MOZ_REQUIRES(*mMonitor) { 474 MOZ_DIAGNOSTIC_ASSERT(mMessage, "message was moved"); 475 return mMessage; 476 } 477 478 void AssertMonitorHeld(const RefCountedMonitor& aMonitor) 479 MOZ_REQUIRES(aMonitor) MOZ_ASSERT_CAPABILITY(*mMonitor) { 480 aMonitor.AssertSameMonitor(*mMonitor); 481 } 482 483 private: 484 ~MessageTask(); 485 486 MessageChannel* Channel() MOZ_REQUIRES(*mMonitor) { 487 mMonitor->AssertCurrentThreadOwns(); 488 MOZ_RELEASE_ASSERT(isInList()); 489 return mChannel; 490 } 491 492 // The connected MessageChannel's monitor. Guards `mChannel` and 493 // `mScheduled`. 494 RefPtr<RefCountedMonitor> const mMonitor; 495 // The channel which this MessageTask is associated with. Only valid while 496 // `mMonitor` is held, and this MessageTask `isInList()`. 497 MessageChannel* const mChannel; 498 UniquePtr<Message> mMessage MOZ_GUARDED_BY(*mMonitor); 499 uint32_t const mPriority; 500 bool mScheduled : 1 MOZ_GUARDED_BY(*mMonitor); 501 #ifdef FUZZING_SNAPSHOT 502 const bool mIsFuzzMsg; 503 bool mFuzzStopped MOZ_GUARDED_BY(*mMonitor); 504 #endif 505 }; 506 507 bool ShouldRunMessage(const Message& aMsg) MOZ_REQUIRES(*mMonitor); 508 void RunMessage(ActorLifecycleProxy* aProxy, MessageTask& aTask) 509 MOZ_REQUIRES(*mMonitor); 510 511 class WorkerTargetShutdownTask final : public nsITargetShutdownTask { 512 public: 513 NS_DECL_THREADSAFE_ISUPPORTS 514 515 WorkerTargetShutdownTask(nsISerialEventTarget* aTarget, 516 MessageChannel* aChannel); 517 518 void TargetShutdown() override; 519 void Clear(); 520 521 private: 522 ~WorkerTargetShutdownTask() = default; 523 524 const nsCOMPtr<nsISerialEventTarget> mTarget; 525 // Cleared by MessageChannel before it is destroyed. 526 MessageChannel* MOZ_NON_OWNING_REF mChannel; 527 }; 528 529 class FlushLazySendMessagesRunnable final : public CancelableRunnable { 530 public: 531 explicit FlushLazySendMessagesRunnable(MessageChannel* aChannel); 532 533 NS_DECL_ISUPPORTS_INHERITED 534 535 NS_IMETHOD Run() override; 536 nsresult Cancel() override; 537 538 void PushMessage(UniquePtr<Message> aMsg); 539 nsTArray<UniquePtr<Message>> TakeMessages(); 540 541 private: 542 ~FlushLazySendMessagesRunnable() = default; 543 544 // Cleared by MessageChannel before it is destroyed. 545 MessageChannel* MOZ_NON_OWNING_REF mChannel; 546 547 // LazySend messages which haven't been sent yet, but will be sent as soon 548 // as a non-LazySend message is sent, or this runnable is executed. 549 nsTArray<UniquePtr<Message>> mQueue; 550 }; 551 552 typedef LinkedList<RefPtr<MessageTask>> MessageQueue; 553 typedef IPC::Message::msgid_t msgid_t; 554 555 private: 556 // This will be a string literal, so lifetime is not an issue. 557 const char* const mName; 558 559 // ID for each MessageChannel. Set when it is opened, and never cleared 560 // afterwards. 561 // 562 // This ID is only intended for diagnostics, debugging, and reporting 563 // purposes, and shouldn't be used for message routing or permissions checks. 564 nsID mMessageChannelId MOZ_GUARDED_BY(*mMonitor) = {}; 565 566 // Based on presumption the listener owns and overlives the channel, 567 // this is never nullified. 568 IToplevelProtocol* const mListener; 569 570 // This monitor guards all state in this MessageChannel, except where 571 // otherwise noted. It is refcounted so a reference to it can be shared with 572 // IPC listener objects which need to access weak references to this 573 // `MessageChannel`. 574 RefPtr<RefCountedMonitor> const mMonitor; 575 576 ChannelState mChannelState MOZ_GUARDED_BY(*mMonitor) = ChannelClosed; 577 Side mSide = UnknownSide; 578 bool mIsCrossProcess MOZ_GUARDED_BY(*mMonitor) = false; 579 UniquePtr<MessageLink> mLink MOZ_GUARDED_BY(*mMonitor); 580 581 // NotifyMaybeChannelError runnable 582 RefPtr<CancelableRunnable> mChannelErrorTask MOZ_GUARDED_BY(*mMonitor); 583 584 // Thread we are allowed to send and receive on. Set in Open(); never 585 // changed, and we can only call Open() once. We shouldn't be accessing 586 // from multiple threads before Open(). 587 nsCOMPtr<nsISerialEventTarget> mWorkerThread; 588 589 // Shutdown task to close the channel before mWorkerThread goes away. 590 RefPtr<WorkerTargetShutdownTask> mShutdownTask MOZ_GUARDED_BY(*mMonitor); 591 592 // Task to force sending lazy messages when mQueuedLazyMessages is non-empty. 593 RefPtr<FlushLazySendMessagesRunnable> mFlushLazySendTask 594 MOZ_GUARDED_BY(*mMonitor); 595 596 // Timeout periods are broken up in two to prevent system suspension from 597 // triggering an abort. This method (called by WaitForEvent with a 'did 598 // timeout' flag) decides if we should wait again for half of mTimeoutMs 599 // or give up. 600 // only accessed on WorkerThread 601 int32_t mTimeoutMs = kNoTimeout; 602 bool mInTimeoutSecondHalf = false; 603 604 // Worker-thread only; sequence numbers for messages that require 605 // replies. 606 seqno_t mNextSeqno = 0; 607 608 static bool sIsPumpingMessages; 609 610 // If ::Send returns false, this gives a more descriptive error. 611 SyncSendError mLastSendError = SyncSendError::SendSuccess; 612 613 template <class T> 614 class AutoSetValue { 615 public: 616 explicit AutoSetValue(T& var, const T& newValue) 617 : mVar(var), mPrev(var), mNew(newValue) { 618 mVar = newValue; 619 } 620 ~AutoSetValue() { 621 // The value may have been zeroed if the transaction was 622 // canceled. In that case we shouldn't return it to its previous 623 // value. 624 if (mVar == mNew) { 625 mVar = mPrev; 626 } 627 } 628 629 private: 630 T& mVar; 631 T mPrev; 632 T mNew; 633 }; 634 635 bool mDispatchingAsyncMessage = false; 636 int mDispatchingAsyncMessageNestedLevel = 0; 637 638 // When we send an urgent request from the parent process, we could race 639 // with an RPC message that was issued by the child beforehand. In this 640 // case, if the parent were to wake up while waiting for the urgent reply, 641 // and process the RPC, it could send an additional urgent message. The 642 // child would wake up to process the urgent message (as it always will), 643 // then send a reply, which could be received by the parent out-of-order 644 // with respect to the first urgent reply. 645 // 646 // To address this problem, urgent or RPC requests are associated with a 647 // "transaction". Whenever one side of the channel wishes to start a 648 // chain of RPC/urgent messages, it allocates a new transaction ID. Any 649 // messages the parent receives, not apart of this transaction, are 650 // deferred. When issuing RPC/urgent requests on top of a started 651 // transaction, the initiating transaction ID is used. 652 // 653 // To ensure IDs are unique, we use sequence numbers for transaction IDs, 654 // which grow in opposite directions from child to parent. 655 656 friend class AutoEnterTransaction; 657 AutoEnterTransaction* mTransactionStack MOZ_GUARDED_BY(*mMonitor) = nullptr; 658 659 seqno_t CurrentNestedInsideSyncTransaction() const MOZ_REQUIRES(*mMonitor); 660 661 bool AwaitingSyncReply() const MOZ_REQUIRES(*mMonitor); 662 int AwaitingSyncReplyNestedLevel() const MOZ_REQUIRES(*mMonitor); 663 664 bool DispatchingSyncMessage() const MOZ_REQUIRES(*mMonitor); 665 int DispatchingSyncMessageNestedLevel() const MOZ_REQUIRES(*mMonitor); 666 667 #ifdef DEBUG 668 void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor); 669 #else 670 void AssertMaybeDeferredCountCorrect() MOZ_REQUIRES(*mMonitor) {} 671 #endif 672 673 // If a sync message times out, we store its sequence number here. Any 674 // future sync messages will fail immediately. Once the reply for original 675 // sync message is received, we allow sync messages again. 676 // 677 // When a message times out, nothing is done to inform the other side. The 678 // other side will eventually dispatch the message and send a reply. Our 679 // side is responsible for replying to all sync messages sent by the other 680 // side when it dispatches the timed out message. The response is always an 681 // error. 682 // 683 // A message is only timed out if it initiated a transaction. This avoids 684 // hitting a lot of corner cases with message nesting that we don't really 685 // care about. 686 seqno_t mTimedOutMessageSeqno MOZ_GUARDED_BY(*mMonitor) = 0; 687 int mTimedOutMessageNestedLevel MOZ_GUARDED_BY(*mMonitor) = 0; 688 689 // Queue of all incoming messages. 690 // 691 // If both this side and the other side are functioning correctly, the other 692 // side can send as many async messages as it wants before sending us a 693 // blocking message. After sending a blocking message, the other side must be 694 // blocked, and thus can't send us any more messages until we process the sync 695 // in-msg. 696 // 697 MessageQueue mPending MOZ_GUARDED_BY(*mMonitor); 698 699 // The number of messages in mPending for which IsAlwaysDeferred is false 700 // (i.e., the number of messages that might not be deferred, depending on 701 // context). 702 size_t mMaybeDeferredPendingCount MOZ_GUARDED_BY(*mMonitor) = 0; 703 704 // Is there currently MessageChannel logic for this channel on the C++ stack? 705 // This member is only accessed on the worker thread, and so is not protected 706 // by mMonitor. 707 bool mOnCxxStack = false; 708 709 #ifdef XP_WIN 710 HANDLE mEvent; 711 #endif 712 713 // Should the channel abort the process from the I/O thread when 714 // a channel error occurs? 715 bool mAbortOnError MOZ_GUARDED_BY(*mMonitor) = false; 716 717 // True if the listener has already been notified of a channel close or 718 // error. 719 bool mNotifiedChannelDone MOZ_GUARDED_BY(*mMonitor) = false; 720 721 // See SetChannelFlags 722 ChannelFlags mFlags = REQUIRE_DEFAULT; 723 724 bool mBuildIDsConfirmedMatch MOZ_GUARDED_BY(*mMonitor) = false; 725 726 // If this is true, both ends of this message channel have event targets 727 // on the same thread. 728 bool mIsSameThreadChannel = false; 729 }; 730 731 void CancelCPOWs(); 732 733 } // namespace ipc 734 } // namespace mozilla 735 736 namespace IPC { 737 template <> 738 struct ParamTraits<mozilla::ipc::ResponseRejectReason> 739 : public ContiguousEnumSerializer< 740 mozilla::ipc::ResponseRejectReason, 741 mozilla::ipc::ResponseRejectReason::SendError, 742 mozilla::ipc::ResponseRejectReason::EndGuard_> {}; 743 } // namespace IPC 744 745 namespace geckoprofiler::markers { 746 747 struct IPCMarker { 748 static constexpr mozilla::Span<const char> MarkerTypeName() { 749 return mozilla::MakeStringSpan("IPC"); 750 } 751 static void StreamJSONMarkerData( 752 mozilla::baseprofiler::SpliceableJSONWriter& aWriter, 753 mozilla::TimeStamp aStart, mozilla::TimeStamp aEnd, int32_t aOtherPid, 754 IPC::Message::seqno_t aMessageSeqno, IPC::Message::msgid_t aMessageType, 755 mozilla::ipc::Side aSide, mozilla::ipc::MessageDirection aDirection, 756 mozilla::ipc::MessagePhase aPhase, bool aSync, 757 mozilla::MarkerThreadId aOriginThreadId) { 758 using namespace mozilla::ipc; 759 // This payload still streams a startTime and endTime property because it 760 // made the migration to MarkerTiming on the front-end easier. 761 aWriter.TimeProperty("startTime", aStart); 762 aWriter.TimeProperty("endTime", aEnd); 763 764 aWriter.IntProperty("otherPid", aOtherPid); 765 aWriter.IntProperty("messageSeqno", aMessageSeqno); 766 aWriter.StringProperty( 767 "messageType", 768 mozilla::MakeStringSpan(IPC::StringFromIPCMessageType(aMessageType))); 769 aWriter.StringProperty("side", IPCSideToString(aSide)); 770 aWriter.StringProperty("direction", 771 aDirection == MessageDirection::eSending 772 ? mozilla::MakeStringSpan("sending") 773 : mozilla::MakeStringSpan("receiving")); 774 aWriter.StringProperty("phase", IPCPhaseToString(aPhase)); 775 aWriter.BoolProperty("sync", aSync); 776 if (!aOriginThreadId.IsUnspecified()) { 777 // Tech note: If `ToNumber()` returns a uint64_t, the conversion to 778 // int64_t is "implementation-defined" before C++20. This is acceptable 779 // here, because this is a one-way conversion to a unique identifier 780 // that's used to visually separate data by thread on the front-end. 781 aWriter.IntProperty( 782 "threadId", 783 static_cast<int64_t>(aOriginThreadId.ThreadId().ToNumber())); 784 } 785 } 786 static mozilla::MarkerSchema MarkerTypeDisplay() { 787 return mozilla::MarkerSchema::SpecialFrontendLocation{}; 788 } 789 790 private: 791 static mozilla::Span<const char> IPCSideToString(mozilla::ipc::Side aSide) { 792 switch (aSide) { 793 case mozilla::ipc::ParentSide: 794 return mozilla::MakeStringSpan("parent"); 795 case mozilla::ipc::ChildSide: 796 return mozilla::MakeStringSpan("child"); 797 case mozilla::ipc::UnknownSide: 798 return mozilla::MakeStringSpan("unknown"); 799 default: 800 MOZ_ASSERT_UNREACHABLE("Invalid IPC side"); 801 return mozilla::MakeStringSpan("<invalid IPC side>"); 802 } 803 } 804 805 static mozilla::Span<const char> IPCPhaseToString( 806 mozilla::ipc::MessagePhase aPhase) { 807 switch (aPhase) { 808 case mozilla::ipc::MessagePhase::Endpoint: 809 return mozilla::MakeStringSpan("endpoint"); 810 case mozilla::ipc::MessagePhase::TransferStart: 811 return mozilla::MakeStringSpan("transferStart"); 812 case mozilla::ipc::MessagePhase::TransferEnd: 813 return mozilla::MakeStringSpan("transferEnd"); 814 default: 815 MOZ_ASSERT_UNREACHABLE("Invalid IPC phase"); 816 return mozilla::MakeStringSpan("<invalid IPC phase>"); 817 } 818 } 819 }; 820 821 } // namespace geckoprofiler::markers 822 823 #endif // ifndef ipc_glue_MessageChannel_h