summaryrefslogtreecommitdiffstats
path: root/runtime/gc/task_processor_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/gc/task_processor_test.cc')
-rw-r--r--runtime/gc/task_processor_test.cc149
1 files changed, 149 insertions, 0 deletions
diff --git a/runtime/gc/task_processor_test.cc b/runtime/gc/task_processor_test.cc
new file mode 100644
index 0000000000..5dd6d8fb7b
--- /dev/null
+++ b/runtime/gc/task_processor_test.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_runtime_test.h"
+#include "task_processor.h"
+#include "thread_pool.h"
+#include "thread-inl.h"
+#include "utils.h"
+
+namespace art {
+namespace gc {
+
+class TaskProcessorTest : public CommonRuntimeTest {
+ public:
+};
+
+class RecursiveTask : public HeapTask {
+ public:
+ RecursiveTask(TaskProcessor* task_processor, Atomic<size_t>* counter, size_t max_recursion)
+ : HeapTask(NanoTime() + MsToNs(10)), task_processor_(task_processor), counter_(counter),
+ max_recursion_(max_recursion) {
+ }
+ virtual void Run(Thread* self) OVERRIDE {
+ if (max_recursion_ > 0) {
+ task_processor_->AddTask(self,
+ new RecursiveTask(task_processor_, counter_, max_recursion_ - 1));
+ counter_->FetchAndAddSequentiallyConsistent(1U);
+ }
+ }
+
+ private:
+ TaskProcessor* const task_processor_;
+ Atomic<size_t>* const counter_;
+ const size_t max_recursion_;
+};
+
+class WorkUntilDoneTask : public SelfDeletingTask {
+ public:
+ WorkUntilDoneTask(TaskProcessor* task_processor, Atomic<bool>* done_running)
+ : task_processor_(task_processor), done_running_(done_running) {
+ }
+ virtual void Run(Thread* self) OVERRIDE {
+ task_processor_->RunAllTasks(self);
+ done_running_->StoreSequentiallyConsistent(true);
+ }
+
+ private:
+ TaskProcessor* const task_processor_;
+ Atomic<bool>* done_running_;
+};
+
+TEST_F(TaskProcessorTest, Interrupt) {
+ ThreadPool thread_pool("task processor test", 1U);
+ Thread* const self = Thread::Current();
+ TaskProcessor task_processor;
+ static constexpr size_t kRecursion = 10;
+ Atomic<bool> done_running(false);
+ Atomic<size_t> counter(0);
+ task_processor.AddTask(self, new RecursiveTask(&task_processor, &counter, kRecursion));
+ task_processor.Start(self);
+ // Add a task which will wait until interrupted to the thread pool.
+ thread_pool.AddTask(self, new WorkUntilDoneTask(&task_processor, &done_running));
+ thread_pool.StartWorkers(self);
+ ASSERT_FALSE(done_running);
+ // Wait until all the tasks are done, but since we didn't interrupt, done_running should be 0.
+ while (counter.LoadSequentiallyConsistent() != kRecursion) {
+ usleep(10);
+ }
+ ASSERT_FALSE(done_running);
+ task_processor.Stop(self);
+ thread_pool.Wait(self, true, false);
+ // After the interrupt and wait, the WorkUntilInterruptedTasktask should have terminated and
+ // set done_running_ to true.
+ ASSERT_TRUE(done_running.LoadSequentiallyConsistent());
+
+ // Test that we finish remaining tasks before returning from RunTasksUntilInterrupted.
+ counter.StoreSequentiallyConsistent(0);
+ done_running.StoreSequentiallyConsistent(false);
+ // Self interrupt before any of the other tasks run, but since we added them we should keep on
+ // working until all the tasks are completed.
+ task_processor.Stop(self);
+ task_processor.AddTask(self, new RecursiveTask(&task_processor, &counter, kRecursion));
+ thread_pool.AddTask(self, new WorkUntilDoneTask(&task_processor, &done_running));
+ thread_pool.StartWorkers(self);
+ thread_pool.Wait(self, true, false);
+ ASSERT_TRUE(done_running.LoadSequentiallyConsistent());
+ ASSERT_EQ(counter.LoadSequentiallyConsistent(), kRecursion);
+}
+
+class TestOrderTask : public HeapTask {
+ public:
+ explicit TestOrderTask(uint64_t expected_time, size_t expected_counter, size_t* counter)
+ : HeapTask(expected_time), expected_counter_(expected_counter), counter_(counter) {
+ }
+ virtual void Run(Thread* thread) OVERRIDE {
+ UNUSED(thread); // Fix cppling bug.
+ ASSERT_EQ(*counter_, expected_counter_);
+ ++*counter_;
+ }
+
+ private:
+ const size_t expected_counter_;
+ size_t* const counter_;
+};
+
+TEST_F(TaskProcessorTest, Ordering) {
+ static const size_t kNumTasks = 25;
+ const uint64_t current_time = NanoTime();
+ Thread* const self = Thread::Current();
+ TaskProcessor task_processor;
+ task_processor.Stop(self);
+ size_t counter = 0;
+ std::vector<std::pair<uint64_t, size_t>> orderings;
+ for (size_t i = 0; i < kNumTasks; ++i) {
+ orderings.push_back(std::make_pair(current_time + MsToNs(10U * i), i));
+ }
+ for (size_t i = 0; i < kNumTasks; ++i) {
+ std::swap(orderings[i], orderings[(i * 87654231 + 12345) % orderings.size()]);
+ }
+ for (const auto& pair : orderings) {
+ auto* task = new TestOrderTask(pair.first, pair.second, &counter);
+ task_processor.AddTask(self, task);
+ }
+ ThreadPool thread_pool("task processor test", 1U);
+ Atomic<bool> done_running(false);
+ // Add a task which will wait until interrupted to the thread pool.
+ thread_pool.AddTask(self, new WorkUntilDoneTask(&task_processor, &done_running));
+ ASSERT_FALSE(done_running.LoadSequentiallyConsistent());
+ thread_pool.StartWorkers(self);
+ thread_pool.Wait(self, true, false);
+ ASSERT_TRUE(done_running.LoadSequentiallyConsistent());
+ ASSERT_EQ(counter, kNumTasks);
+}
+
+} // namespace gc
+} // namespace art