Bug 598869: Test that using actors on non-main threads works

This commit is contained in:
Chris Jones 2011-06-03 13:33:56 -05:00
parent 65c96c70e1
commit d8e7ed4952
2 changed files with 105 additions and 14 deletions

View File

@ -5,6 +5,7 @@ namespace _ipdltest {
protocol PTestOpens {
// This channel is opened and parked on a non-main thread
child opens PTestOpensOpened;
child:

View File

@ -1,7 +1,16 @@
#include "base/thread.h"
#include "TestOpens.h"
#include "IPDLUnitTests.h" // fail etc.
template<>
struct RunnableMethodTraits<mozilla::_ipdltest::TestOpensChild>
{
static void RetainCallee(mozilla::_ipdltest::TestOpensChild* obj) { }
static void ReleaseCallee(mozilla::_ipdltest::TestOpensChild* obj) { }
};
template<>
struct RunnableMethodTraits<mozilla::_ipdltest::TestOpensOpenedChild>
{
@ -9,12 +18,29 @@ struct RunnableMethodTraits<mozilla::_ipdltest::TestOpensOpenedChild>
static void ReleaseCallee(mozilla::_ipdltest::TestOpensOpenedChild* obj) { }
};
using namespace base;
using namespace mozilla::ipc;
namespace mozilla {
namespace _ipdltest {
static MessageLoop* gMainThread;
static void
AssertNotMainThread()
{
if (!gMainThread)
fail("gMainThread is not initialized");
if (MessageLoop::current() == gMainThread)
fail("unexpectedly called on the main thread");
}
//-----------------------------------------------------------------------------
// parent
// Thread on which TestOpensOpenedParent runs
static Thread* gParentThread;
void
TestOpensParent::Main()
{
@ -22,25 +48,49 @@ TestOpensParent::Main()
fail("sending Start");
}
static void
OpenParent(TestOpensOpenedParent* aParent,
Transport* aTransport, ProcessHandle aOtherProcess)
{
AssertNotMainThread();
// Open the actor on the off-main thread to park it there.
// Messages will be delivered to this thread's message loop
// instead of the main thread's.
if (!aParent->Open(aTransport, aOtherProcess,
XRE_GetIOMessageLoop(), AsyncChannel::Parent))
fail("opening Parent");
}
PTestOpensOpenedParent*
TestOpensParent::AllocPTestOpensOpened(Transport* transport,
ProcessId otherProcess)
{
gMainThread = MessageLoop::current();
ProcessHandle h;
if (!base::OpenProcessHandle(otherProcess, &h)) {
return nsnull;
}
nsAutoPtr<TestOpensOpenedParent> a(new TestOpensOpenedParent(transport));
if (!a->Open(transport, h, XRE_GetIOMessageLoop(), AsyncChannel::Parent)) {
return nsnull;
}
return a.forget();
gParentThread = new Thread("ParentThread");
if (!gParentThread->Start())
fail("starting parent thread");
TestOpensOpenedParent* a = new TestOpensOpenedParent(transport);
gParentThread->message_loop()->PostTask(
FROM_HERE,
NewRunnableFunction(OpenParent, a, transport, h));
return a;
}
void
TestOpensParent::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gParentThread;
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
@ -50,24 +100,29 @@ TestOpensParent::ActorDestroy(ActorDestroyReason why)
bool
TestOpensOpenedParent::RecvHello()
{
AssertNotMainThread();
return SendHi();
}
bool
TestOpensOpenedParent::RecvHelloSync()
{
AssertNotMainThread();
return true;
}
bool
TestOpensOpenedParent::AnswerHelloRpc()
{
AssertNotMainThread();
return CallHiRpc();
}
void
TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
if (NormalShutdown != why)
fail("unexpected destruction!");
@ -86,6 +141,8 @@ TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why)
// child
static TestOpensChild* gOpensChild;
// Thread on which TestOpensOpenedChild runs
static Thread* gChildThread;
TestOpensChild::TestOpensChild()
{
@ -100,29 +157,53 @@ TestOpensChild::RecvStart()
return true;
}
static void
OpenChild(TestOpensOpenedChild* aChild,
Transport* aTransport, ProcessHandle aOtherProcess)
{
AssertNotMainThread();
// Open the actor on the off-main thread to park it there.
// Messages will be delivered to this thread's message loop
// instead of the main thread's.
if (!aChild->Open(aTransport, aOtherProcess,
XRE_GetIOMessageLoop(), AsyncChannel::Child))
fail("opening Child");
// Kick off the unit tests
if (!aChild->SendHello())
fail("sending Hello");
}
PTestOpensOpenedChild*
TestOpensChild::AllocPTestOpensOpened(Transport* transport,
ProcessId otherProcess)
{
gMainThread = MessageLoop::current();
ProcessHandle h;
if (!base::OpenProcessHandle(otherProcess, &h)) {
return nsnull;
}
nsAutoPtr<TestOpensOpenedChild> a(new TestOpensOpenedChild(transport));
if (!a->Open(transport, h, XRE_GetIOMessageLoop(), AsyncChannel::Child)) {
return nsnull;
}
gChildThread = new Thread("ChildThread");
if (!gChildThread->Start())
fail("starting child thread");
if (!a->SendHello())
fail("sending Hello");
TestOpensOpenedChild* a = new TestOpensOpenedChild(transport);
gChildThread->message_loop()->PostTask(
FROM_HERE,
NewRunnableFunction(OpenChild, a, transport, h));
return a.forget();
return a;
}
void
TestOpensChild::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gChildThread;
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
@ -131,6 +212,8 @@ TestOpensChild::ActorDestroy(ActorDestroyReason why)
bool
TestOpensOpenedChild::RecvHi()
{
AssertNotMainThread();
if (!SendHelloSync())
fail("sending HelloSync");
if (!CallHelloRpc())
@ -149,6 +232,8 @@ TestOpensOpenedChild::RecvHi()
bool
TestOpensOpenedChild::AnswerHiRpc()
{
AssertNotMainThread();
mGotHi = true; // d00d
return true;
}
@ -156,11 +241,11 @@ TestOpensOpenedChild::AnswerHiRpc()
void
TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
if (NormalShutdown != why)
fail("unexpected destruction!");
gOpensChild->Close();
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
@ -170,6 +255,11 @@ TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why)
XRE_GetIOMessageLoop()->PostTask(
FROM_HERE,
new DeleteTask<Transport>(mTransport));
// Kick off main-thread shutdown.
gMainThread->PostTask(
FROM_HERE,
NewRunnableMethod(gOpensChild, &TestOpensChild::Close));
}
} // namespace _ipdltest