rtengine/src/runtime/jobs.c
2024-01-16 16:10:56 +01:00

66 lines
1.7 KiB
C

#include "jobs.h"
#include "threading.h"
#define MAX_WORKERS 32
#define JOB_QUEUE_SIZE 2048
/* A "chunk" of iterations for a particular job */
typedef struct {
uint32_t base_iteration;
uint32_t iteration_count;
rt_job_fn *fn;
void *param;
} rt_job_chunk;
typedef struct {
/* Queue */
struct {
rt_job_chunk *chunks;
unsigned int head;
unsigned int tail;
rt_condition_var *lock;
} job_queue;
/* Thread data */
rt_thread *thread;
} rt_worker_data;
static volatile bool _keep_running = true;
static rt_worker_data _worker_data[MAX_WORKERS];
static void ExecOneJobIfAvailable(rt_worker_data *wd) {
if (wd->job_queue.head == wd->job_queue.tail) {
/* No job available.
* TODO: Pick one job queue at random and check if we can steal?
*/
return;
}
rt_job_chunk chunk = wd->job_queue.chunks[wd->job_queue.head];
wd->job_queue.head = (wd->job_queue.head + 1) % JOB_QUEUE_SIZE;
for (uint32_t i = 0; i < chunk.iteration_count; ++i) {
chunk.fn(chunk.param, chunk.base_iteration + i);
}
}
static void WorkerEntry(void *param) {
rt_worker_data *wd = param;
while (_keep_running) {
rtLockConditionVar(wd->job_queue.lock);
while (wd->job_queue.head == wd->job_queue.tail && _keep_running) {
rtWaitOnConditionVar(wd->job_queue.lock);
}
ExecOneJobIfAvailable(wd);
rtUnlockConditionVar(wd->job_queue.lock, false);
}
}
void rtInitJobSystem(unsigned int worker_count) {
if (worker_count > MAX_WORKERS)
worker_count = MAX_WORKERS;
for (unsigned int i = 0; i < worker_count; ++i) {
_worker_data[i].thread = rtSpawnThread(WorkerEntry, &_worker_data[i], "JobWorker");
}
}