2017-08-17 05:17:24 +00:00
|
|
|
#if false
|
2017-08-02 03:23:06 +00:00
|
|
|
#include "task.h"
|
|
|
|
|
2017-08-01 08:24:06 +00:00
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
#include <doctest/doctest.h>
|
|
|
|
|
|
|
|
TaskManager::TaskManager() {
|
2017-08-02 03:23:06 +00:00
|
|
|
pending_tasks_[TaskThread::Indexer] = MakeUnique<TaskQueue>();
|
|
|
|
pending_tasks_[TaskThread::QueryDb] = MakeUnique<TaskQueue>();
|
2017-08-01 08:24:06 +00:00
|
|
|
}
|
|
|
|
|
2017-08-02 03:23:06 +00:00
|
|
|
void TaskManager::Post(TaskThread thread, const TTask& task) {
|
|
|
|
TaskQueue* queue = pending_tasks_[thread].get();
|
2017-08-01 08:24:06 +00:00
|
|
|
std::lock_guard<std::mutex> lock_guard(queue->tasks_mutex);
|
|
|
|
queue->tasks.push_back(task);
|
|
|
|
}
|
|
|
|
|
2017-08-02 03:23:06 +00:00
|
|
|
void TaskManager::SetIdle(TaskThread thread, const TIdleTask& task) {
|
|
|
|
TaskQueue* queue = pending_tasks_[thread].get();
|
2017-08-01 08:24:06 +00:00
|
|
|
std::lock_guard<std::mutex> lock_guard(queue->tasks_mutex);
|
|
|
|
assert(!queue->idle_task && "There is already an idle task");
|
|
|
|
queue->idle_task = task;
|
|
|
|
}
|
|
|
|
|
2017-08-02 03:23:06 +00:00
|
|
|
bool TaskManager::RunTasks(TaskThread thread, optional<std::chrono::duration<long long, std::nano>> max_time) {
|
2017-08-01 08:24:06 +00:00
|
|
|
auto start = std::chrono::high_resolution_clock::now();
|
|
|
|
TaskQueue* queue = pending_tasks_[thread].get();
|
|
|
|
|
2017-08-02 03:23:06 +00:00
|
|
|
bool ran_task = false;
|
|
|
|
|
2017-08-01 08:24:06 +00:00
|
|
|
while (true) {
|
2017-08-02 03:23:06 +00:00
|
|
|
optional<TTask> task;
|
2017-08-01 08:24:06 +00:00
|
|
|
|
|
|
|
// Get a task.
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock_guard(queue->tasks_mutex);
|
|
|
|
if (queue->tasks.empty())
|
2017-08-02 03:23:06 +00:00
|
|
|
break;
|
|
|
|
task = std::move(queue->tasks[queue->tasks.size() - 1]);
|
2017-08-01 08:24:06 +00:00
|
|
|
queue->tasks.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Execute task.
|
|
|
|
assert(task);
|
2017-08-02 03:23:06 +00:00
|
|
|
(*task)();
|
|
|
|
ran_task = true;
|
2017-08-01 08:24:06 +00:00
|
|
|
|
2017-08-02 03:23:06 +00:00
|
|
|
// Stop if we've run past our max time. Don't run idle_task.
|
2017-08-01 08:24:06 +00:00
|
|
|
auto elapsed = std::chrono::high_resolution_clock::now() - start;
|
|
|
|
if (max_time && elapsed > *max_time)
|
2017-08-02 03:23:06 +00:00
|
|
|
return ran_task;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queue->idle_task) {
|
|
|
|
// Even if the idle task returns false we still ran something before.
|
|
|
|
ran_task = (*queue->idle_task)() || ran_task;
|
2017-08-01 08:24:06 +00:00
|
|
|
}
|
2017-08-02 03:23:06 +00:00
|
|
|
|
|
|
|
return ran_task;
|
2017-08-01 08:24:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_SUITE("Task");
|
|
|
|
|
|
|
|
TEST_CASE("tasks are run as soon as they are posted") {
|
|
|
|
TaskManager tm;
|
|
|
|
|
|
|
|
// Post three tasks.
|
|
|
|
int next = 1;
|
|
|
|
int a = 0, b = 0, c = 0;
|
2017-08-02 03:23:06 +00:00
|
|
|
tm.Post(TaskThread::QueryDb, [&] {
|
2017-08-01 08:24:06 +00:00
|
|
|
a = next++;
|
2017-08-02 03:23:06 +00:00
|
|
|
});
|
|
|
|
tm.Post(TaskThread::QueryDb, [&] {
|
2017-08-01 08:24:06 +00:00
|
|
|
b = next++;
|
2017-08-02 03:23:06 +00:00
|
|
|
});
|
|
|
|
tm.Post(TaskThread::QueryDb, [&] {
|
2017-08-01 08:24:06 +00:00
|
|
|
c = next++;
|
2017-08-02 03:23:06 +00:00
|
|
|
});
|
2017-08-01 08:24:06 +00:00
|
|
|
|
|
|
|
// Execute all tasks.
|
2017-08-02 03:23:06 +00:00
|
|
|
tm.RunTasks(TaskThread::QueryDb, nullopt);
|
2017-08-01 08:24:06 +00:00
|
|
|
|
|
|
|
// Tasks are executed in reverse order.
|
|
|
|
REQUIRE(a == 3);
|
|
|
|
REQUIRE(b == 2);
|
|
|
|
REQUIRE(c == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("post from inside task manager") {
|
|
|
|
TaskManager tm;
|
|
|
|
|
|
|
|
// Post three tasks.
|
|
|
|
int next = 1;
|
|
|
|
int a = 0, b = 0, c = 0;
|
2017-08-02 03:23:06 +00:00
|
|
|
tm.Post(TaskThread::QueryDb, [&] () {
|
2017-08-01 08:24:06 +00:00
|
|
|
a = next++;
|
|
|
|
|
2017-08-02 03:23:06 +00:00
|
|
|
tm.Post(TaskThread::QueryDb, [&] {
|
2017-08-01 08:24:06 +00:00
|
|
|
b = next++;
|
|
|
|
|
2017-08-02 03:23:06 +00:00
|
|
|
tm.Post(TaskThread::QueryDb, [&] {
|
2017-08-01 08:24:06 +00:00
|
|
|
c = next++;
|
2017-08-02 03:23:06 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2017-08-01 08:24:06 +00:00
|
|
|
|
|
|
|
// Execute all tasks.
|
2017-08-02 03:23:06 +00:00
|
|
|
tm.RunTasks(TaskThread::QueryDb, nullopt);
|
2017-08-01 08:24:06 +00:00
|
|
|
|
|
|
|
// Tasks are executed in normal order because the next task is not posted
|
|
|
|
// until the previous one is executed.
|
|
|
|
REQUIRE(a == 1);
|
|
|
|
REQUIRE(b == 2);
|
|
|
|
REQUIRE(c == 3);
|
|
|
|
}
|
|
|
|
|
2017-08-02 03:23:06 +00:00
|
|
|
TEST_CASE("idle task is run after nested tasks") {
|
|
|
|
TaskManager tm;
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
tm.SetIdle(TaskThread::QueryDb, [&]() {
|
|
|
|
++count;
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
// No tasks posted - idle runs once.
|
|
|
|
REQUIRE(tm.RunTasks(TaskThread::QueryDb, nullopt));
|
|
|
|
REQUIRE(count == 1);
|
|
|
|
count = 0;
|
|
|
|
|
|
|
|
// Idle runs after other posted tasks.
|
|
|
|
bool did_run = false;
|
|
|
|
tm.Post(TaskThread::QueryDb, [&]() {
|
|
|
|
did_run = true;
|
|
|
|
});
|
|
|
|
REQUIRE(tm.RunTasks(TaskThread::QueryDb, nullopt));
|
|
|
|
REQUIRE(did_run);
|
|
|
|
REQUIRE(count == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("RunTasks returns false when idle task returns false and no other tasks were run") {
|
|
|
|
TaskManager tm;
|
|
|
|
|
|
|
|
REQUIRE(tm.RunTasks(TaskThread::QueryDb, nullopt) == false);
|
|
|
|
|
|
|
|
tm.SetIdle(TaskThread::QueryDb, []() { return false; });
|
|
|
|
REQUIRE(tm.RunTasks(TaskThread::QueryDb, nullopt) == false);
|
|
|
|
}
|
|
|
|
|
2017-08-17 05:17:24 +00:00
|
|
|
TEST_SUITE_END();
|
|
|
|
#endif
|