#pragma once #include #include "Containers/List.h" namespace Seele { extern class ThreadPool& getGlobalThreadPool(); template struct JobBase; template struct JobPromiseBase { JobBase get_return_object() noexcept; inline auto initial_suspend() const noexcept; std::suspend_never final_suspend() const noexcept { return {}; } void return_void() noexcept {} void unhandled_exception() noexcept { std::cerr << "Unhandled exception caught" << std::endl; exit(1); }; }; template struct JobBase { public: using promise_type = JobPromiseBase; explicit JobBase(std::coroutine_handle handle) : handle(handle) {} ~JobBase() { if(handle) { handle.destroy(); } } void resume() { handle.resume(); } private: std::coroutine_handle handle; }; using MainJob = JobBase; using Job = JobBase; struct Event { public: Event(); Event(const std::string& name); void raise(); void reset(); bool await_ready(); template constexpr void await_suspend(std::coroutine_handle> h); constexpr void await_resume() {} private: std::string name; RefPtr flag; }; class ThreadPool { public: ThreadPool(uint32 threadCount = std::thread::hardware_concurrency()); virtual ~ThreadPool(); void addJob(Job&& job); void addJob(MainJob&& job); void enqueueWaiting(Event* event, Job&& job); void enqueueWaiting(Event* event, MainJob&& job); void notify(Event* event); private: std::atomic_bool running; std::thread* mainThread; std::vector workers; List mainJobs; std::mutex mainJobLock; List jobQueue; std::mutex jobQueueLock; Map> waitingJobs; std::mutex waitingLock; Map> waitingMainJobs; std::mutex waitingMainLock; void threadLoop(const bool isMainThread); }; template inline JobBase JobPromiseBase::get_return_object() noexcept { return JobBase { std::coroutine_handle>::from_promise(*this) }; } template inline auto JobPromiseBase::initial_suspend() const noexcept { struct JobAwaitable { constexpr bool await_ready() { return false; } constexpr void await_suspend(std::coroutine_handle> h) { getGlobalThreadPool().addJob(JobBase(h)); } constexpr void await_resume() {} }; return JobAwaitable{}; } template inline constexpr void Event::await_suspend(std::coroutine_handle> h) { getGlobalThreadPool().enqueueWaiting(this, JobBase(h)); } } // namespace Seele