Use C++ a bit more with alc.cpp

This commit is contained in:
Chris Robinson 2018-11-14 06:17:47 -08:00
parent 3021a426c0
commit 46301a087c
2 changed files with 116 additions and 141 deletions

View File

@ -30,6 +30,8 @@
#include <signal.h> #include <signal.h>
#include <atomic> #include <atomic>
#include <mutex>
#include <thread>
#include <vector> #include <vector>
#include <string> #include <string>
@ -58,6 +60,8 @@
#include "backends/base.h" #include "backends/base.h"
namespace {
/************************************************ /************************************************
* Backends * Backends
************************************************/ ************************************************/
@ -66,7 +70,7 @@ struct BackendInfo {
ALCbackendFactory* (*getFactory)(void); ALCbackendFactory* (*getFactory)(void);
}; };
static struct BackendInfo BackendList[] = { struct BackendInfo BackendList[] = {
#ifdef HAVE_JACK #ifdef HAVE_JACK
{ "jack", ALCjackBackendFactory_getFactory }, { "jack", ALCjackBackendFactory_getFactory },
#endif #endif
@ -115,18 +119,18 @@ static struct BackendInfo BackendList[] = {
{ "wave", ALCwaveBackendFactory_getFactory }, { "wave", ALCwaveBackendFactory_getFactory },
#endif #endif
}; };
static ALsizei BackendListSize = COUNTOF(BackendList); ALsizei BackendListSize = COUNTOF(BackendList);
#undef EmptyFuncs #undef EmptyFuncs
static struct BackendInfo PlaybackBackend; struct BackendInfo PlaybackBackend;
static struct BackendInfo CaptureBackend; struct BackendInfo CaptureBackend;
/************************************************ /************************************************
* Functions, enums, and errors * Functions, enums, and errors
************************************************/ ************************************************/
#define DECL(x) { #x, (ALCvoid*)(x) } #define DECL(x) { #x, (ALCvoid*)(x) }
static const struct { constexpr struct {
const ALCchar *funcName; const ALCchar *funcName;
ALCvoid *address; ALCvoid *address;
} alcFunctions[] = { } alcFunctions[] = {
@ -305,7 +309,7 @@ static const struct {
#undef DECL #undef DECL
#define DECL(x) { #x, (x) } #define DECL(x) { #x, (x) }
static const struct { constexpr struct {
const ALCchar *enumName; const ALCchar *enumName;
ALCenum value; ALCenum value;
} alcEnumerations[] = { } alcEnumerations[] = {
@ -688,12 +692,12 @@ static const struct {
}; };
#undef DECL #undef DECL
static const ALCchar alcNoError[] = "No Error"; constexpr ALCchar alcNoError[] = "No Error";
static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; constexpr ALCchar alcErrInvalidDevice[] = "Invalid Device";
static const ALCchar alcErrInvalidContext[] = "Invalid Context"; constexpr ALCchar alcErrInvalidContext[] = "Invalid Context";
static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; constexpr ALCchar alcErrInvalidEnum[] = "Invalid Enum";
static const ALCchar alcErrInvalidValue[] = "Invalid Value"; constexpr ALCchar alcErrInvalidValue[] = "Invalid Value";
static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; constexpr ALCchar alcErrOutOfMemory[] = "Out of Memory";
/************************************************ /************************************************
@ -701,17 +705,17 @@ static const ALCchar alcErrOutOfMemory[] = "Out of Memory";
************************************************/ ************************************************/
/* Enumerated device names */ /* Enumerated device names */
static const ALCchar alcDefaultName[] = "OpenAL Soft\0"; constexpr ALCchar alcDefaultName[] = "OpenAL Soft\0";
static al_string alcAllDevicesList; al_string alcAllDevicesList;
static al_string alcCaptureDeviceList; al_string alcCaptureDeviceList;
/* Default is always the first in the list */ /* Default is always the first in the list */
static ALCchar *alcDefaultAllDevicesSpecifier; std::string alcDefaultAllDevicesSpecifier;
static ALCchar *alcCaptureDefaultDeviceSpecifier; std::string alcCaptureDefaultDeviceSpecifier;
/* Default context extensions */ /* Default context extensions */
static const ALchar alExtList[] = constexpr ALchar alExtList[] =
"AL_EXT_ALAW " "AL_EXT_ALAW "
"AL_EXT_BFORMAT " "AL_EXT_BFORMAT "
"AL_EXT_DOUBLE " "AL_EXT_DOUBLE "
@ -742,12 +746,54 @@ static const ALchar alExtList[] =
"AL_SOFT_source_resampler " "AL_SOFT_source_resampler "
"AL_SOFT_source_spatialize"; "AL_SOFT_source_spatialize";
static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); std::atomic<ALCenum> LastNullDeviceError{ALC_NO_ERROR};
/* Thread-local current context */ /* Thread-local current context */
static altss_t LocalContext; altss_t LocalContext;
/* Process-wide current context */ /* Process-wide current context */
static ATOMIC(ALCcontext*) GlobalContext = ATOMIC_INIT_STATIC(nullptr); std::atomic<ALCcontext*> GlobalContext{nullptr};
/* Flag to trap ALC device errors */
bool TrapALCError{false};
/* One-time configuration init control */
std::once_flag alc_config_once{};
/* Default effect that applies to sources that don't have an effect on send 0 */
ALeffect DefaultEffect;
/* Flag to specify if alcSuspendContext/alcProcessContext should defer/process
* updates.
*/
bool SuspendDefers{true};
/************************************************
* ALC information
************************************************/
constexpr ALCchar alcNoDeviceExtList[] =
"ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
"ALC_EXT_thread_local_context ALC_SOFT_loopback";
constexpr ALCchar alcExtensionList[] =
"ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
"ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX "
"ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF "
"ALC_SOFT_loopback ALC_SOFT_output_limiter ALC_SOFT_pause_device";
constexpr ALCint alcMajorVersion = 1;
constexpr ALCint alcMinorVersion = 1;
constexpr ALCint alcEFXMajorVersion = 1;
constexpr ALCint alcEFXMinorVersion = 0;
/************************************************
* Device lists
************************************************/
std::atomic<ALCdevice*> DeviceList{nullptr};
std::recursive_mutex ListLock;
} // namespace
/* Mixing thread piority level */ /* Mixing thread piority level */
ALint RTPrioLevel; ALint RTPrioLevel;
@ -759,56 +805,6 @@ enum LogLevel LogLevel = LogWarning;
enum LogLevel LogLevel = LogError; enum LogLevel LogLevel = LogError;
#endif #endif
/* Flag to trap ALC device errors */
static ALCboolean TrapALCError = ALC_FALSE;
/* One-time configuration init control */
static alonce_flag alc_config_once = AL_ONCE_FLAG_INIT;
/* Default effect that applies to sources that don't have an effect on send 0 */
static ALeffect DefaultEffect;
/* Flag to specify if alcSuspendContext/alcProcessContext should defer/process
* updates.
*/
static ALCboolean SuspendDefers = ALC_TRUE;
/************************************************
* ALC information
************************************************/
static const ALCchar alcNoDeviceExtList[] =
"ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
"ALC_EXT_thread_local_context ALC_SOFT_loopback";
static const ALCchar alcExtensionList[] =
"ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
"ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX "
"ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF "
"ALC_SOFT_loopback ALC_SOFT_output_limiter ALC_SOFT_pause_device";
static const ALCint alcMajorVersion = 1;
static const ALCint alcMinorVersion = 1;
static const ALCint alcEFXMajorVersion = 1;
static const ALCint alcEFXMinorVersion = 0;
/************************************************
* Device lists
************************************************/
static std::atomic<ALCdevice*> DeviceList{nullptr};
static almtx_t ListLock;
static inline void LockLists(void)
{
int ret = almtx_lock(&ListLock);
assert(ret == althrd_success);
}
static inline void UnlockLists(void)
{
int ret = almtx_unlock(&ListLock);
assert(ret == althrd_success);
}
/************************************************ /************************************************
* Library initialization * Library initialization
************************************************/ ************************************************/
@ -899,9 +895,6 @@ static void alc_init(void)
ret = altss_create(&LocalContext, ReleaseThreadCtx); ret = altss_create(&LocalContext, ReleaseThreadCtx);
assert(ret == althrd_success); assert(ret == althrd_success);
ret = almtx_init(&ListLock, almtx_recursive);
assert(ret == althrd_success);
} }
static void alc_initconfig(void) static void alc_initconfig(void)
@ -951,7 +944,7 @@ static void alc_initconfig(void)
{ {
if(strcasecmp(str, "ignore") == 0) if(strcasecmp(str, "ignore") == 0)
{ {
SuspendDefers = ALC_FALSE; SuspendDefers = false;
TRACE("Selected context suspend behavior, \"ignore\"\n"); TRACE("Selected context suspend behavior, \"ignore\"\n");
} }
else else
@ -1023,7 +1016,7 @@ static void alc_initconfig(void)
if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1))
{ {
TrapALError = AL_TRUE; TrapALError = AL_TRUE;
TrapALCError = AL_TRUE; TrapALCError = true;
} }
else else
{ {
@ -1034,8 +1027,8 @@ static void alc_initconfig(void)
str = getenv("ALSOFT_TRAP_ALC_ERROR"); str = getenv("ALSOFT_TRAP_ALC_ERROR");
if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1)) if(str && (strcasecmp(str, "true") == 0 || strtol(str, nullptr, 0) == 1))
TrapALCError = ALC_TRUE; TrapALCError = true;
TrapALCError = GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError); TrapALCError = !!GetConfigValueBool(nullptr, nullptr, "trap-alc-error", TrapALCError);
} }
if(ConfigValueFloat(nullptr, "reverb", "boost", &valf)) if(ConfigValueFloat(nullptr, "reverb", "boost", &valf))
@ -1172,7 +1165,7 @@ static void alc_initconfig(void)
if((str && str[0]) || ConfigValueStr(nullptr, nullptr, "default-reverb", &str)) if((str && str[0]) || ConfigValueStr(nullptr, nullptr, "default-reverb", &str))
LoadReverbPreset(str, &DefaultEffect); LoadReverbPreset(str, &DefaultEffect);
} }
#define DO_INITCONFIG() alcall_once(&alc_config_once, alc_initconfig) #define DO_INITCONFIG() std::call_once(alc_config_once, alc_initconfig)
/************************************************ /************************************************
@ -1183,10 +1176,8 @@ static void alc_cleanup(void)
AL_STRING_DEINIT(alcAllDevicesList); AL_STRING_DEINIT(alcAllDevicesList);
AL_STRING_DEINIT(alcCaptureDeviceList); AL_STRING_DEINIT(alcCaptureDeviceList);
free(alcDefaultAllDevicesSpecifier); alcDefaultAllDevicesSpecifier.clear();
alcDefaultAllDevicesSpecifier = nullptr; alcCaptureDefaultDeviceSpecifier.clear();
free(alcCaptureDefaultDeviceSpecifier);
alcCaptureDefaultDeviceSpecifier = nullptr;
if(ALCdevice *dev{DeviceList.exchange(nullptr)}) if(ALCdevice *dev{DeviceList.exchange(nullptr)})
{ {
@ -1206,7 +1197,6 @@ static void alc_deinit_safe(void)
FreeHrtfs(); FreeHrtfs();
FreeALConfig(); FreeALConfig();
almtx_destroy(&ListLock);
altss_delete(LocalContext); altss_delete(LocalContext);
if(LogFile != stderr) if(LogFile != stderr)
@ -1246,16 +1236,13 @@ static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum
{ {
DO_INITCONFIG(); DO_INITCONFIG();
LockLists(); std::lock_guard<std::recursive_mutex> _{ListLock};
alstr_clear(list); alstr_clear(list);
if(backendinfo->getFactory) if(backendinfo->getFactory)
{ {
ALCbackendFactory *factory = backendinfo->getFactory(); ALCbackendFactory *factory = backendinfo->getFactory();
V(factory,probe)(type, list); V(factory,probe)(type, list);
} }
UnlockLists();
} }
static void ProbeAllDevicesList(void) static void ProbeAllDevicesList(void)
{ ProbeDevices(&alcAllDevicesList, &PlaybackBackend, ALL_DEVICE_PROBE); } { ProbeDevices(&alcAllDevicesList, &PlaybackBackend, ALL_DEVICE_PROBE); }
@ -1634,7 +1621,7 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode)
if(device) if(device)
ATOMIC_STORE_SEQ(&device->LastError, errorCode); ATOMIC_STORE_SEQ(&device->LastError, errorCode);
else else
ATOMIC_STORE_SEQ(&LastNullDeviceError, errorCode); LastNullDeviceError.store(errorCode);
} }
@ -2311,8 +2298,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
* auxiliary sends is changing. Active sources will have updates * auxiliary sends is changing. Active sources will have updates
* respecified in UpdateAllSourceProps. * respecified in UpdateAllSourceProps.
*/ */
vprops = ATOMIC_EXCHANGE_PTR(&context->FreeVoiceProps, static_cast<ALvoiceProps*>(nullptr), vprops = static_cast<ALvoiceProps*>(ATOMIC_EXCHANGE_PTR(&context->FreeVoiceProps,
almemory_order_acq_rel); static_cast<ALvoiceProps*>(nullptr), almemory_order_acq_rel));
while(vprops) while(vprops)
{ {
struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed); struct ALvoiceProps *next = ATOMIC_LOAD(&vprops->next, almemory_order_relaxed);
@ -2537,19 +2524,17 @@ void ALCdevice_DecRef(ALCdevice *device)
*/ */
static ALCboolean VerifyDevice(ALCdevice **device) static ALCboolean VerifyDevice(ALCdevice **device)
{ {
LockLists(); std::lock_guard<std::recursive_mutex> _{ListLock};
ALCdevice *tmpDevice{DeviceList.load()}; ALCdevice *tmpDevice{DeviceList.load()};
while(tmpDevice) while(tmpDevice)
{ {
if(tmpDevice == *device) if(tmpDevice == *device)
{ {
ALCdevice_IncRef(tmpDevice); ALCdevice_IncRef(tmpDevice);
UnlockLists();
return ALC_TRUE; return ALC_TRUE;
} }
tmpDevice = ATOMIC_LOAD(&tmpDevice->next, almemory_order_relaxed); tmpDevice = ATOMIC_LOAD(&tmpDevice->next, almemory_order_relaxed);
} }
UnlockLists();
*device = nullptr; *device = nullptr;
return ALC_FALSE; return ALC_FALSE;
@ -2661,7 +2646,6 @@ static ALvoid InitContext(ALCcontext *Context)
static void FreeContext(ALCcontext *context) static void FreeContext(ALCcontext *context)
{ {
ALlistener *listener = context->Listener; ALlistener *listener = context->Listener;
struct ALeffectslotArray *auxslots;
struct ALeffectslotProps *eprops; struct ALeffectslotProps *eprops;
struct ALlistenerProps *lprops; struct ALlistenerProps *lprops;
struct ALcontextProps *cprops; struct ALcontextProps *cprops;
@ -2694,9 +2678,8 @@ static void FreeContext(ALCcontext *context)
context->DefaultSlot = nullptr; context->DefaultSlot = nullptr;
} }
auxslots = ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots, al_free(ATOMIC_EXCHANGE_PTR(&context->ActiveAuxSlots,
static_cast<ALeffectslotArray*>(nullptr), almemory_order_relaxed); static_cast<ALeffectslotArray*>(nullptr), almemory_order_relaxed));
al_free(auxslots);
ReleaseALSources(context); ReleaseALSources(context);
#define FREE_SOURCESUBLIST(x) al_free((x)->Sources) #define FREE_SOURCESUBLIST(x) al_free((x)->Sources)
@ -2795,7 +2778,7 @@ static bool ReleaseContext(ALCcontext *context, ALCdevice *device)
} }
origctx = context; origctx = context;
if(ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&GlobalContext, &origctx, static_cast<ALCcontext*>(nullptr))) if(GlobalContext.compare_exchange_strong(origctx, nullptr))
ALCcontext_DecRef(context); ALCcontext_DecRef(context);
V0(device->Backend,lock)(); V0(device->Backend,lock)();
@ -2857,7 +2840,7 @@ static void ReleaseThreadCtx(void *ptr)
*/ */
static ALCboolean VerifyContext(ALCcontext **context) static ALCboolean VerifyContext(ALCcontext **context)
{ {
LockLists(); std::lock_guard<std::recursive_mutex> _{ListLock};
ALCdevice *dev{DeviceList.load()}; ALCdevice *dev{DeviceList.load()};
while(dev) while(dev)
{ {
@ -2867,14 +2850,12 @@ static ALCboolean VerifyContext(ALCcontext **context)
if(ctx == *context) if(ctx == *context)
{ {
ALCcontext_IncRef(ctx); ALCcontext_IncRef(ctx);
UnlockLists();
return ALC_TRUE; return ALC_TRUE;
} }
ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed); ctx = ATOMIC_LOAD(&ctx->next, almemory_order_relaxed);
} }
dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed); dev = ATOMIC_LOAD(&dev->next, almemory_order_relaxed);
} }
UnlockLists();
*context = nullptr; *context = nullptr;
return ALC_FALSE; return ALC_FALSE;
@ -2893,10 +2874,9 @@ ALCcontext *GetContextRef(void)
ALCcontext_IncRef(context); ALCcontext_IncRef(context);
else else
{ {
LockLists(); std::lock_guard<std::recursive_mutex> _{ListLock};
context = ATOMIC_LOAD_SEQ(&GlobalContext); context = GlobalContext.load(std::memory_order_acquire);
if(context) ALCcontext_IncRef(context); if(context) ALCcontext_IncRef(context);
UnlockLists();
} }
return context; return context;
@ -3007,7 +2987,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
ALCdevice_DecRef(device); ALCdevice_DecRef(device);
} }
else else
errorCode = ATOMIC_EXCHANGE_SEQ(&LastNullDeviceError, ALC_NO_ERROR); errorCode = LastNullDeviceError.exchange(ALC_NO_ERROR);
return errorCode; return errorCode;
} }
@ -3125,12 +3105,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
VerifyDevice(&Device); VerifyDevice(&Device);
free(alcDefaultAllDevicesSpecifier); alcDefaultAllDevicesSpecifier = alstr_get_cstr(alcAllDevicesList);
alcDefaultAllDevicesSpecifier = strdup(alstr_get_cstr(alcAllDevicesList)); value = alcDefaultAllDevicesSpecifier.c_str();
if(!alcDefaultAllDevicesSpecifier)
alcSetError(Device, ALC_OUT_OF_MEMORY);
value = alcDefaultAllDevicesSpecifier;
if(Device) ALCdevice_DecRef(Device); if(Device) ALCdevice_DecRef(Device);
break; break;
@ -3140,12 +3116,8 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
VerifyDevice(&Device); VerifyDevice(&Device);
free(alcCaptureDefaultDeviceSpecifier); alcCaptureDefaultDeviceSpecifier = alstr_get_cstr(alcCaptureDeviceList);
alcCaptureDefaultDeviceSpecifier = strdup(alstr_get_cstr(alcCaptureDeviceList)); value = alcCaptureDefaultDeviceSpecifier.c_str();
if(!alcCaptureDefaultDeviceSpecifier)
alcSetError(Device, ALC_OUT_OF_MEMORY);
value = alcCaptureDefaultDeviceSpecifier;
if(Device) ALCdevice_DecRef(Device); if(Device) ALCdevice_DecRef(Device);
break; break;
@ -3772,17 +3744,17 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
* device is asynchronously destropyed, to ensure this new context is * device is asynchronously destropyed, to ensure this new context is
* properly cleaned up after being made. * properly cleaned up after being made.
*/ */
LockLists(); std::unique_lock<std::recursive_mutex> listlock{ListLock};
if(!VerifyDevice(&device) || device->Type == Capture || if(!VerifyDevice(&device) || device->Type == Capture ||
!ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed))
{ {
UnlockLists(); listlock.unlock();
alcSetError(device, ALC_INVALID_DEVICE); alcSetError(device, ALC_INVALID_DEVICE);
if(device) ALCdevice_DecRef(device); if(device) ALCdevice_DecRef(device);
return nullptr; return nullptr;
} }
almtx_lock(&device->BackendLock); almtx_lock(&device->BackendLock);
UnlockLists(); listlock.unlock();
ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR); ATOMIC_STORE_SEQ(&device->LastError, ALC_NO_ERROR);
@ -3889,17 +3861,15 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
*/ */
ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
{ {
ALCdevice *Device; std::unique_lock<std::recursive_mutex> listlock{ListLock};
LockLists();
if(!VerifyContext(&context)) if(!VerifyContext(&context))
{ {
UnlockLists(); listlock.unlock();
alcSetError(nullptr, ALC_INVALID_CONTEXT); alcSetError(nullptr, ALC_INVALID_CONTEXT);
return; return;
} }
Device = context->Device; ALCdevice* Device{context->Device};
if(Device) if(Device)
{ {
almtx_lock(&Device->BackendLock); almtx_lock(&Device->BackendLock);
@ -3910,7 +3880,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
} }
almtx_unlock(&Device->BackendLock); almtx_unlock(&Device->BackendLock);
} }
UnlockLists(); listlock.unlock();
ALCcontext_DecRef(context); ALCcontext_DecRef(context);
} }
@ -3923,7 +3893,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
{ {
ALCcontext *Context{static_cast<ALCcontext*>(altss_get(LocalContext))}; ALCcontext *Context{static_cast<ALCcontext*>(altss_get(LocalContext))};
if(!Context) Context = ATOMIC_LOAD_SEQ(&GlobalContext); if(!Context) Context = GlobalContext.load();
return Context; return Context;
} }
@ -3951,7 +3921,7 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
return ALC_FALSE; return ALC_FALSE;
} }
/* context's reference count is already incremented */ /* context's reference count is already incremented */
context = ATOMIC_EXCHANGE_PTR_SEQ(&GlobalContext, context); context = GlobalContext.exchange(context);
if(context) ALCcontext_DecRef(context); if(context) ALCcontext_DecRef(context);
if((context=static_cast<ALCcontext*>(altss_get(LocalContext))) != nullptr) if((context=static_cast<ALCcontext*>(altss_get(LocalContext))) != nullptr)
@ -4206,7 +4176,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
*/ */
ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
{ {
LockLists(); std::unique_lock<std::recursive_mutex> listlock{ListLock};
ALCdevice *iter{DeviceList.load()}; ALCdevice *iter{DeviceList.load()};
do { do {
if(iter == device) if(iter == device)
@ -4216,14 +4186,13 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
if(!iter || iter->Type == Capture) if(!iter || iter->Type == Capture)
{ {
alcSetError(iter, ALC_INVALID_DEVICE); alcSetError(iter, ALC_INVALID_DEVICE);
UnlockLists();
return ALC_FALSE; return ALC_FALSE;
} }
almtx_lock(&device->BackendLock); almtx_lock(&device->BackendLock);
ALCdevice *origdev{device}; ALCdevice *origdev{device};
ALCdevice *nextdev{ATOMIC_LOAD(&device->next, almemory_order_relaxed)}; ALCdevice *nextdev{ATOMIC_LOAD(&device->next, almemory_order_relaxed)};
if(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&DeviceList, &origdev, nextdev)) if(!DeviceList.compare_exchange_strong(origdev, nextdev))
{ {
ALCdevice *list; ALCdevice *list;
do { do {
@ -4231,7 +4200,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
origdev = device; origdev = device;
} while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev));
} }
UnlockLists(); listlock.unlock();
ALCcontext *ctx{ATOMIC_LOAD_SEQ(&device->ContextList)}; ALCcontext *ctx{ATOMIC_LOAD_SEQ(&device->ContextList)};
while(ctx != nullptr) while(ctx != nullptr)
@ -4339,8 +4308,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
{ {
std::unique_lock<std::recursive_mutex> listlock{ListLock};
LockLists();
ALCdevice *iter{DeviceList.load()}; ALCdevice *iter{DeviceList.load()};
do { do {
if(iter == device) if(iter == device)
@ -4350,7 +4319,6 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
if(!iter || iter->Type != Capture) if(!iter || iter->Type != Capture)
{ {
alcSetError(iter, ALC_INVALID_DEVICE); alcSetError(iter, ALC_INVALID_DEVICE);
UnlockLists();
return ALC_FALSE; return ALC_FALSE;
} }
@ -4364,7 +4332,7 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
origdev = device; origdev = device;
} while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev)); } while(!ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(&list->next, &origdev, nextdev));
} }
UnlockLists(); listlock.unlock();
almtx_lock(&device->BackendLock); almtx_lock(&device->BackendLock);
if((device->Flags&DEVICE_RUNNING)) if((device->Flags&DEVICE_RUNNING))
@ -4663,17 +4631,17 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi
{ {
ALCenum err; ALCenum err;
LockLists(); std::unique_lock<std::recursive_mutex> listlock{ListLock};
if(!VerifyDevice(&device) || device->Type == Capture || if(!VerifyDevice(&device) || device->Type == Capture ||
!ATOMIC_LOAD(&device->Connected, almemory_order_relaxed)) !ATOMIC_LOAD(&device->Connected, almemory_order_relaxed))
{ {
UnlockLists(); listlock.unlock();
alcSetError(device, ALC_INVALID_DEVICE); alcSetError(device, ALC_INVALID_DEVICE);
if(device) ALCdevice_DecRef(device); if(device) ALCdevice_DecRef(device);
return ALC_FALSE; return ALC_FALSE;
} }
almtx_lock(&device->BackendLock); almtx_lock(&device->BackendLock);
UnlockLists(); listlock.unlock();
err = UpdateDeviceParams(device, attribs); err = UpdateDeviceParams(device, attribs);
almtx_unlock(&device->BackendLock); almtx_unlock(&device->BackendLock);

View File

@ -32,6 +32,15 @@
#include "threads.h" #include "threads.h"
#ifndef __cplusplus
#define COUNTOF(x) (sizeof(x) / sizeof(0[x]))
#else
template<typename T, size_t N>
constexpr inline size_t countof(const T(&)[N]) noexcept
{ return N; }
#define COUNTOF countof
#endif
#if defined(_WIN64) #if defined(_WIN64)
#define SZFMT "%I64u" #define SZFMT "%I64u"
#elif defined(_WIN32) #elif defined(_WIN32)
@ -197,8 +206,6 @@ static const union {
#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) #define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1)
#endif #endif
#define COUNTOF(x) (sizeof(x) / sizeof(0[x]))
struct ll_ringbuffer; struct ll_ringbuffer;
struct Hrtf; struct Hrtf;