From 18ab9cbbdd4b8db8e5cd9ea6155efafdb79fcad0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Apr 2014 05:19:34 -0700 Subject: Implement a C11-like thread wrapper and use it in mmdevapi and pulseaudio --- Alc/backends/mmdevapi.c | 16 ++--- Alc/backends/pulseaudio.c | 17 ++--- Alc/helpers.c | 169 ++++++++++++++++++++++++++++++++++++++++++--- OpenAL32/Include/threads.h | 82 ++++++++++++++++++++-- 4 files changed, 250 insertions(+), 34 deletions(-) diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c index b713e831..75d80749 100644 --- a/Alc/backends/mmdevapi.c +++ b/Alc/backends/mmdevapi.c @@ -72,7 +72,7 @@ typedef struct { volatile UINT32 Padding; volatile int killNow; - althread_t thread; + althrd_t thread; } MMDevApiData; @@ -212,7 +212,7 @@ static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALu } -FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr) +FORCE_ALIGN static int MMDevApiProc(void *ptr) { ALCdevice *device = ptr; MMDevApiData *data = device->ExtraData; @@ -692,7 +692,8 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr) if(SUCCEEDED(hr)) { data->render = ptr; - if(!StartThread(&data->thread, MMDevApiProc, device)) + data->killNow = 0; + if(althrd_create(&data->thread, MMDevApiProc, device) != althrd_success) { if(data->render) IAudioRenderClient_Release(data->render); @@ -712,13 +713,12 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr) device = (ALCdevice*)msg.lParam; data = device->ExtraData; - if(data->thread) + if(data->render) { - data->killNow = 1; - StopThread(data->thread); - data->thread = NULL; + int res; - data->killNow = 0; + data->killNow = 1; + althrd_join(data->thread, &res); IAudioRenderClient_Release(data->render); data->render = NULL; diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c index bb371453..6b7b00a3 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.c @@ -479,7 +479,7 @@ typedef struct ALCpulsePlayback { pa_context *context; volatile ALboolean killNow; - althread_t thread; + althrd_t thread; } ALCpulsePlayback; DECLARE_ALCBACKEND_VTABLE(ALCpulsePlayback); @@ -496,7 +496,7 @@ static pa_stream *ALCpulsePlayback_connectStream(const char *device_name, pa_thr pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec, pa_channel_map *chanmap); -static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr); +static int ALCpulsePlayback_mixerProc(void *ptr); static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device); static DECLARE_FORWARD(ALCpulsePlayback, ALCbackend, void, Destruct) @@ -751,7 +751,7 @@ static pa_stream *ALCpulsePlayback_connectStream(const char *device_name, } -static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr) +static int ALCpulsePlayback_mixerProc(void *ptr) { ALCpulsePlayback *self = ptr; ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; @@ -1051,7 +1051,8 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self) { - if(!StartThread(&self->thread, ALCpulsePlayback_mixerProc, self)) + self->killNow = AL_FALSE; + if(althrd_create(&self->thread, ALCpulsePlayback_mixerProc, self) != althrd_success) return ALC_FALSE; return ALC_TRUE; } @@ -1059,17 +1060,13 @@ static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self) static void ALCpulsePlayback_stop(ALCpulsePlayback *self) { pa_operation *o; + int res; if(!self->stream) return; self->killNow = AL_TRUE; - if(self->thread) - { - StopThread(self->thread); - self->thread = NULL; - } - self->killNow = AL_FALSE; + althrd_join(self->thread, &res); pa_threaded_mainloop_lock(self->loop); diff --git a/Alc/helpers.c b/Alc/helpers.c index dc8eefaf..7e6b59a5 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -309,11 +309,88 @@ void RestoreFPUMode(const FPUCtl *ctl) } +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); #ifdef _WIN32 + +#define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */ + +typedef struct thread_cntr { + althrd_start_t func; + void *arg; +} thread_cntr; + +static DWORD WINAPI thread_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, thread_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; @@ -329,16 +406,16 @@ void almtx_destroy(almtx_t *mtx) DeleteCriticalSection(mtx); } -int almtx_timedlock(almtx_t *mtx, const alxtime *xt) +int almtx_timedlock(almtx_t *mtx, const struct timespec *ts) { DWORD expire; int ret; - if(!mtx || !xt) + if(!mtx || !ts) return althrd_error; - expire = xt->sec * 1000; - expire += (xt->nsec+999999) / 1000000; + expire = ts->tv_sec * 1000; + expire += (ts->tv_nsec+999999) / 1000000; expire += timeGetTime(); while((ret=almtx_trylock(mtx)) == althrd_busy) @@ -465,6 +542,80 @@ FILE *al_fopen(const char *fname, const char *mode) #include +extern inline althrd_t althrd_current(void); +extern inline int althrd_sleep(const struct timespec *ts, struct timespec *rem); + + +#define THREAD_STACK_SIZE (1*1024*1024) /* 1MB */ + +typedef struct thread_cntr { + althrd_start_t func; + void *arg; +} thread_cntr; + +static void *thread_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, thread_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; @@ -513,16 +664,12 @@ void almtx_destroy(almtx_t *mtx) pthread_mutex_destroy(mtx); } -int almtx_timedlock(almtx_t *mtx, const alxtime *xt) +int almtx_timedlock(almtx_t *mtx, const struct timespec *ts) { - struct timespec ts; - - if(!mtx || !xt) + if(!mtx || !ts) return althrd_error; - ts.tv_sec = xt->sec; - ts.tv_nsec = xt->nsec; - if(pthread_mutex_timedlock(mtx, &ts) != 0) + if(pthread_mutex_timedlock(mtx, ts) != 0) return althrd_busy; return althrd_success; } diff --git a/OpenAL32/Include/threads.h b/OpenAL32/Include/threads.h index 03589d15..8f564cd1 100644 --- a/OpenAL32/Include/threads.h +++ b/OpenAL32/Include/threads.h @@ -1,6 +1,8 @@ #ifndef AL_THREADS_H #define AL_THREADS_H +#include + #include "alMain.h" struct althread_info; @@ -28,18 +30,55 @@ enum { almtx_errorcheck = 8 }; -typedef struct alxtime { - time_t sec; - long nsec; -} alxtime; + +typedef int (*althrd_start_t)(void*); #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include +typedef HANDLE althrd_t; typedef CRITICAL_SECTION almtx_t; +#ifndef __MINGW32__ +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif + + +int althrd_sleep(const struct timespec *ts, struct timespec *rem); + + +#if 0 +inline althrd_t althrd_current(void) +{ + /* This is wrong. GetCurrentThread() returns a psuedo-handle of -1 which + * various functions will interpret as the calling thread. There is no + * apparent way to retrieve the same handle that was returned by + * CreateThread. */ + return GetCurrentThread(); +} +#endif + +inline int althrd_equal(althrd_t thr0, althrd_t thr1) +{ + return GetThreadId(thr0) == GetThreadId(thr1); +} + +inline void althrd_exit(int res) +{ + ExitThread(res); +} + +inline void althrd_yield(void) +{ + SwitchToThread(); +} + + inline int almtx_lock(almtx_t *mtx) { if(!mtx) return althrd_error; @@ -67,8 +106,36 @@ inline int almtx_trylock(almtx_t *mtx) #include +typedef pthread_t althrd_t; typedef pthread_mutex_t almtx_t; + +inline althrd_t althrd_current(void) +{ + return pthread_self(); +} + +inline int althrd_equal(althrd_t thr0, althrd_t thr1) +{ + return pthread_equal(thr0, thr1); +} + +inline void althrd_exit(int res) +{ + pthread_exit((void*)(intptr_t)res); +} + +inline void althrd_yield(void) +{ + sched_yield(); +} + +inline int althrd_sleep(const struct timespec *ts, struct timespec *rem) +{ + return nanosleep(ts, rem); +} + + inline int almtx_lock(almtx_t *mtx) { if(!mtx) return althrd_error; @@ -93,8 +160,13 @@ inline int almtx_trylock(almtx_t *mtx) #endif + +int althrd_create(althrd_t *thr, althrd_start_t func, void *arg); +int althrd_detach(althrd_t thr); +int althrd_join(althrd_t thr, int *res); + int almtx_init(almtx_t *mtx, int type); void almtx_destroy(almtx_t *mtx); -int almtx_timedlock(almtx_t *mtx, const alxtime *xt); +int almtx_timedlock(almtx_t *mtx, const struct timespec *ts); #endif /* AL_THREADS_H */ -- cgit v1.2.3