Worked on runtime and threadpool
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
**.vscode/
|
||||||
|
**build/
|
||||||
10
include/runtime.h
Normal file
10
include/runtime.h
Normal 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
9
include/thread_pool.h
Normal 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
43
makefile
Normal 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
12
src/main.c
Normal 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
100
src/runtime.c
Normal 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
103
src/thread_pool.c
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user