2021-12-16 23:48:52 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <hex.hpp>
|
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
#include <cstdio>
|
|
|
|
#include <thread>
|
|
|
|
#include <functional>
|
|
|
|
#include <cstdint>
|
2022-02-01 18:09:40 +01:00
|
|
|
#include <mutex>
|
2022-08-17 16:15:36 +02:00
|
|
|
#include <chrono>
|
|
|
|
#include <memory>
|
|
|
|
#include <list>
|
2022-10-04 23:37:48 +02:00
|
|
|
#include <condition_variable>
|
2021-12-16 23:48:52 +01:00
|
|
|
|
|
|
|
namespace hex {
|
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
class TaskHolder;
|
|
|
|
class TaskManager;
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief A type representing a running asynchronous task
|
|
|
|
*/
|
2021-12-16 23:48:52 +01:00
|
|
|
class Task {
|
|
|
|
public:
|
2022-07-29 18:49:43 +02:00
|
|
|
Task() = default;
|
2022-09-19 16:09:22 +02:00
|
|
|
Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
|
2021-12-16 23:48:52 +01:00
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
Task(const Task&) = delete;
|
2022-07-29 18:49:43 +02:00
|
|
|
Task(Task &&other) noexcept;
|
2022-08-17 16:15:36 +02:00
|
|
|
~Task();
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief Updates the current process value of the task
|
|
|
|
* @param value Current value
|
|
|
|
*/
|
2022-08-17 16:15:36 +02:00
|
|
|
void update(u64 value = 0);
|
2023-03-21 15:33:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sets the maximum value of the task
|
|
|
|
* @param value Maximum value of the task
|
|
|
|
*/
|
2022-08-17 16:15:36 +02:00
|
|
|
void setMaxValue(u64 value);
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Interrupts the task
|
|
|
|
* For regular Tasks, this just throws an exception to stop the task.
|
|
|
|
* If a custom interrupt callback is set, an exception is thrown and the callback is called.
|
|
|
|
*/
|
|
|
|
void interrupt();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Sets a callback that is called when the task is interrupted
|
|
|
|
* @param callback Callback to be called
|
|
|
|
*/
|
|
|
|
void setInterruptCallback(std::function<void()> callback);
|
|
|
|
|
2022-09-19 16:09:22 +02:00
|
|
|
[[nodiscard]] bool isBackgroundTask() const;
|
2022-08-17 16:15:36 +02:00
|
|
|
[[nodiscard]] bool isFinished() const;
|
|
|
|
[[nodiscard]] bool hadException() const;
|
|
|
|
[[nodiscard]] bool wasInterrupted() const;
|
2022-10-28 14:32:28 +02:00
|
|
|
[[nodiscard]] bool shouldInterrupt() const;
|
2023-03-21 15:33:43 +01:00
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
void clearException();
|
2022-09-03 23:56:57 +02:00
|
|
|
[[nodiscard]] std::string getExceptionMessage() const;
|
2022-07-29 18:49:43 +02:00
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
[[nodiscard]] const std::string &getUnlocalizedName();
|
|
|
|
[[nodiscard]] u64 getValue() const;
|
|
|
|
[[nodiscard]] u64 getMaxValue() const;
|
|
|
|
|
|
|
|
private:
|
2021-12-16 23:48:52 +01:00
|
|
|
void finish();
|
2022-08-17 16:15:36 +02:00
|
|
|
void interruption();
|
2022-09-03 23:56:57 +02:00
|
|
|
void exception(const char *message);
|
2022-08-17 16:15:36 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
mutable std::mutex m_mutex;
|
|
|
|
|
|
|
|
std::string m_unlocalizedName;
|
2022-10-04 23:37:48 +02:00
|
|
|
std::atomic<u64> m_currValue = 0, m_maxValue = 0;
|
2022-09-13 16:05:41 +02:00
|
|
|
std::function<void()> m_interruptCallback;
|
2022-10-04 23:37:48 +02:00
|
|
|
std::function<void(Task &)> m_function;
|
2021-12-16 23:48:52 +01:00
|
|
|
|
2022-10-04 23:37:48 +02:00
|
|
|
std::atomic<bool> m_shouldInterrupt = false;
|
|
|
|
std::atomic<bool> m_background = true;
|
2022-08-17 16:15:36 +02:00
|
|
|
|
2022-10-04 23:37:48 +02:00
|
|
|
std::atomic<bool> m_interrupted = false;
|
|
|
|
std::atomic<bool> m_finished = false;
|
|
|
|
std::atomic<bool> m_hadException = false;
|
2022-09-03 23:56:57 +02:00
|
|
|
std::string m_exceptionMessage;
|
2022-08-17 16:15:36 +02:00
|
|
|
|
|
|
|
struct TaskInterruptor { virtual ~TaskInterruptor() = default; };
|
|
|
|
|
|
|
|
friend class TaskHolder;
|
|
|
|
friend class TaskManager;
|
|
|
|
};
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief A type holding a weak reference to a Task
|
|
|
|
*/
|
2022-08-17 16:15:36 +02:00
|
|
|
class TaskHolder {
|
|
|
|
public:
|
|
|
|
TaskHolder() = default;
|
|
|
|
explicit TaskHolder(std::weak_ptr<Task> task) : m_task(std::move(task)) { }
|
|
|
|
|
|
|
|
[[nodiscard]] bool isRunning() const;
|
|
|
|
[[nodiscard]] bool hadException() const;
|
|
|
|
[[nodiscard]] bool wasInterrupted() const;
|
2022-10-28 14:32:28 +02:00
|
|
|
[[nodiscard]] bool shouldInterrupt() const;
|
2022-08-17 16:15:36 +02:00
|
|
|
|
|
|
|
void interrupt();
|
|
|
|
private:
|
|
|
|
std::weak_ptr<Task> m_task;
|
|
|
|
};
|
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief The Task Manager is responsible for running and managing asynchronous tasks
|
|
|
|
*/
|
2022-08-17 16:15:36 +02:00
|
|
|
class TaskManager {
|
|
|
|
public:
|
|
|
|
TaskManager() = delete;
|
2021-12-16 23:48:52 +01:00
|
|
|
|
2022-10-04 23:37:48 +02:00
|
|
|
static void init();
|
|
|
|
static void exit();
|
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
constexpr static auto NoProgress = 0;
|
2021-12-16 23:48:52 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
/**
|
|
|
|
* @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer
|
|
|
|
* @param name Name of the task
|
|
|
|
* @param maxValue Maximum value of the task
|
|
|
|
* @param function Function to be executed
|
|
|
|
* @return A TaskHolder holding a weak reference to the task
|
|
|
|
*/
|
2022-08-17 16:15:36 +02:00
|
|
|
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
|
2023-03-21 15:33:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Creates a new asynchronous task that does not get displayed in the Task Manager
|
|
|
|
* @param name Name of the task
|
|
|
|
* @param function Function to be executed
|
|
|
|
* @return A TaskHolder holding a weak reference to the task
|
|
|
|
*/
|
2022-09-19 16:09:22 +02:00
|
|
|
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
|
2022-10-04 23:37:48 +02:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame
|
|
|
|
* @param function Function to be executed
|
|
|
|
*/
|
|
|
|
static void doLater(const std::function<void()> &function);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Creates a callback that will be executed when all tasks are finished
|
|
|
|
* @param function Function to be executed
|
|
|
|
*/
|
|
|
|
static void runWhenTasksFinished(const std::function<void()> &function);
|
|
|
|
|
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
static void collectGarbage();
|
2022-01-09 21:27:59 +01:00
|
|
|
|
2022-02-01 18:09:40 +01:00
|
|
|
static size_t getRunningTaskCount();
|
2022-12-27 11:35:20 +01:00
|
|
|
static size_t getRunningBackgroundTaskCount();
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2023-03-21 15:33:43 +01:00
|
|
|
static std::list<std::shared_ptr<Task>> &getRunningTasks();
|
2022-08-17 16:15:36 +02:00
|
|
|
static void runDeferredCalls();
|
2022-12-27 11:35:20 +01:00
|
|
|
|
2021-12-16 23:48:52 +01:00
|
|
|
private:
|
2022-12-28 23:06:27 +01:00
|
|
|
static std::mutex s_deferredCallsMutex, s_tasksFinishedMutex;
|
2022-02-01 18:09:40 +01:00
|
|
|
|
2022-08-17 16:15:36 +02:00
|
|
|
static std::list<std::shared_ptr<Task>> s_tasks;
|
2022-10-05 21:25:52 +02:00
|
|
|
static std::list<std::shared_ptr<Task>> s_taskQueue;
|
2022-08-17 16:15:36 +02:00
|
|
|
static std::list<std::function<void()>> s_deferredCalls;
|
2022-12-27 11:35:20 +01:00
|
|
|
static std::list<std::function<void()>> s_tasksFinishedCallbacks;
|
2022-10-04 23:37:48 +02:00
|
|
|
|
|
|
|
static std::mutex s_queueMutex;
|
|
|
|
static std::condition_variable s_jobCondVar;
|
|
|
|
static std::vector<std::jthread> s_workers;
|
|
|
|
|
|
|
|
static void runner(const std::stop_token &stopToken);
|
2021-12-16 23:48:52 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|