зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 10 changesets (bug 1242097, bug 1240985) for near-permafailing in test_plugin_focus.html
Backed out changeset 30f1acd9387f (bug 1240985) Backed out changeset 6d7f80a057f0 (bug 1240985) Backed out changeset c3dfc2c674ff (bug 1240985) Backed out changeset b7f2ce03b34e (bug 1240985) Backed out changeset 2c0c0ed35656 (bug 1240985) Backed out changeset 85c8cb422bad (bug 1240985) Backed out changeset 06b4cb890ab0 (bug 1240985) Backed out changeset f10c0445c450 (bug 1240985) Backed out changeset 62eaf89ab82f (bug 1242097) Backed out changeset b94c1a472d46 (bug 1240985) --HG-- extra : commitid : 2iDH7HLUMiO
This commit is contained in:
Родитель
28c6b17a8f
Коммит
5648c229cc
|
@ -316,7 +316,6 @@ MessageChannel::MessageChannel(MessageListener *aListener)
|
|||
mTimeoutMs(kNoTimeout),
|
||||
mInTimeoutSecondHalf(false),
|
||||
mNextSeqno(0),
|
||||
mLastSendError(SyncSendError::SendSuccess),
|
||||
mAwaitingSyncReply(false),
|
||||
mAwaitingSyncReplyPriority(0),
|
||||
mDispatchingSyncMessage(false),
|
||||
|
@ -324,7 +323,6 @@ MessageChannel::MessageChannel(MessageListener *aListener)
|
|||
mDispatchingAsyncMessage(false),
|
||||
mDispatchingAsyncMessagePriority(0),
|
||||
mCurrentTransaction(0),
|
||||
mPendingSendPriorities(0),
|
||||
mTimedOutMessageSeqno(0),
|
||||
mTimedOutMessagePriority(0),
|
||||
mRecvdErrors(0),
|
||||
|
@ -572,10 +570,9 @@ MessageChannel::Send(Message* aMsg)
|
|||
class CancelMessage : public IPC::Message
|
||||
{
|
||||
public:
|
||||
CancelMessage(int transaction) :
|
||||
CancelMessage() :
|
||||
IPC::Message(MSG_ROUTING_NONE, CANCEL_MESSAGE_TYPE, PRIORITY_NORMAL)
|
||||
{
|
||||
set_transaction_id(transaction);
|
||||
}
|
||||
static bool Read(const Message* msg) {
|
||||
return true;
|
||||
|
@ -603,9 +600,20 @@ MessageChannel::MaybeInterceptSpecialIOMessage(const Message& aMsg)
|
|||
return true;
|
||||
} else if (CANCEL_MESSAGE_TYPE == aMsg.type()) {
|
||||
IPC_LOG("Cancel from message");
|
||||
CancelTransaction(aMsg.transaction_id());
|
||||
NotifyWorkerThread();
|
||||
return true;
|
||||
|
||||
if (aMsg.transaction_id() == mTimedOutMessageSeqno) {
|
||||
// An unusual case: We timed out a transaction which the other
|
||||
// side then cancelled. In this case we just leave the timedout
|
||||
// state and try to forget this ever happened.
|
||||
mTimedOutMessageSeqno = 0;
|
||||
return true;
|
||||
} else {
|
||||
MOZ_RELEASE_ASSERT(mCurrentTransaction == aMsg.transaction_id());
|
||||
CancelCurrentTransactionInternal();
|
||||
NotifyWorkerThread();
|
||||
IPC_LOG("Notified");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -680,7 +688,7 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
|
|||
if (aMsg.seqno() == mTimedOutMessageSeqno) {
|
||||
// Drop the message, but allow future sync messages to be sent.
|
||||
IPC_LOG("Received reply to timedout message; igoring; xid=%d", mTimedOutMessageSeqno);
|
||||
EndTimeout();
|
||||
mTimedOutMessageSeqno = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -773,23 +781,22 @@ MessageChannel::OnMessageReceivedFromLink(const Message& aMsg)
|
|||
|
||||
if (shouldWakeUp) {
|
||||
NotifyWorkerThread();
|
||||
}
|
||||
|
||||
// It's possible that a Send or Call call on the stack will process the
|
||||
// message. However, it's difficult to ensure that Send always processes all
|
||||
// messages in mPending before exiting, so it's safer to enqueue a task for
|
||||
// each one. If the queue is empty, the task does nothing.
|
||||
if (!compress) {
|
||||
// If we compressed away the previous message, we'll re-use
|
||||
// its pending task.
|
||||
mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
|
||||
} else {
|
||||
// Worker thread is either not blocked on a reply, or this is an
|
||||
// incoming Interrupt that raced with outgoing sync, and needs to be
|
||||
// deferred to a later event-loop iteration.
|
||||
if (!compress) {
|
||||
// If we compressed away the previous message, we'll re-use
|
||||
// its pending task.
|
||||
mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessageChannel::ProcessPendingRequests(int seqno, int transaction)
|
||||
MessageChannel::ProcessPendingRequests(int transaction, int prio)
|
||||
{
|
||||
IPC_LOG("ProcessPendingRequests for seqno=%d, xid=%d", seqno, transaction);
|
||||
IPC_LOG("ProcessPendingRequests");
|
||||
|
||||
// Loop until there aren't any more priority messages to process.
|
||||
for (;;) {
|
||||
|
@ -828,31 +835,50 @@ MessageChannel::ProcessPendingRequests(int seqno, int transaction)
|
|||
// operating with weird state (as if no Send is in progress). That could
|
||||
// cause even normal priority sync messages to be processed (but not
|
||||
// normal priority async messages), which would break message ordering.
|
||||
if (WasTransactionCanceled(transaction)) {
|
||||
if (WasTransactionCanceled(transaction, prio)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MessageChannel::WasTransactionCanceled(int transaction)
|
||||
MessageChannel::WasTransactionCanceled(int transaction, int prio)
|
||||
{
|
||||
if (transaction != mCurrentTransaction) {
|
||||
// Imagine this scenario:
|
||||
// 1. Child sends high prio sync message H1.
|
||||
// 2. Parent sends reply to H1.
|
||||
// 3. Parent sends high prio sync message H2.
|
||||
// 4. Child's link thread receives H1 reply and H2 before worker wakes up.
|
||||
// 5. Child dispatches H2 while still waiting for H1 reply.
|
||||
// 6. Child cancels H2.
|
||||
//
|
||||
// In this case H1 will also be considered cancelled. However, its
|
||||
// reply is still sitting in mRecvd, which can trip up later Sends. So
|
||||
// we null it out here.
|
||||
mRecvd = nullptr;
|
||||
return true;
|
||||
if (transaction == mCurrentTransaction) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
// This isn't an assert so much as an intentional crash because we're in a
|
||||
// situation that we don't know how to recover from: The child is awaiting
|
||||
// a reply to a normal-priority sync message. The transaction that this
|
||||
// message initiated has now been canceled. That could only happen if a CPOW
|
||||
// raced with the sync message and was dispatched by the child while the
|
||||
// child was awaiting the sync reply; at some point while dispatching the
|
||||
// CPOW, the transaction was canceled.
|
||||
//
|
||||
// Notes:
|
||||
//
|
||||
// 1. We don't want to cancel the normal-priority sync message along with
|
||||
// the CPOWs because the browser relies on these messages working
|
||||
// reliably.
|
||||
//
|
||||
// 2. Ideally we would like to avoid dispatching CPOWs while awaiting a sync
|
||||
// response. This isn't possible though. To avoid deadlock, the parent would
|
||||
// have to dispatch the sync message while waiting for the CPOW
|
||||
// response. However, it wouldn't have dispatched async messages at that
|
||||
// time, so we would have a message ordering bug. Dispatching the async
|
||||
// messages first causes other hard-to-handle situations (what if they send
|
||||
// CPOWs?).
|
||||
//
|
||||
// 3. We would like to be able to cancel the CPOWs but not the sync
|
||||
// message. However, that would leave both the parent and the child running
|
||||
// code at the same time, all while the sync message is still
|
||||
// outstanding. That can cause a problem where message replies are received
|
||||
// out of order.
|
||||
IPC_ASSERT(prio != IPC::Message::PRIORITY_NORMAL,
|
||||
"Intentional crash: We canceled a CPOW that was racing with a sync message.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -882,7 +908,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
// message receives a reply, we'll be able to send more sync messages
|
||||
// again.
|
||||
IPC_LOG("Send() failed due to previous timeout");
|
||||
mLastSendError = SyncSendError::PreviousTimeout;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -893,7 +918,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
// Don't allow sending CPOWs while we're dispatching a sync message.
|
||||
// If you want to do that, use sendRpcMessage instead.
|
||||
IPC_LOG("Prio forbids send");
|
||||
mLastSendError = SyncSendError::SendingCPOWWhileDispatchingSync;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -905,8 +929,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
// sync messages it can send are high-priority. Mainly we want to ensure
|
||||
// here that we don't return false for non-CPOW messages.
|
||||
MOZ_ASSERT(msg->priority() == IPC::Message::PRIORITY_HIGH);
|
||||
IPC_LOG("Sending while dispatching urgent message");
|
||||
mLastSendError = SyncSendError::SendingCPOWWhileDispatchingUrgent;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -916,9 +938,10 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
{
|
||||
MOZ_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage());
|
||||
IPC_LOG("Cancel from Send");
|
||||
CancelMessage *cancel = new CancelMessage(mCurrentTransaction);
|
||||
CancelTransaction(mCurrentTransaction);
|
||||
CancelMessage *cancel = new CancelMessage();
|
||||
cancel->set_transaction_id(mCurrentTransaction);
|
||||
mLink->SendMessage(cancel);
|
||||
CancelCurrentTransactionInternal();
|
||||
}
|
||||
|
||||
IPC_ASSERT(msg->is_sync(), "can only Send() sync messages here");
|
||||
|
@ -937,7 +960,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
|
||||
if (!Connected()) {
|
||||
ReportConnectionError("MessageChannel::SendAndWait", msg);
|
||||
mLastSendError = SyncSendError::NotConnectedBeforeSend;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -951,27 +973,24 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
AutoSetValue<int> prioSet(mAwaitingSyncReplyPriority, prio);
|
||||
AutoEnterTransaction transact(this, seqno);
|
||||
|
||||
int prios = mPendingSendPriorities | (1 << prio);
|
||||
AutoSetValue<int> priosSet(mPendingSendPriorities, prios);
|
||||
|
||||
int32_t transaction = mCurrentTransaction;
|
||||
msg->set_transaction_id(transaction);
|
||||
|
||||
IPC_LOG("Send seqno=%d, xid=%d, pending=%d", seqno, transaction, prios);
|
||||
IPC_LOG("Send seqno=%d, xid=%d", seqno, transaction);
|
||||
|
||||
ProcessPendingRequests(transaction, prio);
|
||||
if (WasTransactionCanceled(transaction, prio)) {
|
||||
IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handleWindowsMessages = mListener->HandleWindowsMessages(*aMsg);
|
||||
mLink->SendMessage(msg.forget());
|
||||
|
||||
while (true) {
|
||||
ProcessPendingRequests(seqno, transaction);
|
||||
if (WasTransactionCanceled(transaction)) {
|
||||
ProcessPendingRequests(transaction, prio);
|
||||
if (WasTransactionCanceled(transaction, prio)) {
|
||||
IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction);
|
||||
mLastSendError = SyncSendError::CancelledAfterSend;
|
||||
return false;
|
||||
}
|
||||
if (!Connected()) {
|
||||
ReportConnectionError("MessageChannel::Send");
|
||||
mLastSendError = SyncSendError::DisconnectedDuringSend;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -979,7 +998,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
if (mRecvdErrors) {
|
||||
IPC_LOG("Error: seqno=%d, xid=%d", seqno, transaction);
|
||||
mRecvdErrors--;
|
||||
mLastSendError = SyncSendError::ReplyError;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -995,13 +1013,11 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
|
||||
if (!Connected()) {
|
||||
ReportConnectionError("MessageChannel::SendAndWait");
|
||||
mLastSendError = SyncSendError::DisconnectedDuringSend;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WasTransactionCanceled(transaction)) {
|
||||
if (WasTransactionCanceled(transaction, prio)) {
|
||||
IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction);
|
||||
mLastSendError = SyncSendError::CancelledAfterSend;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1009,29 +1025,22 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
// if neither side has any other message Sends on the stack).
|
||||
bool canTimeOut = transaction == seqno;
|
||||
if (maybeTimedOut && canTimeOut && !ShouldContinueFromTimeout()) {
|
||||
// Since ShouldContinueFromTimeout drops the lock, we need to
|
||||
// re-check all our conditions here. We shouldn't time out if any of
|
||||
// these things happen because there won't be a reply to the timed
|
||||
// out message in these cases.
|
||||
if (WasTransactionCanceled(transaction)) {
|
||||
IPC_LOG("Other side canceled seqno=%d, xid=%d", seqno, transaction);
|
||||
mLastSendError = SyncSendError::CancelledAfterSend;
|
||||
return false;
|
||||
}
|
||||
IPC_LOG("Timing out Send: xid=%d", transaction);
|
||||
|
||||
// We might have received a reply during WaitForSyncNotify or inside
|
||||
// ShouldContinueFromTimeout (which drops the lock). We need to make
|
||||
// sure not to set mTimedOutMessageSeqno if that happens, since then
|
||||
// there would be no way to unset it.
|
||||
if (mRecvdErrors) {
|
||||
mRecvdErrors--;
|
||||
mLastSendError = SyncSendError::ReplyError;
|
||||
return false;
|
||||
}
|
||||
if (mRecvd) {
|
||||
break;
|
||||
}
|
||||
|
||||
IPC_LOG("Timing out Send: xid=%d", transaction);
|
||||
|
||||
mTimedOutMessageSeqno = seqno;
|
||||
mTimedOutMessagePriority = prio;
|
||||
mLastSendError = SyncSendError::TimedOut;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1045,7 +1054,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply)
|
|||
|
||||
*aReply = Move(*mRecvd);
|
||||
mRecvd = nullptr;
|
||||
mLastSendError = SyncSendError::SendSuccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1310,37 +1318,6 @@ MessageChannel::DequeueOne(Message *recvd)
|
|||
if (!mDeferred.empty())
|
||||
MaybeUndeferIncall();
|
||||
|
||||
// If we've timed out a message and we're awaiting the reply to the timed
|
||||
// out message, we have to be careful what messages we process. Here's what
|
||||
// can go wrong:
|
||||
// 1. child sends a normal priority sync message S
|
||||
// 2. parent sends a high priority sync message H at the same time
|
||||
// 3. parent times out H
|
||||
// 4. child starts processing H and sends a high priority message H' nested
|
||||
// within the same transaction
|
||||
// 5. parent dispatches S and sends reply
|
||||
// 6. child asserts because it instead expected a reply to H'.
|
||||
//
|
||||
// To solve this, we refuse to process S in the parent until we get a reply
|
||||
// to H. More generally, let the timed out message be M. We don't process a
|
||||
// message unless the child would need the response to that message in order
|
||||
// to process M. Those messages are the ones that have a higher priority
|
||||
// than M or that are part of the same transaction as M.
|
||||
if (mTimedOutMessageSeqno) {
|
||||
for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); it++) {
|
||||
Message &msg = *it;
|
||||
if (msg.priority() > mTimedOutMessagePriority ||
|
||||
(msg.priority() == mTimedOutMessagePriority
|
||||
&& msg.transaction_id() == mTimedOutMessageSeqno))
|
||||
{
|
||||
*recvd = Move(msg);
|
||||
mPending.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mPending.empty())
|
||||
return false;
|
||||
|
||||
|
@ -1433,7 +1410,22 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply)
|
|||
MessageChannel*& blockingVar = ShouldBlockScripts() ? gParentProcessBlocker : dummy;
|
||||
|
||||
Result rv;
|
||||
{
|
||||
if (mTimedOutMessageSeqno && mTimedOutMessagePriority >= prio) {
|
||||
// If the other side sends a message in response to one of our messages
|
||||
// that we've timed out, then we reply with an error.
|
||||
//
|
||||
// We do this because want to avoid a situation where we process an
|
||||
// incoming message from the child here while it simultaneously starts
|
||||
// processing our timed-out CPOW. It's very bad for both sides to
|
||||
// be processing sync messages concurrently.
|
||||
//
|
||||
// The only exception is if the incoming message has urgent priority and
|
||||
// our timed-out message had only high priority. In that case it's safe
|
||||
// to process the incoming message because we know that the child won't
|
||||
// process anything (the child will defer incoming messages when waiting
|
||||
// for a response to its urgent message).
|
||||
rv = MsgNotAllowed;
|
||||
} else {
|
||||
AutoSetValue<MessageChannel*> blocked(blockingVar, this);
|
||||
AutoSetValue<bool> sync(mDispatchingSyncMessage, true);
|
||||
AutoSetValue<int> prioSet(mDispatchingSyncMessagePriority, prio);
|
||||
|
@ -1836,8 +1828,6 @@ MessageChannel::OnChannelErrorFromLink()
|
|||
AssertLinkThread();
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
IPC_LOG("OnChannelErrorFromLink");
|
||||
|
||||
if (InterruptStackDepth() > 0)
|
||||
NotifyWorkerThread();
|
||||
|
||||
|
@ -2103,25 +2093,7 @@ MessageChannel::GetTopmostMessageRoutingId() const
|
|||
}
|
||||
|
||||
void
|
||||
MessageChannel::EndTimeout()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
IPC_LOG("Ending timeout of seqno=%d", mTimedOutMessageSeqno);
|
||||
mTimedOutMessageSeqno = 0;
|
||||
mTimedOutMessagePriority = 0;
|
||||
|
||||
for (size_t i = 0; i < mPending.size(); i++) {
|
||||
// There may be messages in the queue that we expected to process from
|
||||
// OnMaybeDequeueOne. But during the timeout, that function will skip
|
||||
// some messages. Now they're ready to be processed, so we enqueue more
|
||||
// tasks.
|
||||
mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessageChannel::CancelTransaction(int transaction)
|
||||
MessageChannel::CancelCurrentTransactionInternal()
|
||||
{
|
||||
mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
|
@ -2135,91 +2107,20 @@ MessageChannel::CancelTransaction(int transaction)
|
|||
// tampered with (by us). If so, they don't reset the variable to the old
|
||||
// value.
|
||||
|
||||
IPC_LOG("CancelTransaction: xid=%d prios=%d", transaction, mPendingSendPriorities);
|
||||
IPC_LOG("CancelInternal: current xid=%d", mCurrentTransaction);
|
||||
|
||||
if (mPendingSendPriorities & (1 << IPC::Message::PRIORITY_NORMAL)) {
|
||||
// This isn't an assert so much as an intentional crash because we're in
|
||||
// a situation that we don't know how to recover from: The child is
|
||||
// awaiting a reply to a normal-priority sync message. The transaction
|
||||
// that this message initiated has now been canceled. That could only
|
||||
// happen if a CPOW raced with the sync message and was dispatched by
|
||||
// the child while the child was awaiting the sync reply; at some point
|
||||
// while dispatching the CPOW, the transaction was canceled.
|
||||
//
|
||||
// Notes:
|
||||
//
|
||||
// 1. We don't want to cancel the normal-priority sync message along
|
||||
// with the CPOWs because the browser relies on these messages working
|
||||
// reliably.
|
||||
//
|
||||
// 2. Ideally we would like to avoid dispatching CPOWs while awaiting a
|
||||
// sync response. This isn't possible though. To avoid deadlock, the
|
||||
// parent would have to dispatch the sync message while waiting for the
|
||||
// CPOW response. However, it wouldn't have dispatched async messages at
|
||||
// that time, so we would have a message ordering bug. Dispatching the
|
||||
// async messages first causes other hard-to-handle situations (what if
|
||||
// they send CPOWs?).
|
||||
//
|
||||
// 3. We would like to be able to cancel the CPOWs but not the sync
|
||||
// message. However, that would leave both the parent and the child
|
||||
// running code at the same time, all while the sync message is still
|
||||
// outstanding. That can cause a problem where message replies are
|
||||
// received out of order.
|
||||
mListener->IntentionalCrash();
|
||||
}
|
||||
MOZ_ASSERT(mCurrentTransaction);
|
||||
mCurrentTransaction = 0;
|
||||
|
||||
// An unusual case: We timed out a transaction which the other side then
|
||||
// cancelled. In this case we just leave the timedout state and try to
|
||||
// forget this ever happened.
|
||||
if (transaction == mTimedOutMessageSeqno) {
|
||||
IPC_LOG("Cancelled timed out message %d", mTimedOutMessageSeqno);
|
||||
EndTimeout();
|
||||
|
||||
// Normally mCurrentTransaction == 0 here. But it can be non-zero if:
|
||||
// 1. Parent sends hi prio message H.
|
||||
// 2. Parent times out H.
|
||||
// 3. Child dispatches H and sends nested message H' (same transaction).
|
||||
// 4. Parent dispatches H' and cancels.
|
||||
MOZ_ASSERT_IF(mCurrentTransaction, mCurrentTransaction == transaction);
|
||||
mCurrentTransaction = 0;
|
||||
|
||||
// During a timeout Send should always fail.
|
||||
MOZ_ASSERT(!mAwaitingSyncReply);
|
||||
} else {
|
||||
MOZ_ASSERT(mCurrentTransaction == transaction);
|
||||
mCurrentTransaction = 0;
|
||||
|
||||
mAwaitingSyncReply = false;
|
||||
mAwaitingSyncReplyPriority = 0;
|
||||
}
|
||||
|
||||
DebugOnly<bool> foundSync = false;
|
||||
for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
|
||||
Message &msg = *it;
|
||||
|
||||
// If there was a race between the parent and the child, then we may
|
||||
// have a queued sync message. We want to drop this message from the
|
||||
// queue since it will get cancelled along with the transaction being
|
||||
// cancelled. We don't bother doing this for normal priority messages
|
||||
// because the child is just going to crash in that case, and we want to
|
||||
// avoid processing messages out of order in the short time before it
|
||||
// crashes.
|
||||
if (msg.is_sync() && msg.priority() != IPC::Message::PRIORITY_NORMAL) {
|
||||
MOZ_ASSERT(!foundSync);
|
||||
MOZ_ASSERT(msg.transaction_id() != transaction);
|
||||
IPC_LOG("Removing msg from queue seqno=%d xid=%d", msg.seqno(), msg.transaction_id());
|
||||
foundSync = true;
|
||||
it = mPending.erase(it);
|
||||
continue;
|
||||
}
|
||||
mAwaitingSyncReply = false;
|
||||
mAwaitingSyncReplyPriority = 0;
|
||||
|
||||
for (size_t i = 0; i < mPending.size(); i++) {
|
||||
// There may be messages in the queue that we expected to process from
|
||||
// ProcessPendingRequests. However, Send will no longer call that
|
||||
// function once it's been canceled. So we may need to process these
|
||||
// messages in the normal event loop instead.
|
||||
mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
|
||||
|
||||
it++;
|
||||
}
|
||||
|
||||
// We could also zero out mDispatchingSyncMessage here. However, that would
|
||||
|
@ -2233,17 +2134,10 @@ MessageChannel::CancelCurrentTransaction()
|
|||
{
|
||||
MonitorAutoLock lock(*mMonitor);
|
||||
if (mCurrentTransaction) {
|
||||
if (DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_URGENT ||
|
||||
DispatchingAsyncMessagePriority() == IPC::Message::PRIORITY_URGENT)
|
||||
{
|
||||
mListener->IntentionalCrash();
|
||||
}
|
||||
|
||||
IPC_LOG("Cancel requested: current xid=%d", mCurrentTransaction);
|
||||
MOZ_ASSERT(DispatchingSyncMessage());
|
||||
CancelMessage *cancel = new CancelMessage(mCurrentTransaction);
|
||||
CancelTransaction(mCurrentTransaction);
|
||||
CancelMessage *cancel = new CancelMessage();
|
||||
cancel->set_transaction_id(mCurrentTransaction);
|
||||
mLink->SendMessage(cancel);
|
||||
CancelCurrentTransactionInternal();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,19 +44,6 @@ class RefCountedMonitor : public Monitor
|
|||
~RefCountedMonitor() {}
|
||||
};
|
||||
|
||||
enum class SyncSendError {
|
||||
SendSuccess,
|
||||
PreviousTimeout,
|
||||
SendingCPOWWhileDispatchingSync,
|
||||
SendingCPOWWhileDispatchingUrgent,
|
||||
NotConnectedBeforeSend,
|
||||
DisconnectedDuringSend,
|
||||
CancelledBeforeSend,
|
||||
CancelledAfterSend,
|
||||
TimedOut,
|
||||
ReplyError,
|
||||
};
|
||||
|
||||
class MessageChannel : HasResultCodes
|
||||
{
|
||||
friend class ProcessLink;
|
||||
|
@ -145,13 +132,6 @@ class MessageChannel : HasResultCodes
|
|||
|
||||
bool CanSend() const;
|
||||
|
||||
// If sending a sync message returns an error, this function gives a more
|
||||
// descriptive error message.
|
||||
SyncSendError LastSendError() const {
|
||||
AssertWorkerThread();
|
||||
return mLastSendError;
|
||||
}
|
||||
|
||||
// Currently only for debugging purposes, doesn't aquire mMonitor.
|
||||
ChannelState GetChannelState__TotallyRacy() const {
|
||||
return mChannelState;
|
||||
|
@ -270,7 +250,7 @@ class MessageChannel : HasResultCodes
|
|||
bool InterruptEventOccurred();
|
||||
bool HasPendingEvents();
|
||||
|
||||
void ProcessPendingRequests(int seqno, int transaction);
|
||||
void ProcessPendingRequests(int transaction, int prio);
|
||||
bool ProcessPendingRequest(const Message &aUrgent);
|
||||
|
||||
void MaybeUndeferIncall();
|
||||
|
@ -308,8 +288,7 @@ class MessageChannel : HasResultCodes
|
|||
|
||||
bool ShouldContinueFromTimeout();
|
||||
|
||||
void EndTimeout();
|
||||
void CancelTransaction(int transaction);
|
||||
void CancelCurrentTransactionInternal();
|
||||
|
||||
// The "remote view of stack depth" can be different than the
|
||||
// actual stack depth when there are out-of-turn replies. When we
|
||||
|
@ -447,7 +426,7 @@ class MessageChannel : HasResultCodes
|
|||
// Tell the IO thread to close the channel and wait for it to ACK.
|
||||
void SynchronouslyClose();
|
||||
|
||||
bool WasTransactionCanceled(int transaction);
|
||||
bool WasTransactionCanceled(int transaction, int prio);
|
||||
bool ShouldDeferMessage(const Message& aMsg);
|
||||
void OnMessageReceivedFromLink(const Message& aMsg);
|
||||
void OnChannelErrorFromLink();
|
||||
|
@ -542,9 +521,6 @@ class MessageChannel : HasResultCodes
|
|||
|
||||
static bool sIsPumpingMessages;
|
||||
|
||||
// If ::Send returns false, this gives a more descriptive error.
|
||||
SyncSendError mLastSendError;
|
||||
|
||||
template<class T>
|
||||
class AutoSetValue {
|
||||
public:
|
||||
|
@ -600,13 +576,6 @@ class MessageChannel : HasResultCodes
|
|||
// The current transaction ID.
|
||||
int32_t mCurrentTransaction;
|
||||
|
||||
// This field describes the priorities of the sync Send calls that are
|
||||
// currently on stack. If a Send call for a message with priority P is on
|
||||
// the C stack, then mPendingSendPriorities & (1 << P) will be
|
||||
// non-zero. Note that cancelled Send calls are not removed from this
|
||||
// bitfield (until they return).
|
||||
int mPendingSendPriorities;
|
||||
|
||||
class AutoEnterTransaction
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -76,11 +76,6 @@ class MessageListener
|
|||
return false;
|
||||
}
|
||||
|
||||
// WARNING: This function is called with the MessageChannel monitor held.
|
||||
virtual void IntentionalCrash() {
|
||||
MOZ_CRASH("Intentional IPDL crash");
|
||||
}
|
||||
|
||||
virtual void OnEnteredCxxStack() {
|
||||
NS_RUNTIMEABORT("default impl shouldn't be invoked");
|
||||
}
|
||||
|
|
|
@ -87,7 +87,6 @@ public:
|
|||
, mModules(kInitialModuleCount)
|
||||
, mOutFile(nullptr)
|
||||
, mAddTimestamp(false)
|
||||
, mIsSync(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -104,24 +103,20 @@ public:
|
|||
{
|
||||
bool shouldAppend = false;
|
||||
bool addTimestamp = false;
|
||||
bool isSync = false;
|
||||
const char* modules = PR_GetEnv("NSPR_LOG_MODULES");
|
||||
NSPRLogModulesParser(modules,
|
||||
[&shouldAppend, &addTimestamp, &isSync]
|
||||
[&shouldAppend, &addTimestamp]
|
||||
(const char* aName, LogLevel aLevel) mutable {
|
||||
if (strcmp(aName, "append") == 0) {
|
||||
shouldAppend = true;
|
||||
} else if (strcmp(aName, "timestamp") == 0) {
|
||||
addTimestamp = true;
|
||||
} else if (strcmp(aName, "sync") == 0) {
|
||||
isSync = true;
|
||||
} else {
|
||||
LogModule::Get(aName)->SetLevel(aLevel);
|
||||
}
|
||||
});
|
||||
|
||||
mAddTimestamp = addTimestamp;
|
||||
mIsSync = isSync;
|
||||
|
||||
const char* logFile = PR_GetEnv("NSPR_LOG_FILE");
|
||||
if (logFile && logFile[0]) {
|
||||
|
@ -193,10 +188,6 @@ public:
|
|||
aName, buffToWrite, newline);
|
||||
}
|
||||
|
||||
if (mIsSync) {
|
||||
fflush(out);
|
||||
}
|
||||
|
||||
if (buffToWrite != buff) {
|
||||
PR_smprintf_free(buffToWrite);
|
||||
}
|
||||
|
@ -207,7 +198,6 @@ private:
|
|||
nsClassHashtable<nsCharPtrHashKey, LogModule> mModules;
|
||||
ScopedCloseFile mOutFile;
|
||||
bool mAddTimestamp;
|
||||
bool mIsSync;
|
||||
};
|
||||
|
||||
StaticAutoPtr<LogModuleManager> sLogModuleManager;
|
||||
|
|
Загрузка…
Ссылка в новой задаче