summaryrefslogtreecommitdiffstats
path: root/ipc/ipdl/test/cxx/TestOffMainThreadPainting.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/ipdl/test/cxx/TestOffMainThreadPainting.cpp')
-rw-r--r--ipc/ipdl/test/cxx/TestOffMainThreadPainting.cpp237
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