diff options
Diffstat (limited to 'Alc/threads.c')
-rw-r--r-- | Alc/threads.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/Alc/threads.c b/Alc/threads.c index 64586ae9..d910716c 100644 --- a/Alc/threads.c +++ b/Alc/threads.c @@ -28,12 +28,23 @@ #include "alMain.h" #include "alThunk.h" + +extern inline int althrd_equal(althrd_t thr0, althrd_t thr1); +extern inline void althrd_exit(int res); +extern inline void althrd_yield(void); + +extern inline int almtx_lock(almtx_t *mtx); +extern inline int almtx_unlock(almtx_t *mtx); +extern inline int almtx_trylock(almtx_t *mtx); + + #define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> +#include <mmsystem.h> typedef struct althread_info { ALuint (*func)(ALvoid*); @@ -115,9 +126,122 @@ void SetThreadName(const char *name) #endif } + +typedef struct thread_cntr { + althrd_start_t func; + void *arg; +} thread_cntr; + +static DWORD WINAPI althrd_starter(void *arg) +{ + thread_cntr cntr; + memcpy(&cntr, arg, sizeof(cntr)); + free(arg); + + return (DWORD)((*cntr.func)(cntr.arg)); +} + + +int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) +{ + thread_cntr *cntr; + DWORD dummy; + HANDLE hdl; + + cntr = malloc(sizeof(*cntr)); + if(!cntr) return althrd_nomem; + + cntr->func = func; + cntr->arg = arg; + + hdl = CreateThread(NULL, THREAD_STACK_SIZE, althrd_starter, cntr, 0, &dummy); + if(!hdl) + { + free(cntr); + return althrd_error; + } + + *thr = hdl; + return althrd_success; +} + +int althrd_detach(althrd_t thr) +{ + if(!thr) return althrd_error; + CloseHandle(thr); + + return althrd_success; +} + +int althrd_join(althrd_t thr, int *res) +{ + DWORD code; + + if(!thr) return althrd_error; + + WaitForSingleObject(thr, INFINITE); + GetExitCodeThread(thr, &code); + CloseHandle(thr); + + *res = (int)code; + return althrd_success; +} + +int althrd_sleep(const struct timespec *ts, struct timespec* UNUSED(rem)) +{ + DWORD msec; + msec = ts->tv_sec * 1000; + msec += (ts->tv_nsec+999999) / 1000000; + Sleep(msec); + return 0; +} + + +int almtx_init(almtx_t *mtx, int type) +{ + if(!mtx) return althrd_error; + type &= ~(almtx_recursive|almtx_timed|almtx_normal|almtx_errorcheck); + if(type != 0) return althrd_error; + + InitializeCriticalSection(mtx); + return althrd_success; +} + +void almtx_destroy(almtx_t *mtx) +{ + DeleteCriticalSection(mtx); +} + +int almtx_timedlock(almtx_t *mtx, const struct timespec *ts) +{ + DWORD start, timelen; + int ret; + + if(!mtx || !ts) + return althrd_error; + + timelen = ts->tv_sec * 1000; + timelen += (ts->tv_nsec+999999) / 1000000; + + start = timeGetTime(); + while((ret=almtx_trylock(mtx)) == althrd_busy) + { + DWORD now = timeGetTime(); + if(now-start >= timelen) + break; + SwitchToThread(); + } + + return ret; +} + + #else #include <pthread.h> +#ifdef HAVE_PTHREAD_NP_H +#include <pthread_np.h> +#endif typedef struct althread_info { ALuint (*func)(ALvoid*); @@ -197,4 +321,135 @@ void SetThreadName(const char *name) #endif } + +extern inline althrd_t althrd_current(void); +extern inline int althrd_sleep(const struct timespec *ts, struct timespec *rem); + + +typedef struct thread_cntr { + althrd_start_t func; + void *arg; +} thread_cntr; + +static void *althrd_starter(void *arg) +{ + thread_cntr cntr; + memcpy(&cntr, arg, sizeof(cntr)); + free(arg); + + return (void*)(intptr_t)((*cntr.func)(cntr.arg)); +} + + +int althrd_create(althrd_t *thr, althrd_start_t func, void *arg) +{ + thread_cntr *cntr; + pthread_attr_t attr; + + cntr = malloc(sizeof(*cntr)); + if(!cntr) return althrd_nomem; + + if(pthread_attr_init(&attr) != 0) + { + free(cntr); + return althrd_error; + } + if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE) != 0) + { + pthread_attr_destroy(&attr); + free(cntr); + return althrd_error; + } + + cntr->func = func; + cntr->arg = arg; + if(pthread_create(thr, &attr, althrd_starter, cntr) != 0) + { + pthread_attr_destroy(&attr); + free(cntr); + return althrd_error; + } + pthread_attr_destroy(&attr); + + return althrd_success; +} + +int althrd_detach(althrd_t thr) +{ + if(pthread_detach(thr) != 0) + return althrd_error; + return althrd_success; +} + +int althrd_join(althrd_t thr, int *res) +{ + void *code; + + if(!res) return althrd_error; + + if(pthread_join(thr, &code) != 0) + return althrd_error; + *res = (int)(intptr_t)code; + return althrd_success; +} + + +int almtx_init(almtx_t *mtx, int type) +{ + int ret; + + if(!mtx) return althrd_error; + if((type&~(almtx_normal|almtx_recursive|almtx_timed|almtx_errorcheck)) != 0) + return althrd_error; + + type &= ~almtx_timed; + if(type == almtx_plain) + ret = pthread_mutex_init(mtx, NULL); + else + { + pthread_mutexattr_t attr; + + ret = pthread_mutexattr_init(&attr); + if(ret) return althrd_error; + + switch(type) + { + case almtx_normal: + ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + break; + case almtx_recursive: + ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); +#ifdef HAVE_PTHREAD_NP_H + if(ret != 0) + ret = pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE); +#endif + break; + case almtx_errorcheck: + ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); + break; + default: + ret = 1; + } + if(ret == 0) + ret = pthread_mutex_init(mtx, &attr); + pthread_mutexattr_destroy(&attr); + } + return ret ? althrd_error : althrd_success; +} + +void almtx_destroy(almtx_t *mtx) +{ + pthread_mutex_destroy(mtx); +} + +int almtx_timedlock(almtx_t *mtx, const struct timespec *ts) +{ + if(!mtx || !ts) + return althrd_error; + + if(pthread_mutex_timedlock(mtx, ts) != 0) + return althrd_busy; + return althrd_success; +} + #endif |