summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arena.c2
-rw-r--r--src/arena.h2
-rw-r--r--src/ll-internal.h3
-rw-r--r--src/shared.c107
-rw-r--r--src/shared.h32
-rw-r--r--src/threadpool.c113
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
12typedef struct an { 10typedef 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
11typedef struct arena arena; 13typedef 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
7typedef struct dll { 8typedef 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
227int 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
245int 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
260int 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
278int cleanup_clear(cleanup * const loc) {
279 if(!loc)
280 RETURNWERR(EINVAL, -1);
281
282 loc->used = 0;
283 return 0;
284}
285
286cleanup_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}
294cleanup_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
304void * 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}
312void * 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
322int 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.
51char * xdirname(const char * const path); 51char * 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
56typedef void (*cleanup_callback)(void*);
57
58// Cleanup struct. Stores a STATICALLY defined array of callbacks and void* arguments
59typedef struct cl {
60 cleanup_callback *funcs;
61 void **args;
62
63 int size;
64 int used;
65} cleanup;
66
67int cleanup_init(cleanup * const loc, int size, cleanup_callback funcs[], void *args[]);
68int cleanup_register(cleanup * const loc, cleanup_callback cb, void *arg);
69int cleanup_cndregister(cleanup * const loc, unsigned char flag, cleanup_callback cb, void *arg);
70int cleanup_clear(cleanup * const loc);
71cleanup_callback cleanup_peekf(cleanup * const loc);
72cleanup_callback cleanup_popf(cleanup * const loc);
73void * cleanup_peeka(cleanup * const loc);
74void * cleanup_popa(cleanup * const loc);
75int 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) \
80cleanup __CLEANUP; \
81cleanup_callback __CLEANUP_FUNCS[(size)]; \
82void *__CLEANUP_ARGS[(size)]; \
83cleanup_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
98typedef struct cq { 98typedef int (*task_callback)(void*);
99 void*placehoilder;
100} cqueue;
101
102typedef struct task { 99typedef struct task {
103 int (*callback)(void*); 100 task_callback cb;
104 void *arg; 101 void *arg;
105} task; 102} task;
103
104typedef struct cq {
105 dlinkedlist *list;
106 mtx_t *mutex;
107 cnd_t *conditional;
108} cqueue;
109
106typedef struct tp { 110typedef 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
117task * 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
130void 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
139static void ___ucleanup_mtxd(void *mtx) {
140 if(!mtx)
141 return;
142
143 mtx_destroy((mtx_t *)mtx);
144 return;
145}
146static void ___ucleanup_cndd(void *cnd) {
147 if(!cnd)
148 return;
149
150 cnd_destroy((cnd_t *)cnd);
151 return;
152}
153static void ___ucleanup_dll(void *dll) {
154 if(!dll)
155 return;
156
157 dlinkedlist_free((dlinkedlist *)dll);
158 return;
159}
160
161
162cqueue * 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
201void 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