Worked on runtime and threadpool

This commit is contained in:
2025-06-19 19:21:08 +01:00
commit 0be61851a4
7 changed files with 279 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
**.vscode/
**build/

10
include/runtime.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
typedef void (*system_tick_t)(int type);
void runtime_init();
void runtime_loop();
void runtime_destroy();
int runtime_callback_single(system_tick_t callback, long delay);
int runtime_callback_many(system_tick_t callback, long period, long phase);

9
include/thread_pool.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
typedef struct thread_pool_t thread_pool_t;
thread_pool_t *thread_pool_create(size_t thread_count);
void thread_pool_destroy(thread_pool_t *pool);
long thread_pool_run(thread_pool_t *pool, void *(*func)(void*), void *data);
void thread_pool_join_all(thread_pool_t *pool);

43
makefile Normal file
View File

@ -0,0 +1,43 @@
CC=gcc
C_FLAGS=-Wall -Wextra -pedantic -Wno-unknown-pragmas -g -DDEBUG
DIR_SRC=src
DIR_INC=include
DIR_BUILD=build
DEPS=dl pthread m atomic pigpio rt sus
OUTBIN=$(DIR_BUILD)/bin/main
SRCS=$(shell find $(DIR_SRC) -type f -name '*.c')
OBJS=$(patsubst $(DIR_SRC)/%.c,$(DIR_BUILD)/obj/%.o,$(SRCS))
DEPS_EXT=$(patsubst %,-l%,$(DEPS))
.PHONY: all build rebuild loc clean run
# Compatibility
.WAIT: # No dependencies
# No code
all: $(OUTBIN)
build: $(OUTBIN)
rebuild: clean .WAIT build
run: $(OUTBIN)
sudo ./$(OUTBIN)
$(OUTBIN): $(OBJS)
@mkdir -p $(@D)
$(CC) $(OBJS) $(DEPS_EXT) -o $@
$(DIR_BUILD)/obj/%.o: $(DIR_SRC)/%.c
@mkdir -p $(@D)
$(CC) $(C_FLAGS) -I$(DIR_INC) -c $< -o $@
loc:
@scc -s lines --no-cocomo --no-gitignore -w --size-unit binary src
clean:
@$(RM) -r $(DIR_BUILD)

12
src/main.c Normal file
View File

@ -0,0 +1,12 @@
#include "runtime.h"
int main (int argc, char *argv[])
{
(void)argc; (void)argv;
runtime_init();
runtime_loop();
runtime_destroy();
return 0;
}

100
src/runtime.c Normal file
View File

@ -0,0 +1,100 @@
#include "runtime.h"
#include <sus/hashtable.h>
#include <sus/hashes.h>
#include <sus/ivector.h>
#include "thread_pool.h"
typedef struct recurring_callback_t {
long period;
long phase;
system_tick_t callback;
} recurring_callback_t;
static long _tick;
//hashtable_t<long, ivector_t<system_tick_t>*>
static hashtable_t *_future_callbacks;
//ivector_t<recurring_callback_t>
static ivector_t *_recurring_callbacks;
static thread_pool_t *callback_pool;
static void register_callback(long delay, system_tick_t callback)
{
long tick = delay + _tick;
ivector_t *vector = hashtable_get(_future_callbacks, tick);
if (!vector)
{
vector = ivector_create(sizeof(sizeof(system_tick_t)));
hashtable_add(_future_callbacks, tick, vector);
}
ivector_append(vector, callback);
}
static void handle_callbacks(ivector_t *callbacks)
{
size_t count = ivector_get_count(callbacks);
for (size_t i = 0; i < count; ++i)
{
system_tick_t *tick = ivector_get(callbacks, i);
//TODO: Dispatch work
}
}
static void register_recurring_callbacks()
{
size_t count = ivector_get_count(_recurring_callbacks);
for (size_t i = 0; i < count; ++i)
{
recurring_callback_t *callback = ivector_get(_recurring_callbacks, i);
long phase = _tick % callback->period;
if (phase != callback->phase)
continue;
register_callback(callback->period, callback->callback);
}
}
void runtime_init()
{
_tick = 0;
_future_callbacks = hashtable_create(hash_ptr, compare_ptr);
_recurring_callbacks = ivector_create(sizeof(recurring_callback_t));
}
void runtime_loop()
{
//Runtime loop
//Ticks every 10ms
//Systems request X tick delay callbacks
//Callbacks executed on separate threads
//Handle pending callbacks and register recurring
ivector_t *callbacks = hashtable_get(_future_callbacks, _tick);
if (callbacks)
{
handle_callbacks(callbacks);
hashtable_remove(_future_callbacks, _tick, NULL, NULL);
ivector_destroy(callbacks);
}
register_recurring_callbacks();
//Advance tick
++_tick;
//TODO: Delay and loop
}
void runtime_destroy()
{
hashtable_destroy_free(_future_callbacks, NULL, ivector_destroy);
ivector_destroy(_recurring_callbacks);
}

103
src/thread_pool.c Normal file
View File

@ -0,0 +1,103 @@
#include "thread_pool.h"
#include <stdlib.h>
#include <pthread.h>
#include <sus/ivector.h>
typedef struct thread_info_t
{
pthread_t thread;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *(*func)(void *);
void *data;
long job_id;
} thread_info_t;
struct thread_pool_t
{
size_t count;
thread_info_t *threads;
long job_id_counter;
//ivector_t<size_t>
ivector_t *idle_threads;
pthread_mutex_t idle_mutex;
pthread_cond_t idle_cond;
};
static void *pooled_thread_entry(void *data);
thread_pool_t *thread_pool_create(size_t thread_count)
{
thread_pool_t *pool = malloc(sizeof(thread_pool_t));
if (!pool) return NULL;
pool->job_id_counter = 0;
pool->count = thread_count;
pool->idle_threads = ivector_create(sizeof(size_t));
pool->threads = malloc(sizeof(thread_info_t) * thread_count);
if (!pool->threads)
{
free(pool->threads);
free(pool);
return NULL;
}
pthread_mutex_init(&pool->idle_mutex, NULL);
pthread_cond_init(&pool->idle_cond, NULL);
for (size_t i = 0; i < thread_count; ++i)
{
thread_info_t *info = &pool->threads[i];
pthread_mutex_init(&info->mutex, NULL);
pthread_cond_init(&info->cond, NULL);
info->func = NULL;
info->data = NULL;
info->job_id = 0;
pthread_create(&info->thread, NULL, pooled_thread_entry, info);
}
return pool;
}
void thread_pool_destroy(thread_pool_t *pool)
{
for (size_t i = 0; i < pool->count; ++i)
{
thread_info_t *info = &pool->threads[i];
pthread_mutex_destroy(&info->mutex);
pthread_cond_destroy(&info->cond);
}
free(pool->threads);
free(pool);
}
long thread_pool_run(thread_pool_t *pool, void *(*func)(void*), void *data)
{
//Wait for free thread
pthread_mutex_lock(&pool->idle_mutex);
while (ivector_get_count(pool->idle_threads) == 0)
pthread_cond_wait(&pool->idle_cond, &pool->idle_mutex);
size_t thread_idx = *(size_t*)ivector_get(pool->idle_threads, ivector_get_count(pool->idle_threads));
ivector_pop_back(pool->idle_threads);
pthread_mutex_unlock(&pool->idle_mutex);
//Assign work
thread_info_t *info = &pool->threads[thread_idx];
info->func = func;
info->data = data;
long job_id = info->job_id = ++pool->job_id_counter;
//Start work
pthread_mutex_lock(&info->mutex);
pthread_cond_signal(&info->cond);
pthread_mutex_unlock(&info->mutex);
return job_id;
}