2021-10-12 14:20:30 +02:00
|
|
|
#include "ThreadPool.h"
|
2021-12-02 13:00:03 +01:00
|
|
|
#include <memory_resource>
|
2021-10-12 14:20:30 +02:00
|
|
|
|
|
|
|
|
using namespace Seele;
|
|
|
|
|
|
2022-03-26 12:55:04 +01:00
|
|
|
std::mutex Seele::promisesLock;
|
|
|
|
|
List<Promise*> Seele::promises;
|
2021-10-23 00:22:35 +02:00
|
|
|
|
2022-03-26 17:37:30 +01:00
|
|
|
//Event::Event(nullptr_t)
|
|
|
|
|
//{
|
|
|
|
|
//}
|
2021-12-02 13:00:03 +01:00
|
|
|
|
2022-03-26 12:55:04 +01:00
|
|
|
Event::Event(const std::string &name, const std::source_location &location)
|
2022-03-28 21:18:57 +02:00
|
|
|
: state(std::make_shared<EventState>())
|
2021-12-15 00:05:42 +01:00
|
|
|
{
|
2022-03-28 21:18:57 +02:00
|
|
|
state->name = name;
|
|
|
|
|
state->location = location;
|
2021-12-15 00:05:42 +01:00
|
|
|
}
|
2021-11-01 20:25:16 +01:00
|
|
|
|
2022-03-19 22:45:30 +01:00
|
|
|
Event::Event(const std::source_location &location)
|
2022-03-28 21:18:57 +02:00
|
|
|
: state(std::make_shared<EventState>())
|
2022-03-19 22:45:30 +01:00
|
|
|
{
|
2022-03-28 21:18:57 +02:00
|
|
|
state->name = location.function_name();
|
|
|
|
|
state->location = location;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Event::Event(const Event& other)
|
|
|
|
|
{
|
|
|
|
|
std::scoped_lock lock(other.eventLock);
|
|
|
|
|
state = other.state;
|
2022-03-19 22:45:30 +01:00
|
|
|
}
|
|
|
|
|
|
2022-03-26 17:37:30 +01:00
|
|
|
Event::Event(Event&& other)
|
|
|
|
|
{
|
2022-03-28 21:18:57 +02:00
|
|
|
std::scoped_lock lock(other.eventLock);
|
|
|
|
|
state = std::move(other.state);
|
2022-03-26 17:37:30 +01:00
|
|
|
}
|
|
|
|
|
|
2022-03-28 21:18:57 +02:00
|
|
|
Event& Event::operator=(const Event& other)
|
|
|
|
|
{
|
|
|
|
|
if(this != &other)
|
|
|
|
|
{
|
|
|
|
|
std::scoped_lock lock(eventLock, other.eventLock);
|
|
|
|
|
state = other.state;
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
2022-03-26 17:37:30 +01:00
|
|
|
Event& Event::operator=(Event&& other)
|
|
|
|
|
{
|
|
|
|
|
if(this != &other)
|
|
|
|
|
{
|
|
|
|
|
std::scoped_lock lock(eventLock, other.eventLock);
|
2022-03-28 21:18:57 +02:00
|
|
|
state = std::move(other.state);
|
2022-03-26 17:37:30 +01:00
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-01 20:25:16 +01:00
|
|
|
void Event::raise()
|
2021-10-23 00:22:35 +02:00
|
|
|
{
|
2022-03-26 17:37:30 +01:00
|
|
|
std::scoped_lock lock(eventLock);
|
2022-03-28 21:18:57 +02:00
|
|
|
state->data = true;
|
|
|
|
|
if(state->waitingJobs.size() > 0)
|
2022-03-26 12:55:04 +01:00
|
|
|
{
|
2022-03-28 21:18:57 +02:00
|
|
|
getGlobalThreadPool().scheduleBatch(state->waitingJobs);
|
2022-03-26 12:55:04 +01:00
|
|
|
}
|
2022-03-28 21:18:57 +02:00
|
|
|
if(state->waitingMainJobs.size() > 0)
|
2022-03-26 12:55:04 +01:00
|
|
|
{
|
2022-03-28 21:18:57 +02:00
|
|
|
getGlobalThreadPool().scheduleBatch(state->waitingMainJobs);
|
2022-03-26 12:55:04 +01:00
|
|
|
}
|
2021-11-01 20:25:16 +01:00
|
|
|
}
|
|
|
|
|
void Event::reset()
|
2021-12-15 00:05:42 +01:00
|
|
|
{
|
2022-03-26 17:37:30 +01:00
|
|
|
std::scoped_lock lock(eventLock);
|
2022-03-28 21:18:57 +02:00
|
|
|
state->data = false;
|
2021-10-23 00:22:35 +02:00
|
|
|
}
|
2021-10-12 14:20:30 +02:00
|
|
|
|
2021-11-01 20:25:16 +01:00
|
|
|
bool Event::await_ready()
|
|
|
|
|
{
|
2022-03-26 17:37:30 +01:00
|
|
|
eventLock.lock();
|
2022-03-28 21:18:57 +02:00
|
|
|
bool result = state->data;
|
2022-02-14 16:29:26 +01:00
|
|
|
if(result)
|
|
|
|
|
{
|
2022-03-26 17:37:30 +01:00
|
|
|
eventLock.unlock();
|
2022-02-14 16:29:26 +01:00
|
|
|
}
|
|
|
|
|
return result;
|
2021-10-12 14:20:30 +02:00
|
|
|
}
|
|
|
|
|
|
2022-03-26 12:55:04 +01:00
|
|
|
void Event::await_suspend(std::coroutine_handle<JobPromiseBase<false>> h)
|
|
|
|
|
{
|
|
|
|
|
//h.promise().enqueue(this);
|
2022-03-28 21:18:57 +02:00
|
|
|
state->waitingJobs.add(JobBase<false>(&h.promise()));
|
2022-03-26 17:37:30 +01:00
|
|
|
eventLock.unlock();
|
2022-03-26 12:55:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Event::await_suspend(std::coroutine_handle<JobPromiseBase<true>> h)
|
|
|
|
|
{
|
|
|
|
|
//h.promise().enqueue(this);
|
2022-03-28 21:18:57 +02:00
|
|
|
state->waitingMainJobs.add(JobBase<true>(&h.promise()));
|
2022-03-26 17:37:30 +01:00
|
|
|
eventLock.unlock();
|
2022-03-26 12:55:04 +01:00
|
|
|
}
|
|
|
|
|
|
2021-10-12 14:20:30 +02:00
|
|
|
ThreadPool::ThreadPool(uint32 threadCount)
|
|
|
|
|
: workers(threadCount)
|
|
|
|
|
{
|
2021-11-01 20:25:16 +01:00
|
|
|
running.store(true);
|
2021-12-15 00:05:42 +01:00
|
|
|
for (uint32 i = 0; i < threadCount; ++i)
|
2021-11-01 20:25:16 +01:00
|
|
|
{
|
2022-03-19 22:45:30 +01:00
|
|
|
workers[i] = std::thread(&ThreadPool::threadLoop, this);
|
2021-11-01 20:25:16 +01:00
|
|
|
}
|
2021-10-12 14:20:30 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-23 00:22:35 +02:00
|
|
|
ThreadPool::~ThreadPool()
|
2021-10-12 14:20:30 +02:00
|
|
|
{
|
2022-03-26 12:55:04 +01:00
|
|
|
running.store(false);
|
|
|
|
|
{
|
|
|
|
|
std::unique_lock lock(mainJobLock);
|
|
|
|
|
mainJobCV.notify_all();
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
std::unique_lock lock(jobQueueLock);
|
|
|
|
|
jobQueueCV.notify_all();
|
|
|
|
|
}
|
|
|
|
|
for(auto& worker : workers)
|
|
|
|
|
{
|
|
|
|
|
worker.join();
|
|
|
|
|
}
|
2022-02-14 16:29:26 +01:00
|
|
|
}
|
|
|
|
|
|
2022-03-19 22:45:30 +01:00
|
|
|
void ThreadPool::waitIdle()
|
2022-02-14 16:29:26 +01:00
|
|
|
{
|
2022-03-19 22:45:30 +01:00
|
|
|
while(true)
|
2022-01-12 14:40:26 +01:00
|
|
|
{
|
2022-03-19 22:45:30 +01:00
|
|
|
std::unique_lock lock(numIdlingLock);
|
|
|
|
|
if(numIdling == workers.size())
|
|
|
|
|
{
|
2022-03-28 21:18:57 +02:00
|
|
|
assert(promises.size() == 0);
|
2022-03-19 22:45:30 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2022-03-26 12:55:04 +01:00
|
|
|
numIdlingIncr.wait(lock);
|
2022-01-12 14:40:26 +01:00
|
|
|
}
|
2021-10-23 00:22:35 +02:00
|
|
|
}
|
2022-03-26 12:55:04 +01:00
|
|
|
void ThreadPool::scheduleJob(Job job)
|
2021-11-01 20:25:16 +01:00
|
|
|
{
|
2022-03-26 12:55:04 +01:00
|
|
|
assert(!job.done());
|
2022-01-12 14:40:26 +01:00
|
|
|
std::scoped_lock lock(jobQueueLock);
|
2022-03-26 12:55:04 +01:00
|
|
|
jobQueue.add(std::move(job));
|
2022-01-12 14:40:26 +01:00
|
|
|
jobQueueCV.notify_one();
|
|
|
|
|
}
|
2022-03-26 12:55:04 +01:00
|
|
|
void ThreadPool::scheduleJob(MainJob job)
|
2022-01-12 14:40:26 +01:00
|
|
|
{
|
2022-03-26 12:55:04 +01:00
|
|
|
assert(!job.done());
|
2022-01-12 14:40:26 +01:00
|
|
|
std::scoped_lock lock(mainJobLock);
|
2022-03-26 12:55:04 +01:00
|
|
|
mainJobs.add(std::move(job));
|
2022-01-12 14:40:26 +01:00
|
|
|
mainJobCV.notify_one();
|
2021-11-01 20:25:16 +01:00
|
|
|
}
|
2022-03-19 22:45:30 +01:00
|
|
|
void ThreadPool::mainLoop()
|
2021-11-19 15:08:56 +01:00
|
|
|
{
|
2022-03-26 12:55:04 +01:00
|
|
|
while(running.load())
|
2021-11-19 15:08:56 +01:00
|
|
|
{
|
2022-03-26 12:55:04 +01:00
|
|
|
MainJob job;
|
2021-11-19 15:08:56 +01:00
|
|
|
{
|
2022-03-19 22:45:30 +01:00
|
|
|
std::unique_lock lock(mainJobLock);
|
|
|
|
|
if(mainJobs.empty())
|
2021-12-15 00:05:42 +01:00
|
|
|
{
|
2022-03-19 22:45:30 +01:00
|
|
|
mainJobCV.wait(lock);
|
2021-12-15 00:05:42 +01:00
|
|
|
}
|
2022-03-26 12:55:04 +01:00
|
|
|
[[likely]]
|
|
|
|
|
if(!mainJobs.empty())
|
|
|
|
|
{
|
|
|
|
|
job = mainJobs.front();
|
|
|
|
|
mainJobs.popFront();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-03-19 22:45:30 +01:00
|
|
|
}
|
2022-03-26 12:55:04 +01:00
|
|
|
job.resume();
|
2022-03-19 22:45:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ThreadPool::threadLoop()
|
|
|
|
|
{
|
2022-03-26 12:55:04 +01:00
|
|
|
List<Job> localQueue;
|
|
|
|
|
while (running.load())
|
2022-03-19 22:45:30 +01:00
|
|
|
{
|
|
|
|
|
[[likely]]
|
|
|
|
|
if(!localQueue.empty())
|
|
|
|
|
{
|
2022-03-26 12:55:04 +01:00
|
|
|
Job job = localQueue.retrieve();
|
|
|
|
|
job.resume();
|
2021-11-19 15:08:56 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-03-19 22:45:30 +01:00
|
|
|
std::unique_lock lock(jobQueueLock);
|
|
|
|
|
if (jobQueue.empty())
|
2021-11-01 20:25:16 +01:00
|
|
|
{
|
2021-12-15 00:05:42 +01:00
|
|
|
{
|
2022-03-19 22:45:30 +01:00
|
|
|
std::unique_lock lock2(numIdlingLock);
|
|
|
|
|
numIdling++;
|
|
|
|
|
numIdlingIncr.notify_one();
|
2021-12-15 00:05:42 +01:00
|
|
|
}
|
2022-03-19 22:45:30 +01:00
|
|
|
jobQueueCV.wait(lock);
|
2021-12-15 00:05:42 +01:00
|
|
|
{
|
2022-03-19 22:45:30 +01:00
|
|
|
std::unique_lock lock2(numIdlingLock);
|
|
|
|
|
numIdling--;
|
2021-12-15 00:05:42 +01:00
|
|
|
}
|
2021-11-19 15:08:56 +01:00
|
|
|
}
|
2022-03-19 22:45:30 +01:00
|
|
|
// take 1/numThreads jobs, maybe make this a parameter that
|
|
|
|
|
// adjusts based on past workload
|
2022-03-26 12:55:04 +01:00
|
|
|
uint32 partitionedWorkload = (uint32)(jobQueue.size() / workers.size());
|
|
|
|
|
uint32 numTaken = std::clamp(partitionedWorkload, 1u, localQueueSize);
|
2022-03-19 22:45:30 +01:00
|
|
|
while (!jobQueue.empty() && localQueue.size() < numTaken)
|
|
|
|
|
{
|
|
|
|
|
localQueue.add(jobQueue.retrieve());
|
|
|
|
|
}
|
2021-11-24 12:10:23 +01:00
|
|
|
}
|
2021-11-01 20:25:16 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-12-15 00:05:42 +01:00
|
|
|
ThreadPool &Seele::getGlobalThreadPool()
|
2021-10-23 00:22:35 +02:00
|
|
|
{
|
|
|
|
|
static ThreadPool threadPool;
|
|
|
|
|
return threadPool;
|
2021-10-12 14:20:30 +02:00
|
|
|
}
|