diff options
Diffstat (limited to 'src/util/thread.c')
-rw-r--r-- | src/util/thread.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/src/util/thread.c b/src/util/thread.c new file mode 100644 index 0000000..f3ef4a7 --- /dev/null +++ b/src/util/thread.c @@ -0,0 +1,221 @@ +#ifndef _plan9_ +#include <signal.h> +#include <stdio.h> +#endif +#include <xthread.h> +#ifndef __BEOS__ +struct taskinfo definfo = { + 0, +}; + +#ifndef nthreads + +#define getrange1(range,ncpu) ((range)*(ncpu))/nthreads +#define getrange2(range,ncpu) getrange1(range,(ncpu)+1) + +int ethreads = 0; +int nthreads = 1; + +#ifdef USE_PTHREAD + +/* Well conde follows is probably very ugly, since this is + * my absolutely first application for threads. Please let + * me know how to improvie it + */ + +static pthread_cond_t synccond, startcond; +static struct taskinfo infos[MAXTHREADS]; +static pthread_mutex_t synccondmutex, startcondmutex; +pthread_mutex_t semaphors[MAXSEMAPHORS]; +pthread_cond_t conds[MAXCONDS]; + +/*This loop is executed whole time in slave threads. + Its function is following: + 1) wait for message + 2) call function from message + 3) syncronize + 4) again + + To invoke this mechanizm main thread(#1) should call + xth_function + xth_synchronize forces forces thread to wait for others + */ + +static int nfinished; +static int npending; +static int counter; +static int bcounter; +static int bcounter1; +static int range; +static void *data; +static xfunction function; +static void *control_routine(void *i) +{ + struct taskinfo *info = i; + int mycounter = 0; + int r; + void *d; + xfunction f; + while (1) { + /* quite a lot pthread calls. Please if you are + * reading this code and crying "OH NO!" so ugly + * handling! Why so much calls? Stop crying, I am + * newbie in threads. Please rewrite my code and + * send me better and faster version. + * + * This function comunicates with pth_function from main loop + * as follows: it uses startcond to wait for order start function! + * Counter is used to ensure that main function did not give + * order whie control_routine was busy + * + * after order is received, function adress is readed from global + * variables and started. Pth_function then executes its + * own part of calculation. After that it waits counter + * nfinished to reach number of thasks-1. This is done + * using cond synccond and synccondmutex. Quite complex + * but it seems to work. Looking forward for someone, who + * should reduce number of _lock/_unlock + */ + pthread_mutex_lock(&synccondmutex); + nfinished++; + pthread_cond_signal(&synccond); + pthread_mutex_unlock(&synccondmutex); + + pthread_mutex_lock(&startcondmutex); + while (mycounter >= counter) { + if (bcounter > bcounter1) { + /*Well we are already locked using start lock..should be OK */ + mycounter--; + bcounter1++; + break; + } + pthread_cond_wait(&startcond, &startcondmutex); + } + r = range; + d = data; + f = function; + npending--; + pthread_mutex_unlock(&startcondmutex); + mycounter++; + f(d, info, getrange1(r, info->n), getrange2(r, info->n)); + } + return NULL; +} + +void pth_init(int nthreads1) +{ + int i; + pthread_attr_t attr; + if (ethreads) + return; + + if (nthreads1 == 1 || nthreads1 == 0) + return; /*use nothreads_* calls */ + if (nthreads1 > MAXTHREADS) + nthreads1 = MAXTHREADS; + nthreads = nthreads1; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + if (pthread_cond_init(&synccond, NULL)) + exit(1); + if (pthread_cond_init(&startcond, NULL)) + exit(1); + if (pthread_mutex_init(&synccondmutex, NULL)) + exit(1); + if (pthread_mutex_init(&startcondmutex, NULL)) + exit(1); + + infos[0].n = 0; + /*infos[0].id = pthread_self(); */ + + for (i = 0; i < MAXSEMAPHORS; i++) { + pthread_mutex_init(semaphors + i, NULL); + } + for (i = 0; i < MAXCONDS; i++) { + pthread_cond_init(conds + i, NULL); + } + + nfinished = 0; + for (i = 0; i < nthreads - 1; i++) { + if (pthread_create + (&infos[i + 1].id, &attr, control_routine, infos + i + 1)) { + nthreads = i + 1; + break; + } + infos[i + 1].n = i + 1; + } + if (nthreads != 1) + ethreads = 1; +} + +void pth_synchronize() +{ + /*Our job is done, synchronize now */ + if (nfinished < nthreads - 1) { + pthread_mutex_lock(&synccondmutex); + while (nfinished < nthreads - 1) { + pthread_cond_wait(&synccond, &synccondmutex); + } + pthread_mutex_unlock(&synccondmutex); + } + /*Ok job is done, lets continue :) */ +} + +void pth_bgjob(xfunction f, void *d) +{ + pthread_mutex_lock(&startcondmutex); + if (npending) { + printf("Collision!\n"); /*FIXME:remove this..I just want to know how often this happends */ + pthread_mutex_unlock(&startcondmutex); + f(d, infos, 0, 0); + } + if (bcounter < bcounter1) { + printf("Internal error\a\n"); + } + if (!nfinished) { + pthread_mutex_unlock(&startcondmutex); + /*no more CPU available :( */ + f(d, infos, 0, 0); + } + data = d; + range = 0; + function = f; + bcounter++; + nfinished--; + npending++; + pthread_cond_signal(&startcond); + pthread_mutex_unlock(&startcondmutex); +} + +void pth_function(xfunction f, void *d, int r) +{ + pth_synchronize(); + pthread_mutex_lock(&startcondmutex); + data = d; + range = r; + function = f; + /*And lets start it:) */ + nfinished = 0; + npending = nthreads - 1; + counter++; + if (nthreads == 2) + pthread_cond_signal(&startcond); + else + pthread_cond_broadcast(&startcond); + pthread_mutex_unlock(&startcondmutex); + + function(data, infos, getrange1(range, 0), getrange2(range, 0)); +} + +void pth_uninit() +{ + /*Should be empty for now since all threads will be killed after exit call */ + /*FIXME should be added something if necessary :) */ + nthreads = 1; + ethreads = 0; +} +#endif /*POSIX threads */ +#endif /*nthreads */ +#endif /*__BEOS__*/ |