#include "threadpool.h" #include "shared.h" #include "ll-internal.h" #include "ll.h" #include #include #include /* Mutex: Lock a shared resource. Used to prevent race conditions when accessing / modifying some shared resource. A lock must // always be followed by an unlock // Semaphore: Send / wait on a signal; solves the consumer/producer problem. A function that sends should never wait, and a // function that waits should never send */ // Pair some data with a mutex. Specifically a way to deal with mutices easier, not for data storage (mtxpair_free does not free the `(void*)data` member) typedef struct mtxp { void *data; mtx_t *mtx; } mtxpair; mtxpair * mtxpair_init(void * const data, int type) { mtxpair *mtxp = malloc(1 * sizeof(*mtxp)); if(!mtxp) return NULL; // Make room for the mutex mtxp->mtx = malloc(1 * sizeof(*mtxp->mtx)); if(!mtxp->mtx) { free(mtxp); return NULL; } // Init the mutex if(mtx_init(mtxp->mtx, type) == thrd_error) { free(mtxp->mtx); free(mtxp); RETURNWERR(errno, NULL); } mtxp->data = data; return mtxp; } void mtxpair_free(mtxpair *mp) { if(!mp) return; mtx_destroy(mp->mtx); free(mp->mtx); free(mp); return; } int mtxpair_setdata(mtxpair * const mp, void * const data) { if(!mp) RETURNWERR(EINVAL, -1); mp->data = data; return 0; } // thrd_create which calls mtx_lock/unlock on `arg` automatically int thrd_createwmx(thrd_t * const thr, thrd_start_t func, mtxpair * const mtxd) { if(!thr) RETURNWERR(EINVAL, thrd_error); if(!func) RETURNWERR(EINVAL, thrd_error); if(!mtxd) RETURNWERR(EINVAL, thrd_error); if(mtx_lock(mtxd->mtx) == thrd_error) {RETURNWERR(errno, thrd_error);} int retval = thrd_create(thr, func, mtxd->data); if(mtx_unlock(mtxd->mtx) == thrd_error) {RETURNWERR(errno, thrd_error);} return retval; } /* Ok, after doing a little more research, the best way to do this is probaby via a producer/consumer architecture. Spawn a bunch of // threads waiting on a queue (via semaphore) and when one is notified pop a task of the queue and execute it. In this case, the // producer would be the filesystem scanner funciton providing new files to encrypt, and the consumers would be threads waiting // to encrypt them */ // Threadpool: // Array of threads // Task Queue // Readiness semaphore // Linked List of Tasks // Task: // int (*callback)(void*) // void *arg // 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 struct task { int (*callback)(void*); void *arg; } task; typedef struct tp { thrd_t **threads; int nthreads; cqueue *taskqueue; } threadpool;