Bug 998863: Asynchronous Plugin Initialization, Part 3: ipc/glue changes; r=dvander

This commit is contained in:
Aaron Klotz 2014-12-24 17:56:06 -07:00
parent 15edf3ffa5
commit fc2f0c6a2e
3 changed files with 67 additions and 3 deletions

View File

@ -298,6 +298,7 @@ MessageChannel::MessageChannel(MessageListener *aListener)
mRecvdErrors(0),
mRemoteStackDepthGuess(false),
mSawInterruptOutMsg(false),
mIsWaitingForIncoming(false),
mAbortOnError(false),
mBlockScripts(false),
mFlags(REQUIRE_DEFAULT),
@ -664,7 +665,8 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
}
bool shouldWakeUp = AwaitingInterruptReply() ||
(AwaitingSyncReply() && !ShouldDeferMessage(aMsg));
(AwaitingSyncReply() && !ShouldDeferMessage(aMsg)) ||
AwaitingIncomingMessage();
// There are three cases we're concerned about, relating to the state of the
// main thread:
@ -987,6 +989,35 @@ MessageChannel::Call(Message* aMsg, Message* aReply)
return true;
}
bool
MessageChannel::WaitForIncomingMessage()
{
#ifdef OS_WIN
SyncStackFrame frame(this, true);
#endif
{ // Scope for lock
MonitorAutoLock lock(*mMonitor);
AutoEnterWaitForIncoming waitingForIncoming(*this);
if (mChannelState != ChannelConnected) {
return false;
}
if (!HasPendingEvents()) {
return WaitForInterruptNotify();
}
}
return OnMaybeDequeueOne();
}
bool
MessageChannel::HasPendingEvents()
{
AssertWorkerThread();
mMonitor->AssertCurrentThreadOwns();
return Connected() && !mPending.empty();
}
bool
MessageChannel::InterruptEventOccurred()
{
@ -1546,7 +1577,7 @@ MessageChannel::OnChannelErrorFromLink()
if (InterruptStackDepth() > 0)
NotifyWorkerThread();
if (AwaitingSyncReply())
if (AwaitingSyncReply() || AwaitingIncomingMessage())
NotifyWorkerThread();
if (ChannelClosing != mChannelState) {

View File

@ -124,6 +124,9 @@ class MessageChannel : HasResultCodes
// Make an Interrupt call to the other side of the channel
bool Call(Message* aMsg, Message* aReply);
// Wait until a message is received
bool WaitForIncomingMessage();
bool CanSend() const;
void SetReplyTimeoutMs(int32_t aTimeoutMs);
@ -214,6 +217,7 @@ class MessageChannel : HasResultCodes
void DispatchOnChannelConnected();
bool InterruptEventOccurred();
bool HasPendingEvents();
bool ProcessPendingRequest(const Message &aUrgent);
@ -319,6 +323,30 @@ class MessageChannel : HasResultCodes
mMonitor->AssertCurrentThreadOwns();
return !mInterruptStack.empty();
}
bool AwaitingIncomingMessage() const {
mMonitor->AssertCurrentThreadOwns();
return mIsWaitingForIncoming;
}
class MOZ_STACK_CLASS AutoEnterWaitForIncoming
{
public:
explicit AutoEnterWaitForIncoming(MessageChannel& aChannel)
: mChannel(aChannel)
{
aChannel.mMonitor->AssertCurrentThreadOwns();
aChannel.mIsWaitingForIncoming = true;
}
~AutoEnterWaitForIncoming()
{
mChannel.mIsWaitingForIncoming = false;
}
private:
MessageChannel& mChannel;
};
friend class AutoEnterWaitForIncoming;
// Returns true if we're dispatching a sync message's callback.
bool DispatchingSyncMessage() const {
@ -639,6 +667,11 @@ class MessageChannel : HasResultCodes
// ExitedCxxStack(), from which this variable is reset.
bool mSawInterruptOutMsg;
// Are we waiting on this channel for an incoming message? This is used
// to implement WaitForIncomingMessage(). Must only be accessed while owning
// mMonitor.
bool mIsWaitingForIncoming;
// Map of replies received "out of turn", because of Interrupt
// in-calls racing with replies to outstanding in-calls. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=521929.

View File

@ -966,7 +966,7 @@ MessageChannel::WaitForInterruptNotify()
return WaitForSyncNotify();
}
if (!InterruptStackDepth()) {
if (!InterruptStackDepth() && !AwaitingIncomingMessage()) {
// There is currently no way to recover from this condition.
NS_RUNTIMEABORT("StackDepth() is 0 in call to MessageChannel::WaitForNotify!");
}