Implement a C11-like thread wrapper and use it in mmdevapi and pulseaudio
This commit is contained in:
parent
29cb5058c0
commit
18ab9cbbdd
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
169
Alc/helpers.c
169
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 <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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user