66 lines
1.7 KiB
C
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");
|
|
}
|
|
}
|