2021-10-12 14:20:30 +02:00
|
|
|
#pragma once
|
|
|
|
|
#include <thread>
|
2021-11-18 12:48:21 +01:00
|
|
|
#include <coroutine>
|
2021-11-05 00:01:12 +01:00
|
|
|
#include "MinimalEngine.h"
|
2021-10-23 00:22:35 +02:00
|
|
|
#include "Containers/List.h"
|
2021-10-12 14:20:30 +02:00
|
|
|
|
|
|
|
|
namespace Seele
|
|
|
|
|
{
|
2021-11-01 20:25:16 +01:00
|
|
|
extern class ThreadPool& getGlobalThreadPool();
|
2021-10-12 14:20:30 +02:00
|
|
|
|
2021-11-01 20:25:16 +01:00
|
|
|
template<bool MainJob>
|
|
|
|
|
struct JobBase;
|
|
|
|
|
template<bool MainJob>
|
|
|
|
|
struct JobPromiseBase
|
|
|
|
|
{
|
|
|
|
|
JobBase<MainJob> get_return_object() noexcept;
|
|
|
|
|
|
|
|
|
|
inline auto initial_suspend() const noexcept;
|
2021-12-02 13:00:03 +01:00
|
|
|
inline auto final_suspend() const noexcept;
|
2021-10-12 14:20:30 +02:00
|
|
|
|
|
|
|
|
void return_void() noexcept {}
|
|
|
|
|
void unhandled_exception() noexcept {
|
2021-12-02 13:00:03 +01:00
|
|
|
std::cerr << "Unhandled exception" << std::endl;
|
2021-10-12 14:20:30 +02:00
|
|
|
exit(1);
|
|
|
|
|
};
|
2021-12-02 13:00:03 +01:00
|
|
|
std::coroutine_handle<> continuation;
|
2021-10-12 14:20:30 +02:00
|
|
|
};
|
2021-11-01 20:25:16 +01:00
|
|
|
|
|
|
|
|
struct Event
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Event();
|
2021-12-02 13:00:03 +01:00
|
|
|
Event(nullptr_t);
|
2021-11-01 20:25:16 +01:00
|
|
|
Event(const std::string& name);
|
2021-11-11 20:12:50 +01:00
|
|
|
auto operator<=>(const Event& other) const
|
|
|
|
|
{
|
2021-11-13 19:28:18 +01:00
|
|
|
return flag <=> other.flag;
|
2021-11-11 20:12:50 +01:00
|
|
|
}
|
|
|
|
|
Event operator co_await()
|
|
|
|
|
{
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
2021-11-14 20:36:53 +01:00
|
|
|
operator bool()
|
|
|
|
|
{
|
|
|
|
|
return flag->load();
|
|
|
|
|
}
|
2021-11-11 20:12:50 +01:00
|
|
|
|
2021-11-01 20:25:16 +01:00
|
|
|
void raise();
|
|
|
|
|
void reset();
|
|
|
|
|
bool await_ready();
|
|
|
|
|
template<bool MainJob>
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h);
|
|
|
|
|
constexpr void await_resume() {}
|
|
|
|
|
private:
|
|
|
|
|
std::string name;
|
|
|
|
|
RefPtr<std::atomic_bool> flag;
|
2021-11-11 20:12:50 +01:00
|
|
|
friend class ThreadPool;
|
2021-10-12 14:20:30 +02:00
|
|
|
};
|
|
|
|
|
|
2021-12-02 13:00:03 +01:00
|
|
|
|
2021-11-24 12:10:23 +01:00
|
|
|
static std::atomic_uint64_t globalCounter;
|
|
|
|
|
template<bool MainJob>
|
|
|
|
|
struct JobBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using promise_type = JobPromiseBase<MainJob>;
|
|
|
|
|
|
|
|
|
|
explicit JobBase()
|
|
|
|
|
: id(-1)
|
|
|
|
|
{}
|
|
|
|
|
explicit JobBase(std::coroutine_handle<promise_type> handle)
|
|
|
|
|
: handle(handle)
|
|
|
|
|
, id(globalCounter++)
|
2021-12-02 13:00:03 +01:00
|
|
|
, event(std::format("Job {}", id))
|
2021-11-24 12:10:23 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
JobBase(const JobBase & rhs) = delete;
|
|
|
|
|
JobBase(JobBase&& rhs)
|
|
|
|
|
: handle(std::move(rhs.handle))
|
|
|
|
|
, id(std::move(rhs.id))
|
|
|
|
|
{
|
|
|
|
|
rhs.id = -1;
|
|
|
|
|
rhs.handle = nullptr;
|
|
|
|
|
}
|
|
|
|
|
~JobBase()
|
|
|
|
|
{
|
2021-12-02 13:00:03 +01:00
|
|
|
if(handle && handle.done())
|
2021-11-24 12:10:23 +01:00
|
|
|
{
|
|
|
|
|
handle.destroy();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
JobBase& operator=(const JobBase& rhs) = delete;
|
|
|
|
|
JobBase& operator=(JobBase&& rhs)
|
|
|
|
|
{
|
|
|
|
|
if(this != &rhs)
|
|
|
|
|
{
|
|
|
|
|
handle = std::move(rhs.handle);
|
|
|
|
|
id = std::move(rhs.id);
|
|
|
|
|
rhs.id = -1;
|
|
|
|
|
rhs.handle = nullptr;
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
void resume()
|
|
|
|
|
{
|
|
|
|
|
handle.resume();
|
|
|
|
|
}
|
2021-12-02 13:00:03 +01:00
|
|
|
void then(JobBase continuation)
|
|
|
|
|
{
|
|
|
|
|
handle.promise().continuation = continuation.handle;
|
|
|
|
|
}
|
|
|
|
|
bool done()
|
|
|
|
|
{
|
|
|
|
|
return handle.done();
|
|
|
|
|
}
|
|
|
|
|
void raise()
|
|
|
|
|
{
|
|
|
|
|
event.raise();
|
|
|
|
|
}
|
|
|
|
|
void reset()
|
|
|
|
|
{
|
|
|
|
|
event.reset();
|
|
|
|
|
}
|
|
|
|
|
Event operator co_await()
|
|
|
|
|
{
|
|
|
|
|
return event;
|
|
|
|
|
}
|
|
|
|
|
template<typename... Awaitable>
|
|
|
|
|
static JobBase all(Awaitable... jobs)
|
|
|
|
|
{
|
|
|
|
|
co_await jobs;
|
|
|
|
|
}
|
|
|
|
|
template<typename Iterable>
|
|
|
|
|
static JobBase all(Iterable&& collection)
|
|
|
|
|
{
|
|
|
|
|
for(auto&& it : collection)
|
|
|
|
|
{
|
|
|
|
|
co_await it;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
template<typename JobFunc, typename IterableParams>
|
|
|
|
|
static JobBase launchJobs(JobFunc&& func, IterableParams params)
|
|
|
|
|
{
|
|
|
|
|
List<JobBase> jobs;
|
|
|
|
|
for(auto&& param : params)
|
|
|
|
|
{
|
|
|
|
|
jobs.add(func(param));
|
|
|
|
|
}
|
|
|
|
|
for(auto job : jobs)
|
|
|
|
|
{
|
|
|
|
|
co_await job;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-24 12:10:23 +01:00
|
|
|
private:
|
|
|
|
|
std::coroutine_handle<promise_type> handle;
|
2021-12-02 13:00:03 +01:00
|
|
|
Event event;
|
2021-11-24 12:10:23 +01:00
|
|
|
uint64 id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using MainJob = JobBase<true>;
|
|
|
|
|
using Job = JobBase<false>;
|
|
|
|
|
|
2021-10-12 14:20:30 +02:00
|
|
|
class ThreadPool
|
|
|
|
|
{
|
|
|
|
|
public:
|
2021-12-02 13:00:03 +01:00
|
|
|
ThreadPool(uint32 threadCount = std::thread::hardware_concurrency());
|
2021-10-12 14:20:30 +02:00
|
|
|
virtual ~ThreadPool();
|
2021-11-01 20:25:16 +01:00
|
|
|
void addJob(Job&& job);
|
|
|
|
|
void addJob(MainJob&& job);
|
2021-12-02 13:00:03 +01:00
|
|
|
void enqueueWaiting(Event& event, Job&& job);
|
|
|
|
|
void enqueueWaiting(Event& event, MainJob&& job);
|
2021-11-24 12:10:23 +01:00
|
|
|
void notify(Event& event);
|
2021-12-02 13:00:03 +01:00
|
|
|
void threadLoop(const bool isMainThread);
|
2021-10-12 14:20:30 +02:00
|
|
|
private:
|
2021-11-01 20:25:16 +01:00
|
|
|
std::atomic_bool running;
|
2021-10-23 00:22:35 +02:00
|
|
|
std::vector<std::thread> workers;
|
2021-11-01 20:25:16 +01:00
|
|
|
|
|
|
|
|
List<MainJob> mainJobs;
|
|
|
|
|
std::mutex mainJobLock;
|
2021-11-11 20:12:50 +01:00
|
|
|
std::condition_variable mainJobCV;
|
2021-11-01 20:25:16 +01:00
|
|
|
|
|
|
|
|
List<Job> jobQueue;
|
|
|
|
|
std::mutex jobQueueLock;
|
2021-11-11 20:12:50 +01:00
|
|
|
std::condition_variable jobQueueCV;
|
2021-11-01 20:25:16 +01:00
|
|
|
|
2021-11-11 20:12:50 +01:00
|
|
|
Map<Event, List<Job>> waitingJobs;
|
2021-11-01 20:25:16 +01:00
|
|
|
std::mutex waitingLock;
|
|
|
|
|
|
2021-11-11 20:12:50 +01:00
|
|
|
Map<Event, List<MainJob>> waitingMainJobs;
|
2021-11-01 20:25:16 +01:00
|
|
|
std::mutex waitingMainLock;
|
|
|
|
|
|
2021-11-19 15:08:56 +01:00
|
|
|
void tryMainJob();
|
2021-10-12 14:20:30 +02:00
|
|
|
};
|
2021-11-01 20:25:16 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
template<bool MainJob>
|
|
|
|
|
inline JobBase<MainJob> JobPromiseBase<MainJob>::get_return_object() noexcept {
|
2021-11-11 20:12:50 +01:00
|
|
|
return JobBase<MainJob>();
|
2021-11-01 20:25:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<bool MainJob>
|
|
|
|
|
inline auto JobPromiseBase<MainJob>::initial_suspend() const noexcept
|
|
|
|
|
{
|
|
|
|
|
struct JobAwaitable
|
|
|
|
|
{
|
|
|
|
|
constexpr bool await_ready() { return false; }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h)
|
|
|
|
|
{
|
2021-11-11 20:12:50 +01:00
|
|
|
getGlobalThreadPool().addJob(std::move(JobBase<MainJob>(h)));
|
2021-11-01 20:25:16 +01:00
|
|
|
}
|
|
|
|
|
constexpr void await_resume() {}
|
|
|
|
|
};
|
|
|
|
|
return JobAwaitable{};
|
|
|
|
|
}
|
2021-12-02 13:00:03 +01:00
|
|
|
template<bool MainJob>
|
|
|
|
|
inline auto JobPromiseBase<MainJob>::final_suspend() const noexcept
|
|
|
|
|
{
|
|
|
|
|
struct JobAwaitable
|
|
|
|
|
{
|
|
|
|
|
constexpr bool await_ready() const noexcept { return false; }
|
|
|
|
|
constexpr auto await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h) const noexcept
|
|
|
|
|
{
|
|
|
|
|
return h.promise().continuation;
|
|
|
|
|
}
|
|
|
|
|
constexpr void await_resume() const noexcept {}
|
|
|
|
|
};
|
|
|
|
|
return JobAwaitable{};
|
|
|
|
|
}
|
2021-11-01 20:25:16 +01:00
|
|
|
|
|
|
|
|
template<bool MainJob>
|
|
|
|
|
inline constexpr void Event::await_suspend(std::coroutine_handle<JobPromiseBase<MainJob>> h)
|
|
|
|
|
{
|
2021-11-24 12:10:23 +01:00
|
|
|
getGlobalThreadPool().enqueueWaiting(*this, std::move(JobBase<MainJob>(h)));
|
2021-11-01 20:25:16 +01:00
|
|
|
}
|
|
|
|
|
|
2021-10-12 14:20:30 +02:00
|
|
|
} // namespace Seele
|