| git.druid.rocks | index | militantprogrammer | astral_canvas | src/ | lib/ | queue.h |
src/lib/queue.h
#ifndef LIB_QUEUE_H
#define LIB_QUEUE_H
#include <pthread.h>
/*
* Job queue (internal). Today a mutex + linked list + eventfd wake.
* Design guide: replace with a double ring of CANVAS_RING_SIZE commands
* per frame; A_Wait drains both rings dry.
*
* Two instances live on the lib runtime: API→worker and worker→main.
*/
/* Function the worker or main thread runs with job->data. */
typedef void (*JobFn)(void *data);
typedef struct Job Job;
struct Job {
JobFn fn; /* NULL jobs are still popped and freed */
void *data; /* payload; owned by the job if own is set */
int own; /* non-zero: jobFree() free(data) */
Job *next; /* intrusive list; NULL at tail */
};
typedef struct {
pthread_mutex_t mu;
Job *head; /* pop from here */
Job *tail; /* push onto here */
int wake_fd; /* eventfd; written on push so poll() wakes */
int ready; /* non-zero after queueInit */
} JobQueue;
/* Which of the two lib queues a push is aimed at (runtime check). */
typedef enum {
QUEUE_TO_WORKER = 1, /* main/API thread only */
QUEUE_TO_MAIN /* worker only */
} QueueDir;
/* Init mutex + eventfd. Returns 0 or -1. */
int queueInit(JobQueue *q);
void queueDestroy(JobQueue *q);
/* Append job. Wakes wake_fd. Returns 0 or -1. */
int queuePush(JobQueue *q, Job *job);
/* Detach the head job, or NULL if empty. Caller jobFree()s it after run. */
Job *queuePop(JobQueue *q);
/* Consume the eventfd so poll() does not spin. */
void queueDrainWake(JobQueue *q);
/* fd for poll(); -1 if the queue is not ready. */
int queueWakeFd(const JobQueue *q);
/* Heap-allocate a job. data may be NULL. Returns NULL on OOM. */
Job *jobCreate(JobFn fn, void *data, int own);
/* free(data) if own, then free(job). */
void jobFree(Job *job);
#endif