From ecc63d70476ad0bda0c0e80ec0f23c0216d93f23 Mon Sep 17 00:00:00 2001 From: ac-stef Date: Tue, 15 Sep 2015 02:58:02 +0200 Subject: [PATCH] more thread wrapper functions Add code to detach threads without losing any ressources. (use POSIX libs when SDL is not available) --- source/src/tools.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++-- source/src/tools.h | 3 ++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/source/src/tools.cpp b/source/src/tools.cpp index 940acce4..9fbd49c8 100644 --- a/source/src/tools.cpp +++ b/source/src/tools.cpp @@ -594,15 +594,21 @@ void sl_semaphore::post() // (wrapping threads is slightly ugly, since SDL threads use a different return value (int) than pthreads (void *) - and that can't be solved with a typecast) #ifdef AC_USE_SDL_THREADS -struct sl_threadinfo { int (*fn)(void *); void *data; SDL_Thread *handle; }; +struct sl_threadinfo { int (*fn)(void *); void *data; SDL_Thread *handle; volatile char done; }; -static int sl_thread_indir(void *info) { return (*((sl_threadinfo*)info)->fn)(((sl_threadinfo*)info)->data); } +static int sl_thread_indir(void *info) +{ + int res = (*((sl_threadinfo*)info)->fn)(((sl_threadinfo*)info)->data); + ((sl_threadinfo*)info)->done = 1; + return res; +} void *sl_createthread(int (*fn)(void *), void *data) { sl_threadinfo *ti = new sl_threadinfo; ti->data = data; ti->fn = fn; + ti->done = 0; ti->handle = SDL_CreateThread(sl_thread_indir, ti); return (void *) ti; } @@ -614,13 +620,41 @@ int sl_waitthread(void *ti) delete (sl_threadinfo *) ti; return res; } + +static vector oldthreads; +static sl_semaphore sem_oldthreads(1, NULL); + +void sl_detachthread(void *ti) // SDL can't actually detach threads, so this is manual cleanup +{ + if(ti && sl_pollthread(ti)) + { + SDL_WaitThread(((sl_threadinfo *)ti)->handle, NULL); + delete (sl_threadinfo *) ti; + ti = NULL; + } + if(ti || sem_oldthreads.getvalue() > 0) + { + sem_oldthreads.wait(); + if(ti) oldthreads.add((sl_threadinfo *)ti); + loopvrev(oldthreads) + { + if(oldthreads[i]->done) + { + SDL_WaitThread(oldthreads[i]->handle, NULL); + delete oldthreads.remove(i); + } + } + sem_oldthreads.post(); + } +} #else -struct sl_threadinfo { int (*fn)(void *); void *data; pthread_t handle; int res; }; +struct sl_threadinfo { int (*fn)(void *); void *data; pthread_t handle; int res; volatile char done; }; static void *sl_thread_indir(void *info) { sl_threadinfo *ti = (sl_threadinfo*) info; ti->res = (ti->fn)(ti->data); + ti->done = 1; return &ti->res; } @@ -629,6 +663,7 @@ void *sl_createthread(int (*fn)(void *), void *data) sl_threadinfo *ti = new sl_threadinfo; ti->data = data; ti->fn = fn; + ti->done = 0; pthread_create(&(ti->handle), NULL, sl_thread_indir, ti); return (void *) ti; } @@ -641,6 +676,40 @@ int sl_waitthread(void *ti) delete (sl_threadinfo *) ti; return ires; } + +static vector oldthreads; +static sl_semaphore sem_oldthreads(1, NULL); + +void sl_detachthread(void *ti) +{ + if(ti) pthread_detach(((sl_threadinfo *)ti)->handle); + if(ti || sem_oldthreads.getvalue() > 0) + { + sem_oldthreads.wait(); + if(ti) oldthreads.add((sl_threadinfo *)ti); + loopvrev(oldthreads) if(oldthreads[i]->done) delete oldthreads.remove(i); + sem_oldthreads.post(); + } +} +#endif + +bool sl_pollthread(void *ti) +{ + return ((sl_threadinfo*)ti)->done != 0; +} + +// platform dependent stuff not covered by enet (use POSIX or, if possible, SDL) +#ifdef AC_USE_SDL_THREADS +void sl_sleep(int duration) +{ + SDL_Delay(duration); +} +#else +void sl_sleep(int duration) +{ + struct timespec t = { duration / 1000, (duration % 1000) * 1000000 }; + nanosleep(&t, NULL); +} #endif void parseupdatelist(hashtable &ht, char *buf, const char *prefix, const char *suffix) diff --git a/source/src/tools.h b/source/src/tools.h index 88d12ddc..fa9f10f5 100644 --- a/source/src/tools.h +++ b/source/src/tools.h @@ -1010,6 +1010,9 @@ struct sl_semaphore extern void *sl_createthread(int (*fn)(void *), void *data); extern int sl_waitthread(void *ti); +extern bool sl_pollthread(void *ti); +extern void sl_detachthread(void *ti); +extern void sl_sleep(int duration); #endif