Files

118 lines
3.3 KiB
C
Raw Permalink Normal View History

2026-05-24 23:24:25 -07:00
#include "threadpool.h"
2026-05-25 17:25:50 -07:00
#include "util.h"
#include <pthread.h>
2026-05-24 23:24:25 -07:00
#include <stdlib.h>
struct thread_pool_queue {
Task task;
2026-05-25 23:13:27 -07:00
void *arg;
2026-05-25 17:37:16 -07:00
FreeFunc ff;
2026-05-25 23:13:27 -07:00
struct thread_pool_queue *next;
2026-05-24 23:24:25 -07:00
};
struct _ThreadPool {
2026-05-25 17:25:50 -07:00
bool running;
2026-05-24 23:24:25 -07:00
size_t nthreads;
2026-05-25 17:25:50 -07:00
sigset_t thread_sig_mask;
2026-05-25 23:13:27 -07:00
pthread_t *threads;
2026-05-24 23:24:25 -07:00
2026-05-25 17:25:50 -07:00
pthread_cond_t queue_cnd;
pthread_mutex_t queue_mtx;
2026-05-25 23:13:27 -07:00
struct thread_pool_queue *queue;
2026-05-24 23:24:25 -07:00
};
2026-05-25 17:25:50 -07:00
// return false if we need to stop
2026-05-25 23:13:27 -07:00
static bool get_task(ThreadPool *pool, Task *task, void **task_arg) {
2026-05-25 17:25:50 -07:00
pthread_mutex_lock(&pool->queue_mtx);
if (!pool->running) {
pthread_mutex_unlock(&pool->queue_mtx);
return false;
}
while (true) {
pthread_cond_wait(&pool->queue_cnd, &pool->queue_mtx);
if (!pool->running) {
pthread_mutex_unlock(&pool->queue_mtx);
return false;
}
2026-05-25 23:13:27 -07:00
struct thread_pool_queue *ent = pool->queue;
2026-05-25 17:25:50 -07:00
if (ent) {
pool->queue = pool->queue->next;
pthread_mutex_unlock(&pool->queue_mtx);
*task = ent->task;
*task_arg = ent->arg;
free(ent);
return true;
}
}
abort();
2026-05-24 23:24:25 -07:00
}
2026-05-25 23:13:27 -07:00
static void *pool_thread_function(void *arg) {
ThreadPool *pool = arg;
2026-05-25 17:25:50 -07:00
pthread_sigmask(SIG_SETMASK, &pool->thread_sig_mask, NULL);
Task task;
2026-05-25 23:13:27 -07:00
void *task_arg;
2026-05-25 17:25:50 -07:00
while (get_task(pool, &task, &task_arg)) {
task(task_arg);
}
return NULL;
}
2026-05-24 23:24:25 -07:00
2026-05-25 23:13:27 -07:00
ThreadPool *make_thread_pool(size_t parallelism, sigset_t sig_mask) {
ThreadPool *pool = malloc_safe(sizeof(ThreadPool));
2026-05-25 17:25:50 -07:00
pthread_mutex_init(&pool->queue_mtx, NULL);
pthread_cond_init(&pool->queue_cnd, NULL);
pool->running = true;
pool->queue = NULL;
pool->nthreads = parallelism;
pool->thread_sig_mask = sig_mask;
pool->threads = malloc_safe(sizeof(pthread_t) * parallelism);
// create don't race with any received signals
sigset_t sset_full;
sigfillset(&sset_full);
sigset_t sset_save;
pthread_sigmask(SIG_SETMASK, &sset_full, &sset_save);
for (size_t i = 0; i < parallelism; ++i) {
pthread_create(&pool->threads[i], NULL, &pool_thread_function, pool);
}
pthread_sigmask(SIG_SETMASK, &sset_save, NULL);
return pool;
}
2026-05-25 23:13:27 -07:00
void destroy_thread_pool(ThreadPool *pool) {
2026-05-25 17:25:50 -07:00
pthread_mutex_lock(&pool->queue_mtx);
pool->running = false;
pthread_cond_broadcast(&pool->queue_cnd);
pthread_mutex_unlock(&pool->queue_mtx);
for (size_t i = 0; i < pool->nthreads; ++i) {
pthread_join(pool->threads[i], NULL);
}
free(pool->threads);
pthread_mutex_destroy(&pool->queue_mtx);
pthread_cond_destroy(&pool->queue_cnd);
2026-05-25 23:13:27 -07:00
struct thread_pool_queue *queue = pool->queue;
2026-05-25 17:37:16 -07:00
while (queue) {
2026-05-25 23:13:27 -07:00
struct thread_pool_queue *next = queue->next;
2026-05-25 17:37:16 -07:00
if (queue->ff) {
queue->ff(queue->arg);
}
free(queue);
queue = next;
}
2026-05-25 17:25:50 -07:00
free(pool);
}
2026-05-25 23:13:27 -07:00
void thread_pool_enqueue(ThreadPool *pool, Task task, void *arg, FreeFunc ff) {
2026-05-25 17:25:50 -07:00
pthread_mutex_lock(&pool->queue_mtx);
2026-05-25 23:13:27 -07:00
struct thread_pool_queue *new = malloc_safe(sizeof(struct thread_pool_queue));
2026-05-25 17:25:50 -07:00
new->task = task;
new->arg = arg;
2026-05-25 17:37:16 -07:00
new->ff = ff;
2026-05-25 17:25:50 -07:00
new->next = pool->queue;
pool->queue = new;
pthread_cond_signal(&pool->queue_cnd);
pthread_mutex_unlock(&pool->queue_mtx);
}