mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Allow IPDL message sends to be deferred and re-sent as needed. (bug 1369529 part 2, r=billm)
--HG-- extra : rebase_source : 46d2af94da6b38e8c2fe70fd4566650d8cec8fe4
This commit is contained in:
parent
1951b4cd34
commit
aa1457713c
@ -537,7 +537,8 @@ MessageChannel::MessageChannel(const char* aName,
|
||||
mNotifiedChannelDone(false),
|
||||
mFlags(REQUIRE_DEFAULT),
|
||||
mPeerPidSet(false),
|
||||
mPeerPid(-1)
|
||||
mPeerPid(-1),
|
||||
mIsPostponingSends(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ipc::MessageChannel);
|
||||
|
||||
@ -901,10 +902,53 @@ MessageChannel::Send(Message* aMsg)
|
||||
ReportConnectionError("MessageChannel", msg);
|
||||
return false;
|
||||
}
|
||||
mLink->SendMessage(msg.forget());
|
||||
|
||||
SendMessageToLink(msg.forget());
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MessageChannel::SendMessageToLink(Message* aMsg)
|
||||
{
|
||||
if (mIsPostponingSends) {
|
||||
UniquePtr<Message> msg(aMsg);
|
||||
mPostponedSends.push_back(Move(msg));
|
||||
return;
|
||||
}
|
||||
mLink->SendMessage(aMsg);
|
||||
}
|
||||
|
||||
void
|
||||
MessageChannel::BeginPostponingSends()
|
||||
{
|
||||
AssertWorkerThread();
|
||||
mMonitor->AssertNotCurrentThreadOwns();
|
||||
|
||||
MonitorAutoLock lock(*mMonitor);
|
||||
{
|
||||
MOZ_ASSERT(!mIsPostponingSends);
|
||||
mIsPostponingSends = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessageChannel::StopPostponingSends()
|
||||
{
|
||||
// Note: this can be called from any thread.
|
||||
MonitorAutoLock lock(*mMonitor);
|
||||
|
||||
MOZ_ASSERT(mIsPostponingSends);
|
||||
|
||||
for (UniquePtr<Message>& iter : mPostponedSends) {
|
||||
mLink->SendMessage(iter.release());
|
||||
}
|
||||
|
||||
// We unset this after SendMessage so we can make correct thread
|
||||
// assertions in MessageLink.
|
||||
mIsPostponingSends = false;
|
||||
mPostponedSends.clear();
|
||||
}
|
||||
|
||||
already_AddRefed<MozPromiseRefcountable>
|
||||
MessageChannel::PopPromise(const Message& aMsg)
|
||||
{
|
||||
@ -1365,6 +1409,7 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
||||
msg->nested_level() < AwaitingSyncReplyNestedLevel())
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage());
|
||||
MOZ_RELEASE_ASSERT(!mIsPostponingSends);
|
||||
IPC_LOG("Cancel from Send");
|
||||
CancelMessage *cancel = new CancelMessage(CurrentNestedInsideSyncTransaction());
|
||||
CancelTransaction(CurrentNestedInsideSyncTransaction());
|
||||
@ -1413,7 +1458,7 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
||||
// msg will be destroyed soon, but name() is not owned by msg.
|
||||
const char* msgName = msg->name();
|
||||
|
||||
mLink->SendMessage(msg.forget());
|
||||
SendMessageToLink(msg.forget());
|
||||
|
||||
while (true) {
|
||||
MOZ_RELEASE_ASSERT(!transact.IsCanceled());
|
||||
@ -1544,6 +1589,7 @@ MessageChannel::Call(Message* aMsg, Message* aReply)
|
||||
IPC_ASSERT(!DispatchingSyncMessage(),
|
||||
"violation of sync handler invariant");
|
||||
IPC_ASSERT(msg->is_interrupt(), "can only Call() Interrupt messages here");
|
||||
IPC_ASSERT(!mIsPostponingSends, "not postponing sends");
|
||||
|
||||
msg->set_seqno(NextSeqno());
|
||||
msg->set_interrupt_remote_stack_depth_guess(mRemoteStackDepthGuess);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <map>
|
||||
#include <math.h>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
@ -254,6 +255,22 @@ class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver
|
||||
bool IsInTransaction() const;
|
||||
void CancelCurrentTransaction();
|
||||
|
||||
// Force all calls to Send to defer actually sending messages. This will
|
||||
// cause sync messages to block until another thread calls
|
||||
// StopPostponingSends.
|
||||
//
|
||||
// This must be called from the worker thread.
|
||||
void BeginPostponingSends();
|
||||
|
||||
// Stop postponing sent messages, and immediately flush all postponed
|
||||
// messages to the link. This may be called from any thread.
|
||||
//
|
||||
// Note that there are no ordering guarantees between two different
|
||||
// MessageChannels. If channel B sends a message, then stops postponing
|
||||
// channel A, messages from A may arrive before B. The easiest way to order
|
||||
// this, if needed, is to make B send a sync message.
|
||||
void StopPostponingSends();
|
||||
|
||||
/**
|
||||
* This function is used by hang annotation code to determine which IPDL
|
||||
* actor is highest in the call stack at the time of the hang. It should
|
||||
@ -491,6 +508,10 @@ class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver
|
||||
// depending on context.
|
||||
static bool IsAlwaysDeferred(const Message& aMsg);
|
||||
|
||||
// Helper for sending a message via the link. This should only be used for
|
||||
// non-special messages that might have to be postponed.
|
||||
void SendMessageToLink(Message* aMsg);
|
||||
|
||||
bool WasTransactionCanceled(int transaction);
|
||||
bool ShouldDeferMessage(const Message& aMsg);
|
||||
bool ShouldDeferInterruptMessage(const Message& aMsg, size_t aStackDepth);
|
||||
@ -797,6 +818,11 @@ class MessageChannel : HasResultCodes, MessageLoop::DestructionObserver
|
||||
RefPtr<CancelableRunnable> mOnChannelConnectedTask;
|
||||
bool mPeerPidSet;
|
||||
int32_t mPeerPid;
|
||||
|
||||
// Channels can enter messages are not sent immediately; instead, they are
|
||||
// held in a queue until another thread deems it is safe to send them.
|
||||
bool mIsPostponingSends;
|
||||
std::vector<UniquePtr<Message>> mPostponedSends;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -149,7 +149,9 @@ ProcessLink::SendMessage(Message *msg)
|
||||
MOZ_CRASH("IPC message size is too large");
|
||||
}
|
||||
|
||||
mChan->AssertWorkerThread();
|
||||
if (!mChan->mIsPostponingSends) {
|
||||
mChan->AssertWorkerThread();
|
||||
}
|
||||
mChan->mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
mIOLoop->PostTask(NewNonOwningRunnableMethod<Message*>(mTransport, &Transport::Send, msg));
|
||||
@ -212,7 +214,9 @@ ThreadLink::EchoMessage(Message *msg)
|
||||
void
|
||||
ThreadLink::SendMessage(Message *msg)
|
||||
{
|
||||
mChan->AssertWorkerThread();
|
||||
if (!mChan->mIsPostponingSends) {
|
||||
mChan->AssertWorkerThread();
|
||||
}
|
||||
mChan->mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
if (mTargetChan)
|
||||
|
@ -231,6 +231,8 @@ description =
|
||||
description =
|
||||
[PTestLayoutThread::SyncMessage]
|
||||
description =
|
||||
[PTestPaintThread::FinishedPaint]
|
||||
description =
|
||||
|
||||
# A11y code
|
||||
[PDocAccessible::State]
|
||||
|
@ -3,10 +3,10 @@ namespace mozilla {
|
||||
namespace _ipdltest {
|
||||
|
||||
// This is supposed to be analagous to PPaintingBridge.
|
||||
protocol PTestPaintThread
|
||||
sync protocol PTestPaintThread
|
||||
{
|
||||
parent:
|
||||
async FinishedPaint(uint64_t aTxnId);
|
||||
sync FinishedPaint(uint64_t aTxnId);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -141,7 +141,7 @@ TestOffMainThreadPaintingChild::RecvStartTest(ipc::Endpoint<PTestPaintThreadChil
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
mPaintActor = new TestPaintThreadChild();
|
||||
mPaintActor = new TestPaintThreadChild(GetIPCChannel());
|
||||
RefPtr<Runnable> task = NewRunnableMethod<ipc::Endpoint<PTestPaintThreadChild>&&>(
|
||||
"TestPaintthreadChild::Bind", mPaintActor, &TestPaintThreadChild::Bind, Move(aEndpoint));
|
||||
mPaintThread->message_loop()->PostTask(task.forget());
|
||||
@ -170,6 +170,8 @@ TestOffMainThreadPaintingChild::ProcessingError(Result aCode, const char* aReaso
|
||||
void
|
||||
TestOffMainThreadPaintingChild::IssueTransaction()
|
||||
{
|
||||
GetIPCChannel()->BeginPostponingSends();
|
||||
|
||||
uint64_t txnId = mNextTxnId++;
|
||||
|
||||
// Start painting before we send the message.
|
||||
@ -230,8 +232,9 @@ TestPaintThreadParent::DeallocPTestPaintThreadParent()
|
||||
* PTestPaintThreadChild *
|
||||
*************************/
|
||||
|
||||
TestPaintThreadChild::TestPaintThreadChild()
|
||||
: mCanSend(false)
|
||||
TestPaintThreadChild::TestPaintThreadChild(MessageChannel* aMainChannel)
|
||||
: mCanSend(false),
|
||||
mMainChannel(aMainChannel)
|
||||
{
|
||||
}
|
||||
|
||||
@ -257,6 +260,8 @@ TestPaintThreadChild::BeginPaintingForTxn(uint64_t aTxnId)
|
||||
// Sleep for some time to simulate painting being slow.
|
||||
PR_Sleep(PR_MillisecondsToInterval(500));
|
||||
SendFinishedPaint(aTxnId);
|
||||
|
||||
mMainChannel->StopPostponingSends();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -89,7 +89,7 @@ private:
|
||||
class TestPaintThreadChild final : public PTestPaintThreadChild
|
||||
{
|
||||
public:
|
||||
TestPaintThreadChild();
|
||||
explicit TestPaintThreadChild(MessageChannel* aOtherChannel);
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestPaintThreadChild);
|
||||
|
||||
@ -103,6 +103,7 @@ private:
|
||||
~TestPaintThreadChild() override;
|
||||
|
||||
bool mCanSend;
|
||||
MessageChannel* mMainChannel;
|
||||
};
|
||||
|
||||
} // namespace _ipdltest
|
||||
|
Loading…
Reference in New Issue
Block a user