import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,32 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ipc/IOThreadChild.h"
#include "IPDLUnitTestProcessChild.h"
#include "IPDLUnitTests.h"
#include "nsRegion.h"
using mozilla::ipc::IOThreadChild;
namespace mozilla {
namespace _ipdltest {
bool
IPDLUnitTestProcessChild::Init()
{
IPDLUnitTestChildInit(IOThreadChild::channel(),
ParentPid(),
IOThreadChild::message_loop());
if (NS_FAILED(nsRegion::InitStatic()))
return false;
return true;
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,32 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h
#define mozilla__ipdltest_IPDLUnitTestThreadChild_h 1
#include "mozilla/ipc/ProcessChild.h"
namespace mozilla {
namespace _ipdltest {
class IPDLUnitTestProcessChild : public mozilla::ipc::ProcessChild
{
typedef mozilla::ipc::ProcessChild ProcessChild;
public:
explicit IPDLUnitTestProcessChild(ProcessId aParentPid) :
ProcessChild(aParentPid)
{ }
~IPDLUnitTestProcessChild()
{ }
virtual bool Init();
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h

View file

@ -0,0 +1,23 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IPDLUnitTestSubprocess.h"
using mozilla::ipc::GeckoChildProcessHost;
namespace mozilla {
namespace _ipdltest {
IPDLUnitTestSubprocess::IPDLUnitTestSubprocess() :
GeckoChildProcessHost(GeckoProcessType_IPDLUnitTest)
{
}
IPDLUnitTestSubprocess::~IPDLUnitTestSubprocess()
{
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,37 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h
#define mozilla__ipdltest_IPDLUnitTestTestSubprocess_h 1
#include "mozilla/ipc/GeckoChildProcessHost.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
class IPDLUnitTestSubprocess : public mozilla::ipc::GeckoChildProcessHost
{
public:
IPDLUnitTestSubprocess();
~IPDLUnitTestSubprocess();
/**
* Asynchronously launch the plugin process.
*/
// Could override parent Launch, but don't need to here
//bool Launch();
private:
DISALLOW_EVIL_CONSTRUCTORS(IPDLUnitTestSubprocess);
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_IPDLUnitTestTestSubprocess_h

View file

@ -0,0 +1,44 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla__ipdltest_IPDLUnitTestTypes_h
#define mozilla__ipdltest_IPDLUnitTestTypes_h
#include "mozilla/ipc/ProtocolUtils.h" // ActorDestroyReason
namespace mozilla {
namespace _ipdltest {
struct DirtyRect
{
int x; int y; int w; int h;
};
}
}
namespace IPC {
template<>
struct ParamTraits<mozilla::_ipdltest::DirtyRect>
{
typedef mozilla::_ipdltest::DirtyRect paramType;
static void Write(Message* aMsg, const paramType& aParam) {
WriteParam(aMsg, aParam.x);
WriteParam(aMsg, aParam.y);
WriteParam(aMsg, aParam.w);
WriteParam(aMsg, aParam.h);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return (ReadParam(aMsg, aIter, &aResult->x) &&
ReadParam(aMsg, aIter, &aResult->y) &&
ReadParam(aMsg, aIter, &aResult->w) &&
ReadParam(aMsg, aIter, &aResult->h));
}
};
}
#endif // ifndef mozilla__ipdltest_IPDLUnitTestTypes_h

View file

@ -0,0 +1,27 @@
#ifndef mozilla__ipdltest_IPDLUnitTestUtils
#define mozilla__ipdltest_IPDLUnitTestUtils 1
namespace mozilla {
namespace _ipdltest {
struct Bad {};
} // namespace _ipdltest
} // namespace mozilla
namespace IPC {
template<>
struct ParamTraits<mozilla::_ipdltest::Bad>
{
typedef mozilla::_ipdltest::Bad paramType;
// Defined in TestActorPunning.cpp.
static void Write(Message* aMsg, const paramType& aParam);
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult);
};
} // namespace IPC
#endif // mozilla__ipdltest_IPDLUnitTestUtils

View file

@ -0,0 +1,93 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla__ipdltest_IPDLUnitTests_h
#define mozilla__ipdltest_IPDLUnitTests_h 1
#include "base/message_loop.h"
#include "base/process.h"
#include "chrome/common/ipc_channel.h"
#include "nsIAppShell.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "nsServiceManagerUtils.h" // do_GetService()
#include "nsWidgetsCID.h" // NS_APPSHELL_CID
#include "nsXULAppAPI.h"
#define MOZ_IPDL_TESTFAIL_LABEL "TEST-UNEXPECTED-FAIL"
#define MOZ_IPDL_TESTPASS_LABEL "TEST-PASS"
#define MOZ_IPDL_TESTINFO_LABEL "TEST-INFO"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// both processes
const char* IPDLUnitTestName();
// NB: these are named like the similar functions in
// xpcom/test/TestHarness.h. The names should nominally be kept in
// sync.
inline void fail(const char* fmt, ...)
{
va_list ap;
fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL " | %s | ", IPDLUnitTestName());
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
NS_RUNTIMEABORT("failed test");
}
inline void passed(const char* fmt, ...)
{
va_list ap;
printf(MOZ_IPDL_TESTPASS_LABEL " | %s | ", IPDLUnitTestName());
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fputc('\n', stdout);
}
//-----------------------------------------------------------------------------
// parent process only
class IPDLUnitTestSubprocess;
extern void* gParentActor;
extern IPDLUnitTestSubprocess* gSubprocess;
void IPDLUnitTestMain(void* aData);
void QuitParent();
//-----------------------------------------------------------------------------
// child process only
extern void* gChildActor;
void IPDLUnitTestChildInit(IPC::Channel* transport,
base::ProcessId parentPid,
MessageLoop* worker);
void QuitChild();
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_IPDLUnitTests_h

View file

@ -0,0 +1,390 @@
//
// Autogenerated from Python template. Hands off.
//
#include <stdlib.h>
#include <string.h>
#include "IPDLUnitTests.h"
#include "base/command_line.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/thread.h"
#include "nsRegion.h"
#include "IPDLUnitTestSubprocess.h"
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${INCLUDES}
//-----------------------------------------------------------------------------
using namespace std;
using base::Thread;
namespace mozilla {
namespace _ipdltest {
void* gParentActor;
IPDLUnitTestSubprocess* gSubprocess;
void* gChildActor;
// Note: in threaded mode, this will be non-null (for both parent and
// child, since they share one set of globals).
Thread* gChildThread;
MessageLoop *gParentMessageLoop;
bool gParentDone;
bool gChildDone;
void
DeleteChildActor();
//-----------------------------------------------------------------------------
// data/functions accessed by both parent and child processes
char* gIPDLUnitTestName = nullptr;
const char*
IPDLUnitTestName()
{
if (!gIPDLUnitTestName) {
#if defined(OS_WIN)
vector<wstring> args =
CommandLine::ForCurrentProcess()->GetLooseValues();
gIPDLUnitTestName = ::strdup(WideToUTF8(args[0]).c_str());
#elif defined(OS_POSIX)
vector<string> argv = CommandLine::ForCurrentProcess()->argv();
gIPDLUnitTestName = ::moz_xstrdup(argv[1].c_str());
#else
# error Sorry
#endif
}
return gIPDLUnitTestName;
}
} // namespace _ipdltest
} // namespace mozilla
namespace {
enum IPDLUnitTestType {
NoneTest = 0,
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${ENUM_VALUES}
LastTest = ${LAST_ENUM}
//-----------------------------------------------------------------------------
};
IPDLUnitTestType
IPDLUnitTestFromString(const char* const aString)
{
if (!aString)
return static_cast<IPDLUnitTestType>(0);
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${STRING_TO_ENUMS}
//-----------------------------------------------------------------------------
else
return static_cast<IPDLUnitTestType>(0);
}
const char*
IPDLUnitTestToString(IPDLUnitTestType aTest)
{
switch (aTest) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${ENUM_TO_STRINGS}
//-----------------------------------------------------------------------------
default:
return nullptr;
}
}
IPDLUnitTestType
IPDLUnitTest()
{
return IPDLUnitTestFromString(::mozilla::_ipdltest::IPDLUnitTestName());
}
} // namespace <anon>
//-----------------------------------------------------------------------------
// parent process only
namespace mozilla {
namespace _ipdltest {
void
DeferredParentShutdown();
void
IPDLUnitTestThreadMain(char *testString);
void
IPDLUnitTestMain(void* aData)
{
char* testString = reinterpret_cast<char*>(aData);
// Check if we are to run the test using threads instead:
const char *prefix = "thread:";
const int prefixLen = strlen(prefix);
if (!strncmp(testString, prefix, prefixLen)) {
IPDLUnitTestThreadMain(testString + prefixLen);
return;
}
IPDLUnitTestType test = IPDLUnitTestFromString(testString);
if (!test) {
// use this instead of |fail()| because we don't know what the test is
fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
"<--->", testString);
NS_RUNTIMEABORT("can't continue");
}
gIPDLUnitTestName = testString;
// Check whether this test is enabled for processes:
switch (test) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_ENABLED_CASES_PROC}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
std::vector<std::string> testCaseArgs;
testCaseArgs.push_back(testString);
gSubprocess = new IPDLUnitTestSubprocess();
if (!gSubprocess->SyncLaunch(testCaseArgs))
fail("problem launching subprocess");
IPC::Channel* transport = gSubprocess->GetChannel();
if (!transport)
fail("no transport");
base::ProcessId child = base::GetProcId(gSubprocess->GetChildProcessHandle());
switch (test) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_MAIN_CASES_PROC}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
}
void
IPDLUnitTestThreadMain(char *testString)
{
IPDLUnitTestType test = IPDLUnitTestFromString(testString);
if (!test) {
// use this instead of |fail()| because we don't know what the test is
fprintf(stderr, MOZ_IPDL_TESTFAIL_LABEL "| %s | unknown unit test %s\n",
"<--->", testString);
NS_RUNTIMEABORT("can't continue");
}
gIPDLUnitTestName = testString;
// Check whether this test is enabled for threads:
switch (test) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_ENABLED_CASES_THREAD}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
printf(MOZ_IPDL_TESTINFO_LABEL "| running test | %s\n", gIPDLUnitTestName);
std::vector<std::string> testCaseArgs;
testCaseArgs.push_back(testString);
gChildThread = new Thread("ParentThread");
if (!gChildThread->Start())
fail("starting parent thread");
gParentMessageLoop = MessageLoop::current();
MessageLoop *childMessageLoop = gChildThread->message_loop();
switch (test) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_MAIN_CASES_THREAD}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
}
void
DeleteParentActor()
{
if (!gParentActor)
return;
switch (IPDLUnitTest()) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${PARENT_DELETE_CASES}
//-----------------------------------------------------------------------------
default: ::mozilla::_ipdltest::fail("???");
}
}
void
QuitXPCOM()
{
DeleteParentActor();
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
appShell->Exit();
}
void
DeleteSubprocess(MessageLoop* uiLoop)
{
// pong to QuitXPCOM
delete gSubprocess;
uiLoop->PostTask(NewRunnableFunction(QuitXPCOM));
}
void
DeferredParentShutdown()
{
// ping to DeleteSubprocess
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(DeleteSubprocess, MessageLoop::current()));
}
void
TryThreadedShutdown()
{
// Stop if either:
// - the child has not finished,
// - the parent has not finished,
// - or this code has already executed.
// Remember: this TryThreadedShutdown() task is enqueued
// by both parent and child (though always on parent's msg loop).
if (!gChildDone || !gParentDone || !gChildThread)
return;
delete gChildThread;
gChildThread = 0;
DeferredParentShutdown();
}
void
ChildCompleted()
{
// Executes on the parent message loop once child has completed.
gChildDone = true;
TryThreadedShutdown();
}
void
QuitParent()
{
if (gChildThread) {
gParentDone = true;
MessageLoop::current()->PostTask(
NewRunnableFunction(TryThreadedShutdown));
} else {
// defer "real" shutdown to avoid *Channel::Close() racing with the
// deletion of the subprocess
MessageLoop::current()->PostTask(
NewRunnableFunction(DeferredParentShutdown));
}
}
static void
ChildDie()
{
DeleteChildActor();
XRE_ShutdownChildProcess();
}
void
QuitChild()
{
if (gChildThread) { // Threaded-mode test
gParentMessageLoop->PostTask(
NewRunnableFunction(ChildCompleted));
} else { // Process-mode test
MessageLoop::current()->PostTask(
NewRunnableFunction(ChildDie));
}
}
} // namespace _ipdltest
} // namespace mozilla
//-----------------------------------------------------------------------------
// child process only
namespace mozilla {
namespace _ipdltest {
void
DeleteChildActor()
{
if (!gChildActor)
return;
switch (IPDLUnitTest()) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${CHILD_DELETE_CASES}
//-----------------------------------------------------------------------------
default: ::mozilla::_ipdltest::fail("???");
}
}
void
IPDLUnitTestChildInit(IPC::Channel* transport,
base::ProcessId parentPid,
MessageLoop* worker)
{
switch (IPDLUnitTest()) {
//-----------------------------------------------------------------------------
//===== TEMPLATED =====
${CHILD_INIT_CASES}
//-----------------------------------------------------------------------------
default:
fail("not reached");
return; // unreached
}
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,46 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
IPDLTESTSRCS = $(filter Test%,$(CPPSRCS))
IPDLTESTS = $(IPDLTESTSRCS:.cpp=)
EXTRA_PROTOCOLS = \
TestBridgeSub \
TestEndpointBridgeSub \
$(NULL)
IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS)))
TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp
GENTESTER := $(srcdir)/genIPDLUnitTests.py
include $(topsrcdir)/config/rules.mk
IPDLUNITTEST_BIN = $(DEPTH)/dist/bin/ipdlunittest$(BIN_SUFFIX)
IPDLUnitTests.cpp : Makefile.in moz.build $(GENTESTER) $(TESTER_TEMPLATE) $(IPDLTESTHDRS)
$(PYTHON) $(GENTESTER) $(TESTER_TEMPLATE) -t $(IPDLTESTS) -e $(EXTRA_PROTOCOLS) > $@
check-proc::
@$(EXIT_ON_ERROR) \
for test in $(IPDLTESTS); do \
$(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) $$test ; \
done
check-thread::
@$(EXIT_ON_ERROR) \
for test in $(IPDLTESTS); do \
$(RUN_TEST_PROGRAM) $(IPDLUNITTEST_BIN) thread:$$test ; \
done
check:: check-proc check-thread
check-valgrind::
@$(EXIT_ON_ERROR) \
for test in $(IPDLTESTS); do \
$(RUN_TEST_PROGRAM) -g -d \
valgrind -a '--leak-check=full --trace-children=yes -q' \
$(IPDLUNITTEST_BIN) $$test ; \
done

View file

@ -0,0 +1,39 @@
include protocol PTestActorPunningPunned;
include protocol PTestActorPunningSub;
include "mozilla/_ipdltest/IPDLUnitTestUtils.h";
using struct mozilla::_ipdltest::Bad from "mozilla/_ipdltest/IPDLUnitTestUtils.h";
namespace mozilla {
namespace _ipdltest {
protocol PTestActorPunning {
manages PTestActorPunningPunned;
manages PTestActorPunningSub;
child:
async Start();
parent:
async PTestActorPunningPunned();
async PTestActorPunningSub();
async Pun(PTestActorPunningSub a, Bad bad);
async __delete__();
state PING:
send Start goto CONSTRUCTING;
state CONSTRUCTING:
recv PTestActorPunningPunned goto CONSTRUCTING;
recv PTestActorPunningSub goto CONSTRUCTING;
recv Pun goto DEAD;
// We never make it past this transition, --> error.
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,15 @@
include protocol PTestActorPunning;
namespace mozilla {
namespace _ipdltest {
protocol PTestActorPunningPunned {
manager PTestActorPunning;
child:
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltes

View file

@ -0,0 +1,16 @@
include protocol PTestActorPunning;
namespace mozilla {
namespace _ipdltest {
protocol PTestActorPunningSub {
manager PTestActorPunning;
child:
async Bad();
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltes

View file

@ -0,0 +1,18 @@
include protocol PTestBadActorSub;
namespace mozilla {
namespace _ipdltest {
// Test that a parent sending a reentrant __delete__ message
// is not killed if a child's message races with the reply.
intr protocol PTestBadActor {
manages PTestBadActorSub;
child:
async PTestBadActorSub();
async __delete__();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,17 @@
include protocol PTestBadActor;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestBadActorSub {
manager PTestBadActor;
child:
intr __delete__();
parent:
async Ping();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,26 @@
include protocol PTestBridgeMainSub;
include protocol PTestBridgeSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestBridgeMain {
child spawns PTestBridgeSub;
child opens PTestBridgeMainSub;
child:
async Start();
parent:
async __delete__();
state START:
send Start goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,33 @@
include protocol PTestBridgeMain;
include protocol PTestBridgeSub;
namespace mozilla {
namespace _ipdltest {
// (Bridge protocols can have different semantics than the endpoints
// they bridge)
intr protocol PTestBridgeMainSub {
bridges PTestBridgeMain, PTestBridgeSub;
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
async __delete__();
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,25 @@
include protocol PTestBridgeMainSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestBridgeSub {
child:
async Ping();
parent:
async BridgeEm();
async __delete__();
state START:
send Ping goto BRIDGEEM;
state BRIDGEEM:
recv BridgeEm goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,36 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_sync) sync protocol PTestCancel
{
// Test1
child:
nested(inside_sync) sync Test1_1();
parent:
async Done1();
// Test2
child:
async Start2();
nested(inside_sync) sync Test2_2();
parent:
sync Test2_1();
// Test3
child:
nested(inside_sync) sync Test3_1();
parent:
async Start3();
nested(inside_sync) sync Test3_2();
parent:
async Done();
child:
nested(inside_sync) sync CheckChild() returns (uint32_t reply);
parent:
nested(inside_sync) sync CheckParent() returns (uint32_t reply);
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,22 @@
// See bug 538586: if the top-level protocol's actor is deleted before
// the "connection error" notification comes in from the IO thread,
// IPDL teardown never occurs, even if Channel::Close() is called
// after the error.
namespace mozilla {
namespace _ipdltest {
// NB: needs to be RPC so that the parent blocks on the child's crash.
intr protocol PTestCrashCleanup {
child:
intr DIEDIEDIE();
async __delete__();
state ALIVE:
call DIEDIEDIE goto CRASH;
state CRASH:
send __delete__;
};
}
}

View file

@ -0,0 +1,132 @@
include protocol PTestDataStructuresSub;
include PTestDataStructuresCommon;
include "mozilla/GfxMessageUtils.h";
namespace mozilla {
namespace _ipdltest {
sync protocol PTestDataStructures {
manages PTestDataStructuresSub;
child:
async PTestDataStructuresSub(int i);
async Start();
parent:
async __delete__();
sync Test1(int[] i1)
returns (int[] o1);
sync Test2(PTestDataStructuresSub[] i1)
returns (PTestDataStructuresSub[] o1);
sync Test3(IntDouble i1,
IntDouble i2)
returns (IntDouble o1,
IntDouble o2);
sync Test4(IntDouble[] i1)
returns (IntDouble[] o1);
sync Test5(IntDoubleArrays i1,
IntDoubleArrays i2,
IntDoubleArrays i3)
returns (IntDoubleArrays o1,
IntDoubleArrays o2,
IntDoubleArrays o3);
sync Test6(IntDoubleArrays[] i1)
returns (IntDoubleArrays[] o1);
sync Test7_0(ActorWrapper a1)
returns (ActorWrapper o1);
sync Test7(Actors i1,
Actors i2,
Actors i3)
returns (Actors o1,
Actors o2,
Actors o3);
sync Test8(Actors[] i1)
returns (Actors[] o1);
sync Test9(Unions i1,
Unions i2,
Unions i3,
Unions i4)
returns (Unions o1,
Unions o2,
Unions o3,
Unions o4);
sync Test10(Unions[] i1)
returns (Unions[] o1);
sync Test11(SIntDouble i)
returns (SIntDouble o);
sync Test12(SIntDoubleArrays i)
returns (SIntDoubleArrays o);
sync Test13(SActors i)
returns (SActors o);
sync Test14(Structs i)
returns (Structs o);
sync Test15(WithStructs i1,
WithStructs i2,
WithStructs i3,
WithStructs i4,
WithStructs i5)
returns (WithStructs o1,
WithStructs o2,
WithStructs o3,
WithStructs o4,
WithStructs o5);
sync Test16(WithUnions i)
returns (WithUnions o);
sync Test17(Op[] ops);
// test that the ParamTraits<nsTArray>::Read() workaround for
// nsTArray's incorrect memmove() semantics works properly
// (nsIntRegion isn't memmove()able)
sync Test18(nsIntRegion[] ops);
sync Dummy(ShmemUnion su) returns (ShmemUnion rsu);
state CONSTRUCTING:
send PTestDataStructuresSub goto CONSTRUCTING;
send Start goto TEST1;
state TEST1: recv Test1 goto TEST2;
state TEST2: recv Test2 goto TEST3;
state TEST3: recv Test3 goto TEST4;
state TEST4: recv Test4 goto TEST5;
state TEST5: recv Test5 goto TEST6;
state TEST6: recv Test6 goto TEST7;
state TEST7: recv Test7 goto TEST8;
state TEST8: recv Test8 goto TEST9;
state TEST9: recv Test9 goto TEST10;
state TEST10: recv Test10 goto TEST11;
state TEST11: recv Test11 goto TEST12;
state TEST12: recv Test12 goto TEST13;
state TEST13: recv Test13 goto TEST14;
state TEST14: recv Test14 goto TEST15;
state TEST15: recv Test15 goto TEST16;
state TEST16: recv Test16 goto TEST17;
state TEST17: recv Test17 goto TEST18;
state TEST18: recv Test18 goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,107 @@
include protocol PTestDataStructuresSub;
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
using nsIntRegion from "nsRegion.h";
namespace mozilla {
namespace _foo {
union IntDouble {
int;
double;
};
struct SIntDouble {
int i;
double d;
};
union IntDoubleArrays {
int;
int[];
double[];
};
struct SIntDoubleArrays {
int i;
int[] ai;
double[] ad;
};
struct ActorWrapper {
PTestDataStructuresSub actor;
};
union Actors {
int;
int[];
PTestDataStructuresSub[];
};
struct SActors {
int i;
int[] ai;
PTestDataStructuresSub[] ap;
};
union Unions {
int;
int[];
PTestDataStructuresSub[];
Actors[];
};
struct Structs {
int i;
int[] ai;
PTestDataStructuresSub[] ap;
SActors[] aa;
};
union WithStructs {
int;
int[];
PTestDataStructuresSub[];
SActors[];
Structs[];
};
struct WithUnions {
int i;
int[] ai;
PTestDataStructuresSub[] ap;
Actors[] aa;
Unions[] au;
};
struct CommonAttrs { bool dummy; };
struct FooAttrs { int dummy; };
struct BarAttrs { float dummy; };
union SpecificAttrs {
FooAttrs;
BarAttrs;
};
struct Attrs {
CommonAttrs common;
SpecificAttrs specific;
};
struct SetAttrs {
PTestDataStructuresSub x;
Attrs attrs;
};
union Op { null_t; SetAttrs; };
struct ShmemStruct {
int i;
Shmem mem;
};
union ShmemUnion {
int;
Shmem;
};
struct Empty { };
} // namespace _foo
} // namespace mozilla

View file

@ -0,0 +1,15 @@
include PTestDataStructuresCommon;
include protocol PTestDataStructures;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestDataStructuresSub {
manager PTestDataStructures;
parent:
sync __delete__();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,21 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_cpow) sync protocol PTestDemon
{
child:
async Start();
both:
async AsyncMessage(int n);
nested(inside_sync) sync HiPrioSyncMessage();
parent:
sync SyncMessage(int n);
nested(inside_cpow) async UrgentAsyncMessage(int n);
nested(inside_cpow) sync UrgentSyncMessage(int n);
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,31 @@
include protocol PTestDescSub;
include protocol PTestDescSubsub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestDesc {
manages PTestDescSub;
child:
intr PTestDescSub(nullable PTestDescSubsub dummy);
async Test(PTestDescSubsub a);
async __delete__();
parent:
async Ok(PTestDescSubsub a);
state CONSTRUCT:
call PTestDescSub goto TEST;
state TEST:
send Test goto ACK;
state ACK:
recv Ok goto DEAD;
state DEAD:
send __delete__;
};
}
}

View file

@ -0,0 +1,18 @@
include protocol PTestDesc;
include protocol PTestDescSubsub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestDescSub {
manager PTestDesc;
manages PTestDescSubsub;
child:
async __delete__();
intr PTestDescSubsub();
};
}
}

View file

@ -0,0 +1,15 @@
include protocol PTestDescSub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestDescSubsub {
manager PTestDescSub;
child:
intr __delete__();
};
}
}

View file

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
include protocol PTestEndpointBridgeMainSub;
include protocol PTestEndpointBridgeSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestEndpointBridgeMain {
child spawns PTestEndpointBridgeSub;
child:
async Start();
parent:
async Bridged(Endpoint<PTestEndpointBridgeMainSubParent> endpoint);
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
include protocol PTestEndpointBridgeMain;
include protocol PTestEndpointBridgeSub;
namespace mozilla {
namespace _ipdltest {
// (Bridge protocols can have different semantics than the endpoints
// they bridge)
intr protocol PTestEndpointBridgeMainSub {
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,22 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
include protocol PTestEndpointBridgeMainSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestEndpointBridgeSub {
child:
async Ping();
async Bridged(Endpoint<PTestEndpointBridgeMainSubChild> endpoint);
parent:
async BridgeEm();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,19 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
include protocol PTestEndpointOpensOpened;
namespace mozilla {
namespace _ipdltest {
protocol PTestEndpointOpens {
child:
async Start();
parent:
async StartSubprotocol(Endpoint<PTestEndpointOpensOpenedParent> endpoint);
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
namespace mozilla {
namespace _ipdltest2 {
// (Opens protocols can have different semantics than the endpoints
// that opened them)
intr protocol PTestEndpointOpensOpened {
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
async __delete__();
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest2

View file

@ -0,0 +1,19 @@
include protocol PTestFailedCtorSub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestFailedCtor {
manages PTestFailedCtorSub;
child:
intr PTestFailedCtorSub();
async __delete__();
state CONSTRUCT:
call PTestFailedCtorSub goto DEAD;
state DEAD:
send __delete__;
};
}
}

View file

@ -0,0 +1,18 @@
include protocol PTestFailedCtor;
include protocol PTestFailedCtorSubsub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestFailedCtorSub {
manager PTestFailedCtor;
manages PTestFailedCtorSubsub;
parent:
async PTestFailedCtorSubsub();
sync Sync();
async __delete__();
};
}
}

View file

@ -0,0 +1,15 @@
include protocol PTestFailedCtorSub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestFailedCtorSubsub {
manager PTestFailedCtorSub;
parent:
async __delete__();
};
}
}

View file

@ -0,0 +1,14 @@
include protocol PTestJSON;
namespace mozilla {
namespace _ipdltest {
protocol PTestHandle {
manager PTestJSON;
child:
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,40 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestHangs {
both:
intr StackFrame();
parent:
async Nonce();
child:
async Start();
intr Hang();
async __delete__();
state START:
send Start goto RACE;
state RACE:
recv Nonce goto RACE1;
call StackFrame goto RACE2;
state RACE1:
call StackFrame goto FRAME2;
state RACE2:
recv Nonce goto FRAME2;
// So as to test unwinding the RPC stack
state FRAME2: answer StackFrame goto FRAME3;
state FRAME3: call StackFrame goto FRAME4;
state FRAME4: answer StackFrame goto HANG;
state HANG: call Hang goto DEATH;
state DEATH:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,18 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_cpow) sync protocol PTestHighestPrio
{
parent:
nested(inside_cpow) async Msg1();
nested(inside_sync) sync Msg2();
nested(inside_cpow) async Msg3();
nested(inside_cpow) sync Msg4();
child:
async Start();
nested(inside_sync) sync StartInner();
};
}
}

View file

@ -0,0 +1,15 @@
include protocol PTestIndirectProtocolParamSecond;
namespace mozilla {
namespace _ipdltest {
struct IndirectParamStruct {
PTestIndirectProtocolParamSecond actor;
};
union IndirectParamUnion {
IndirectParamStruct;
};
}
}

View file

@ -0,0 +1,19 @@
include protocol PTestIndirectProtocolParamManage;
// FIXME/bug 792908 protocol PTestIndirectProtocolParamSecond is
// already included in PTestIndirectProtocolParam.ipdlh
include protocol PTestIndirectProtocolParamSecond;
include PTestIndirectProtocolParam;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestIndirectProtocolParamFirst {
manager PTestIndirectProtocolParamManage;
parent:
sync Test(IndirectParamUnion actor);
both:
async __delete__();
};
}
}

View file

@ -0,0 +1,17 @@
include protocol PTestIndirectProtocolParamFirst;
include protocol PTestIndirectProtocolParamSecond;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestIndirectProtocolParamManage {
manages PTestIndirectProtocolParamFirst;
manages PTestIndirectProtocolParamSecond;
both:
async PTestIndirectProtocolParamFirst();
async PTestIndirectProtocolParamSecond();
async __delete__();
};
}
}

View file

@ -0,0 +1,13 @@
include protocol PTestIndirectProtocolParamManage;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestIndirectProtocolParamSecond {
manager PTestIndirectProtocolParamManage;
both:
async __delete__();
};
}
}

View file

@ -0,0 +1,11 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestInterruptErrorCleanup {
child:
intr Error();
intr __delete__();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,82 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestInterruptRaces {
both:
intr Race() returns (bool hasReply);
intr StackFrame() returns ();
intr StackFrame3() returns ();
parent:
sync StartRace();
intr Parent();
sync GetAnsweredParent() returns (bool answeredParent);
child:
async Start();
async Wakeup();
async Wakeup3();
intr Child();
async __delete__();
state START:
send Start goto TEST1;
// First test: race while no other messages are on the Interrupt stack
state TEST1:
recv StartRace goto RACE1;
state RACE1:
call Race goto DUMMY1_1;
answer Race goto DUMMY1_2;
state DUMMY1_1:
answer Race goto TEST2;
state DUMMY1_2:
call Race goto TEST2;
// Second test: race while other messages are on the Interrupt stack
state TEST2:
call StackFrame goto MORESTACK;
state MORESTACK:
answer StackFrame goto STARTRACE;
state STARTRACE:
send Wakeup goto RACE2;
state RACE2:
call Race goto DUMMY2_1;
answer Race goto DUMMY2_2;
state DUMMY2_1:
answer Race goto TEST3;
state DUMMY2_2:
call Race goto TEST3;
// Third test: resolve race using custom policy
state TEST3:
call StackFrame3 goto MORESTACK3;
state MORESTACK3:
answer StackFrame3 goto STARTRACE3;
state STARTRACE3:
send Wakeup3 goto RACE3;
state RACE3:
call Child goto DUMMY3_1;
answer Parent goto DUMMY3_2;
state DUMMY3_1:
// the parent receives this from the child in this state
recv GetAnsweredParent goto CHECK;
// this transition is never taken (if the custom race resolution
// works correctly)
answer Parent goto CHECK;
state DUMMY3_2:
call Child goto CHECK;
state CHECK:
// the child sends this from this state
recv GetAnsweredParent goto DYING;
// because of deferred processing, the parent receives the child's
// message here
answer Parent goto DYING;
state DYING:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,34 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestInterruptShutdownRace {
parent:
sync StartDeath();
async Orphan();
child:
async Start();
intr Exit();
async __delete__();
state START:
send Start goto START_DEATH;
state START_DEATH:
recv StartDeath goto EXITING;
state EXITING:
recv Orphan goto QUITTING1;
call Exit goto QUITTING2;
state QUITTING1:
call Exit goto DEAD;
state QUITTING2:
recv Orphan goto DEAD;
state DEAD:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,54 @@
include protocol PTestHandle;
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
namespace mozilla {
namespace _ipdltest {
union Key {
// int;
// double;
nsString;
};
struct KeyValue {
Key key;
JSONVariant value;
};
union JSONVariant {
void_t;
null_t;
bool;
int;
double;
nsString;
PTestHandle;
KeyValue[];
JSONVariant[];
};
sync protocol PTestJSON {
manages PTestHandle;
child:
async Start();
parent:
async PTestHandle();
sync Test(JSONVariant i)
returns (JSONVariant o);
async __delete__();
state START:
send Start goto TEST;
state TEST:
recv PTestHandle goto TEST;
recv Test goto TEST;
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,75 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestLatency {
child:
async __delete__();
async Ping();
async Ping5();
intr Rpc();
async Spam();
intr Synchro();
async CompressedSpam(uint32_t seqno) compress;
intr Synchro2() returns (uint32_t lastSeqno,
uint32_t numMessagesDispatched);
parent:
async Pong();
async Pong5();
state START:
// if the timing resolution is too low, abort the test
send __delete__;
// otherwise, kick off the ping/pong trials
send Ping goto PONG;
// Trial 1: single ping/pong latency
state PING:
send Ping goto PONG;
send Ping5 goto PING4;
state PONG:
recv Pong goto PING;
// Trial 2: "overlapped" ping/pong latency
state PING5:
send Ping5 goto PING4;
call Rpc goto RPC;
state PING4: send Ping5 goto PING3;
state PING3: send Ping5 goto PING2;
state PING2: send Ping5 goto PING1;
state PING1: send Ping5 goto PONG1;
state PONG1: recv Pong5 goto PONG2;
state PONG2: recv Pong5 goto PONG3;
state PONG3: recv Pong5 goto PONG4;
state PONG4: recv Pong5 goto PONG5;
state PONG5: recv Pong5 goto PING5;
// Trial 3: lotsa RPC
state RPC:
call Rpc goto RPC;
send Spam goto SPAM;
// Trial 4: lots of sequential asyn messages, which tests pipelining
state SPAM:
send Spam goto SPAM;
call Synchro goto COMPRESSED_SPAM;
// Trial 5: lots of async spam, but compressed to cut down on
// dispatch overhead
state COMPRESSED_SPAM: // compressed spam, mmm
send CompressedSpam goto COMPRESSED_SPAM;
call Synchro2 goto DONE;
state DONE:
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,19 @@
include protocol PTestManyChildAllocsSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestManyChildAllocs {
manages PTestManyChildAllocsSub;
child:
async Go(); // start allocating
parent:
async Done();
async PTestManyChildAllocsSub();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,19 @@
include protocol PTestManyChildAllocs;
namespace mozilla {
namespace _ipdltest {
protocol PTestManyChildAllocsSub {
manager PTestManyChildAllocs;
child:
async __delete__();
parent:
async Hello();
// empty
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,34 @@
include protocol PTestMultiMgrsLeft;
include protocol PTestMultiMgrsRight;
namespace mozilla {
namespace _ipdltest {
protocol PTestMultiMgrs {
manages PTestMultiMgrsLeft;
manages PTestMultiMgrsRight;
parent:
async OK();
child:
async PTestMultiMgrsLeft();
async PTestMultiMgrsRight();
async Check();
async __delete__();
state START:
send PTestMultiMgrsLeft goto CONSTRUCT_RIGHT;
state CONSTRUCT_RIGHT:
send PTestMultiMgrsRight goto CHILD_CHECK;
state CHILD_CHECK:
send Check goto CHILD_ACK;
state CHILD_ACK:
recv OK goto DONE;
state DONE:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,18 @@
include protocol PTestMultiMgrsLeft;
include protocol PTestMultiMgrsRight;
namespace mozilla {
namespace _ipdltest {
protocol PTestMultiMgrsBottom {
manager PTestMultiMgrsLeft or PTestMultiMgrsRight;
child:
async __delete__();
state DOA:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,24 @@
include protocol PTestMultiMgrs;
include protocol PTestMultiMgrsBottom;
namespace mozilla {
namespace _ipdltest {
protocol PTestMultiMgrsLeft {
manager PTestMultiMgrs;
manages PTestMultiMgrsBottom;
child:
async PTestMultiMgrsBottom();
async __delete__();
state START:
send PTestMultiMgrsBottom goto DONE;
state DONE:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,24 @@
include protocol PTestMultiMgrs;
include protocol PTestMultiMgrsBottom;
namespace mozilla {
namespace _ipdltest {
protocol PTestMultiMgrsRight {
manager PTestMultiMgrs;
manages PTestMultiMgrsBottom;
child:
async PTestMultiMgrsBottom();
async __delete__();
state START:
send PTestMultiMgrsBottom goto DONE;
state DONE:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,34 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestNestedLoops {
child:
async Start();
intr R();
async __delete__();
parent:
async Nonce();
state START:
send Start goto RACE;
state RACE:
recv Nonce goto RACE1;
call R goto RACE2;
state RACE1:
call R goto DEAD;
state RACE2:
recv Nonce goto DEAD;
state DEAD:
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,25 @@
include protocol PTestOpensOpened;
namespace mozilla {
namespace _ipdltest {
protocol PTestOpens {
// This channel is opened and parked on a non-main thread
child opens PTestOpensOpened;
child:
async Start();
parent:
async __delete__();
state START:
send Start goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest2 {
// (Opens protocols can have different semantics than the endpoints
// that opened them)
intr protocol PTestOpensOpened {
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
async __delete__();
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest2

View file

@ -0,0 +1,14 @@
namespace mozilla {
namespace _ipdltest {
sync protocol PTestPriority {
parent:
prio(high) async Msg1();
prio(high) sync Msg2();
child:
prio(high) async Msg3();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,21 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_sync) sync protocol PTestRPC
{
parent:
nested(inside_sync) sync Test1_Start() returns (uint32_t result);
nested(inside_sync) sync Test1_InnerEvent() returns (uint32_t result);
async Test2_Start();
nested(inside_sync) sync Test2_OutOfOrder();
child:
async Start();
nested(inside_sync) sync Test1_InnerQuery() returns (uint32_t result);
nested(inside_sync) sync Test1_NoReenter() returns (uint32_t result);
nested(inside_sync) sync Test2_FirstUrgent();
nested(inside_sync) sync Test2_SecondUrgent();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,20 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRaceDeadlock {
both:
async StartRace();
parent:
intr Lose();
child:
intr Win();
intr Rpc();
async __delete__();
/* Tests that race resolution does not cause deadlocks */
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,45 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRaceDeferral {
parent:
intr Lose();
child:
async StartRace();
intr Win();
intr Rpc();
async __delete__();
// Test that messages deferred due to race resolution are
// re-considered when the winner makes later RPCs
// IPDL's type system can't express this protocol because the race
// resolution causes state to diverge for multiple steps, so we'll
// leave it "stateless"
/*
state START:
send StartRace goto DEFER;
state DEFER:
call Win goto PARENT;
answer Lose goto CHILD;
state PARENT:
// 'Lose' is received here but deferred
call Rpc goto PARENT_LOSE;
state PARENT_LOSE:
// Calling 'Rpc' undefers 'Lose', and it wins the "race" with 'Rpc'
answer Lose goto DONE;
state CHILD:
call Win goto CHILD_RPC;
state CHILD_RPC:
call Rpc goto DONE;
state DONE:
send __delete__;
*/
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,41 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRacyInterruptReplies {
child:
intr R_() returns (int replyNum);
async _A();
async ChildTest();
async __delete__();
parent:
intr _R() returns (int replyNum);
async A_();
state PARENT_START:
call R_ goto PARENT_S1;
state PARENT_S1:
recv A_ goto PARENT_S2;
state PARENT_S2:
call R_ goto CHILD_TEST;
state CHILD_TEST:
send ChildTest goto CHILD_START;
state CHILD_START:
answer _R goto CHILD_S1;
state CHILD_S1:
send _A goto CHILD_S2;
state CHILD_S2:
answer _R goto DYING;
state DYING:
send __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,21 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRacyReentry {
parent:
intr E();
async __delete__();
child:
async Start();
async N();
intr H();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestRacyUndefer {
child:
async Start();
async AwakenSpam();
async AwakenRaceWinTwice();
intr Race();
async __delete__();
parent:
intr Spam();
intr RaceWinTwice();
async Done();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest {
protocol PTestSanity {
child:
async Ping(int zero, float zeroPtFive, int8_t dummy);
async __delete__();
parent:
async Pong(int one, float zeroPtTwoFive, uint8_t dummy);
state PING:
send Ping goto PONG;
state PONG:
recv Pong goto DEAD;
state DEAD:
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,22 @@
include protocol PTestSelfManageRoot;
namespace mozilla {
namespace _ipdltest {
protocol PTestSelfManage {
manager PTestSelfManageRoot or PTestSelfManage;
manages PTestSelfManage;
child:
async PTestSelfManage();
async __delete__();
state LIVE:
send PTestSelfManage goto LIVE;
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,23 @@
include protocol PTestSelfManage;
namespace mozilla {
namespace _ipdltest {
protocol PTestSelfManageRoot {
manages PTestSelfManage;
child:
async PTestSelfManage();
async __delete__();
state LIVE:
send PTestSelfManage goto DEAD;
state DEAD:
send __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,22 @@
namespace mozilla {
namespace _ipdltest {
protocol PTestShmem {
child:
async Give(Shmem mem, Shmem unsafe, size_t expectedSize);
parent:
async Take(Shmem mem, Shmem unsafe, size_t expectedSize);
async __delete__();
state GIVING:
send Give goto TAKING;
state TAKING:
recv Take goto TAKING;
recv __delete__;
};
}
}

View file

@ -0,0 +1,37 @@
include protocol PTestShutdownSub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestShutdown {
manages PTestShutdownSub;
child:
async Start();
parent:
// NB: we test deletion and crashing only, not shutdown, because
// crashing is the same code path as shutdown, and other IPDL unit
// tests check shutdown semantics
async PTestShutdownSub(bool expectCrash);
// Used to synchronize between parent and child, to avoid races
// around flushing socket write queues
sync Sync();
async __delete__();
state START:
send Start goto TESTING;
state TESTING:
recv PTestShutdownSub goto TESTING;
recv Sync goto DYING;
state DYING:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,30 @@
include protocol PTestShutdown;
include protocol PTestShutdownSubsub;
namespace mozilla {
namespace _ipdltest {
intr protocol PTestShutdownSub {
manager PTestShutdown;
manages PTestShutdownSubsub;
both:
intr StackFrame();
parent:
async PTestShutdownSubsub(bool expectParentDeleted);
sync __delete__();
state CREATING:
recv PTestShutdownSubsub goto CREATING;
answer StackFrame goto DUMMYFRAME;
state DUMMYFRAME:
call StackFrame goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,17 @@
include protocol PTestShutdownSub;
namespace mozilla {
namespace _ipdltest {
sync protocol PTestShutdownSubsub {
manager PTestShutdownSub;
parent:
sync __delete__();
state LIVE:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,56 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestStackHooks {
child:
async Start();
// These tests are more fruitful running child->parent, because
// children can send |sync| messages
parent:
async Async();
sync Sync();
intr Rpc();
both:
intr StackFrame();
parent:
async __delete__();
state START:
send Start goto TEST1;
state TEST1:
recv Async goto TEST2;
state TEST2:
recv Sync goto TEST3;
state TEST3:
answer Rpc goto TEST4;
state TEST4:
answer StackFrame goto TEST4_2;
state TEST4_2:
call StackFrame goto TEST4_3;
state TEST4_3:
recv Async goto TEST5;
state TEST5:
answer StackFrame goto TEST5_2;
state TEST5_2:
call StackFrame goto TEST5_3;
state TEST5_3:
recv Sync goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest {
sync protocol PTestSyncError {
child:
async Start();
parent:
sync Error();
async __delete__();
state START:
send Start goto SYNC_ERROR;
state SYNC_ERROR:
recv Error goto DEAD;
state DEAD:
recv __delete__;
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,15 @@
namespace mozilla {
namespace _ipdltest {
protocol PTestSyncHang {
child:
async __delete__();
};
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,41 @@
namespace mozilla {
namespace _ipdltest {
intr protocol PTestSyncWakeup {
both:
intr StackFrame();
child:
async Start();
async Note1();
async Note2();
parent:
sync Sync1();
sync Sync2();
async __delete__();
state START:
send Start goto TEST1;
state TEST1:
recv Sync1 goto TEST1_P2;
state TEST1_P2:
send Note1 goto TEST2;
state TEST2:
answer StackFrame goto TEST2_P2;
state TEST2_P2:
call StackFrame goto TEST2_P3;
state TEST2_P3:
recv Sync2 goto TEST2_P4;
state TEST2_P4:
send Note2 goto DONE;
state DONE:
recv __delete__;
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,19 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_cpow) sync protocol PTestUrgency
{
parent:
nested(inside_sync) sync Test1() returns (uint32_t result);
async Test2();
sync Test3() returns (uint32_t result);
sync FinalTest_Begin();
child:
async Start();
nested(inside_sync) sync Reply1() returns (uint32_t result);
nested(inside_sync) sync Reply2() returns (uint32_t result);
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,28 @@
namespace mozilla {
namespace _ipdltest {
nested(upto inside_cpow) sync protocol PTestUrgentHangs
{
parent:
nested(inside_sync) sync Test1_2();
nested(inside_sync) sync TestInner();
nested(inside_cpow) sync TestInnerUrgent();
child:
nested(inside_sync) sync Test1_1();
nested(inside_sync) sync Test1_3();
nested(inside_sync) sync Test2();
nested(inside_sync) sync Test3();
async Test4();
nested(inside_sync) sync Test4_1();
async Test5();
nested(inside_sync) sync Test5_1();
};
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,61 @@
To add a new IPDL C++ unit test, you need to create (at least) the
following files (for a test "TestFoo"):
- PTestFoo.ipdl, specifying the top-level protocol used for the test
- TestFoo.h, declaring the top-level parent/child actors used for
the test
- TestFoo.cpp, defining the top-level actors
- (make sure all are in the namespace mozilla::_ipdltest)
Next
- add PTestFoo.ipdl to ipdl.mk
- append TestFoo to the variable IPDLTESTS in Makefile.in
You must define three methods in your |TestFooParent| class:
- static methods |bool RunTestInProcesses()| and
|bool RunTestInThreads()|. These methods control whether
to execute the test using actors in separate processes and
threads respectively. Generally, both should return true.
- an instance method |void Main()|. The test harness wil first
initialize the processes or threads, create and open both actors,
and then kick off the test using |Main()|. Make sure you define
it.
If your test passes its criteria, please call
|MOZ_IPDL_TESTPASS("msg")| and "exit gracefully".
If your tests fails, please call |MOZ_IPDL_TESTFAIL("msg")| and "exit
ungracefully", preferably by abort()ing.
If all goes well, running
make -C $OBJDIR/ipc/ipdl/test/cxx
will update the file IPDLUnitTests.cpp (the test launcher), and your
new code will be built automatically.
You can launch your new test by invoking one of
make -C $OBJDIR/ipc/ipdl/test/cxx check-proc (test process-based tests)
make -C $OBJDIR/ipc/ipdl/test/cxx check-threads (test thread-based tests)
make -C $OBJDIR/ipc/ipdl/test/cxx check (tests both)
If you want to launch only your test, run
cd $OBJDIR/dist/bin
./run-mozilla.sh ./ipdlunittest TestFoo (test in two processes, if appl.)
./run-mozilla.sh ./ipdlunittest thread:TestFoo (test in two threads, if appl.)
For a bare-bones example of adding a test, take a look at
PTestSanity.ipdl, TestSanity.h, TestSanity.cpp, and how "TestSanity"
is included in ipdl.mk and Makefile.in.

View file

@ -0,0 +1,128 @@
#include "TestActorPunning.h"
#include "IPDLUnitTests.h" // fail etc.
#include "mozilla/Unused.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
void
TestActorPunningParent::Main()
{
if (!SendStart())
fail("sending Start");
}
bool
TestActorPunningParent::RecvPun(PTestActorPunningSubParent* a, const Bad& bad)
{
if (a->SendBad())
fail("bad!");
fail("shouldn't have received this message in the first place");
return true;
}
PTestActorPunningPunnedParent*
TestActorPunningParent::AllocPTestActorPunningPunnedParent()
{
return new TestActorPunningPunnedParent();
}
bool
TestActorPunningParent::DeallocPTestActorPunningPunnedParent(PTestActorPunningPunnedParent* a)
{
delete a;
return true;
}
PTestActorPunningSubParent*
TestActorPunningParent::AllocPTestActorPunningSubParent()
{
return new TestActorPunningSubParent();
}
bool
TestActorPunningParent::DeallocPTestActorPunningSubParent(PTestActorPunningSubParent* a)
{
delete a;
return true;
}
//-----------------------------------------------------------------------------
// child
PTestActorPunningPunnedChild*
TestActorPunningChild::AllocPTestActorPunningPunnedChild()
{
return new TestActorPunningPunnedChild();
}
bool
TestActorPunningChild::DeallocPTestActorPunningPunnedChild(PTestActorPunningPunnedChild*)
{
fail("should have died by now");
return true;
}
PTestActorPunningSubChild*
TestActorPunningChild::AllocPTestActorPunningSubChild()
{
return new TestActorPunningSubChild();
}
bool
TestActorPunningChild::DeallocPTestActorPunningSubChild(PTestActorPunningSubChild*)
{
fail("should have died by now");
return true;
}
bool
TestActorPunningChild::RecvStart()
{
SendPTestActorPunningSubConstructor();
SendPTestActorPunningPunnedConstructor();
PTestActorPunningSubChild* a = SendPTestActorPunningSubConstructor();
// We can't assert whether this succeeds or fails, due to race
// conditions.
SendPun(a, Bad());
return true;
}
bool
TestActorPunningSubChild::RecvBad()
{
fail("things are going really badly right now");
return true;
}
} // namespace _ipdltest
} // namespace mozilla
namespace IPC {
using namespace mozilla::_ipdltest;
using namespace mozilla::ipc;
/*static*/ void
ParamTraits<Bad>::Write(Message* aMsg, const paramType& aParam)
{
// Skip past the sentinel for the actor as well as the actor.
int32_t* ptr = aMsg->GetInt32PtrForTest(2 * sizeof(int32_t));
ActorHandle* ah = reinterpret_cast<ActorHandle*>(ptr);
if (ah->mId != -3)
fail("guessed wrong offset (value is %d, should be -3)", ah->mId);
ah->mId = -2;
}
/*static*/ bool
ParamTraits<Bad>::Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
return true;
}
} // namespace IPC

View file

@ -0,0 +1,110 @@
#ifndef mozilla__ipdltest_TestActorPunning_h
#define mozilla__ipdltest_TestActorPunning_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestActorPunningParent.h"
#include "mozilla/_ipdltest/PTestActorPunningPunnedParent.h"
#include "mozilla/_ipdltest/PTestActorPunningSubParent.h"
#include "mozilla/_ipdltest/PTestActorPunningChild.h"
#include "mozilla/_ipdltest/PTestActorPunningPunnedChild.h"
#include "mozilla/_ipdltest/PTestActorPunningSubChild.h"
namespace mozilla {
namespace _ipdltest {
class TestActorPunningParent :
public PTestActorPunningParent
{
public:
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
PTestActorPunningPunnedParent* AllocPTestActorPunningPunnedParent() override;
bool DeallocPTestActorPunningPunnedParent(PTestActorPunningPunnedParent* a) override;
PTestActorPunningSubParent* AllocPTestActorPunningSubParent() override;
bool DeallocPTestActorPunningSubParent(PTestActorPunningSubParent* a) override;
virtual bool RecvPun(PTestActorPunningSubParent* a, const Bad& bad) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (NormalShutdown == why)
fail("should have died from error!");
passed("ok");
QuitParent();
}
};
class TestActorPunningPunnedParent :
public PTestActorPunningPunnedParent
{
public:
TestActorPunningPunnedParent() {}
virtual ~TestActorPunningPunnedParent() {}
protected:
virtual void ActorDestroy(ActorDestroyReason why) override {}
};
class TestActorPunningSubParent :
public PTestActorPunningSubParent
{
public:
TestActorPunningSubParent() {}
virtual ~TestActorPunningSubParent() {}
protected:
virtual void ActorDestroy(ActorDestroyReason why) override {}
};
class TestActorPunningChild :
public PTestActorPunningChild
{
public:
TestActorPunningChild() {}
virtual ~TestActorPunningChild() {}
protected:
PTestActorPunningPunnedChild* AllocPTestActorPunningPunnedChild() override;
bool DeallocPTestActorPunningPunnedChild(PTestActorPunningPunnedChild* a) override;
PTestActorPunningSubChild* AllocPTestActorPunningSubChild() override;
bool DeallocPTestActorPunningSubChild(PTestActorPunningSubChild* a) override;
virtual bool RecvStart() override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
fail("should have been killed off!");
}
};
class TestActorPunningPunnedChild :
public PTestActorPunningPunnedChild
{
public:
TestActorPunningPunnedChild() {}
virtual ~TestActorPunningPunnedChild() {}
};
class TestActorPunningSubChild :
public PTestActorPunningSubChild
{
public:
TestActorPunningSubChild() {}
virtual ~TestActorPunningSubChild() {}
virtual bool RecvBad() override;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestActorPunning_h

View file

@ -0,0 +1,51 @@
#include "TestBadActor.h"
#include "IPDLUnitTests.h"
#include "mozilla/Unused.h"
namespace mozilla {
namespace _ipdltest {
void
TestBadActorParent::Main()
{
// This test is designed to test a race condition where the child sends us
// a message on an actor that we've already destroyed. The child process
// should die, and the parent process should not abort.
PTestBadActorSubParent* child = SendPTestBadActorSubConstructor();
if (!child)
fail("Sending constructor");
Unused << child->Call__delete__(child);
}
PTestBadActorSubParent*
TestBadActorParent::AllocPTestBadActorSubParent()
{
return new TestBadActorSubParent();
}
bool
TestBadActorSubParent::RecvPing()
{
fail("Shouldn't have received ping.");
return false;
}
PTestBadActorSubChild*
TestBadActorChild::AllocPTestBadActorSubChild()
{
return new TestBadActorSubChild();
}
bool
TestBadActorChild::RecvPTestBadActorSubConstructor(PTestBadActorSubChild* actor)
{
if (!actor->SendPing()) {
fail("Couldn't send ping to an actor which supposedly isn't dead yet.");
}
return true;
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,91 @@
#ifndef mozilla__ipdltest_TestBadActor_h
#define mozilla__ipdltest_TestBadActor_h
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestBadActorParent.h"
#include "mozilla/_ipdltest/PTestBadActorChild.h"
#include "mozilla/_ipdltest/PTestBadActorSubParent.h"
#include "mozilla/_ipdltest/PTestBadActorSubChild.h"
namespace mozilla {
namespace _ipdltest {
class TestBadActorParent
: public PTestBadActorParent
{
public:
TestBadActorParent() { }
virtual ~TestBadActorParent() { }
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (AbnormalShutdown != why)
fail("unexpected destruction");
passed("ok");
QuitParent();
}
virtual PTestBadActorSubParent*
AllocPTestBadActorSubParent();
virtual bool
DeallocPTestBadActorSubParent(PTestBadActorSubParent* actor) {
delete actor;
return true;
}
};
class TestBadActorSubParent
: public PTestBadActorSubParent
{
public:
TestBadActorSubParent() { }
virtual ~TestBadActorSubParent() { }
protected:
virtual void ActorDestroy(ActorDestroyReason why) override {}
virtual bool RecvPing();
};
class TestBadActorChild
: public PTestBadActorChild
{
public:
TestBadActorChild() { }
virtual ~TestBadActorChild() { }
protected:
virtual PTestBadActorSubChild*
AllocPTestBadActorSubChild();
virtual bool
DeallocPTestBadActorSubChild(PTestBadActorSubChild* actor)
{
delete actor;
return true;
}
virtual bool
RecvPTestBadActorSubConstructor(PTestBadActorSubChild* actor);
};
class TestBadActorSubChild
: public PTestBadActorSubChild
{
public:
TestBadActorSubChild() { }
virtual ~TestBadActorSubChild() { }
};
} // namespace _ipdltest
} // namespace mozilla
#endif // mozilla__ipdltest_TestBadActor_h

View file

@ -0,0 +1,227 @@
#include "TestBridgeMain.h"
#include "base/task.h"
#include "IPDLUnitTests.h" // fail etc.
#include "IPDLUnitTestSubprocess.h"
#include "nsAutoPtr.h"
using namespace std;
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// main process
void
TestBridgeMainParent::Main()
{
if (!SendStart())
fail("sending Start");
}
PTestBridgeMainSubParent*
TestBridgeMainParent::AllocPTestBridgeMainSubParent(Transport* transport,
ProcessId otherPid)
{
nsAutoPtr<TestBridgeMainSubParent> a(new TestBridgeMainSubParent(transport));
if (!a->Open(transport, otherPid, XRE_GetIOMessageLoop(), ipc::ParentSide)) {
return nullptr;
}
return a.forget();
}
void
TestBridgeMainParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
bool
TestBridgeMainSubParent::RecvHello()
{
return SendHi();
}
bool
TestBridgeMainSubParent::RecvHelloSync()
{
return true;
}
bool
TestBridgeMainSubParent::AnswerHelloRpc()
{
return CallHiRpc();
}
void
TestBridgeMainSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
// 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.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestBridgeMainSubParent>(this)));
}
//-----------------------------------------------------------------------------
// sub process --- child of main
TestBridgeMainChild* gBridgeMainChild;
TestBridgeMainChild::TestBridgeMainChild()
: mSubprocess(nullptr)
{
gBridgeMainChild = this;
}
bool
TestBridgeMainChild::RecvStart()
{
vector<string> subsubArgs;
subsubArgs.push_back("TestBridgeSub");
mSubprocess = new IPDLUnitTestSubprocess();
if (!mSubprocess->SyncLaunch(subsubArgs))
fail("problem launching subprocess");
IPC::Channel* transport = mSubprocess->GetChannel();
if (!transport)
fail("no transport");
TestBridgeSubParent* bsp = new TestBridgeSubParent();
bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle()));
bsp->Main();
return true;
}
void
TestBridgeMainChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
// NB: this is kosher because QuitChild() joins with the IO thread
XRE_GetIOMessageLoop()->PostTask(
do_AddRef(new DeleteTask<IPDLUnitTestSubprocess>(mSubprocess)));
QuitChild();
}
void
TestBridgeSubParent::Main()
{
if (!SendPing())
fail("sending Ping");
}
bool
TestBridgeSubParent::RecvBridgeEm()
{
if (NS_FAILED(PTestBridgeMainSub::Bridge(gBridgeMainChild, this)))
fail("bridging Main and Sub");
return true;
}
void
TestBridgeSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
gBridgeMainChild->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.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestBridgeSubParent>(this)));
}
//-----------------------------------------------------------------------------
// subsub process --- child of sub
static TestBridgeSubChild* gBridgeSubChild;
TestBridgeSubChild::TestBridgeSubChild()
{
gBridgeSubChild = this;
}
bool
TestBridgeSubChild::RecvPing()
{
if (!SendBridgeEm())
fail("sending BridgeEm");
return true;
}
PTestBridgeMainSubChild*
TestBridgeSubChild::AllocPTestBridgeMainSubChild(Transport* transport,
ProcessId otherPid)
{
nsAutoPtr<TestBridgeMainSubChild> a(new TestBridgeMainSubChild(transport));
if (!a->Open(transport, otherPid, XRE_GetIOMessageLoop(), ipc::ChildSide)) {
return nullptr;
}
if (!a->SendHello())
fail("sending Hello");
return a.forget();
}
void
TestBridgeSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
bool
TestBridgeMainSubChild::RecvHi()
{
if (!SendHelloSync())
fail("sending HelloSync");
if (!CallHelloRpc())
fail("calling HelloRpc");
if (!mGotHi)
fail("didn't answer HiRpc");
// Need to close the channel without message-processing frames on
// the C++ stack
MessageLoop::current()->PostTask(
NewNonOwningRunnableMethod(this, &TestBridgeMainSubChild::Close));
return true;
}
bool
TestBridgeMainSubChild::AnswerHiRpc()
{
mGotHi = true; // d00d
return true;
}
void
TestBridgeMainSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
gBridgeSubChild->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.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestBridgeMainSubChild>(this)));
}
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,149 @@
#ifndef mozilla__ipdltest_TestBridgeMain_h
#define mozilla__ipdltest_TestBridgeMain_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestBridgeMainParent.h"
#include "mozilla/_ipdltest/PTestBridgeMainChild.h"
#include "mozilla/_ipdltest/PTestBridgeSubParent.h"
#include "mozilla/_ipdltest/PTestBridgeSubChild.h"
#include "mozilla/_ipdltest/PTestBridgeMainSubParent.h"
#include "mozilla/_ipdltest/PTestBridgeMainSubChild.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// "Main" process
//
class TestBridgeMainParent :
public PTestBridgeMainParent
{
public:
TestBridgeMainParent() {}
virtual ~TestBridgeMainParent() {}
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual PTestBridgeMainSubParent*
AllocPTestBridgeMainSubParent(Transport* transport,
ProcessId otherProcess) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
class TestBridgeMainSubParent :
public PTestBridgeMainSubParent
{
public:
explicit TestBridgeMainSubParent(Transport* aTransport)
: mTransport(aTransport)
{}
virtual ~TestBridgeMainSubParent() {}
protected:
virtual bool RecvHello() override;
virtual bool RecvHelloSync() override;
virtual bool AnswerHelloRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
Transport* mTransport;
};
//-----------------------------------------------------------------------------
// "Sub" process --- child of "main"
//
class TestBridgeSubParent;
class TestBridgeMainChild :
public PTestBridgeMainChild
{
public:
TestBridgeMainChild();
virtual ~TestBridgeMainChild() {}
protected:
virtual bool RecvStart() override;
virtual PTestBridgeMainSubChild*
AllocPTestBridgeMainSubChild(Transport* transport,
ProcessId otherProcess) override
{
// This shouldn't be called. It's just a byproduct of testing that
// the right code is generated for a bridged protocol that's also
// opened, but we only test bridging here.
MOZ_CRASH();
}
virtual void ActorDestroy(ActorDestroyReason why) override;
IPDLUnitTestSubprocess* mSubprocess;
};
class TestBridgeSubParent :
public PTestBridgeSubParent
{
public:
TestBridgeSubParent() {}
virtual ~TestBridgeSubParent() {}
void Main();
protected:
virtual bool RecvBridgeEm() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
//-----------------------------------------------------------------------------
// "Subsub" process --- child of "sub"
//
class TestBridgeSubChild :
public PTestBridgeSubChild
{
public:
TestBridgeSubChild();
virtual ~TestBridgeSubChild() {}
protected:
virtual bool RecvPing() override;
virtual PTestBridgeMainSubChild*
AllocPTestBridgeMainSubChild(Transport* transport,
ProcessId otherProcess) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
class TestBridgeMainSubChild :
public PTestBridgeMainSubChild
{
public:
explicit TestBridgeMainSubChild(Transport* aTransport)
: mGotHi(false)
, mTransport(aTransport)
{}
virtual ~TestBridgeMainSubChild() {}
protected:
virtual bool RecvHi() override;
virtual bool AnswerHiRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
bool mGotHi;
Transport* mTransport;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestBridgeMain_h

View file

@ -0,0 +1,168 @@
#include "TestCancel.h"
#include "IPDLUnitTests.h" // fail etc.
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
TestCancelParent::TestCancelParent()
{
MOZ_COUNT_CTOR(TestCancelParent);
}
TestCancelParent::~TestCancelParent()
{
MOZ_COUNT_DTOR(TestCancelParent);
}
void
TestCancelParent::Main()
{
if (SendTest1_1())
fail("sending Test1_1");
uint32_t value = 0;
if (!SendCheckChild(&value))
fail("Test1 CheckChild");
if (value != 12)
fail("Test1 CheckChild reply");
}
bool
TestCancelParent::RecvDone1()
{
if (!SendStart2())
fail("sending Start2");
return true;
}
bool
TestCancelParent::RecvTest2_1()
{
if (SendTest2_2())
fail("sending Test2_2");
return true;
}
bool
TestCancelParent::RecvStart3()
{
if (SendTest3_1())
fail("sending Test3_1");
uint32_t value = 0;
if (!SendCheckChild(&value))
fail("Test1 CheckChild");
if (value != 12)
fail("Test1 CheckChild reply");
return true;
}
bool
TestCancelParent::RecvTest3_2()
{
GetIPCChannel()->CancelCurrentTransaction();
return true;
}
bool
TestCancelParent::RecvDone()
{
MessageLoop::current()->PostTask(
NewNonOwningRunnableMethod(this, &TestCancelParent::Close));
return true;
}
bool
TestCancelParent::RecvCheckParent(uint32_t *reply)
{
*reply = 12;
return true;
}
//-----------------------------------------------------------------------------
// child
bool
TestCancelChild::RecvTest1_1()
{
GetIPCChannel()->CancelCurrentTransaction();
uint32_t value = 0;
if (!SendCheckParent(&value))
fail("Test1 CheckParent");
if (value != 12)
fail("Test1 CheckParent reply");
if (!SendDone1())
fail("Test1 CheckParent");
return true;
}
bool
TestCancelChild::RecvStart2()
{
if (!SendTest2_1())
fail("sending Test2_1");
if (!SendStart3())
fail("sending Start3");
return true;
}
bool
TestCancelChild::RecvTest2_2()
{
GetIPCChannel()->CancelCurrentTransaction();
return true;
}
bool
TestCancelChild::RecvTest3_1()
{
if (SendTest3_2())
fail("sending Test3_2");
uint32_t value = 0;
if (!SendCheckParent(&value))
fail("Test1 CheckParent");
if (value != 12)
fail("Test1 CheckParent reply");
if (!SendDone())
fail("sending Done");
return true;
}
bool
TestCancelChild::RecvCheckChild(uint32_t *reply)
{
*reply = 12;
return true;
}
TestCancelChild::TestCancelChild()
{
MOZ_COUNT_CTOR(TestCancelChild);
}
TestCancelChild::~TestCancelChild()
{
MOZ_COUNT_DTOR(TestCancelChild);
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,66 @@
#ifndef mozilla__ipdltest_TestCancel_h
#define mozilla__ipdltest_TestCancel_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestCancelParent.h"
#include "mozilla/_ipdltest/PTestCancelChild.h"
namespace mozilla {
namespace _ipdltest {
class TestCancelParent :
public PTestCancelParent
{
public:
TestCancelParent();
virtual ~TestCancelParent();
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
virtual bool RecvDone1() override;
virtual bool RecvTest2_1() override;
virtual bool RecvStart3() override;
virtual bool RecvTest3_2() override;
virtual bool RecvDone() override;
virtual bool RecvCheckParent(uint32_t *reply) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
passed("ok");
QuitParent();
}
};
class TestCancelChild :
public PTestCancelChild
{
public:
TestCancelChild();
virtual ~TestCancelChild();
virtual bool RecvTest1_1() override;
virtual bool RecvStart2() override;
virtual bool RecvTest2_2() override;
virtual bool RecvTest3_1() override;
virtual bool RecvCheckChild(uint32_t *reply) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
QuitChild();
}
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestCancel_h

View file

@ -0,0 +1,116 @@
#include "TestCrashCleanup.h"
#include "base/task.h"
#include "mozilla/CondVar.h"
#include "mozilla/Mutex.h"
#include "IPDLUnitTests.h" // fail etc.
#include "IPDLUnitTestSubprocess.h"
using mozilla::CondVar;
using mozilla::Mutex;
using mozilla::MutexAutoLock;
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(Mutex* mutex, CondVar* cvar)
{
MutexAutoLock lock(*mutex);
delete gSubprocess;
gSubprocess = nullptr;
cvar->Notify();
}
void DeleteTheWorld()
{
delete static_cast<TestCrashCleanupParent*>(gParentActor);
gParentActor = nullptr;
// needs to be synchronous to avoid affecting event ordering on
// the main thread
Mutex mutex("TestCrashCleanup.DeleteTheWorld.mutex");
CondVar cvar(mutex, "TestCrashCleanup.DeleteTheWorld.cvar");
MutexAutoLock lock(mutex);
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction(DeleteSubprocess, &mutex, &cvar));
cvar.Wait();
}
void Done()
{
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
nsCOMPtr<nsIAppShell> appShell (do_GetService(kAppShellCID));
appShell->Exit();
passed(__FILE__);
}
} // namespace <anon>
TestCrashCleanupParent::TestCrashCleanupParent() : mCleanedUp(false)
{
MOZ_COUNT_CTOR(TestCrashCleanupParent);
}
TestCrashCleanupParent::~TestCrashCleanupParent()
{
MOZ_COUNT_DTOR(TestCrashCleanupParent);
if (!mCleanedUp)
fail("should have been ActorDestroy()d!");
}
void
TestCrashCleanupParent::Main()
{
// NB: has to be enqueued before IO thread's error notification
MessageLoop::current()->PostTask(
NewRunnableFunction(DeleteTheWorld));
if (CallDIEDIEDIE())
fail("expected an error!");
Close();
MessageLoop::current()->PostTask(NewRunnableFunction(Done));
}
//-----------------------------------------------------------------------------
// child
TestCrashCleanupChild::TestCrashCleanupChild()
{
MOZ_COUNT_CTOR(TestCrashCleanupChild);
}
TestCrashCleanupChild::~TestCrashCleanupChild()
{
MOZ_COUNT_DTOR(TestCrashCleanupChild);
}
bool
TestCrashCleanupChild::AnswerDIEDIEDIE()
{
_exit(0);
NS_RUNTIMEABORT("unreached");
return false;
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,58 @@
#ifndef mozilla__ipdltest_TestCrashCleanup_h
#define mozilla__ipdltest_TestCrashCleanup_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestCrashCleanupParent.h"
#include "mozilla/_ipdltest/PTestCrashCleanupChild.h"
namespace mozilla {
namespace _ipdltest {
class TestCrashCleanupParent :
public PTestCrashCleanupParent
{
public:
TestCrashCleanupParent();
virtual ~TestCrashCleanupParent();
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (AbnormalShutdown != why)
fail("unexpected destruction!");
mCleanedUp = true;
}
bool mCleanedUp;
};
class TestCrashCleanupChild :
public PTestCrashCleanupChild
{
public:
TestCrashCleanupChild();
virtual ~TestCrashCleanupChild();
protected:
virtual bool AnswerDIEDIEDIE() override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
fail("should have 'crashed'!");
}
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestCrashCleanup_h

View file

@ -0,0 +1,984 @@
#include "TestDataStructures.h"
#include "mozilla/Unused.h"
#include "IPDLUnitTests.h" // fail etc.
typedef InfallibleTArray<nsIntRegion> RegionArray;
namespace mozilla {
namespace _ipdltest {
static const uint32_t nactors = 10;
#define test_assert(_cond, _msg) \
if (!(_cond)) fail(_msg)
template<typename T>
static void
assert_arrays_equal(const InfallibleTArray<T>& a, const InfallibleTArray<T>& b)
{
test_assert(a == b, "arrays equal");
}
inline static TestDataStructuresSub&
Cast(PTestDataStructuresSubParent* a)
{
return *static_cast<TestDataStructuresSub*>(a);
}
inline static TestDataStructuresSub&
Cast(PTestDataStructuresSubChild* a)
{
return *static_cast<TestDataStructuresSub*>(a);
}
//-----------------------------------------------------------------------------
// parent
TestDataStructuresParent::TestDataStructuresParent()
{
MOZ_COUNT_CTOR(TestDataStructuresParent);
}
TestDataStructuresParent::~TestDataStructuresParent()
{
MOZ_COUNT_DTOR(TestDataStructuresParent);
}
void
TestDataStructuresParent::Main()
{
for (uint32_t i = 0; i < nactors; ++i)
if (!SendPTestDataStructuresSubConstructor(i))
fail("can't alloc actor");
if (!SendStart())
fail("can't send Start()");
}
bool
TestDataStructuresParent::DeallocPTestDataStructuresSubParent(PTestDataStructuresSubParent* actor)
{
test_assert(Cast(actor).mI == Cast(mKids[0]).mI,
"dtor sent to wrong actor");
mKids.RemoveElementAt(0);
delete actor;
if (mKids.Length() > 0)
return true;
return true;
}
bool TestDataStructuresParent::RecvTest1(
InfallibleTArray<int>&& ia,
InfallibleTArray<int>* oa)
{
test_assert(5 == ia.Length(), "wrong length");
for (int i = 0; i < 5; ++i)
test_assert(i == ia[i], "wrong value");
*oa = ia;
return true;
}
bool TestDataStructuresParent::RecvTest2(
InfallibleTArray<PTestDataStructuresSubParent*>&& i1,
InfallibleTArray<PTestDataStructuresSubParent*>* o1)
{
test_assert(nactors == i1.Length(), "wrong #actors");
for (uint32_t i = 0; i < i1.Length(); ++i)
test_assert(i == Cast(i1[i]).mI, "wrong mI value");
*o1 = i1;
return true;
}
bool TestDataStructuresParent::RecvTest3(
const IntDouble& i1,
const IntDouble& i2,
IntDouble* o1,
IntDouble* o2)
{
test_assert(42 == i1.get_int(), "wrong value");
test_assert(4.0 == i2.get_double(), "wrong value");
*o1 = i1;
*o2 = i2;
return true;
}
bool TestDataStructuresParent::RecvTest4(
InfallibleTArray<IntDouble>&& i1,
InfallibleTArray<IntDouble>* o1)
{
test_assert(4 == i1.Length(), "wrong length");
test_assert(1 == i1[0].get_int(), "wrong value");
test_assert(2.0 == i1[1].get_double(), "wrong value");
test_assert(3 == i1[2].get_int(), "wrong value");
test_assert(4.0 == i1[3].get_double(), "wrong value");
*o1 = i1;
return true;
}
bool TestDataStructuresParent::RecvTest5(
const IntDoubleArrays& i1,
const IntDoubleArrays& i2,
const IntDoubleArrays& i3,
IntDoubleArrays* o1,
IntDoubleArrays* o2,
IntDoubleArrays* o3)
{
test_assert(42 == i1.get_int(), "wrong value");
const InfallibleTArray<int>& i2a = i2.get_ArrayOfint();
test_assert(3 == i2a.Length(), "wrong length");
test_assert(1 == i2a[0], "wrong value");
test_assert(2 == i2a[1], "wrong value");
test_assert(3 == i2a[2], "wrong value");
const InfallibleTArray<double>& i3a = i3.get_ArrayOfdouble();
test_assert(3 == i3a.Length(), "wrong length");
test_assert(1.0 == i3a[0], "wrong value");
test_assert(2.0 == i3a[1], "wrong value");
test_assert(3.0 == i3a[2], "wrong value");
*o1 = i1;
*o2 = i2a;
*o3 = i3a;
return true;
}
bool
TestDataStructuresParent::RecvTest7_0(const ActorWrapper& i1,
ActorWrapper* o1)
{
if (i1.actorChild() != nullptr)
fail("child side actor should always be null");
if (i1.actorParent() != mKids[0])
fail("should have got back same actor on parent side");
o1->actorParent() = mKids[0];
// malicious behavior
o1->actorChild() =
reinterpret_cast<PTestDataStructuresSubChild*>(uintptr_t(0xdeadbeef));
return true;
}
bool TestDataStructuresParent::RecvTest6(
InfallibleTArray<IntDoubleArrays>&& i1,
InfallibleTArray<IntDoubleArrays>* o1)
{
test_assert(3 == i1.Length(), "wrong length");
IntDoubleArrays id1(i1[0]);
test_assert(42 == id1.get_int(), "wrong value");
InfallibleTArray<int> i2a(i1[1].get_ArrayOfint());
test_assert(3 == i2a.Length(), "wrong length");
test_assert(1 == i2a[0], "wrong value");
test_assert(2 == i2a[1], "wrong value");
test_assert(3 == i2a[2], "wrong value");
InfallibleTArray<double> i3a(i1[2].get_ArrayOfdouble());
test_assert(3 == i3a.Length(), "wrong length");
test_assert(1.0 == i3a[0], "wrong value");
test_assert(2.0 == i3a[1], "wrong value");
test_assert(3.0 == i3a[2], "wrong value");
o1->AppendElement(id1);
o1->AppendElement(IntDoubleArrays(i2a));
o1->AppendElement(IntDoubleArrays(i3a));
return true;
}
bool TestDataStructuresParent::RecvTest7(
const Actors& i1,
const Actors& i2,
const Actors& i3,
Actors* o1,
Actors* o2,
Actors* o3)
{
test_assert(42 == i1.get_int(), "wrong value");
InfallibleTArray<int> i2a(i2.get_ArrayOfint());
test_assert(3 == i2a.Length(), "wrong length");
test_assert(1 == i2a[0], "wrong value");
test_assert(2 == i2a[1], "wrong value");
test_assert(3 == i2a[2], "wrong value");
assert_arrays_equal(mKids, i3.get_ArrayOfPTestDataStructuresSubParent());
*o1 = 42;
*o2 = i2a;
*o3 = mKids;
return true;
}
bool TestDataStructuresParent::RecvTest8(
InfallibleTArray<Actors>&& i1,
InfallibleTArray<Actors>* o1)
{
test_assert(3 == i1.Length(), "wrong length");
test_assert(42 == i1[0].get_int(), "wrong value");
const InfallibleTArray<int>& i2a = i1[1].get_ArrayOfint();
test_assert(3 == i2a.Length(), "wrong length");
test_assert(1 == i2a[0], "wrong value");
test_assert(2 == i2a[1], "wrong value");
test_assert(3 == i2a[2], "wrong value");
assert_arrays_equal(mKids, i1[2].get_ArrayOfPTestDataStructuresSubParent());
*o1 = i1;
return true;
}
bool TestDataStructuresParent::RecvTest9(
const Unions& i1,
const Unions& i2,
const Unions& i3,
const Unions& i4,
Unions* o1,
Unions* o2,
Unions* o3,
Unions* o4)
{
test_assert(42 == i1.get_int(), "wrong value");
const InfallibleTArray<int>& i2a = i2.get_ArrayOfint();
test_assert(3 == i2a.Length(), "wrong length");
test_assert(1 == i2a[0], "wrong value");
test_assert(2 == i2a[1], "wrong value");
test_assert(3 == i2a[2], "wrong value");
assert_arrays_equal(mKids, i3.get_ArrayOfPTestDataStructuresSubParent());
const InfallibleTArray<PTestDataStructuresSubParent*>& i4a =
i4.get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubParent();
assert_arrays_equal(mKids, i4a);
*o1 = i1;
*o2 = i2;
*o3 = i3;
*o4 = i4;
return true;
}
bool TestDataStructuresParent::RecvTest10(
InfallibleTArray<Unions>&& i1,
InfallibleTArray<Unions>* o1)
{
test_assert(42 == i1[0].get_int(), "wrong value");
const InfallibleTArray<int>& i2a = i1[1].get_ArrayOfint();
test_assert(3 == i2a.Length(), "wrong length");
test_assert(1 == i2a[0], "wrong value");
test_assert(2 == i2a[1], "wrong value");
test_assert(3 == i2a[2], "wrong value");
assert_arrays_equal(mKids, i1[2].get_ArrayOfPTestDataStructuresSubParent());
const InfallibleTArray<PTestDataStructuresSubParent*>& i4a =
i1[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubParent();
assert_arrays_equal(mKids, i4a);
*o1 = i1;
return true;
}
bool TestDataStructuresParent::RecvTest11(
const SIntDouble& i,
SIntDouble* o)
{
test_assert(1 == i.i(), "wrong value");
test_assert(2.0 == i.d(), "wrong value");
*o = i;
return true;
}
bool TestDataStructuresParent::RecvTest12(
const SIntDoubleArrays& i,
SIntDoubleArrays* o)
{
InfallibleTArray<int> ai;
ai.AppendElement(1);
ai.AppendElement(2);
ai.AppendElement(3);
InfallibleTArray<double> ad;
ad.AppendElement(.5);
ad.AppendElement(1.0);
ad.AppendElement(2.0);
test_assert(42 == i.i(), "wrong value");
assert_arrays_equal(ai, i.ai());
assert_arrays_equal(ad, i.ad());
*o = i;
return true;
}
bool TestDataStructuresParent::RecvTest13(
const SActors& i,
SActors* o)
{
InfallibleTArray<int> ai;
ai.AppendElement(1); ai.AppendElement(2); ai.AppendElement(3);
test_assert(42 == i.i(), "wrong value");
assert_arrays_equal(ai, i.ai());
assert_arrays_equal(mKids, i.apParent());
*o = i;
return true;
}
bool TestDataStructuresParent::RecvTest14(
const Structs& i,
Structs* o)
{
InfallibleTArray<int> ai;
ai.AppendElement(1); ai.AppendElement(2); ai.AppendElement(3);
test_assert(42 == i.i(), "wrong value");
assert_arrays_equal(ai, i.ai());
assert_arrays_equal(mKids, i.apParent());
const SActors& ia = i.aa()[0];
test_assert(42 == ia.i(), "wrong value");
assert_arrays_equal(ai, ia.ai());
assert_arrays_equal(mKids, ia.apParent());
*o = i;
return true;
}
bool TestDataStructuresParent::RecvTest15(
const WithStructs& i1,
const WithStructs& i2,
const WithStructs& i3,
const WithStructs& i4,
const WithStructs& i5,
WithStructs* o1,
WithStructs* o2,
WithStructs* o3,
WithStructs* o4,
WithStructs* o5)
{
InfallibleTArray<int> ai;
ai.AppendElement(1); ai.AppendElement(2); ai.AppendElement(3);
test_assert(i1 == int(42), "wrong value");
assert_arrays_equal(i2.get_ArrayOfint(), ai);
assert_arrays_equal(i3.get_ArrayOfPTestDataStructuresSubParent(), mKids);
const SActors& ia = i4.get_ArrayOfSActors()[0];
test_assert(42 == ia.i(), "wrong value");
assert_arrays_equal(ai, ia.ai());
assert_arrays_equal(mKids, ia.apParent());
const Structs& is = i5.get_ArrayOfStructs()[0];
test_assert(42 == is.i(), "wrong value");
assert_arrays_equal(ai, is.ai());
assert_arrays_equal(mKids, is.apParent());
const SActors& isa = is.aa()[0];
test_assert(42 == isa.i(), "wrong value");
assert_arrays_equal(ai, isa.ai());
assert_arrays_equal(mKids, isa.apParent());
*o1 = i1;
*o2 = i2;
*o3 = i3;
*o4 = i4;
*o5 = i5;
return true;
}
bool TestDataStructuresParent::RecvTest16(
const WithUnions& i,
WithUnions* o)
{
test_assert(i.i() == 42, "wrong value");
InfallibleTArray<int> ai;
ai.AppendElement(1); ai.AppendElement(2); ai.AppendElement(3);
assert_arrays_equal(ai, i.ai());
assert_arrays_equal(i.apParent(), mKids);
assert_arrays_equal(mKids, i.aa()[0].get_ArrayOfPTestDataStructuresSubParent());
const InfallibleTArray<Unions>& iau = i.au();
test_assert(iau[0] == 42, "wrong value");
assert_arrays_equal(ai, iau[1].get_ArrayOfint());
assert_arrays_equal(mKids, iau[2].get_ArrayOfPTestDataStructuresSubParent());
assert_arrays_equal(mKids,
iau[3].get_ArrayOfActors()[0]
.get_ArrayOfPTestDataStructuresSubParent());
*o = i;
return true;
}
bool TestDataStructuresParent::RecvTest17(InfallibleTArray<Op>&& sa)
{
test_assert(sa.Length() == 1 && Op::TSetAttrs == sa[0].type(),
"wrong value");
return true;
}
bool TestDataStructuresParent::RecvTest18(RegionArray&& ra)
{
for (RegionArray::index_type i = 0; i < ra.Length(); ++i) {
// if |ra| has been realloc()d and given a different allocator
// chunk, this loop will nondeterministically crash or iloop.
for (auto iter = ra[i].RectIter(); !iter.Done(); iter.Next()) {
Unused << iter.Get();
}
}
return true;
}
//-----------------------------------------------------------------------------
// child
TestDataStructuresChild::TestDataStructuresChild()
{
MOZ_COUNT_CTOR(TestDataStructuresChild);
}
TestDataStructuresChild::~TestDataStructuresChild()
{
MOZ_COUNT_DTOR(TestDataStructuresChild);
}
bool
TestDataStructuresChild::RecvStart()
{
puts("[TestDataStructuresChild] starting");
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7_0();
Test7();
Test8();
Test9();
Test10();
Test11();
Test12();
Test13();
Test14();
Test15();
Test16();
Test17();
if (OtherPid() != base::GetCurrentProcId()) {
//FIXME/bug 703317 allocation of nsIntRegion uses a global
//region pool which breaks threads
Test18();
}
for (uint32_t i = 0; i < nactors; ++i)
if (!PTestDataStructuresSubChild::Send__delete__(mKids[i]))
fail("can't send dtor");
Close();
return true;
}
void
TestDataStructuresChild::Test1()
{
InfallibleTArray<int> ia;
for (int i = 0; i < 5; ++i)
ia.AppendElement(i);
InfallibleTArray<int> oa;
if (!SendTest1(ia, &oa))
fail("can't send Test1");
assert_arrays_equal(ia, oa);
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test2()
{
InfallibleTArray<PTestDataStructuresSubChild*> oa;
if (!SendTest2(mKids, &oa))
fail("can't send Test2");
assert_arrays_equal(mKids, oa);
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test3()
{
int i1i = 42;
double i2d = 4.0;
IntDouble i1(i1i);
IntDouble i2(i2d);
IntDouble o1, o2;
SendTest3(i1, i2, &o1, &o2);
test_assert(i1i == o1.get_int(), "wrong value");
test_assert(i2d == o2.get_double(), "wrong value");
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test4()
{
InfallibleTArray<IntDouble> i1;
i1.AppendElement(IntDouble(int(1)));
i1.AppendElement(IntDouble(2.0));
i1.AppendElement(IntDouble(int(3)));
i1.AppendElement(IntDouble(4.0));
InfallibleTArray<IntDouble> o1;
if (!SendTest4(i1, &o1))
fail("can't send Test4");
// TODO Union::operator==()
test_assert(i1.Length() == o1.Length(), "wrong length");
test_assert(1 == o1[0].get_int(), "wrong value");
test_assert(2.0 == o1[1].get_double(), "wrong value");
test_assert(3 == o1[2].get_int(), "wrong value");
test_assert(4.0 == o1[3].get_double(), "wrong value");
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test5()
{
IntDoubleArrays i1(int(42));
InfallibleTArray<int> i2;
i2.AppendElement(1); i2.AppendElement(2); i2.AppendElement(3);
InfallibleTArray<double> i3;
i3.AppendElement(1.0); i3.AppendElement(2.0); i3.AppendElement(3.0);
IntDoubleArrays o1, o2, o3;
if (!SendTest5(i1, IntDoubleArrays(i2), IntDoubleArrays(i3),
&o1, &o2, &o3))
fail("can't send Test5");
test_assert(42 == o1.get_int(), "wrong value");
assert_arrays_equal(i2, o2.get_ArrayOfint());
assert_arrays_equal(i3, o3.get_ArrayOfdouble());
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test6()
{
IntDoubleArrays id1(int(42));
InfallibleTArray<int> id2;
id2.AppendElement(1); id2.AppendElement(2); id2.AppendElement(3);
InfallibleTArray<double> id3;
id3.AppendElement(1.0); id3.AppendElement(2.0); id3.AppendElement(3.0);
InfallibleTArray<IntDoubleArrays> i1;
i1.AppendElement(id1);
i1.AppendElement(IntDoubleArrays(id2));
i1.AppendElement(IntDoubleArrays(id3));
InfallibleTArray<IntDoubleArrays> o1;
if (!SendTest6(i1, &o1))
fail("can't send Test6");
test_assert(3 == o1.Length(), "wrong length");
IntDoubleArrays od1(o1[0]);
InfallibleTArray<int> od2(o1[1].get_ArrayOfint());
InfallibleTArray<double> od3(o1[2].get_ArrayOfdouble());
test_assert(42 == od1.get_int(), "wrong value");
assert_arrays_equal(id2, od2);
assert_arrays_equal(id3, od3);
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test7_0()
{
ActorWrapper iaw;
if (iaw.actorChild() != nullptr || iaw.actorParent() != nullptr)
fail("actor members should be null initially");
iaw.actorChild() = mKids[0];
if (iaw.actorParent() != nullptr)
fail("parent should be null on child side after set");
ActorWrapper oaw;
if (!SendTest7_0(iaw, &oaw))
fail("sending Test7_0");
if (oaw.actorParent() != nullptr)
fail("parent accessor on actor-struct members should always be null in child");
if (oaw.actorChild() != mKids[0])
fail("should have got back same child-side actor");
}
void
TestDataStructuresChild::Test7()
{
Actors i1(42);
InfallibleTArray<int> i2a;
i2a.AppendElement(1); i2a.AppendElement(2); i2a.AppendElement(3);
Actors o1, o2, o3;
if (!SendTest7(i1, Actors(i2a), Actors(mKids), &o1, &o2, &o3))
fail("can't send Test7");
test_assert(42 == o1.get_int(), "wrong value");
assert_arrays_equal(i2a, o2.get_ArrayOfint());
assert_arrays_equal(mKids, o3.get_ArrayOfPTestDataStructuresSubChild());
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test8()
{
Actors i1e(42);
InfallibleTArray<int> i2a;
i2a.AppendElement(1); i2a.AppendElement(2); i2a.AppendElement(3);
InfallibleTArray<Actors> i1;
i1.AppendElement(i1e);
i1.AppendElement(i2a);
i1.AppendElement(mKids);
InfallibleTArray<Actors> o1;
if (!SendTest8(i1, &o1))
fail("can't send Test8");
test_assert(3 == o1.Length(), "wrong length");
test_assert(42 == o1[0].get_int(), "wrong value");
assert_arrays_equal(i2a, o1[1].get_ArrayOfint());
assert_arrays_equal(mKids, o1[2].get_ArrayOfPTestDataStructuresSubChild());
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test9()
{
Unions i1(int(42));
InfallibleTArray<int> i2a;
i2a.AppendElement(1);
i2a.AppendElement(2);
i2a.AppendElement(3);
InfallibleTArray<Actors> i4a;
i4a.AppendElement(mKids);
Unions o1, o2, o3, o4;
if (!SendTest9(i1, Unions(i2a), Unions(mKids), Unions(i4a),
&o1, &o2, &o3, &o4))
fail("can't send Test9");
test_assert(42 == o1.get_int(), "wrong value");
assert_arrays_equal(i2a, o2.get_ArrayOfint());
assert_arrays_equal(mKids, o3.get_ArrayOfPTestDataStructuresSubChild());
assert_arrays_equal(
mKids,
o4.get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubChild());
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test10()
{
Unions i1a(int(42));
InfallibleTArray<int> i2a;
i2a.AppendElement(1);
i2a.AppendElement(2);
i2a.AppendElement(3);
InfallibleTArray<Actors> i4a;
i4a.AppendElement(mKids);
InfallibleTArray<Unions> i1;
i1.AppendElement(i1a);
i1.AppendElement(Unions(i2a));
i1.AppendElement(Unions(mKids));
i1.AppendElement(Unions(i4a));
InfallibleTArray<Unions> o1;
if (!SendTest10(i1, &o1))
fail("can't send Test10");
test_assert(4 == o1.Length(), "wrong length");
test_assert(42 == o1[0].get_int(), "wrong value");
assert_arrays_equal(i2a, o1[1].get_ArrayOfint());
assert_arrays_equal(mKids, o1[2].get_ArrayOfPTestDataStructuresSubChild());
assert_arrays_equal(
mKids,
o1[3].get_ArrayOfActors()[0].get_ArrayOfPTestDataStructuresSubChild());
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test11()
{
SIntDouble i(1, 2.0);
SIntDouble o;
if (!SendTest11(i, &o))
fail("sending Test11");
test_assert(1 == o.i() && 2.0 == o.d(), "wrong values");
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test12()
{
InfallibleTArray<int> ai;
ai.AppendElement(1); ai.AppendElement(2); ai.AppendElement(3);
InfallibleTArray<double> ad;
ad.AppendElement(.5); ad.AppendElement(1.0); ad.AppendElement(2.0);
SIntDoubleArrays i(42, ai, ad);
SIntDoubleArrays o;
if (!SendTest12(i, &o))
fail("sending Test12");
test_assert(42 == o.i(), "wrong value");
assert_arrays_equal(ai, o.ai());
assert_arrays_equal(ad, o.ad());
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test13()
{
InfallibleTArray<int> ai;
ai.AppendElement(1); ai.AppendElement(2); ai.AppendElement(3);
SActors i;
i.i() = 42;
i.ai() = ai;
i.apChild() = mKids;
SActors o;
if (!SendTest13(i, &o))
fail("can't send Test13");
test_assert(42 == o.i(), "wrong value");
assert_arrays_equal(ai, o.ai());
assert_arrays_equal(mKids, o.apChild());
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test14()
{
InfallibleTArray<int> ai;
ai.AppendElement(1); ai.AppendElement(2); ai.AppendElement(3);
SActors ia;
ia.i() = 42;
ia.ai() = ai;
ia.apChild() = mKids;
InfallibleTArray<SActors> aa; aa.AppendElement(ia);
Structs i;
i.i() = 42;
i.ai() = ai;
i.apChild() = mKids;
i.aa() = aa;
Structs o;
if (!SendTest14(i, &o))
fail("can't send Test14");
test_assert(42 == o.i(), "wrong value");
assert_arrays_equal(ai, o.ai());
assert_arrays_equal(mKids, o.apChild());
const SActors& os = o.aa()[0];
test_assert(42 == os.i(), "wrong value");
assert_arrays_equal(ai, os.ai());
assert_arrays_equal(mKids, os.apChild());
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test15()
{
InfallibleTArray<int> ai;
ai.AppendElement(1); ai.AppendElement(2); ai.AppendElement(3);
SActors ia;
ia.i() = 42;
ia.ai() = ai;
ia.apChild() = mKids;
InfallibleTArray<SActors> iaa; iaa.AppendElement(ia);
Structs is;
is.i() = 42;
is.ai() = ai;
is.apChild() = mKids;
is.aa() = iaa;
InfallibleTArray<Structs> isa; isa.AppendElement(is);
WithStructs o1, o2, o3, o4, o5;
if (!SendTest15(WithStructs(42),
WithStructs(ai),
WithStructs(mKids),
WithStructs(iaa),
WithStructs(isa),
&o1, &o2, &o3, &o4, &o5))
fail("sending Test15");
test_assert(o1 == int(42), "wrong value");
assert_arrays_equal(o2.get_ArrayOfint(), ai);
assert_arrays_equal(o3.get_ArrayOfPTestDataStructuresSubChild(), mKids);
const SActors& oa = o4.get_ArrayOfSActors()[0];
test_assert(42 == oa.i(), "wrong value");
assert_arrays_equal(ai, oa.ai());
assert_arrays_equal(mKids, oa.apChild());
const Structs& os = o5.get_ArrayOfStructs()[0];
test_assert(42 == os.i(), "wrong value");
assert_arrays_equal(ai, os.ai());
assert_arrays_equal(mKids, os.apChild());
const SActors& osa = os.aa()[0];
test_assert(42 == osa.i(), "wrong value");
assert_arrays_equal(ai, osa.ai());
assert_arrays_equal(mKids, osa.apChild());
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test16()
{
WithUnions i;
i.i() = 42;
InfallibleTArray<int> ai;
ai.AppendElement(1); ai.AppendElement(2); ai.AppendElement(3);
i.ai() = ai;
i.apChild() = mKids;
InfallibleTArray<Actors> iaa;
iaa.AppendElement(mKids);
i.aa() = iaa;
InfallibleTArray<Unions> iau;
iau.AppendElement(int(42));
iau.AppendElement(ai);
iau.AppendElement(mKids);
iau.AppendElement(iaa);
i.au() = iau;
WithUnions o;
if (!SendTest16(i, &o))
fail("sending Test16");
test_assert(42 == o.i(), "wrong value");
assert_arrays_equal(o.ai(), ai);
assert_arrays_equal(o.apChild(), mKids);
const Actors& oaa = o.aa()[0];
assert_arrays_equal(oaa.get_ArrayOfPTestDataStructuresSubChild(), mKids);
const InfallibleTArray<Unions>& oau = o.au();
test_assert(oau[0] == 42, "wrong value");
assert_arrays_equal(oau[1].get_ArrayOfint(), ai);
assert_arrays_equal(oau[2].get_ArrayOfPTestDataStructuresSubChild(),
mKids);
assert_arrays_equal(oau[3].get_ArrayOfActors()[0]
.get_ArrayOfPTestDataStructuresSubChild(),
mKids);
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test17()
{
Attrs attrs;
attrs.common() = CommonAttrs(true);
attrs.specific() = BarAttrs(1.0f);
InfallibleTArray<Op> ops;
ops.AppendElement(SetAttrs(nullptr, mKids[0], attrs));
if (!SendTest17(ops))
fail("sending Test17");
printf(" passed %s\n", __FUNCTION__);
}
void
TestDataStructuresChild::Test18()
{
const int nelements = 1000;
RegionArray ra;
// big enough to hopefully force a realloc to a different chunk of
// memory on the receiving side, if the workaround isn't working
// correctly. But SetCapacity() here because we don't want to
// crash on the sending side.
ra.SetCapacity(nelements);
for (int i = 0; i < nelements; ++i) {
nsIntRegion r;
r.Or(nsIntRect(0, 0, 10, 10), nsIntRect(10, 10, 10, 10));
ra.AppendElement(r);
}
if (!SendTest18(ra))
fail("sending Test18");
printf(" passed %s\n", __FUNCTION__);
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,234 @@
#ifndef mozilla__ipdltest_TestDataStructures_h
#define mozilla__ipdltest_TestDataStructures_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestDataStructuresParent.h"
#include "mozilla/_ipdltest/PTestDataStructuresChild.h"
#include "mozilla/_ipdltest/PTestDataStructuresSubParent.h"
#include "mozilla/_ipdltest/PTestDataStructuresSubChild.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// Subprotocol actors
class TestDataStructuresSub :
public PTestDataStructuresSubParent,
public PTestDataStructuresSubChild
{
public:
explicit TestDataStructuresSub(uint32_t i) : mI(i)
{ }
virtual ~TestDataStructuresSub()
{ }
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (Deletion != why)
fail("unexpected destruction!");
}
uint32_t mI;
};
//-----------------------------------------------------------------------------
// Main actors
class TestDataStructuresParent :
public PTestDataStructuresParent
{
public:
TestDataStructuresParent();
virtual ~TestDataStructuresParent();
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return true; }
void Main();
protected:
virtual PTestDataStructuresSubParent* AllocPTestDataStructuresSubParent(const int& i) override
{
PTestDataStructuresSubParent* actor = new TestDataStructuresSub(i);
mKids.AppendElement(actor);
return actor;
}
virtual bool DeallocPTestDataStructuresSubParent(PTestDataStructuresSubParent* actor) override;
virtual bool RecvTest1(
InfallibleTArray<int>&& i1,
InfallibleTArray<int>* o1) override;
virtual bool RecvTest2(
InfallibleTArray<PTestDataStructuresSubParent*>&& i1,
InfallibleTArray<PTestDataStructuresSubParent*>* o1) override;
virtual bool RecvTest3(
const IntDouble& i1,
const IntDouble& i2,
IntDouble* o1,
IntDouble* o2) override;
virtual bool RecvTest4(
InfallibleTArray<IntDouble>&& i1,
InfallibleTArray<IntDouble>* o1) override;
virtual bool RecvTest5(
const IntDoubleArrays& i1,
const IntDoubleArrays& i2,
const IntDoubleArrays& i3,
IntDoubleArrays* o1,
IntDoubleArrays* o2,
IntDoubleArrays* o3) override;
virtual bool RecvTest6(
InfallibleTArray<IntDoubleArrays>&& i1,
InfallibleTArray<IntDoubleArrays>* o1) override;
virtual bool RecvTest7_0(const ActorWrapper& i1,
ActorWrapper* o1) override;
virtual bool RecvTest7(
const Actors& i1,
const Actors& i2,
const Actors& i3,
Actors* o1,
Actors* o2,
Actors* o3) override;
virtual bool RecvTest8(
InfallibleTArray<Actors>&& i1,
InfallibleTArray<Actors>* o1) override;
virtual bool RecvTest9(
const Unions& i1,
const Unions& i2,
const Unions& i3,
const Unions& i4,
Unions* o1,
Unions* o2,
Unions* o3,
Unions* o4) override;
virtual bool RecvTest10(
InfallibleTArray<Unions>&& i1,
InfallibleTArray<Unions>* o1) override;
virtual bool RecvTest11(
const SIntDouble& i,
SIntDouble* o) override;
virtual bool RecvTest12(
const SIntDoubleArrays& i,
SIntDoubleArrays* o) override;
virtual bool RecvTest13(
const SActors& i,
SActors* o) override;
virtual bool RecvTest14(
const Structs& i,
Structs* o) override;
virtual bool RecvTest15(
const WithStructs& i1,
const WithStructs& i2,
const WithStructs& i3,
const WithStructs& i4,
const WithStructs& i5,
WithStructs* o1,
WithStructs* o2,
WithStructs* o3,
WithStructs* o4,
WithStructs* o5) override;
virtual bool RecvTest16(
const WithUnions& i,
WithUnions* o) override;
virtual bool RecvTest17(InfallibleTArray<Op>&& sa) override;
virtual bool RecvTest18(InfallibleTArray<nsIntRegion>&& ra) override;
virtual bool RecvDummy(const ShmemUnion& su, ShmemUnion* rsu) override
{
*rsu = su;
return true;
}
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
private:
InfallibleTArray<PTestDataStructuresSubParent*> mKids;
};
class TestDataStructuresChild :
public PTestDataStructuresChild
{
public:
TestDataStructuresChild();
virtual ~TestDataStructuresChild();
protected:
virtual PTestDataStructuresSubChild* AllocPTestDataStructuresSubChild(const int& i) override
{
PTestDataStructuresSubChild* actor = new TestDataStructuresSub(i);
mKids.AppendElement(actor);
return actor;
}
virtual bool DeallocPTestDataStructuresSubChild(PTestDataStructuresSubChild* actor) override
{
delete actor;
return true;
}
virtual bool RecvStart() override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
private:
void Test1();
void Test2();
void Test3();
void Test4();
void Test5();
void Test6();
void Test7_0();
void Test7();
void Test8();
void Test9();
void Test10();
void Test11();
void Test12();
void Test13();
void Test14();
void Test15();
void Test16();
void Test17();
void Test18();
InfallibleTArray<PTestDataStructuresSubChild*> mKids;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestDataStructures_h

View file

@ -0,0 +1,417 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=4 ts=4 et :
*/
#include "TestDemon.h"
#include <stdlib.h>
#include "IPDLUnitTests.h" // fail etc.
#if defined(OS_POSIX)
#include <sys/time.h>
#include <unistd.h>
#else
#include <time.h>
#include <windows.h>
#endif
namespace mozilla {
namespace _ipdltest {
const int kMaxStackHeight = 4;
static LazyLogModule sLogModule("demon");
#define DEMON_LOG(...) MOZ_LOG(sLogModule, LogLevel::Debug, (__VA_ARGS__))
static int gStackHeight = 0;
static bool gFlushStack = false;
static int
Choose(int count)
{
#if defined(OS_POSIX)
return random() % count;
#else
return rand() % count;
#endif
}
//-----------------------------------------------------------------------------
// parent
TestDemonParent::TestDemonParent()
: mDone(false),
mIncoming(),
mOutgoing()
{
MOZ_COUNT_CTOR(TestDemonParent);
}
TestDemonParent::~TestDemonParent()
{
MOZ_COUNT_DTOR(TestDemonParent);
}
void
TestDemonParent::Main()
{
if (!getenv("MOZ_TEST_IPC_DEMON")) {
QuitParent();
return;
}
#if defined(OS_POSIX)
srandom(time(nullptr));
#else
srand(time(nullptr));
#endif
DEMON_LOG("Start demon");
if (!SendStart())
fail("sending Start");
RunUnlimitedSequence();
}
#ifdef DEBUG
bool
TestDemonParent::ShouldContinueFromReplyTimeout()
{
return Choose(2) == 0;
}
bool
TestDemonParent::ArtificialTimeout()
{
return Choose(5) == 0;
}
void
TestDemonParent::ArtificialSleep()
{
if (Choose(2) == 0) {
// Sleep for anywhere from 0 to 100 milliseconds.
unsigned micros = Choose(100) * 1000;
#ifdef OS_POSIX
usleep(micros);
#else
Sleep(micros / 1000);
#endif
}
}
#endif
bool
TestDemonParent::RecvAsyncMessage(const int& n)
{
DEMON_LOG("Start RecvAsync [%d]", n);
MOZ_ASSERT(n == mIncoming[0]);
mIncoming[0]++;
RunLimitedSequence();
DEMON_LOG("End RecvAsync [%d]", n);
return true;
}
bool
TestDemonParent::RecvHiPrioSyncMessage()
{
DEMON_LOG("Start RecvHiPrioSyncMessage");
RunLimitedSequence();
DEMON_LOG("End RecvHiPrioSyncMessage");
return true;
}
bool
TestDemonParent::RecvSyncMessage(const int& n)
{
DEMON_LOG("Start RecvSync [%d]", n);
MOZ_ASSERT(n == mIncoming[0]);
mIncoming[0]++;
RunLimitedSequence(ASYNC_ONLY);
DEMON_LOG("End RecvSync [%d]", n);
return true;
}
bool
TestDemonParent::RecvUrgentAsyncMessage(const int& n)
{
DEMON_LOG("Start RecvUrgentAsyncMessage [%d]", n);
MOZ_ASSERT(n == mIncoming[2]);
mIncoming[2]++;
RunLimitedSequence(ASYNC_ONLY);
DEMON_LOG("End RecvUrgentAsyncMessage [%d]", n);
return true;
}
bool
TestDemonParent::RecvUrgentSyncMessage(const int& n)
{
DEMON_LOG("Start RecvUrgentSyncMessage [%d]", n);
MOZ_ASSERT(n == mIncoming[2]);
mIncoming[2]++;
RunLimitedSequence(ASYNC_ONLY);
DEMON_LOG("End RecvUrgentSyncMessage [%d]", n);
return true;
}
void
TestDemonParent::RunUnlimitedSequence()
{
if (mDone) {
return;
}
gFlushStack = false;
DoAction();
MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(this, &TestDemonParent::RunUnlimitedSequence));
}
void
TestDemonParent::RunLimitedSequence(int flags)
{
if (gStackHeight >= kMaxStackHeight) {
return;
}
gStackHeight++;
int count = Choose(20);
for (int i = 0; i < count; i++) {
if (!DoAction(flags)) {
gFlushStack = true;
}
if (gFlushStack) {
gStackHeight--;
return;
}
}
gStackHeight--;
}
static bool
AllowAsync(int outgoing, int incoming)
{
return incoming >= outgoing - 5;
}
bool
TestDemonParent::DoAction(int flags)
{
if (flags & ASYNC_ONLY) {
if (AllowAsync(mOutgoing[0], mIncoming[0])) {
DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]);
return SendAsyncMessage(mOutgoing[0]++);
} else {
return true;
}
} else {
switch (Choose(3)) {
case 0:
if (AllowAsync(mOutgoing[0], mIncoming[0])) {
DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]);
return SendAsyncMessage(mOutgoing[0]++);
} else {
return true;
}
case 1: {
DEMON_LOG("Start SendHiPrioSyncMessage");
bool r = SendHiPrioSyncMessage();
DEMON_LOG("End SendHiPrioSyncMessage result=%d", r);
return r;
}
case 2:
DEMON_LOG("Cancel");
GetIPCChannel()->CancelCurrentTransaction();
return true;
}
}
MOZ_CRASH();
return false;
}
//-----------------------------------------------------------------------------
// child
TestDemonChild::TestDemonChild()
: mIncoming(),
mOutgoing()
{
MOZ_COUNT_CTOR(TestDemonChild);
}
TestDemonChild::~TestDemonChild()
{
MOZ_COUNT_DTOR(TestDemonChild);
}
bool
TestDemonChild::RecvStart()
{
#ifdef OS_POSIX
srandom(time(nullptr));
#else
srand(time(nullptr));
#endif
DEMON_LOG("RecvStart");
RunUnlimitedSequence();
return true;
}
#ifdef DEBUG
void
TestDemonChild::ArtificialSleep()
{
if (Choose(2) == 0) {
// Sleep for anywhere from 0 to 100 milliseconds.
unsigned micros = Choose(100) * 1000;
#ifdef OS_POSIX
usleep(micros);
#else
Sleep(micros / 1000);
#endif
}
}
#endif
bool
TestDemonChild::RecvAsyncMessage(const int& n)
{
DEMON_LOG("Start RecvAsyncMessage [%d]", n);
MOZ_ASSERT(n == mIncoming[0]);
mIncoming[0]++;
RunLimitedSequence();
DEMON_LOG("End RecvAsyncMessage [%d]", n);
return true;
}
bool
TestDemonChild::RecvHiPrioSyncMessage()
{
DEMON_LOG("Start RecvHiPrioSyncMessage");
RunLimitedSequence();
DEMON_LOG("End RecvHiPrioSyncMessage");
return true;
}
void
TestDemonChild::RunUnlimitedSequence()
{
gFlushStack = false;
DoAction();
MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(this, &TestDemonChild::RunUnlimitedSequence));
}
void
TestDemonChild::RunLimitedSequence()
{
if (gStackHeight >= kMaxStackHeight) {
return;
}
gStackHeight++;
int count = Choose(20);
for (int i = 0; i < count; i++) {
if (!DoAction()) {
gFlushStack = true;
}
if (gFlushStack) {
gStackHeight--;
return;
}
}
gStackHeight--;
}
bool
TestDemonChild::DoAction()
{
switch (Choose(6)) {
case 0:
if (AllowAsync(mOutgoing[0], mIncoming[0])) {
DEMON_LOG("SendAsyncMessage [%d]", mOutgoing[0]);
return SendAsyncMessage(mOutgoing[0]++);
} else {
return true;
}
case 1: {
DEMON_LOG("Start SendHiPrioSyncMessage");
bool r = SendHiPrioSyncMessage();
DEMON_LOG("End SendHiPrioSyncMessage result=%d", r);
return r;
}
case 2: {
DEMON_LOG("Start SendSyncMessage [%d]", mOutgoing[0]);
bool r = SendSyncMessage(mOutgoing[0]++);
switch (GetIPCChannel()->LastSendError()) {
case SyncSendError::PreviousTimeout:
case SyncSendError::SendingCPOWWhileDispatchingSync:
case SyncSendError::SendingCPOWWhileDispatchingUrgent:
case SyncSendError::NotConnectedBeforeSend:
case SyncSendError::CancelledBeforeSend:
mOutgoing[0]--;
break;
default:
break;
}
DEMON_LOG("End SendSyncMessage result=%d", r);
return r;
}
case 3:
DEMON_LOG("SendUrgentAsyncMessage [%d]", mOutgoing[2]);
return SendUrgentAsyncMessage(mOutgoing[2]++);
case 4: {
DEMON_LOG("Start SendUrgentSyncMessage [%d]", mOutgoing[2]);
bool r = SendUrgentSyncMessage(mOutgoing[2]++);
switch (GetIPCChannel()->LastSendError()) {
case SyncSendError::PreviousTimeout:
case SyncSendError::SendingCPOWWhileDispatchingSync:
case SyncSendError::SendingCPOWWhileDispatchingUrgent:
case SyncSendError::NotConnectedBeforeSend:
case SyncSendError::CancelledBeforeSend:
mOutgoing[2]--;
break;
default:
break;
}
DEMON_LOG("End SendUrgentSyncMessage result=%d", r);
return r;
}
case 5:
DEMON_LOG("Cancel");
GetIPCChannel()->CancelCurrentTransaction();
return true;
}
MOZ_CRASH();
return false;
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,106 @@
#ifndef mozilla__ipdltest_TestDemon_h
#define mozilla__ipdltest_TestDemon_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestDemonParent.h"
#include "mozilla/_ipdltest/PTestDemonChild.h"
using namespace mozilla::ipc;
namespace mozilla {
namespace _ipdltest {
class TestDemonParent :
public PTestDemonParent
{
public:
TestDemonParent();
virtual ~TestDemonParent();
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return true; }
void Main();
#ifdef DEBUG
bool ShouldContinueFromReplyTimeout() override;
bool ArtificialTimeout() override;
bool NeedArtificialSleep() override { return true; }
void ArtificialSleep() override;
#endif
bool RecvAsyncMessage(const int& n) override;
bool RecvHiPrioSyncMessage() override;
bool RecvSyncMessage(const int& n) override;
bool RecvUrgentAsyncMessage(const int& n) override;
bool RecvUrgentSyncMessage(const int& n) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
mDone = true;
printf("Parent ActorDestroy\n");
passed("ok");
QuitParent();
}
private:
bool mDone;
int mIncoming[3];
int mOutgoing[3];
enum {
ASYNC_ONLY = 1,
};
void RunUnlimitedSequence();
void RunLimitedSequence(int flags = 0);
bool DoAction(int flags = 0);
};
class TestDemonChild :
public PTestDemonChild
{
public:
TestDemonChild();
virtual ~TestDemonChild();
bool RecvStart() override;
#ifdef DEBUG
bool NeedArtificialSleep() override { return true; }
void ArtificialSleep() override;
#endif
bool RecvAsyncMessage(const int& n) override;
bool RecvHiPrioSyncMessage() override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
_exit(0);
}
virtual void IntentionalCrash() override
{
_exit(0);
}
private:
int mIncoming[3];
int mOutgoing[3];
void RunUnlimitedSequence();
void RunLimitedSequence();
bool DoAction();
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestDemon_h

View file

@ -0,0 +1,105 @@
#include "TestDesc.h"
#include "IPDLUnitTests.h" // fail etc.
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
void
TestDescParent::Main()
{
PTestDescSubParent* p = CallPTestDescSubConstructor(0);
if (!p)
fail("can't allocate Sub");
PTestDescSubsubParent* pp = p->CallPTestDescSubsubConstructor();
if (!pp)
fail("can't allocate Subsub");
if (!SendTest(pp))
fail("can't send Subsub");
}
bool
TestDescParent::RecvOk(PTestDescSubsubParent* a)
{
if (!a)
fail("didn't receive Subsub");
if (!PTestDescSubsubParent::Call__delete__(a))
fail("deleting Subsub");
Close();
return true;
}
PTestDescSubParent*
TestDescParent::AllocPTestDescSubParent(PTestDescSubsubParent* dummy) {
if (dummy)
fail("actor supposed to be null");
return new TestDescSubParent();
}
bool
TestDescParent::DeallocPTestDescSubParent(PTestDescSubParent* actor)
{
delete actor;
return true;
}
PTestDescSubsubParent*
TestDescSubParent::AllocPTestDescSubsubParent()
{
return new TestDescSubsubParent();
}
bool
TestDescSubParent::DeallocPTestDescSubsubParent(PTestDescSubsubParent* actor)
{
delete actor;
return true;
}
//-----------------------------------------------------------------------------
// child
bool
TestDescChild::RecvTest(PTestDescSubsubChild* a)
{
if (!a)
fail("didn't receive Subsub");
if (!SendOk(a))
fail("couldn't send Ok()");
return true;
}
PTestDescSubChild*
TestDescChild::AllocPTestDescSubChild(PTestDescSubsubChild* dummy) {
if (dummy)
fail("actor supposed to be null");
return new TestDescSubChild();
}
bool
TestDescChild::DeallocPTestDescSubChild(PTestDescSubChild* actor)
{
delete actor;
return true;
}
PTestDescSubsubChild*
TestDescSubChild::AllocPTestDescSubsubChild()
{
return new TestDescSubsubChild();
}
bool
TestDescSubChild::DeallocPTestDescSubsubChild(PTestDescSubsubChild* actor)
{
delete actor;
return true;
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,128 @@
#ifndef mozilla_ipdltest_TestDesc_h
#define mozilla_ipdltest_TestDesc_h
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestDescParent.h"
#include "mozilla/_ipdltest/PTestDescChild.h"
#include "mozilla/_ipdltest/PTestDescSubParent.h"
#include "mozilla/_ipdltest/PTestDescSubChild.h"
#include "mozilla/_ipdltest/PTestDescSubsubParent.h"
#include "mozilla/_ipdltest/PTestDescSubsubChild.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// Top-level
//
class TestDescParent :
public PTestDescParent
{
public:
TestDescParent() { }
virtual ~TestDescParent() { }
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return true; }
void Main();
virtual bool RecvOk(PTestDescSubsubParent* a) override;
protected:
virtual PTestDescSubParent* AllocPTestDescSubParent(PTestDescSubsubParent*) override;
virtual bool DeallocPTestDescSubParent(PTestDescSubParent* actor) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
};
class TestDescChild :
public PTestDescChild
{
public:
TestDescChild() { }
virtual ~TestDescChild() { }
protected:
virtual PTestDescSubChild* AllocPTestDescSubChild(PTestDescSubsubChild*) override;
virtual bool DeallocPTestDescSubChild(PTestDescSubChild* actor) override;
virtual bool RecvTest(PTestDescSubsubChild* a) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
};
//-----------------------------------------------------------------------------
// First descendent
//
class TestDescSubParent :
public PTestDescSubParent
{
public:
TestDescSubParent() { }
virtual ~TestDescSubParent() { }
protected:
virtual void ActorDestroy(ActorDestroyReason why) override {}
virtual PTestDescSubsubParent* AllocPTestDescSubsubParent() override;
virtual bool DeallocPTestDescSubsubParent(PTestDescSubsubParent* actor) override;
};
class TestDescSubChild :
public PTestDescSubChild
{
public:
TestDescSubChild() { }
virtual ~TestDescSubChild() { }
protected:
virtual PTestDescSubsubChild* AllocPTestDescSubsubChild() override;
virtual bool DeallocPTestDescSubsubChild(PTestDescSubsubChild* actor) override;
};
//-----------------------------------------------------------------------------
// Grand-descendent
//
class TestDescSubsubParent :
public PTestDescSubsubParent
{
public:
TestDescSubsubParent() { }
virtual ~TestDescSubsubParent() { }
protected:
virtual void ActorDestroy(ActorDestroyReason why) override {}
};
class TestDescSubsubChild :
public PTestDescSubsubChild
{
public:
TestDescSubsubChild() { }
virtual ~TestDescSubsubChild() { }
};
}
}
#endif // ifndef mozilla_ipdltest_TestDesc_h

View file

@ -0,0 +1,257 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
#include "TestEndpointBridgeMain.h"
#include "base/task.h"
#include "IPDLUnitTests.h" // fail etc.
#include "IPDLUnitTestSubprocess.h"
using namespace std;
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// main process
void
TestEndpointBridgeMainParent::Main()
{
if (!SendStart()) {
fail("sending Start");
}
}
bool
TestEndpointBridgeMainParent::RecvBridged(Endpoint<PTestEndpointBridgeMainSubParent>&& endpoint)
{
TestEndpointBridgeMainSubParent* a = new TestEndpointBridgeMainSubParent();
if (!endpoint.Bind(a)) {
fail("Bind failed");
}
return true;
}
void
TestEndpointBridgeMainParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why) {
fail("unexpected destruction!");
}
passed("ok");
QuitParent();
}
bool
TestEndpointBridgeMainSubParent::RecvHello()
{
return SendHi();
}
bool
TestEndpointBridgeMainSubParent::RecvHelloSync()
{
return true;
}
bool
TestEndpointBridgeMainSubParent::AnswerHelloRpc()
{
return CallHiRpc();
}
void
TestEndpointBridgeMainSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why) {
fail("unexpected destruction!");
}
// 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.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestEndpointBridgeMainSubParent>(this)));
}
//-----------------------------------------------------------------------------
// sub process --- child of main
TestEndpointBridgeMainChild* gEndpointBridgeMainChild;
TestEndpointBridgeMainChild::TestEndpointBridgeMainChild()
: mSubprocess(nullptr)
{
gEndpointBridgeMainChild = this;
}
bool
TestEndpointBridgeMainChild::RecvStart()
{
vector<string> subsubArgs;
subsubArgs.push_back("TestEndpointBridgeSub");
mSubprocess = new IPDLUnitTestSubprocess();
if (!mSubprocess->SyncLaunch(subsubArgs)) {
fail("problem launching subprocess");
}
IPC::Channel* transport = mSubprocess->GetChannel();
if (!transport) {
fail("no transport");
}
TestEndpointBridgeSubParent* bsp = new TestEndpointBridgeSubParent();
bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle()));
bsp->Main();
return true;
}
void
TestEndpointBridgeMainChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why) {
fail("unexpected destruction!");
}
// NB: this is kosher because QuitChild() joins with the IO thread
XRE_GetIOMessageLoop()->PostTask(
do_AddRef(new DeleteTask<IPDLUnitTestSubprocess>(mSubprocess)));
QuitChild();
}
void
TestEndpointBridgeSubParent::Main()
{
if (!SendPing()) {
fail("sending Ping");
}
}
bool
TestEndpointBridgeSubParent::RecvBridgeEm()
{
Endpoint<PTestEndpointBridgeMainSubParent> parent;
Endpoint<PTestEndpointBridgeMainSubChild> child;
nsresult rv;
rv = PTestEndpointBridgeMainSub::CreateEndpoints(
gEndpointBridgeMainChild->OtherPid(), OtherPid(),
&parent, &child);
if (NS_FAILED(rv)) {
fail("opening PTestEndpointOpensOpened");
}
if (!gEndpointBridgeMainChild->SendBridged(mozilla::Move(parent))) {
fail("SendBridge failed for parent");
}
if (!SendBridged(mozilla::Move(child))) {
fail("SendBridge failed for child");
}
return true;
}
void
TestEndpointBridgeSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why) {
fail("unexpected destruction!");
}
gEndpointBridgeMainChild->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.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestEndpointBridgeSubParent>(this)));
}
//-----------------------------------------------------------------------------
// subsub process --- child of sub
static TestEndpointBridgeSubChild* gBridgeSubChild;
TestEndpointBridgeSubChild::TestEndpointBridgeSubChild()
{
gBridgeSubChild = this;
}
bool
TestEndpointBridgeSubChild::RecvPing()
{
if (!SendBridgeEm()) {
fail("sending BridgeEm");
}
return true;
}
bool
TestEndpointBridgeSubChild::RecvBridged(Endpoint<PTestEndpointBridgeMainSubChild>&& endpoint)
{
TestEndpointBridgeMainSubChild* a = new TestEndpointBridgeMainSubChild();
if (!endpoint.Bind(a)) {
fail("failed to Bind");
}
if (!a->SendHello()) {
fail("sending Hello");
}
return true;
}
void
TestEndpointBridgeSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why) {
fail("unexpected destruction!");
}
QuitChild();
}
bool
TestEndpointBridgeMainSubChild::RecvHi()
{
if (!SendHelloSync()) {
fail("sending HelloSync");
}
if (!CallHelloRpc()) {
fail("calling HelloRpc");
}
if (!mGotHi) {
fail("didn't answer HiRpc");
}
// Need to close the channel without message-processing frames on
// the C++ stack
MessageLoop::current()->PostTask(
NewNonOwningRunnableMethod(this, &TestEndpointBridgeMainSubChild::Close));
return true;
}
bool
TestEndpointBridgeMainSubChild::AnswerHiRpc()
{
mGotHi = true; // d00d
return true;
}
void
TestEndpointBridgeMainSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why) {
fail("unexpected destruction!");
}
gBridgeSubChild->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.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestEndpointBridgeMainSubChild>(this)));
}
} // namespace mozilla
} // namespace _ipdltest

View file

@ -0,0 +1,133 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
#ifndef mozilla__ipdltest_TestEndpointBridgeMain_h
#define mozilla__ipdltest_TestEndpointBridgeMain_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestEndpointBridgeMainParent.h"
#include "mozilla/_ipdltest/PTestEndpointBridgeMainChild.h"
#include "mozilla/_ipdltest/PTestEndpointBridgeSubParent.h"
#include "mozilla/_ipdltest/PTestEndpointBridgeSubChild.h"
#include "mozilla/_ipdltest/PTestEndpointBridgeMainSubParent.h"
#include "mozilla/_ipdltest/PTestEndpointBridgeMainSubChild.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// "Main" process
//
class TestEndpointBridgeMainParent :
public PTestEndpointBridgeMainParent
{
public:
TestEndpointBridgeMainParent() {}
virtual ~TestEndpointBridgeMainParent() {}
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
bool RecvBridged(mozilla::ipc::Endpoint<PTestEndpointBridgeMainSubParent>&& endpoint) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
class TestEndpointBridgeMainSubParent :
public PTestEndpointBridgeMainSubParent
{
public:
explicit TestEndpointBridgeMainSubParent()
{}
virtual ~TestEndpointBridgeMainSubParent() {}
protected:
virtual bool RecvHello() override;
virtual bool RecvHelloSync() override;
virtual bool AnswerHelloRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
//-----------------------------------------------------------------------------
// "Sub" process --- child of "main"
//
class TestEndpointBridgeSubParent;
class TestEndpointBridgeMainChild :
public PTestEndpointBridgeMainChild
{
public:
TestEndpointBridgeMainChild();
virtual ~TestEndpointBridgeMainChild() {}
protected:
virtual bool RecvStart() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
IPDLUnitTestSubprocess* mSubprocess;
};
class TestEndpointBridgeSubParent :
public PTestEndpointBridgeSubParent
{
public:
TestEndpointBridgeSubParent() {}
virtual ~TestEndpointBridgeSubParent() {}
void Main();
protected:
virtual bool RecvBridgeEm() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
//-----------------------------------------------------------------------------
// "Subsub" process --- child of "sub"
//
class TestEndpointBridgeSubChild :
public PTestEndpointBridgeSubChild
{
public:
TestEndpointBridgeSubChild();
virtual ~TestEndpointBridgeSubChild() {}
protected:
virtual bool RecvPing() override;
bool RecvBridged(Endpoint<PTestEndpointBridgeMainSubChild>&& endpoint) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
class TestEndpointBridgeMainSubChild :
public PTestEndpointBridgeMainSubChild
{
public:
explicit TestEndpointBridgeMainSubChild()
: mGotHi(false)
{}
virtual ~TestEndpointBridgeMainSubChild() {}
protected:
virtual bool RecvHi() override;
virtual bool AnswerHiRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
bool mGotHi;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestEndpointBridgeMain_h

View file

@ -0,0 +1,271 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
#include "base/task.h"
#include "base/thread.h"
#include "TestEndpointOpens.h"
#include "IPDLUnitTests.h" // fail etc.
using namespace mozilla::ipc;
using base::ProcessHandle;
using base::Thread;
namespace mozilla {
// NB: this is generally bad style, but I am lazy.
using namespace _ipdltest;
using namespace _ipdltest2;
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 TestEndpointOpensOpenedParent runs
static Thread* gParentThread;
void
TestEndpointOpensParent::Main()
{
if (!SendStart()) {
fail("sending Start");
}
}
static void
OpenParent(TestEndpointOpensOpenedParent* aParent,
Endpoint<PTestEndpointOpensOpenedParent>&& aEndpoint)
{
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 (!aEndpoint.Bind(aParent)) {
fail("binding Parent");
}
}
bool
TestEndpointOpensParent::RecvStartSubprotocol(
mozilla::ipc::Endpoint<PTestEndpointOpensOpenedParent>&& endpoint)
{
gMainThread = MessageLoop::current();
gParentThread = new Thread("ParentThread");
if (!gParentThread->Start()) {
fail("starting parent thread");
}
TestEndpointOpensOpenedParent* a = new TestEndpointOpensOpenedParent();
gParentThread->message_loop()->PostTask(
NewRunnableFunction(OpenParent, a, mozilla::Move(endpoint)));
return true;
}
void
TestEndpointOpensParent::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gParentThread;
if (NormalShutdown != why) {
fail("unexpected destruction A!");
}
passed("ok");
QuitParent();
}
bool
TestEndpointOpensOpenedParent::RecvHello()
{
AssertNotMainThread();
return SendHi();
}
bool
TestEndpointOpensOpenedParent::RecvHelloSync()
{
AssertNotMainThread();
return true;
}
bool
TestEndpointOpensOpenedParent::AnswerHelloRpc()
{
AssertNotMainThread();
return CallHiRpc();
}
static void
ShutdownTestEndpointOpensOpenedParent(TestEndpointOpensOpenedParent* parent,
Transport* transport)
{
delete parent;
}
void
TestEndpointOpensOpenedParent::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
if (NormalShutdown != why) {
fail("unexpected destruction B!");
}
// 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.
gParentThread->message_loop()->PostTask(
NewRunnableFunction(ShutdownTestEndpointOpensOpenedParent,
this, GetTransport()));
}
//-----------------------------------------------------------------------------
// child
static TestEndpointOpensChild* gOpensChild;
// Thread on which TestEndpointOpensOpenedChild runs
static Thread* gChildThread;
TestEndpointOpensChild::TestEndpointOpensChild()
{
gOpensChild = this;
}
static void
OpenChild(TestEndpointOpensOpenedChild* aChild,
Endpoint<PTestEndpointOpensOpenedChild>&& endpoint)
{
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 (!endpoint.Bind(aChild)) {
fail("binding child endpoint");
}
// Kick off the unit tests
if (!aChild->SendHello()) {
fail("sending Hello");
}
}
bool
TestEndpointOpensChild::RecvStart()
{
Endpoint<PTestEndpointOpensOpenedParent> parent;
Endpoint<PTestEndpointOpensOpenedChild> child;
nsresult rv;
rv = PTestEndpointOpensOpened::CreateEndpoints(OtherPid(), base::GetCurrentProcId(),
&parent, &child);
if (NS_FAILED(rv)) {
fail("opening PTestEndpointOpensOpened");
}
gMainThread = MessageLoop::current();
gChildThread = new Thread("ChildThread");
if (!gChildThread->Start()) {
fail("starting child thread");
}
TestEndpointOpensOpenedChild* a = new TestEndpointOpensOpenedChild();
gChildThread->message_loop()->PostTask(
NewRunnableFunction(OpenChild, a, mozilla::Move(child)));
if (!SendStartSubprotocol(parent)) {
fail("send StartSubprotocol");
}
return true;
}
void
TestEndpointOpensChild::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gChildThread;
if (NormalShutdown != why) {
fail("unexpected destruction C!");
}
QuitChild();
}
bool
TestEndpointOpensOpenedChild::RecvHi()
{
AssertNotMainThread();
if (!SendHelloSync()) {
fail("sending HelloSync");
}
if (!CallHelloRpc()) {
fail("calling HelloRpc");
}
if (!mGotHi) {
fail("didn't answer HiRpc");
}
// Need to close the channel without message-processing frames on
// the C++ stack
MessageLoop::current()->PostTask(
NewNonOwningRunnableMethod(this, &TestEndpointOpensOpenedChild::Close));
return true;
}
bool
TestEndpointOpensOpenedChild::AnswerHiRpc()
{
AssertNotMainThread();
mGotHi = true; // d00d
return true;
}
static void
ShutdownTestEndpointOpensOpenedChild(TestEndpointOpensOpenedChild* child,
Transport* transport)
{
delete child;
// Kick off main-thread shutdown.
gMainThread->PostTask(
NewNonOwningRunnableMethod(gOpensChild, &TestEndpointOpensChild::Close));
}
void
TestEndpointOpensOpenedChild::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
if (NormalShutdown != why) {
fail("unexpected destruction D!");
}
// 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. Defer shutdown to
// let cleanup finish.
gChildThread->message_loop()->PostTask(
NewRunnableFunction(ShutdownTestEndpointOpensOpenedChild,
this, GetTransport()));
}
} // namespace mozilla

View file

@ -0,0 +1,101 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
#ifndef mozilla__ipdltest_TestEndpointOpens_h
#define mozilla__ipdltest_TestEndpointOpens_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestEndpointOpensParent.h"
#include "mozilla/_ipdltest/PTestEndpointOpensChild.h"
#include "mozilla/_ipdltest2/PTestEndpointOpensOpenedParent.h"
#include "mozilla/_ipdltest2/PTestEndpointOpensOpenedChild.h"
namespace mozilla {
// parent process
namespace _ipdltest {
class TestEndpointOpensParent : public PTestEndpointOpensParent
{
public:
TestEndpointOpensParent() {}
virtual ~TestEndpointOpensParent() {}
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual bool RecvStartSubprotocol(mozilla::ipc::Endpoint<PTestEndpointOpensOpenedParent>&& endpoint);
virtual void ActorDestroy(ActorDestroyReason why) override;
};
} // namespace _ipdltest
namespace _ipdltest2 {
class TestEndpointOpensOpenedParent : public PTestEndpointOpensOpenedParent
{
public:
explicit TestEndpointOpensOpenedParent()
{}
virtual ~TestEndpointOpensOpenedParent() {}
protected:
virtual bool RecvHello() override;
virtual bool RecvHelloSync() override;
virtual bool AnswerHelloRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
} // namespace _ipdltest2
// child process
namespace _ipdltest {
class TestEndpointOpensChild : public PTestEndpointOpensChild
{
public:
TestEndpointOpensChild();
virtual ~TestEndpointOpensChild() {}
protected:
virtual bool RecvStart() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
} // namespace _ipdltest
namespace _ipdltest2 {
class TestEndpointOpensOpenedChild : public PTestEndpointOpensOpenedChild
{
public:
explicit TestEndpointOpensOpenedChild()
: mGotHi(false)
{}
virtual ~TestEndpointOpensOpenedChild() {}
protected:
virtual bool RecvHi() override;
virtual bool AnswerHiRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
bool mGotHi;
};
} // namespace _ipdltest2
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestEndpointOpens_h

View file

@ -0,0 +1,137 @@
#include "TestFailedCtor.h"
#include "IPDLUnitTests.h" // fail etc.
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
void
TestFailedCtorParent::Main()
{
PTestFailedCtorSubParent* p = CallPTestFailedCtorSubConstructor();
if (p)
fail("expected ctor to fail");
Close();
}
PTestFailedCtorSubParent*
TestFailedCtorParent::AllocPTestFailedCtorSubParent()
{
return new TestFailedCtorSubParent();
}
bool
TestFailedCtorParent::DeallocPTestFailedCtorSubParent(PTestFailedCtorSubParent* actor)
{
delete actor;
return true;
}
PTestFailedCtorSubsubParent*
TestFailedCtorSubParent::AllocPTestFailedCtorSubsubParent()
{
TestFailedCtorSubsub* a = new TestFailedCtorSubsub();
if (!mOne) {
return mOne = a;
} else if (!mTwo) {
return mTwo = a;
} else if (!mThree) {
return mThree = a;
} else {
fail("unexpected Alloc()");
return nullptr;
}
}
bool
TestFailedCtorSubParent::DeallocPTestFailedCtorSubsubParent(PTestFailedCtorSubsubParent* actor)
{
static_cast<TestFailedCtorSubsub*>(actor)->mDealloced = true;
return true;
}
void
TestFailedCtorSubParent::ActorDestroy(ActorDestroyReason why)
{
if (mOne->mWhy != Deletion)
fail("Subsub one got wrong ActorDestroyReason");
if (mTwo->mWhy != AncestorDeletion)
fail("Subsub two got wrong ActorDestroyReason");
if (mThree->mWhy != AncestorDeletion)
fail("Subsub three got wrong ActorDestroyReason");
if (FailedConstructor != why)
fail("unexpected destruction!");
}
TestFailedCtorSubParent::~TestFailedCtorSubParent()
{
if (!(mOne->mDealloced && mTwo->mDealloced && mThree->mDealloced))
fail("Not all subsubs were Dealloc'd");
delete mOne;
delete mTwo;
delete mThree;
}
//-----------------------------------------------------------------------------
// child
PTestFailedCtorSubChild*
TestFailedCtorChild::AllocPTestFailedCtorSubChild()
{
return new TestFailedCtorSubChild();
}
bool
TestFailedCtorChild::AnswerPTestFailedCtorSubConstructor(PTestFailedCtorSubChild* actor)
{
PTestFailedCtorSubsubChild* c1 = actor->SendPTestFailedCtorSubsubConstructor();
PTestFailedCtorSubsubChild::Send__delete__(c1);
if (!actor->SendPTestFailedCtorSubsubConstructor() ||
!actor->SendPTestFailedCtorSubsubConstructor() ||
!actor->SendSync())
fail("setting up test");
// This causes our process to die
return false;
}
bool
TestFailedCtorChild::DeallocPTestFailedCtorSubChild(PTestFailedCtorSubChild* actor)
{
delete actor;
return true;
}
void
TestFailedCtorChild::ProcessingError(Result aCode, const char* aReason)
{
if (OtherPid() != base::GetCurrentProcId()) // thread-mode
_exit(0);
}
PTestFailedCtorSubsubChild*
TestFailedCtorSubChild::AllocPTestFailedCtorSubsubChild()
{
return new TestFailedCtorSubsub();
}
bool
TestFailedCtorSubChild::DeallocPTestFailedCtorSubsubChild(PTestFailedCtorSubsubChild* actor)
{
delete actor;
return true;
}
void
TestFailedCtorSubChild::ActorDestroy(ActorDestroyReason why)
{
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,136 @@
#ifndef mozilla_ipdltest_TestFailedCtor_h
#define mozilla_ipdltest_TestFailedCtor_h
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestFailedCtorParent.h"
#include "mozilla/_ipdltest/PTestFailedCtorChild.h"
#include "mozilla/_ipdltest/PTestFailedCtorSubParent.h"
#include "mozilla/_ipdltest/PTestFailedCtorSubChild.h"
#include "mozilla/_ipdltest/PTestFailedCtorSubsubParent.h"
#include "mozilla/_ipdltest/PTestFailedCtorSubsubChild.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// Top-level
//
class TestFailedCtorParent :
public PTestFailedCtorParent
{
public:
TestFailedCtorParent() { }
virtual ~TestFailedCtorParent() { }
static bool RunTestInProcesses() { return true; }
// FIXME/bug 703322 Disabled because child calls exit() to end
// test, not clear how to handle failed ctor in
// threaded mode.
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual PTestFailedCtorSubParent* AllocPTestFailedCtorSubParent() override;
virtual bool DeallocPTestFailedCtorSubParent(PTestFailedCtorSubParent* actor) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (AbnormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
};
class TestFailedCtorChild :
public PTestFailedCtorChild
{
public:
TestFailedCtorChild() { }
virtual ~TestFailedCtorChild() { }
protected:
virtual PTestFailedCtorSubChild* AllocPTestFailedCtorSubChild() override;
virtual bool AnswerPTestFailedCtorSubConstructor(PTestFailedCtorSubChild* actor) override;
virtual bool DeallocPTestFailedCtorSubChild(PTestFailedCtorSubChild* actor) override;
virtual void ProcessingError(Result aCode, const char* aReason) override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
fail("should have _exit()ed");
}
};
//-----------------------------------------------------------------------------
// First descendent
//
class TestFailedCtorSubsub;
class TestFailedCtorSubParent :
public PTestFailedCtorSubParent
{
public:
TestFailedCtorSubParent() : mOne(nullptr), mTwo(nullptr), mThree(nullptr) { }
virtual ~TestFailedCtorSubParent();
protected:
virtual PTestFailedCtorSubsubParent* AllocPTestFailedCtorSubsubParent() override;
virtual bool DeallocPTestFailedCtorSubsubParent(PTestFailedCtorSubsubParent* actor) override;
virtual bool RecvSync() override { return true; }
virtual void ActorDestroy(ActorDestroyReason why) override;
TestFailedCtorSubsub* mOne;
TestFailedCtorSubsub* mTwo;
TestFailedCtorSubsub* mThree;
};
class TestFailedCtorSubChild :
public PTestFailedCtorSubChild
{
public:
TestFailedCtorSubChild() { }
virtual ~TestFailedCtorSubChild() { }
protected:
virtual PTestFailedCtorSubsubChild* AllocPTestFailedCtorSubsubChild() override;
virtual bool DeallocPTestFailedCtorSubsubChild(PTestFailedCtorSubsubChild* actor) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
//-----------------------------------------------------------------------------
// Grand-descendent
//
class TestFailedCtorSubsub :
public PTestFailedCtorSubsubParent,
public PTestFailedCtorSubsubChild
{
public:
TestFailedCtorSubsub() : mWhy(ActorDestroyReason(-1)), mDealloced(false) {}
virtual ~TestFailedCtorSubsub() {}
virtual void ActorDestroy(ActorDestroyReason why) override { mWhy = why; }
ActorDestroyReason mWhy;
bool mDealloced;
};
}
}
#endif // ifndef mozilla_ipdltest_TestFailedCtor_h

View file

@ -0,0 +1,146 @@
#include "base/process_util.h"
#include "TestHangs.h"
#include "IPDLUnitTests.h" // fail etc.
using base::KillProcess;
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// parent
TestHangsParent::TestHangsParent() : mDetectedHang(false)
{
MOZ_COUNT_CTOR(TestHangsParent);
}
TestHangsParent::~TestHangsParent()
{
MOZ_COUNT_DTOR(TestHangsParent);
}
void
TestHangsParent::Main()
{
// Here we try to set things up to test the following sequence of events:
//
// - subprocess causes an OnMaybeDequeueOne() task to be posted to
// this thread
//
// - subprocess hangs just long enough for the hang timer to expire
//
// - hang-kill code in the parent starts running
//
// - subprocess replies to message while hang code runs
//
// - reply is processed in OnMaybeDequeueOne() before Close() has
// been called or the channel error notification has been posted
// this tells the subprocess to send us Nonce()
if (!SendStart())
fail("sending Start");
// now we sleep here for a while awaiting the Nonce() message from
// the child. since we're not blocked on anything, the IO thread
// will enqueue an OnMaybeDequeueOne() task to process that
// message
//
// NB: PR_Sleep is exactly what we want, only the current thread
// sleeping
PR_Sleep(5000);
// when we call into this, we'll pull the Nonce() message out of
// the mPending queue, but that doesn't matter ... the
// OnMaybeDequeueOne() event will remain
if (CallStackFrame() && mDetectedHang)
fail("should have timed out!");
// the Close() task in the queue will shut us down
}
bool
TestHangsParent::ShouldContinueFromReplyTimeout()
{
mDetectedHang = true;
// so we've detected a timeout after 2 ms ... now we cheat and
// sleep for a long time, to allow the subprocess's reply to come
// in
PR_Sleep(5000);
// reply should be here; we'll post a task to shut things down.
// This must be after OnMaybeDequeueOne() in the event queue.
MessageLoop::current()->PostTask(
NewNonOwningRunnableMethod(this, &TestHangsParent::CleanUp));
GetIPCChannel()->CloseWithTimeout();
return false;
}
bool
TestHangsParent::AnswerStackFrame()
{
if (PTestHangs::HANG != state()) {
if (CallStackFrame())
fail("should have timed out!");
}
else {
// minimum possible, 2 ms. We want to detecting a hang to race
// with the reply coming in, as reliably as possible
SetReplyTimeoutMs(2);
if (CallHang())
fail("should have timed out!");
}
return true;
}
void
TestHangsParent::CleanUp()
{
ipc::ScopedProcessHandle otherProcessHandle;
if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle.rwget())) {
fail("couldn't open child process");
} else {
if (!KillProcess(otherProcessHandle, 0, false)) {
fail("terminating child process");
}
}
Close();
}
//-----------------------------------------------------------------------------
// child
TestHangsChild::TestHangsChild()
{
MOZ_COUNT_CTOR(TestHangsChild);
}
TestHangsChild::~TestHangsChild()
{
MOZ_COUNT_DTOR(TestHangsChild);
}
bool
TestHangsChild::AnswerHang()
{
puts(" (child process is 'hanging' now)");
// just sleep until we're reasonably confident the 1ms hang
// detector fired in the parent process and it's sleeping in
// ShouldContinueFromReplyTimeout()
PR_Sleep(1000);
return true;
}
} // namespace _ipdltest
} // namespace mozilla

View file

@ -0,0 +1,87 @@
#ifndef mozilla__ipdltest_TestHangs_h
#define mozilla__ipdltest_TestHangs_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestHangsParent.h"
#include "mozilla/_ipdltest/PTestHangsChild.h"
namespace mozilla {
namespace _ipdltest {
class TestHangsParent :
public PTestHangsParent
{
public:
TestHangsParent();
virtual ~TestHangsParent();
static bool RunTestInProcesses() { return true; }
// FIXME/bug 703320 Disabled because parent kills child proc, not
// clear how that should work in threads.
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual bool ShouldContinueFromReplyTimeout() override;
virtual bool RecvNonce() {
return true;
}
virtual bool AnswerStackFrame() override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (AbnormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
void CleanUp();
bool mDetectedHang;
};
class TestHangsChild :
public PTestHangsChild
{
public:
TestHangsChild();
virtual ~TestHangsChild();
protected:
virtual bool RecvStart() override {
if (!SendNonce())
fail("sending Nonce");
return true;
}
virtual bool AnswerStackFrame() override
{
if (CallStackFrame())
fail("should have failed");
return true;
}
virtual bool AnswerHang() override;
virtual void ActorDestroy(ActorDestroyReason why) override
{
if (AbnormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestHangs_h

Some files were not shown because too many files have changed in this diff Show more