summaryrefslogtreecommitdiffstats
path: root/xpcom/tests/gtest/TestTaskController.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--xpcom/tests/gtest/TestTaskController.cpp214
1 files changed, 214 insertions, 0 deletions
diff --git a/xpcom/tests/gtest/TestTaskController.cpp b/xpcom/tests/gtest/TestTaskController.cpp
new file mode 100644
index 0000000000..c7d71ae0f8
--- /dev/null
+++ b/xpcom/tests/gtest/TestTaskController.cpp
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "gtest/gtest.h"
+
+#include <stdint.h> // uint32_t
+
+#include "nsString.h" // nsACString
+#include "nsThreadUtils.h" // NS_ProcessNextEvent
+#include "mozilla/Atomics.h" // Atomic
+#include "mozilla/EventQueue.h" // EventQueuePriority
+#include "mozilla/Mutex.h" // Mutex, MutexAutoLock
+#include "mozilla/RefPtr.h" // RefPtr, do_AddRef
+#include "mozilla/TaskController.h" // TaskController, Task
+#include "prthread.h" // PR_Sleep
+
+using namespace mozilla;
+
+namespace TestTaskController {
+
+class Logger {
+ public:
+ Logger() : mMutex("Logger") {}
+
+ void Add(const char* aText) {
+ MutexAutoLock lock(mMutex);
+
+ mLog += aText;
+ }
+
+ const nsAutoCString& GetLog() const { return mLog; }
+
+ private:
+ nsAutoCString mLog;
+ Mutex mMutex;
+};
+
+class ReschedulingTask : public Task {
+ static constexpr uint32_t LoopCount = 3;
+
+ public:
+ explicit ReschedulingTask(Kind aKind, Logger* aLogger, const char* aName)
+ : Task(aKind, EventQueuePriority::Normal),
+ mCount(0),
+ mIsDone(false),
+ mLogger(aLogger),
+ mName(aName) {}
+
+ TaskResult Run() override {
+ mLogger->Add(mName);
+
+ mCount++;
+
+ if (mCount < LoopCount) {
+ return TaskResult::Incomplete;
+ }
+
+ mIsDone = true;
+
+ return TaskResult::Complete;
+ }
+
+#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
+ bool GetName(nsACString& aName) override {
+ aName.AssignLiteral("AsyncScriptCompileTask");
+ return true;
+ }
+#endif
+
+ bool IsDone() const { return mIsDone; }
+
+ private:
+ Atomic<uint32_t> mCount;
+ Atomic<bool> mIsDone;
+ Logger* mLogger;
+ const char* mName;
+};
+
+using namespace mozilla;
+
+TEST(TaskController, RescheduleOnMainThread)
+{
+ Logger logger;
+
+ RefPtr<ReschedulingTask> mainThreadTask =
+ new ReschedulingTask(Task::Kind::MainThreadOnly, &logger, "1");
+
+ TaskController::Get()->AddTask(do_AddRef(mainThreadTask));
+
+ while (NS_ProcessNextEvent(nullptr, false)) {
+ }
+
+ ASSERT_TRUE(mainThreadTask->IsDone());
+
+ ASSERT_TRUE(logger.GetLog() == "111");
+}
+
+TEST(TaskController, RescheduleOffMainThread)
+{
+ Logger logger;
+
+ RefPtr<ReschedulingTask> offThreadTask =
+ new ReschedulingTask(Task::Kind::OffMainThreadOnly, &logger, "1");
+
+ TaskController::Get()->AddTask(do_AddRef(offThreadTask));
+
+ uint32_t count = 0;
+ while (!offThreadTask->IsDone() && count < 100) {
+ PR_Sleep(PR_MillisecondsToInterval(100));
+ count++;
+ }
+ ASSERT_TRUE(offThreadTask->IsDone());
+
+ ASSERT_TRUE(logger.GetLog() == "111");
+}
+
+TEST(TaskController, RescheduleMainAndOffMainThreads)
+{
+ Logger logger;
+
+ RefPtr<ReschedulingTask> offThreadTask =
+ new ReschedulingTask(Task::Kind::OffMainThreadOnly, &logger, "1");
+ RefPtr<ReschedulingTask> mainThreadTask =
+ new ReschedulingTask(Task::Kind::MainThreadOnly, &logger, "2");
+
+ mainThreadTask->AddDependency(offThreadTask.get());
+
+ TaskController::Get()->AddTask(do_AddRef(offThreadTask));
+ TaskController::Get()->AddTask(do_AddRef(mainThreadTask));
+
+ uint32_t count = 0;
+ while (!offThreadTask->IsDone() && count < 100) {
+ PR_Sleep(PR_MillisecondsToInterval(100));
+ count++;
+ }
+ ASSERT_TRUE(offThreadTask->IsDone());
+
+ // At this point, the main thread task shouldn't have run.
+ ASSERT_TRUE(logger.GetLog() == "111");
+
+ while (NS_ProcessNextEvent(nullptr, false)) {
+ }
+
+ ASSERT_TRUE(mainThreadTask->IsDone());
+
+ ASSERT_TRUE(logger.GetLog() == "111222");
+}
+
+TEST(TaskController, RescheduleOrder)
+{
+ Logger logger;
+
+ RefPtr<ReschedulingTask> mainThreadTask1 =
+ new ReschedulingTask(Task::Kind::MainThreadOnly, &logger, "1");
+ RefPtr<ReschedulingTask> mainThreadTask2 =
+ new ReschedulingTask(Task::Kind::MainThreadOnly, &logger, "2");
+ RefPtr<ReschedulingTask> mainThreadTask3 =
+ new ReschedulingTask(Task::Kind::MainThreadOnly, &logger, "3");
+
+ TaskController::Get()->AddTask(do_AddRef(mainThreadTask1));
+ TaskController::Get()->AddTask(do_AddRef(mainThreadTask2));
+ TaskController::Get()->AddTask(do_AddRef(mainThreadTask3));
+
+ while (NS_ProcessNextEvent(nullptr, false)) {
+ }
+
+ ASSERT_TRUE(mainThreadTask1->IsDone());
+ ASSERT_TRUE(mainThreadTask2->IsDone());
+ ASSERT_TRUE(mainThreadTask3->IsDone());
+
+ // Rescheduled tasks should be added to the beginning of the queue.
+ ASSERT_TRUE(logger.GetLog() == "111222333");
+}
+
+TEST(TaskController, RescheduleOrderOffMainThread)
+{
+ Logger logger1;
+ Logger logger2;
+ Logger logger3;
+
+ RefPtr<ReschedulingTask> offThreadTask1 =
+ new ReschedulingTask(Task::Kind::OffMainThreadOnly, &logger1, "1");
+ RefPtr<ReschedulingTask> offThreadTask2 =
+ new ReschedulingTask(Task::Kind::OffMainThreadOnly, &logger2, "2");
+ RefPtr<ReschedulingTask> offThreadTask3 =
+ new ReschedulingTask(Task::Kind::OffMainThreadOnly, &logger3, "3");
+
+ TaskController::Get()->AddTask(do_AddRef(offThreadTask1));
+ TaskController::Get()->AddTask(do_AddRef(offThreadTask2));
+ TaskController::Get()->AddTask(do_AddRef(offThreadTask3));
+
+ uint32_t count = 0;
+ while (!(offThreadTask1->IsDone() && offThreadTask2->IsDone() &&
+ offThreadTask3->IsDone()) &&
+ count < 100) {
+ PR_Sleep(PR_MillisecondsToInterval(100));
+ count++;
+ }
+
+ ASSERT_TRUE(offThreadTask1->IsDone());
+ ASSERT_TRUE(offThreadTask2->IsDone());
+ ASSERT_TRUE(offThreadTask3->IsDone());
+
+ // Rescheduled tasks should be enqueued.
+ // The order between off-thread tasks are not deterministic.
+ ASSERT_TRUE(logger1.GetLog() == "111");
+ ASSERT_TRUE(logger2.GetLog() == "222");
+ ASSERT_TRUE(logger3.GetLog() == "333");
+}
+
+} // namespace TestTaskController