--- a/ipc/ipdl/test/cxx/Makefile.in
+++ b/ipc/ipdl/test/cxx/Makefile.in
@@ -60,16 +60,17 @@ EXPORT_LIBRARY = 1
# Please keep these organized in the order "easy"-to-"hard"
IPDLTESTS = \
TestSanity \
TestRPCErrorCleanup \
TestCrashCleanup \
TestSyncWakeup \
TestLatency \
TestRPCRaces \
+ TestRacyRPCReplies \
TestManyChildAllocs \
TestDesc \
TestShmem \
TestShutdown \
TestArrays \
$(NULL)
IPDLTESTSRCS = $(addsuffix .cpp,$(IPDLTESTS))
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestRacyRPCReplies.ipdl
@@ -0,0 +1,27 @@
+namespace mozilla {
+namespace _ipdltest {
+
+rpc protocol PTestRacyRPCReplies {
+child:
+ rpc R() returns (int replyNum);
+ async __delete__();
+
+parent:
+ async A();
+
+
+state START:
+ call R goto S1;
+
+state S1:
+ recv A goto S2;
+
+state S2:
+ call R goto DYING;
+
+state DYING:
+ send __delete__;
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRacyRPCReplies.cpp
@@ -0,0 +1,78 @@
+#include "TestRacyRPCReplies.h"
+
+#include "IPDLUnitTests.h" // fail etc.
+
+namespace mozilla {
+namespace _ipdltest {
+
+//-----------------------------------------------------------------------------
+// parent
+
+TestRacyRPCRepliesParent::TestRacyRPCRepliesParent()
+{
+ MOZ_COUNT_CTOR(TestRacyRPCRepliesParent);
+}
+
+TestRacyRPCRepliesParent::~TestRacyRPCRepliesParent()
+{
+ MOZ_COUNT_DTOR(TestRacyRPCRepliesParent);
+}
+
+void
+TestRacyRPCRepliesParent::Main()
+{
+ int replyNum = -1;
+ if (!CallR(&replyNum))
+ fail("calling R()");
+
+ if (1 != replyNum)
+ fail("this should have been the first reply to R()");
+
+ Close();
+}
+
+bool
+TestRacyRPCRepliesParent::RecvA()
+{
+ int replyNum = -1;
+ // this R() call races with the reply being generated by the other
+ // side to the R() call from Main(). This is a pretty nasty edge
+ // case for which one could argue we're breaking in-order message
+ // delivery, since this side will process the second reply to R()
+ // before the first.
+ if (!CallR(&replyNum))
+ fail("calling R()");
+
+ if (2 != replyNum)
+ fail("this should have been the second reply to R()");
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// child
+
+TestRacyRPCRepliesChild::TestRacyRPCRepliesChild() : mReplyNum(0)
+{
+ MOZ_COUNT_CTOR(TestRacyRPCRepliesChild);
+}
+
+TestRacyRPCRepliesChild::~TestRacyRPCRepliesChild()
+{
+ MOZ_COUNT_DTOR(TestRacyRPCRepliesChild);
+}
+
+bool
+TestRacyRPCRepliesChild::AnswerR(int* replyNum)
+{
+ *replyNum = ++mReplyNum;
+
+ if (1 == *replyNum)
+ SendA();
+
+ return true;
+}
+
+
+} // namespace _ipdltest
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/TestRacyRPCReplies.h
@@ -0,0 +1,65 @@
+#ifndef mozilla__ipdltest_TestRacyRPCReplies_h
+#define mozilla__ipdltest_TestRacyRPCReplies_h 1
+
+#include "mozilla/_ipdltest/IPDLUnitTests.h"
+
+#include "mozilla/_ipdltest/PTestRacyRPCRepliesParent.h"
+#include "mozilla/_ipdltest/PTestRacyRPCRepliesChild.h"
+
+namespace mozilla {
+namespace _ipdltest {
+
+
+class TestRacyRPCRepliesParent :
+ public PTestRacyRPCRepliesParent
+{
+public:
+ TestRacyRPCRepliesParent();
+ virtual ~TestRacyRPCRepliesParent();
+
+ void Main();
+
+protected:
+ NS_OVERRIDE
+ virtual bool RecvA();
+
+ NS_OVERRIDE
+ virtual void ActorDestroy(ActorDestroyReason why)
+ {
+ if (NormalShutdown != why)
+ fail("unexpected destruction!");
+ passed("ok");
+ QuitParent();
+ }
+};
+
+
+class TestRacyRPCRepliesChild :
+ public PTestRacyRPCRepliesChild
+{
+public:
+ TestRacyRPCRepliesChild();
+ virtual ~TestRacyRPCRepliesChild();
+
+protected:
+ NS_OVERRIDE
+ virtual bool AnswerR(int* replyNum);
+
+ NS_OVERRIDE
+ virtual void ActorDestroy(ActorDestroyReason why)
+ {
+ if (NormalShutdown != why)
+ fail("unexpected destruction!");
+ QuitChild();
+ }
+
+private:
+ int mReplyNum;
+};
+
+
+} // namespace _ipdltest
+} // namespace mozilla
+
+
+#endif // ifndef mozilla__ipdltest_TestRacyRPCReplies_h
--- a/ipc/ipdl/test/cxx/ipdl.mk
+++ b/ipc/ipdl/test/cxx/ipdl.mk
@@ -3,16 +3,17 @@ IPDLSRCS = \
PTestArraysSub.ipdl \
PTestCrashCleanup.ipdl \
PTestDesc.ipdl \
PTestDescSub.ipdl \
PTestDescSubsub.ipdl \
PTestLatency.ipdl \
PTestManyChildAllocs.ipdl \
PTestManyChildAllocsSub.ipdl \
+ PTestRacyRPCReplies.ipdl \
PTestRPCErrorCleanup.ipdl \
PTestRPCRaces.ipdl \
PTestSanity.ipdl \
PTestShmem.ipdl \
PTestShutdown.ipdl \
PTestShutdownSub.ipdl \
PTestShutdownSubsub.ipdl \
PTestSyncWakeup.ipdl \