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

This commit is contained in:
Aaron Klotz
2014-12-29 16:12:47 -07:00
parent 6f33132d43
commit 5eababe304
3 changed files with 67 additions and 3 deletions

View File

@@ -298,6 +298,7 @@ MessageChannel::MessageChannel(MessageListener *aListener)
mRecvdErrors(0), mRecvdErrors(0),
mRemoteStackDepthGuess(false), mRemoteStackDepthGuess(false),
mSawInterruptOutMsg(false), mSawInterruptOutMsg(false),
mIsWaitingForIncoming(false),
mAbortOnError(false), mAbortOnError(false),
mBlockScripts(false), mBlockScripts(false),
mFlags(REQUIRE_DEFAULT), mFlags(REQUIRE_DEFAULT),
@@ -664,7 +665,8 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
} }
bool shouldWakeUp = AwaitingInterruptReply() || bool shouldWakeUp = AwaitingInterruptReply() ||
(AwaitingSyncReply() && !ShouldDeferMessage(aMsg)); (AwaitingSyncReply() && !ShouldDeferMessage(aMsg)) ||
AwaitingIncomingMessage();
// There are three cases we're concerned about, relating to the state of the // There are three cases we're concerned about, relating to the state of the
// main thread: // main thread:
@@ -987,6 +989,35 @@ MessageChannel::Call(Message* aMsg, Message* aReply)
return true; 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 bool
MessageChannel::InterruptEventOccurred() MessageChannel::InterruptEventOccurred()
{ {
@@ -1546,7 +1577,7 @@ MessageChannel::OnChannelErrorFromLink()
if (InterruptStackDepth() > 0) if (InterruptStackDepth() > 0)
NotifyWorkerThread(); NotifyWorkerThread();
if (AwaitingSyncReply()) if (AwaitingSyncReply() || AwaitingIncomingMessage())
NotifyWorkerThread(); NotifyWorkerThread();
if (ChannelClosing != mChannelState) { if (ChannelClosing != mChannelState) {

View File

@@ -124,6 +124,9 @@ class MessageChannel : HasResultCodes
// Make an Interrupt call to the other side of the channel // Make an Interrupt call to the other side of the channel
bool Call(Message* aMsg, Message* aReply); bool Call(Message* aMsg, Message* aReply);
// Wait until a message is received
bool WaitForIncomingMessage();
bool CanSend() const; bool CanSend() const;
void SetReplyTimeoutMs(int32_t aTimeoutMs); void SetReplyTimeoutMs(int32_t aTimeoutMs);
@@ -214,6 +217,7 @@ class MessageChannel : HasResultCodes
void DispatchOnChannelConnected(); void DispatchOnChannelConnected();
bool InterruptEventOccurred(); bool InterruptEventOccurred();
bool HasPendingEvents();
bool ProcessPendingRequest(const Message &aUrgent); bool ProcessPendingRequest(const Message &aUrgent);
@@ -319,6 +323,30 @@ class MessageChannel : HasResultCodes
mMonitor->AssertCurrentThreadOwns(); mMonitor->AssertCurrentThreadOwns();
return !mInterruptStack.empty(); 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. // Returns true if we're dispatching a sync message's callback.
bool DispatchingSyncMessage() const { bool DispatchingSyncMessage() const {
@@ -639,6 +667,11 @@ class MessageChannel : HasResultCodes
// ExitedCxxStack(), from which this variable is reset. // ExitedCxxStack(), from which this variable is reset.
bool mSawInterruptOutMsg; 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 // Map of replies received "out of turn", because of Interrupt
// in-calls racing with replies to outstanding in-calls. See // in-calls racing with replies to outstanding in-calls. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=521929. // https://bugzilla.mozilla.org/show_bug.cgi?id=521929.

View File

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