forked from mirrors/gecko-dev
290 lines
6.3 KiB
C++
290 lines
6.3 KiB
C++
#include "TestOffMainThreadPainting.h"
|
|
|
|
#include "IPDLUnitTests.h" // fail etc.
|
|
#include "mozilla/Unused.h"
|
|
#include <prinrval.h>
|
|
#include <prthread.h>
|
|
|
|
namespace mozilla {
|
|
namespace _ipdltest {
|
|
|
|
TestOffMainThreadPaintingParent::TestOffMainThreadPaintingParent()
|
|
: mAsyncMessages(0),
|
|
mSyncMessages(0)
|
|
{
|
|
}
|
|
|
|
TestOffMainThreadPaintingParent::~TestOffMainThreadPaintingParent()
|
|
{
|
|
}
|
|
|
|
void
|
|
TestOffMainThreadPaintingParent::Main()
|
|
{
|
|
ipc::Endpoint<PTestPaintThreadParent> parentPipe;
|
|
ipc::Endpoint<PTestPaintThreadChild> childPipe;
|
|
nsresult rv = PTestPaintThread::CreateEndpoints(
|
|
base::GetCurrentProcId(),
|
|
OtherPid(),
|
|
&parentPipe,
|
|
&childPipe);
|
|
if (NS_FAILED(rv)) {
|
|
fail("create pipes");
|
|
}
|
|
|
|
mPaintActor = new TestPaintThreadParent(this);
|
|
if (!mPaintActor->Bind(Move(parentPipe))) {
|
|
fail("bind parent pipe");
|
|
}
|
|
|
|
if (!SendStartTest(Move(childPipe))) {
|
|
fail("sending Start");
|
|
}
|
|
}
|
|
|
|
ipc::IPCResult
|
|
TestOffMainThreadPaintingParent::RecvFinishedLayout(const uint64_t& aTxnId)
|
|
{
|
|
if (!mPaintedTxn || mPaintedTxn.value() != aTxnId) {
|
|
fail("received transaction before receiving paint");
|
|
}
|
|
mPaintedTxn = Nothing();
|
|
mCompletedTxn = Some(aTxnId);
|
|
return IPC_OK();
|
|
}
|
|
|
|
void
|
|
TestOffMainThreadPaintingParent::NotifyFinishedPaint(const uint64_t& aTxnId)
|
|
{
|
|
if (mCompletedTxn && mCompletedTxn.value() >= aTxnId) {
|
|
fail("received paint after receiving transaction");
|
|
}
|
|
if (mPaintedTxn) {
|
|
fail("painted again before completing previous transaction");
|
|
}
|
|
mPaintedTxn = Some(aTxnId);
|
|
}
|
|
|
|
ipc::IPCResult
|
|
TestOffMainThreadPaintingParent::RecvAsyncMessage(const uint64_t& aTxnId)
|
|
{
|
|
if (!mCompletedTxn || mCompletedTxn.value() != aTxnId) {
|
|
fail("sync message received out of order");
|
|
return IPC_FAIL_NO_REASON(this);
|
|
}
|
|
mAsyncMessages++;
|
|
return IPC_OK();
|
|
}
|
|
|
|
ipc::IPCResult
|
|
TestOffMainThreadPaintingParent::RecvSyncMessage(const uint64_t& aTxnId)
|
|
{
|
|
if (!mCompletedTxn || mCompletedTxn.value() != aTxnId) {
|
|
fail("sync message received out of order");
|
|
return IPC_FAIL_NO_REASON(this);
|
|
}
|
|
if (mSyncMessages >= mAsyncMessages) {
|
|
fail("sync message received before async message");
|
|
return IPC_FAIL_NO_REASON(this);
|
|
}
|
|
mSyncMessages++;
|
|
return IPC_OK();
|
|
}
|
|
|
|
ipc::IPCResult
|
|
TestOffMainThreadPaintingParent::RecvEndTest()
|
|
{
|
|
if (!mCompletedTxn || mCompletedTxn.value() != 1) {
|
|
fail("expected to complete a transaction");
|
|
}
|
|
if (mAsyncMessages != 1) {
|
|
fail("expected to get 1 async message");
|
|
}
|
|
if (mSyncMessages != 1) {
|
|
fail("expected to get 1 sync message");
|
|
}
|
|
|
|
passed("ok");
|
|
|
|
mPaintActor->Close();
|
|
Close();
|
|
return IPC_OK();
|
|
}
|
|
|
|
void
|
|
TestOffMainThreadPaintingParent::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
if (aWhy != NormalShutdown) {
|
|
fail("child process aborted");
|
|
}
|
|
QuitParent();
|
|
}
|
|
|
|
/**************************
|
|
* PTestLayoutThreadChild *
|
|
**************************/
|
|
|
|
TestOffMainThreadPaintingChild::TestOffMainThreadPaintingChild()
|
|
: mNextTxnId(1)
|
|
{
|
|
}
|
|
|
|
TestOffMainThreadPaintingChild::~TestOffMainThreadPaintingChild()
|
|
{
|
|
}
|
|
|
|
ipc::IPCResult
|
|
TestOffMainThreadPaintingChild::RecvStartTest(ipc::Endpoint<PTestPaintThreadChild>&& aEndpoint)
|
|
{
|
|
mPaintThread = MakeUnique<base::Thread>("PaintThread");
|
|
if (!mPaintThread->Start()) {
|
|
return IPC_FAIL_NO_REASON(this);
|
|
}
|
|
|
|
mPaintActor = new TestPaintThreadChild(GetIPCChannel());
|
|
RefPtr<Runnable> task = NewRunnableMethod<ipc::Endpoint<PTestPaintThreadChild>&&>(
|
|
"TestPaintthreadChild::Bind", mPaintActor, &TestPaintThreadChild::Bind, Move(aEndpoint));
|
|
mPaintThread->message_loop()->PostTask(task.forget());
|
|
|
|
IssueTransaction();
|
|
return IPC_OK();
|
|
}
|
|
|
|
void
|
|
TestOffMainThreadPaintingChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
RefPtr<Runnable> task = NewRunnableMethod(
|
|
"TestPaintThreadChild::Close", mPaintActor, &TestPaintThreadChild::Close);
|
|
mPaintThread->message_loop()->PostTask(task.forget());
|
|
mPaintThread = nullptr;
|
|
|
|
QuitChild();
|
|
}
|
|
|
|
void
|
|
TestOffMainThreadPaintingChild::ProcessingError(Result aCode, const char* aReason)
|
|
{
|
|
MOZ_CRASH("Aborting child due to IPC error");
|
|
}
|
|
|
|
void
|
|
TestOffMainThreadPaintingChild::IssueTransaction()
|
|
{
|
|
GetIPCChannel()->BeginPostponingSends();
|
|
|
|
uint64_t txnId = mNextTxnId++;
|
|
|
|
// Start painting before we send the message.
|
|
RefPtr<Runnable> task = NewRunnableMethod<uint64_t>(
|
|
"TestPaintThreadChild::BeginPaintingForTxn", mPaintActor, &TestPaintThreadChild::BeginPaintingForTxn, txnId);
|
|
mPaintThread->message_loop()->PostTask(task.forget());
|
|
|
|
// Simulate some gecko main thread stuff.
|
|
SendFinishedLayout(txnId);
|
|
SendAsyncMessage(txnId);
|
|
SendSyncMessage(txnId);
|
|
SendEndTest();
|
|
}
|
|
|
|
/**************************
|
|
* PTestPaintThreadParent *
|
|
**************************/
|
|
|
|
TestPaintThreadParent::TestPaintThreadParent(TestOffMainThreadPaintingParent* aMainBridge)
|
|
: mMainBridge(aMainBridge)
|
|
{
|
|
}
|
|
|
|
TestPaintThreadParent::~TestPaintThreadParent()
|
|
{
|
|
}
|
|
|
|
bool
|
|
TestPaintThreadParent::Bind(ipc::Endpoint<PTestPaintThreadParent>&& aEndpoint)
|
|
{
|
|
if (!aEndpoint.Bind(this)) {
|
|
return false;
|
|
}
|
|
|
|
AddRef();
|
|
return true;
|
|
}
|
|
|
|
ipc::IPCResult
|
|
TestPaintThreadParent::RecvFinishedPaint(const uint64_t& aTxnId)
|
|
{
|
|
mMainBridge->NotifyFinishedPaint(aTxnId);
|
|
return IPC_OK();
|
|
}
|
|
|
|
void
|
|
TestPaintThreadParent::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
}
|
|
|
|
void
|
|
TestPaintThreadParent::DeallocPTestPaintThreadParent()
|
|
{
|
|
Release();
|
|
}
|
|
|
|
/*************************
|
|
* PTestPaintThreadChild *
|
|
*************************/
|
|
|
|
TestPaintThreadChild::TestPaintThreadChild(MessageChannel* aMainChannel)
|
|
: mCanSend(false),
|
|
mMainChannel(aMainChannel)
|
|
{
|
|
}
|
|
|
|
TestPaintThreadChild::~TestPaintThreadChild()
|
|
{
|
|
}
|
|
|
|
void
|
|
TestPaintThreadChild::Bind(ipc::Endpoint<PTestPaintThreadChild>&& aEndpoint)
|
|
{
|
|
if (!aEndpoint.Bind(this)) {
|
|
MOZ_CRASH("could not bind paint child endpoint");
|
|
}
|
|
AddRef();
|
|
mCanSend = true;
|
|
}
|
|
|
|
void
|
|
TestPaintThreadChild::BeginPaintingForTxn(uint64_t aTxnId)
|
|
{
|
|
MOZ_RELEASE_ASSERT(!NS_IsMainThread());
|
|
|
|
// Sleep for some time to simulate painting being slow.
|
|
PR_Sleep(PR_MillisecondsToInterval(500));
|
|
SendFinishedPaint(aTxnId);
|
|
|
|
mMainChannel->StopPostponingSends();
|
|
}
|
|
|
|
void
|
|
TestPaintThreadChild::ActorDestroy(ActorDestroyReason aWhy)
|
|
{
|
|
mCanSend = false;
|
|
}
|
|
|
|
void
|
|
TestPaintThreadChild::Close()
|
|
{
|
|
MOZ_RELEASE_ASSERT(!NS_IsMainThread());
|
|
|
|
if (mCanSend) {
|
|
PTestPaintThreadChild::Close();
|
|
}
|
|
}
|
|
|
|
void
|
|
TestPaintThreadChild::DeallocPTestPaintThreadChild()
|
|
{
|
|
Release();
|
|
}
|
|
|
|
} // namespace _ipdltest
|
|
} // namespace mozilla
|