commit 0be61851a4055459b41dc25de90844ee14e4249e Author: Didas72 Date: Thu Jun 19 19:21:08 2025 +0100 Worked on runtime and threadpool diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af05924 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**.vscode/ +**build/ diff --git a/include/runtime.h b/include/runtime.h new file mode 100644 index 0000000..8021e29 --- /dev/null +++ b/include/runtime.h @@ -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); diff --git a/include/thread_pool.h b/include/thread_pool.h new file mode 100644 index 0000000..c829ab6 --- /dev/null +++ b/include/thread_pool.h @@ -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); diff --git a/makefile b/makefile new file mode 100644 index 0000000..2241e9c --- /dev/null +++ b/makefile @@ -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) diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..513ff99 --- /dev/null +++ b/src/main.c @@ -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; +} diff --git a/src/runtime.c b/src/runtime.c new file mode 100644 index 0000000..a3a6ae7 --- /dev/null +++ b/src/runtime.c @@ -0,0 +1,100 @@ +#include "runtime.h" + +#include +#include +#include + +#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*> +static hashtable_t *_future_callbacks; +//ivector_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); +} diff --git a/src/thread_pool.c b/src/thread_pool.c new file mode 100644 index 0000000..07c6ab7 --- /dev/null +++ b/src/thread_pool.c @@ -0,0 +1,103 @@ +#include "thread_pool.h" + +#include +#include + +#include + +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 + 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; +}