Implement a C11-like thread wrapper and use it in mmdevapi and pulseaudio

This commit is contained in:
Chris Robinson 2014-04-16 05:19:34 -07:00
parent 29cb5058c0
commit 18ab9cbbdd
4 changed files with 250 additions and 34 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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 <sys/time.h>
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;
}

View File

@ -1,6 +1,8 @@
#ifndef AL_THREADS_H
#define AL_THREADS_H
#include <time.h>
#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 <windows.h>
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 <pthread.h>
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 */