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 37387 f942158f094501d1cec6cfbaf1fe123380cd1f38
parent 37386 908c2e08e36436a151dcc381159f13edc8f302f2
child 37388 ee7a869fcd568c20f6c458be5b9cd76ede855b59
push id11270
push userbsmedberg@mozilla.com
push dateThu, 21 Jan 2010 20:50:28 +0000
treeherdermozilla-central@4a603215351c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
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();