From 9cf4667331b97f1123f4156273a46558e27c2d2d Mon Sep 17 00:00:00 2001 From: "@syxhe" Date: Mon, 21 Apr 2025 17:31:37 -0500 Subject: Start work on cqueue implementation, create cleanup set of functions --- src/arena.c | 2 - src/arena.h | 2 + src/ll-internal.h | 3 +- src/shared.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/shared.h | 32 ++++++++++++++++ src/threadpool.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 6 files changed, 250 insertions(+), 9 deletions(-) diff --git a/src/arena.c b/src/arena.c index 07c28dc..f944661 100644 --- a/src/arena.c +++ b/src/arena.c @@ -7,8 +7,6 @@ #include #include -#define VALLOC(nmemb, size) ((___VXGG___USE_XALLOC_FOR_ARENAS___ > 0) ? xmalloc((nmemb) * (size)) : malloc((nmemb) * (size))) - typedef struct an { void *membase; void *memcur; diff --git a/src/arena.h b/src/arena.h index 1377fa1..e65b041 100644 --- a/src/arena.h +++ b/src/arena.h @@ -7,6 +7,8 @@ // enables XALLOC functionality #define ___VXGG___USE_XALLOC_FOR_ARENAS___ 1 +#define VALLOC(nmemb, size) ((___VXGG___USE_XALLOC_FOR_ARENAS___ > 0) ? xmalloc((nmemb) * (size)) : malloc((nmemb) * (size))) + // Normal arena. Can expand in size beyond original allocation typedef struct arena arena; diff --git a/src/ll-internal.h b/src/ll-internal.h index f627807..e829669 100644 --- a/src/ll-internal.h +++ b/src/ll-internal.h @@ -1,8 +1,9 @@ #ifndef __VXGG_REWRITE___LL_INTERNAL_H___21242172227746___ #define __VXGG_REWRITE___LL_INTERNAL_H___21242172227746___ -#define __VXGG_REWRITE___LL_INTERNAL___ +#define __VXGG_REWRITE___LL_INTERNAL___ 1 #include "ll.h" +#undef __VXGG_REWRITE___LL_INTERNAL___ typedef struct dll { void *data; diff --git a/src/shared.c b/src/shared.c index bec0354..02fe9a0 100644 --- a/src/shared.c +++ b/src/shared.c @@ -221,4 +221,111 @@ char * xdirname(const char * const path) { free(tmp); return actual; +} + + +int cleanup_init(cleanup * const loc, int size, cleanup_callback funcs[], void *args[]) { + if(!loc) + RETURNWERR(EINVAL, -1); + if(size < 1) + RETURNWERR(EINVAL, -1); + if(!funcs) + RETURNWERR(EINVAL, -1); + if(!args) + RETURNWERR(EINVAL, -1); + + loc->funcs = funcs; + loc->args = args; + loc->size = size; + loc->used = 0; + + return 0; +} + +int cleanup_register(cleanup * const loc, cleanup_callback cb, void *arg) { + if(!loc) + RETURNWERR(EINVAL, -1); + if(loc->used >= loc->size) + RETURNWERR(ENOMEM, -1); + if(!cb) + RETURNWERR(EINVAL, -1); + + loc->funcs[loc->used] = cb; + loc->args[loc->used] = arg; + loc->used++; + + return 0; +} + +int cleanup_cndregister(cleanup * const loc, unsigned char flag, cleanup_callback cb, void *arg) { + if(flag) + return 0; + + if(!loc) + RETURNWERR(EINVAL, -1); + if(loc->used >= loc->size) + RETURNWERR(ENOMEM, -1); + if(!cb) + RETURNWERR(EINVAL, -1); + + loc->funcs[loc->used] = cb; + loc->args[loc->used] = arg; + loc->used++; + + return 0; +} + +int cleanup_clear(cleanup * const loc) { + if(!loc) + RETURNWERR(EINVAL, -1); + + loc->used = 0; + return 0; +} + +cleanup_callback cleanup_peekf(cleanup * const loc) { + if(!loc) + RETURNWERR(EINVAL, NULL); + if(loc->used == 0) + RETURNWERR(ENODATA, NULL); + + return loc->funcs[loc->used - 1]; +} +cleanup_callback cleanup_popf(cleanup * const loc) { + cleanup_callback cb = cleanup_peekf(loc); + if(cb == NULL) + RETURNWERR(EINVAL, NULL); + + loc->used--; + + return cb; +} + +void * cleanup_peeka(cleanup * const loc) { + if(!loc) + RETURNWERR(EINVAL, NULL); + if(loc->used == 0) + RETURNWERR(ENODATA, NULL); + + return loc->args[loc->used - 1]; +} +void * cleanup_popa(cleanup * const loc) { + void *mem = cleanup_peeka(loc); + if(!mem) + RETURNWERR(EINVAL, NULL); + + loc->used--; + + return mem; +} + +int cleanup_fire(cleanup * const loc) { + if(!loc) + RETURNWERR(EINVAL, -1); + + for(int i = (loc->used - 1); i >= 0; i--) + loc->funcs[i](loc->args[i]); + loc->used = 0; + + return 0; } \ No newline at end of file diff --git a/src/shared.h b/src/shared.h index b7fe7c3..1a629e6 100644 --- a/src/shared.h +++ b/src/shared.h @@ -50,4 +50,36 @@ int wwbuf(int fd, const unsigned char *buf, int len); // `dirname()` reimplementation that returns a malloc()'ed string. According to the `x___` naming scheme, exits/aborts on alloc error. char * xdirname(const char * const path); + + +// Cleanup callback. Should act like `free()`, in that it doesn't crash if the pointer it's given is null +typedef void (*cleanup_callback)(void*); + +// Cleanup struct. Stores a STATICALLY defined array of callbacks and void* arguments +typedef struct cl { + cleanup_callback *funcs; + void **args; + + int size; + int used; +} cleanup; + +int cleanup_init(cleanup * const loc, int size, cleanup_callback funcs[], void *args[]); +int cleanup_register(cleanup * const loc, cleanup_callback cb, void *arg); +int cleanup_cndregister(cleanup * const loc, unsigned char flag, cleanup_callback cb, void *arg); +int cleanup_clear(cleanup * const loc); +cleanup_callback cleanup_peekf(cleanup * const loc); +cleanup_callback cleanup_popf(cleanup * const loc); +void * cleanup_peeka(cleanup * const loc); +void * cleanup_popa(cleanup * const loc); +int cleanup_fire(cleanup * const loc); + +/* Cleanup environment creator. Automatically defines the variables `__CLEANUP`, `__CLEANUP_FUNCS`, and `__CLEANUP_ARGS` and initializes +// via `cleanup_init()` using these variables. */ +#define cleanup_create(size) \ +cleanup __CLEANUP; \ +cleanup_callback __CLEANUP_FUNCS[(size)]; \ +void *__CLEANUP_ARGS[(size)]; \ +cleanup_init(&__CLEANUP, (size), __CLEANUP_FUNCS, __CLEANUP_ARGS) + #endif \ No newline at end of file diff --git a/src/threadpool.c b/src/threadpool.c index d058d52..e230ebb 100644 --- a/src/threadpool.c +++ b/src/threadpool.c @@ -1,7 +1,7 @@ #include "threadpool.h" +#include "arena.h" #include "shared.h" -#include "ll-internal.h" #include "ll.h" #include @@ -95,14 +95,18 @@ int thrd_createwmx(thrd_t * const thr, thrd_start_t func, mtxpair * const mtxd) // Here's a good reference of this implemented in C++ using Boost: https://gist.github.com/mikeando/482342 -typedef struct cq { - void*placehoilder; -} cqueue; - +typedef int (*task_callback)(void*); typedef struct task { - int (*callback)(void*); + task_callback cb; void *arg; } task; + +typedef struct cq { + dlinkedlist *list; + mtx_t *mutex; + cnd_t *conditional; +} cqueue; + typedef struct tp { thrd_t **threads; int nthreads; @@ -110,3 +114,100 @@ typedef struct tp { cqueue *taskqueue; } threadpool; +task * task_init(task_callback cb, void *arg) { + if(cb == NULL) + RETURNWERR(EINVAL, NULL); + task *task = VALLOC(1, sizeof(*task)); + if(!task) + return NULL; + + task->cb = cb; + task->arg = arg; + + return task; +} + +void task_free(task *ts) { + if(!ts) + return; + + free(ts); // Not making any assumptions about the data in the task + return; +} + + +static void ___ucleanup_mtxd(void *mtx) { + if(!mtx) + return; + + mtx_destroy((mtx_t *)mtx); + return; +} +static void ___ucleanup_cndd(void *cnd) { + if(!cnd) + return; + + cnd_destroy((cnd_t *)cnd); + return; +} +static void ___ucleanup_dll(void *dll) { + if(!dll) + return; + + dlinkedlist_free((dlinkedlist *)dll); + return; +} + + +cqueue * cqueue_init(int mtx_type) { + unsigned char flag = 0; + cleanup_create(10); + + cqueue *cq = VALLOC(1, sizeof(*cq)); + if(!cq) + return NULL; + cleanup_register(&__CLEANUP, free, cq); + + cq->mutex = VALLOC(1, sizeof(*(cq->mutex))); + if(!(cq->mutex)) + flag++; + cleanup_cndregister(&__CLEANUP, flag, free, cq->mutex); + + if(!flag && mtx_init(cq->mutex, mtx_type) != thrd_success) + flag++; + cleanup_cndregister(&__CLEANUP, flag, ___ucleanup_mtxd, cq->mutex); + + if(!flag && !(cq->conditional = VALLOC(1, sizeof(*(cq->conditional))))) + flag++; + cleanup_cndregister(&__CLEANUP, flag, free, cq->conditional); + + if(!flag && cnd_init(cq->conditional) != thrd_success) + flag++; + cleanup_cndregister(&__CLEANUP, flag, ___ucleanup_cndd, cq->conditional); + + cq->list = dlinkedlist_init(); + if(!flag && !cq->list) + flag++; + cleanup_cndregister(&__CLEANUP, flag, ___ucleanup_dll, cq->list); + + if(flag) + cleanup_fire(&__CLEANUP); + + // This implementation is better and should be far less error prone than the thing I did earlier, but it would be nicer if C had anonymous functions + + return cq; +} + +void cqueue_free(cqueue *cq) { + if(!cq) + return; + + dlinkedlist_free(cq->list); + cnd_destroy(cq->conditional); + mtx_destroy(cq->mutex); + free(cq->conditional); + free(cq->mutex); + free(cq); + + return; +} \ No newline at end of file -- cgit v1.2.3