Bug 538239: Guard against async messages unblocking sync message waits. r=bent
authorChris Jones <jones.chris.g@gmail.com>
Wed, 20 Jan 2010 21:50:36 -0600
changeset 46554 2e3e142612b180bc605de527de11c6755259f336
parent 46553 38659e873fd1eea73aab1984adc1dd13ce82e377
child 46555 2d7afd99367d89bd09e8e24c230e1c4b21ac281c
push idunknown
push userunknown
push dateunknown
reviewersbent
bugs538239
milestone1.9.3a1pre
Bug 538239: Guard against async messages unblocking sync message waits. r=bent
ipc/glue/SyncChannel.cpp
--- a/ipc/glue/SyncChannel.cpp
+++ b/ipc/glue/SyncChannel.cpp
@@ -88,37 +88,47 @@ SyncChannel::Send(Message* msg, Message*
         return false;
     }
 
     mPendingReply = msg->type() + 1;
     mIOLoop->PostTask(
         FROM_HERE,
         NewRunnableMethod(this, &SyncChannel::OnSend, msg));
 
-    // wait for the next sync message to arrive
-    WaitForNotify();
+    // NB: this is a do-while loop instead of a single wait because if
+    // there's a pending RPC out- or in-call below us, and the sync
+    // message handler on the other side sends us an async message,
+    // the IO thread will Notify() this thread of the async message.
+    // See https://bugzilla.mozilla.org/show_bug.cgi?id=538239.
+    do {
+        // wait for the next sync message to arrive
+        WaitForNotify();
+    } while(Connected() &&
+            mPendingReply != mRecvd.type() && !mRecvd.is_reply_error());
 
     if (!Connected()) {
         ReportConnectionError("SyncChannel");
         return false;
     }
 
     // we just received a synchronous message from the other side.
     // If it's not the reply we were awaiting, there's a serious
     // error: either a mistimed/malformed message or a sync in-message
     // that raced with our sync out-message.
     // (NB: IPDL prevents the latter from occuring in actor code)
 
     // FIXME/cjones: real error handling
     NS_ABORT_IF_FALSE(mRecvd.is_sync() && mRecvd.is_reply() &&
-                      (mPendingReply == mRecvd.type() || mRecvd.is_reply_error()),
+                      (mPendingReply == mRecvd.type() ||
+                       mRecvd.is_reply_error()),
                       "unexpected sync message");
 
     mPendingReply = 0;
     *reply = mRecvd;
+    mRecvd = Message();
 
     return true;
 }
 
 void
 SyncChannel::OnDispatchMessage(const Message& msg)
 {
     AssertWorkerThread();