more thread wrapper functions

Add code to detach threads without losing any ressources.
(use POSIX libs when SDL is not available)
This commit is contained in:
ac-stef
2015-09-15 13:18:03 +02:00
parent f6c161bcc5
commit ecc63d7047
2 changed files with 75 additions and 3 deletions
+72 -3
View File
@@ -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<sl_threadinfo *> 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<sl_threadinfo *> 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<const char *, int> &ht, char *buf, const char *prefix, const char *suffix)