diff options
Diffstat (limited to 'ipc/ipdl/test/cxx/TestOffMainThreadPainting.cpp')
-rw-r--r-- | ipc/ipdl/test/cxx/TestOffMainThreadPainting.cpp | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/ipc/ipdl/test/cxx/TestOffMainThreadPainting.cpp b/ipc/ipdl/test/cxx/TestOffMainThreadPainting.cpp new file mode 100644 index 0000000000..7a1bf2cf87 --- /dev/null +++ b/ipc/ipdl/test/cxx/TestOffMainThreadPainting.cpp @@ -0,0 +1,237 @@ +#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(std::move(parentPipe))) { + fail("bind parent pipe"); + } + + if (!SendStartTest(std::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, std::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 |