diff options
| author | @syxhe <https://t.me/syxhe> | 2025-04-21 17:31:37 -0500 |
|---|---|---|
| committer | @syxhe <https://t.me/syxhe> | 2025-04-21 17:31:37 -0500 |
| commit | 9cf4667331b97f1123f4156273a46558e27c2d2d (patch) | |
| tree | 091766ab0cb3345bc9e61a2387dc65ca7714569c | |
| parent | d47f45a5e3e40b48131409071b119b442c78bffc (diff) | |
Start work on cqueue implementation, create cleanup set of functions
| -rw-r--r-- | src/arena.c | 2 | ||||
| -rw-r--r-- | src/arena.h | 2 | ||||
| -rw-r--r-- | src/ll-internal.h | 3 | ||||
| -rw-r--r-- | src/shared.c | 107 | ||||
| -rw-r--r-- | src/shared.h | 32 | ||||
| -rw-r--r-- | 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 @@ | |||
| 7 | #include <errno.h> | 7 | #include <errno.h> |
| 8 | #include <error.h> | 8 | #include <error.h> |
| 9 | 9 | ||
| 10 | #define VALLOC(nmemb, size) ((___VXGG___USE_XALLOC_FOR_ARENAS___ > 0) ? xmalloc((nmemb) * (size)) : malloc((nmemb) * (size))) | ||
| 11 | |||
| 12 | typedef struct an { | 10 | typedef struct an { |
| 13 | void *membase; | 11 | void *membase; |
| 14 | void *memcur; | 12 | 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 @@ | |||
| 7 | // enables XALLOC functionality | 7 | // enables XALLOC functionality |
| 8 | #define ___VXGG___USE_XALLOC_FOR_ARENAS___ 1 | 8 | #define ___VXGG___USE_XALLOC_FOR_ARENAS___ 1 |
| 9 | 9 | ||
| 10 | #define VALLOC(nmemb, size) ((___VXGG___USE_XALLOC_FOR_ARENAS___ > 0) ? xmalloc((nmemb) * (size)) : malloc((nmemb) * (size))) | ||
| 11 | |||
| 10 | // Normal arena. Can expand in size beyond original allocation | 12 | // Normal arena. Can expand in size beyond original allocation |
| 11 | typedef struct arena arena; | 13 | typedef struct arena arena; |
| 12 | 14 | ||
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 @@ | |||
| 1 | #ifndef __VXGG_REWRITE___LL_INTERNAL_H___21242172227746___ | 1 | #ifndef __VXGG_REWRITE___LL_INTERNAL_H___21242172227746___ |
| 2 | #define __VXGG_REWRITE___LL_INTERNAL_H___21242172227746___ | 2 | #define __VXGG_REWRITE___LL_INTERNAL_H___21242172227746___ |
| 3 | 3 | ||
| 4 | #define __VXGG_REWRITE___LL_INTERNAL___ | 4 | #define __VXGG_REWRITE___LL_INTERNAL___ 1 |
| 5 | #include "ll.h" | 5 | #include "ll.h" |
| 6 | #undef __VXGG_REWRITE___LL_INTERNAL___ | ||
| 6 | 7 | ||
| 7 | typedef struct dll { | 8 | typedef struct dll { |
| 8 | void *data; | 9 | 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) { | |||
| 221 | free(tmp); | 221 | free(tmp); |
| 222 | 222 | ||
| 223 | return actual; | 223 | return actual; |
| 224 | } | ||
| 225 | |||
| 226 | |||
| 227 | int cleanup_init(cleanup * const loc, int size, cleanup_callback funcs[], void *args[]) { | ||
| 228 | if(!loc) | ||
| 229 | RETURNWERR(EINVAL, -1); | ||
| 230 | if(size < 1) | ||
| 231 | RETURNWERR(EINVAL, -1); | ||
| 232 | if(!funcs) | ||
| 233 | RETURNWERR(EINVAL, -1); | ||
| 234 | if(!args) | ||
| 235 | RETURNWERR(EINVAL, -1); | ||
| 236 | |||
| 237 | loc->funcs = funcs; | ||
| 238 | loc->args = args; | ||
| 239 | loc->size = size; | ||
| 240 | loc->used = 0; | ||
| 241 | |||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | |||
| 245 | int cleanup_register(cleanup * const loc, cleanup_callback cb, void *arg) { | ||
| 246 | if(!loc) | ||
| 247 | RETURNWERR(EINVAL, -1); | ||
| 248 | if(loc->used >= loc->size) | ||
| 249 | RETURNWERR(ENOMEM, -1); | ||
| 250 | if(!cb) | ||
| 251 | RETURNWERR(EINVAL, -1); | ||
| 252 | |||
| 253 | loc->funcs[loc->used] = cb; | ||
| 254 | loc->args[loc->used] = arg; | ||
| 255 | loc->used++; | ||
| 256 | |||
| 257 | return 0; | ||
| 258 | } | ||
| 259 | |||
| 260 | int cleanup_cndregister(cleanup * const loc, unsigned char flag, cleanup_callback cb, void *arg) { | ||
| 261 | if(flag) | ||
| 262 | return 0; | ||
| 263 | |||
| 264 | if(!loc) | ||
| 265 | RETURNWERR(EINVAL, -1); | ||
| 266 | if(loc->used >= loc->size) | ||
| 267 | RETURNWERR(ENOMEM, -1); | ||
| 268 | if(!cb) | ||
| 269 | RETURNWERR(EINVAL, -1); | ||
| 270 | |||
| 271 | loc->funcs[loc->used] = cb; | ||
| 272 | loc->args[loc->used] = arg; | ||
| 273 | loc->used++; | ||
| 274 | |||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | int cleanup_clear(cleanup * const loc) { | ||
| 279 | if(!loc) | ||
| 280 | RETURNWERR(EINVAL, -1); | ||
| 281 | |||
| 282 | loc->used = 0; | ||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | cleanup_callback cleanup_peekf(cleanup * const loc) { | ||
| 287 | if(!loc) | ||
| 288 | RETURNWERR(EINVAL, NULL); | ||
| 289 | if(loc->used == 0) | ||
| 290 | RETURNWERR(ENODATA, NULL); | ||
| 291 | |||
| 292 | return loc->funcs[loc->used - 1]; | ||
| 293 | } | ||
| 294 | cleanup_callback cleanup_popf(cleanup * const loc) { | ||
| 295 | cleanup_callback cb = cleanup_peekf(loc); | ||
| 296 | if(cb == NULL) | ||
| 297 | RETURNWERR(EINVAL, NULL); | ||
| 298 | |||
| 299 | loc->used--; | ||
| 300 | |||
| 301 | return cb; | ||
| 302 | } | ||
| 303 | |||
| 304 | void * cleanup_peeka(cleanup * const loc) { | ||
| 305 | if(!loc) | ||
| 306 | RETURNWERR(EINVAL, NULL); | ||
| 307 | if(loc->used == 0) | ||
| 308 | RETURNWERR(ENODATA, NULL); | ||
| 309 | |||
| 310 | return loc->args[loc->used - 1]; | ||
| 311 | } | ||
| 312 | void * cleanup_popa(cleanup * const loc) { | ||
| 313 | void *mem = cleanup_peeka(loc); | ||
| 314 | if(!mem) | ||
| 315 | RETURNWERR(EINVAL, NULL); | ||
| 316 | |||
| 317 | loc->used--; | ||
| 318 | |||
| 319 | return mem; | ||
| 320 | } | ||
| 321 | |||
| 322 | int cleanup_fire(cleanup * const loc) { | ||
| 323 | if(!loc) | ||
| 324 | RETURNWERR(EINVAL, -1); | ||
| 325 | |||
| 326 | for(int i = (loc->used - 1); i >= 0; i--) | ||
| 327 | loc->funcs[i](loc->args[i]); | ||
| 328 | loc->used = 0; | ||
| 329 | |||
| 330 | return 0; | ||
| 224 | } \ No newline at end of file | 331 | } \ 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); | |||
| 50 | // `dirname()` reimplementation that returns a malloc()'ed string. According to the `x___` naming scheme, exits/aborts on alloc error. | 50 | // `dirname()` reimplementation that returns a malloc()'ed string. According to the `x___` naming scheme, exits/aborts on alloc error. |
| 51 | char * xdirname(const char * const path); | 51 | char * xdirname(const char * const path); |
| 52 | 52 | ||
| 53 | |||
| 54 | |||
| 55 | // Cleanup callback. Should act like `free()`, in that it doesn't crash if the pointer it's given is null | ||
| 56 | typedef void (*cleanup_callback)(void*); | ||
| 57 | |||
| 58 | // Cleanup struct. Stores a STATICALLY defined array of callbacks and void* arguments | ||
| 59 | typedef struct cl { | ||
| 60 | cleanup_callback *funcs; | ||
| 61 | void **args; | ||
| 62 | |||
| 63 | int size; | ||
| 64 | int used; | ||
| 65 | } cleanup; | ||
| 66 | |||
| 67 | int cleanup_init(cleanup * const loc, int size, cleanup_callback funcs[], void *args[]); | ||
| 68 | int cleanup_register(cleanup * const loc, cleanup_callback cb, void *arg); | ||
| 69 | int cleanup_cndregister(cleanup * const loc, unsigned char flag, cleanup_callback cb, void *arg); | ||
| 70 | int cleanup_clear(cleanup * const loc); | ||
| 71 | cleanup_callback cleanup_peekf(cleanup * const loc); | ||
| 72 | cleanup_callback cleanup_popf(cleanup * const loc); | ||
| 73 | void * cleanup_peeka(cleanup * const loc); | ||
| 74 | void * cleanup_popa(cleanup * const loc); | ||
| 75 | int cleanup_fire(cleanup * const loc); | ||
| 76 | |||
| 77 | /* Cleanup environment creator. Automatically defines the variables `__CLEANUP`, `__CLEANUP_FUNCS`, and `__CLEANUP_ARGS` and initializes | ||
| 78 | // via `cleanup_init()` using these variables. */ | ||
| 79 | #define cleanup_create(size) \ | ||
| 80 | cleanup __CLEANUP; \ | ||
| 81 | cleanup_callback __CLEANUP_FUNCS[(size)]; \ | ||
| 82 | void *__CLEANUP_ARGS[(size)]; \ | ||
| 83 | cleanup_init(&__CLEANUP, (size), __CLEANUP_FUNCS, __CLEANUP_ARGS) | ||
| 84 | |||
| 53 | #endif \ No newline at end of file | 85 | #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 @@ | |||
| 1 | #include "threadpool.h" | 1 | #include "threadpool.h" |
| 2 | #include "arena.h" | ||
| 2 | #include "shared.h" | 3 | #include "shared.h" |
| 3 | 4 | ||
| 4 | #include "ll-internal.h" | ||
| 5 | #include "ll.h" | 5 | #include "ll.h" |
| 6 | 6 | ||
| 7 | #include <threads.h> | 7 | #include <threads.h> |
| @@ -95,14 +95,18 @@ int thrd_createwmx(thrd_t * const thr, thrd_start_t func, mtxpair * const mtxd) | |||
| 95 | 95 | ||
| 96 | // Here's a good reference of this implemented in C++ using Boost: https://gist.github.com/mikeando/482342 | 96 | // Here's a good reference of this implemented in C++ using Boost: https://gist.github.com/mikeando/482342 |
| 97 | 97 | ||
| 98 | typedef struct cq { | 98 | typedef int (*task_callback)(void*); |
| 99 | void*placehoilder; | ||
| 100 | } cqueue; | ||
| 101 | |||
| 102 | typedef struct task { | 99 | typedef struct task { |
| 103 | int (*callback)(void*); | 100 | task_callback cb; |
| 104 | void *arg; | 101 | void *arg; |
| 105 | } task; | 102 | } task; |
| 103 | |||
| 104 | typedef struct cq { | ||
| 105 | dlinkedlist *list; | ||
| 106 | mtx_t *mutex; | ||
| 107 | cnd_t *conditional; | ||
| 108 | } cqueue; | ||
| 109 | |||
| 106 | typedef struct tp { | 110 | typedef struct tp { |
| 107 | thrd_t **threads; | 111 | thrd_t **threads; |
| 108 | int nthreads; | 112 | int nthreads; |
| @@ -110,3 +114,100 @@ typedef struct tp { | |||
| 110 | cqueue *taskqueue; | 114 | cqueue *taskqueue; |
| 111 | } threadpool; | 115 | } threadpool; |
| 112 | 116 | ||
| 117 | task * task_init(task_callback cb, void *arg) { | ||
| 118 | if(cb == NULL) | ||
| 119 | RETURNWERR(EINVAL, NULL); | ||
| 120 | task *task = VALLOC(1, sizeof(*task)); | ||
| 121 | if(!task) | ||
| 122 | return NULL; | ||
| 123 | |||
| 124 | task->cb = cb; | ||
| 125 | task->arg = arg; | ||
| 126 | |||
| 127 | return task; | ||
| 128 | } | ||
| 129 | |||
| 130 | void task_free(task *ts) { | ||
| 131 | if(!ts) | ||
| 132 | return; | ||
| 133 | |||
| 134 | free(ts); // Not making any assumptions about the data in the task | ||
| 135 | return; | ||
| 136 | } | ||
| 137 | |||
| 138 | |||
| 139 | static void ___ucleanup_mtxd(void *mtx) { | ||
| 140 | if(!mtx) | ||
| 141 | return; | ||
| 142 | |||
| 143 | mtx_destroy((mtx_t *)mtx); | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | static void ___ucleanup_cndd(void *cnd) { | ||
| 147 | if(!cnd) | ||
| 148 | return; | ||
| 149 | |||
| 150 | cnd_destroy((cnd_t *)cnd); | ||
| 151 | return; | ||
| 152 | } | ||
| 153 | static void ___ucleanup_dll(void *dll) { | ||
| 154 | if(!dll) | ||
| 155 | return; | ||
| 156 | |||
| 157 | dlinkedlist_free((dlinkedlist *)dll); | ||
| 158 | return; | ||
| 159 | } | ||
| 160 | |||
| 161 | |||
| 162 | cqueue * cqueue_init(int mtx_type) { | ||
| 163 | unsigned char flag = 0; | ||
| 164 | cleanup_create(10); | ||
| 165 | |||
| 166 | cqueue *cq = VALLOC(1, sizeof(*cq)); | ||
| 167 | if(!cq) | ||
| 168 | return NULL; | ||
| 169 | cleanup_register(&__CLEANUP, free, cq); | ||
| 170 | |||
| 171 | cq->mutex = VALLOC(1, sizeof(*(cq->mutex))); | ||
| 172 | if(!(cq->mutex)) | ||
| 173 | flag++; | ||
| 174 | cleanup_cndregister(&__CLEANUP, flag, free, cq->mutex); | ||
| 175 | |||
| 176 | if(!flag && mtx_init(cq->mutex, mtx_type) != thrd_success) | ||
| 177 | flag++; | ||
| 178 | cleanup_cndregister(&__CLEANUP, flag, ___ucleanup_mtxd, cq->mutex); | ||
| 179 | |||
| 180 | if(!flag && !(cq->conditional = VALLOC(1, sizeof(*(cq->conditional))))) | ||
| 181 | flag++; | ||
| 182 | cleanup_cndregister(&__CLEANUP, flag, free, cq->conditional); | ||
| 183 | |||
| 184 | if(!flag && cnd_init(cq->conditional) != thrd_success) | ||
| 185 | flag++; | ||
| 186 | cleanup_cndregister(&__CLEANUP, flag, ___ucleanup_cndd, cq->conditional); | ||
| 187 | |||
| 188 | cq->list = dlinkedlist_init(); | ||
| 189 | if(!flag && !cq->list) | ||
| 190 | flag++; | ||
| 191 | cleanup_cndregister(&__CLEANUP, flag, ___ucleanup_dll, cq->list); | ||
| 192 | |||
| 193 | if(flag) | ||
| 194 | cleanup_fire(&__CLEANUP); | ||
| 195 | |||
| 196 | // 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 | ||
| 197 | |||
| 198 | return cq; | ||
| 199 | } | ||
| 200 | |||
| 201 | void cqueue_free(cqueue *cq) { | ||
| 202 | if(!cq) | ||
| 203 | return; | ||
| 204 | |||
| 205 | dlinkedlist_free(cq->list); | ||
| 206 | cnd_destroy(cq->conditional); | ||
| 207 | mtx_destroy(cq->mutex); | ||
| 208 | free(cq->conditional); | ||
| 209 | free(cq->mutex); | ||
| 210 | free(cq); | ||
| 211 | |||
| 212 | return; | ||
| 213 | } \ No newline at end of file | ||
