ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp
author Kan-Ru Chen <kanru@kanru.info>
Tue, 15 Nov 2016 04:26:00 +0100
changeset 322595 39ac4382a2c019178604b90acd816753fe142908
parent 299372 64fcfbf2da25d2563d53fcb518fa355eb72cb2c5
child 364866 9846de3bd9545fb2c2b803a36af85568ccf2473b
permissions -rw-r--r--
Bug 1314254 - Add mozilla::ipc::IPCResult type and convert IPDL handlers to use new return type. r=billm We will use the new type for the generated IPDL message handler prototype to make sure correct error handling method is called. MozReview-Commit-ID: AzVbApxFGZ0

#include "TestInterruptShutdownRace.h"

#include "base/task.h"
#include "IPDLUnitTests.h"      // fail etc.
#include "IPDLUnitTestSubprocess.h"

namespace mozilla {
namespace _ipdltest {

//-----------------------------------------------------------------------------
// parent

namespace {

// NB: this test does its own shutdown, rather than going through
// QuitParent(), because it's testing degenerate edge cases

void DeleteSubprocess()
{
    delete gSubprocess;
    gSubprocess = nullptr;
}

void Done()
{
    passed(__FILE__);
    QuitParent();
}

} // namespace <anon>

TestInterruptShutdownRaceParent::TestInterruptShutdownRaceParent()
{
    MOZ_COUNT_CTOR(TestInterruptShutdownRaceParent);
}

TestInterruptShutdownRaceParent::~TestInterruptShutdownRaceParent()
{
    MOZ_COUNT_DTOR(TestInterruptShutdownRaceParent);
}

void
TestInterruptShutdownRaceParent::Main()
{
    if (!SendStart())
        fail("sending Start");
}

mozilla::ipc::IPCResult
TestInterruptShutdownRaceParent::RecvStartDeath()
{
    // this will be ordered before the OnMaybeDequeueOne event of
    // Orphan in the queue
    MessageLoop::current()->PostTask(
        NewNonOwningRunnableMethod(this,
				   &TestInterruptShutdownRaceParent::StartShuttingDown));
    return IPC_OK();
}

void
TestInterruptShutdownRaceParent::StartShuttingDown()
{
    // NB: we sleep here to try and avoid receiving the Orphan message
    // while waiting for the CallExit() reply.  if we fail at that, it
    // will cause the test to pass spuriously, because there won't be
    // an OnMaybeDequeueOne task for Orphan
    PR_Sleep(2000);

    if (CallExit())
        fail("connection was supposed to be interrupted");

    Close();

    delete static_cast<TestInterruptShutdownRaceParent*>(gParentActor);
    gParentActor = nullptr;

    XRE_GetIOMessageLoop()->PostTask(NewRunnableFunction(DeleteSubprocess));

    // this is ordered after the OnMaybeDequeueOne event in the queue
    MessageLoop::current()->PostTask(NewRunnableFunction(Done));

    // |this| has been deleted, be mindful
}

mozilla::ipc::IPCResult
TestInterruptShutdownRaceParent::RecvOrphan()
{
    // it would be nice to fail() here, but we'll process this message
    // while waiting for the reply CallExit().  The OnMaybeDequeueOne
    // task will still be in the queue, it just wouldn't have had any
    // work to do, if we hadn't deleted ourself
    return IPC_OK();
}

//-----------------------------------------------------------------------------
// child

TestInterruptShutdownRaceChild::TestInterruptShutdownRaceChild()
{
    MOZ_COUNT_CTOR(TestInterruptShutdownRaceChild);
}

TestInterruptShutdownRaceChild::~TestInterruptShutdownRaceChild()
{
    MOZ_COUNT_DTOR(TestInterruptShutdownRaceChild);
}

mozilla::ipc::IPCResult
TestInterruptShutdownRaceChild::RecvStart()
{
    if (!SendStartDeath())
        fail("sending StartDeath");

    // See comment in StartShuttingDown(): we want to send Orphan()
    // while the parent is in its PR_Sleep()
    PR_Sleep(1000);

    if (!SendOrphan())
        fail("sending Orphan");

    return IPC_OK();
}

mozilla::ipc::IPCResult
TestInterruptShutdownRaceChild::AnswerExit()
{
    _exit(0);
    NS_RUNTIMEABORT("unreached");
    return IPC_FAIL_NO_REASON(this);
}


} // namespace _ipdltest
} // namespace mozilla