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