From 3ede2b1f8812e8c5dc10b37ca11036df7f64ac65 Mon Sep 17 00:00:00 2001 From: David Reid Date: Mon, 13 Nov 2017 20:35:14 +1000 Subject: [PATCH] API CHANGE: Expose and improve mutex APIs. --- mini_al.h | 164 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 66 deletions(-) diff --git a/mini_al.h b/mini_al.h index 8ea468d1..c3a46d72 100644 --- a/mini_al.h +++ b/mini_al.h @@ -292,13 +292,37 @@ typedef void* mal_handle; typedef void* mal_ptr; typedef void (* mal_proc)(); +typedef struct mal_context mal_context; +typedef struct mal_device mal_device; + +typedef struct +{ + mal_context* pContext; + + union + { +#ifdef MAL_WIN32 + struct + { + /*HANDLE*/ mal_handle hMutex; + } win32; +#endif +#ifdef MAL_POSIX + struct + { + pthread_mutex_t mutex; + } posix; +#endif + + int _unused; + }; +} mal_mutex; + #ifdef MAL_WIN32 typedef mal_handle mal_thread; - typedef mal_handle mal_mutex; typedef mal_handle mal_event; #else typedef pthread_t mal_thread; - typedef pthread_mutex_t mal_mutex; typedef struct { pthread_mutex_t mutex; @@ -393,9 +417,6 @@ typedef int mal_result; #define MAL_WINMM_FAILED_TO_GET_DEVICE_CAPS -4096 #define MAL_WINMM_FAILED_TO_GET_SUPPORTED_FORMATS -4097 -typedef struct mal_context mal_context; -typedef struct mal_device mal_device; - typedef void (* mal_log_proc) (mal_context* pContext, mal_device* pDevice, const char* message); typedef void (* mal_recv_proc)(mal_device* pDevice, mal_uint32 frameCount, const void* pSamples); typedef mal_uint32 (* mal_send_proc)(mal_device* pDevice, mal_uint32 frameCount, void* pSamples); @@ -1332,10 +1353,19 @@ mal_uint32 mal_convert_frames(void* pOut, mal_format formatOut, mal_uint32 chann // /////////////////////////////////////////////////////////////////////////////// -mal_bool32 mal_mutex_create(mal_context* pContext, mal_mutex* pMutex); -void mal_mutex_delete(mal_context* pContext, mal_mutex* pMutex); -void mal_mutex_lock(mal_context* pContext, mal_mutex* pMutex); -void mal_mutex_unlock(mal_context* pContext, mal_mutex* pMutex); +// Creates a mutex. +// +// A mutex must be created from a valid context. A mutex is initially unlocked. +mal_result mal_mutex_init(mal_context* pContext, mal_mutex* pMutex); + +// Deletes a mutex. +void mal_mutex_uninit(mal_mutex* pMutex); + +// Locks a mutex with an infinite timeout. +void mal_mutex_lock(mal_mutex* pMutex); + +// Unlocks a mutex. +void mal_mutex_unlock(mal_mutex* pMutex); @@ -1938,37 +1968,31 @@ void mal_sleep__win32(mal_uint32 milliseconds) } -mal_bool32 mal_mutex_create__win32(mal_context* pContext, mal_mutex* pMutex) +mal_result mal_mutex_init__win32(mal_context* pContext, mal_mutex* pMutex) { (void)pContext; - *pMutex = CreateEventA(NULL, FALSE, TRUE, NULL); - if (*pMutex == NULL) { - return MAL_FALSE; + pMutex->win32.hMutex = CreateEventA(NULL, FALSE, TRUE, NULL); + if (pMutex->win32.hMutex == NULL) { + return MAL_FAILED_TO_CREATE_MUTEX; } - return MAL_TRUE; + return MAL_SUCCESS; } -void mal_mutex_delete__win32(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_uninit__win32(mal_mutex* pMutex) { - (void)pContext; - - CloseHandle(*pMutex); + CloseHandle(pMutex->win32.hMutex); } -void mal_mutex_lock__win32(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_lock__win32(mal_mutex* pMutex) { - (void)pContext; - - WaitForSingleObject(*pMutex, INFINITE); + WaitForSingleObject(pMutex->win32.hMutex, INFINITE); } -void mal_mutex_unlock__win32(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_unlock__win32(mal_mutex* pMutex) { - (void)pContext; - - SetEvent(*pMutex); + SetEvent(pMutex->win32.hMutex); } @@ -2035,24 +2059,29 @@ void mal_sleep__posix(mal_uint32 milliseconds) } -mal_bool32 mal_mutex_create__posix(mal_context* pContext, mal_mutex* pMutex) +mal_result mal_mutex_init__posix(mal_context* pContext, mal_mutex* pMutex) { - return ((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(pMutex, NULL) == 0; + int result = ((mal_pthread_mutex_init_proc)pContext->posix.pthread_mutex_init)(&pMutex->posix.mutex, NULL); + if (result != 0) { + return MAL_FAILED_TO_CREATE_MUTEX; + } + + return MAL_SUCCESS; } -void mal_mutex_delete__posix(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_uninit__posix(mal_mutex* pMutex) { - ((mal_pthread_mutex_destroy_proc)pContext->posix.pthread_mutex_destroy)(pMutex); + ((mal_pthread_mutex_destroy_proc)pMutex->pContext->posix.pthread_mutex_destroy)(&pMutex->posix.mutex); } -void mal_mutex_lock__posix(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_lock__posix(mal_mutex* pMutex) { - ((mal_pthread_mutex_lock_proc)pContext->posix.pthread_mutex_lock)(pMutex); + ((mal_pthread_mutex_lock_proc)pMutex->pContext->posix.pthread_mutex_lock)(&pMutex->posix.mutex); } -void mal_mutex_unlock__posix(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_unlock__posix(mal_mutex* pMutex) { - ((mal_pthread_mutex_unlock_proc)pContext->posix.pthread_mutex_unlock)(pMutex); + ((mal_pthread_mutex_unlock_proc)pMutex->pContext->posix.pthread_mutex_unlock)(&pMutex->posix.mutex); } @@ -2139,51 +2168,53 @@ void mal_sleep(mal_uint32 milliseconds) } -mal_bool32 mal_mutex_create(mal_context* pContext, mal_mutex* pMutex) +mal_result mal_mutex_init(mal_context* pContext, mal_mutex* pMutex) { - if (pMutex == NULL) return MAL_FALSE; + if (pContext == NULL || pMutex == NULL) return MAL_INVALID_ARGS; + + pMutex->pContext = pContext; #ifdef MAL_WIN32 - return mal_mutex_create__win32(pContext, pMutex); + return mal_mutex_init__win32(pContext, pMutex); #endif #ifdef MAL_POSIX - return mal_mutex_create__posix(pContext, pMutex); + return mal_mutex_init__posix(pContext, pMutex); #endif } -void mal_mutex_delete(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_uninit(mal_mutex* pMutex) { - if (pMutex == NULL) return; + if (pMutex == NULL || pMutex->pContext == NULL) return; #ifdef MAL_WIN32 - mal_mutex_delete__win32(pContext, pMutex); + mal_mutex_uninit__win32(pMutex); #endif #ifdef MAL_POSIX - mal_mutex_delete__posix(pContext, pMutex); + mal_mutex_uninit__posix(pMutex); #endif } -void mal_mutex_lock(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_lock(mal_mutex* pMutex) { - if (pMutex == NULL) return; + if (pMutex == NULL || pMutex->pContext == NULL) return; #ifdef MAL_WIN32 - mal_mutex_lock__win32(pContext, pMutex); + mal_mutex_lock__win32(pMutex); #endif #ifdef MAL_POSIX - mal_mutex_lock__posix(pContext, pMutex); + mal_mutex_lock__posix(pMutex); #endif } -void mal_mutex_unlock(mal_context* pContext, mal_mutex* pMutex) +void mal_mutex_unlock(mal_mutex* pMutex) { - if (pMutex == NULL) return; + if (pMutex == NULL || pMutex->pContext == NULL) return; #ifdef MAL_WIN32 - mal_mutex_unlock__win32(pContext, pMutex); + mal_mutex_unlock__win32(pMutex); #endif #ifdef MAL_POSIX - mal_mutex_unlock__posix(pContext, pMutex); + mal_mutex_unlock__posix(pMutex); #endif } @@ -8692,7 +8723,7 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi pDevice->internalSampleRate = pDevice->sampleRate; mal_copy_memory(pDevice->internalChannelMap, pDevice->channelMap, sizeof(pDevice->channelMap)); - if (!mal_mutex_create(pContext, &pDevice->lock)) { + if (mal_mutex_init(pContext, &pDevice->lock) != MAL_SUCCESS) { return mal_post_error(pDevice, "Failed to create mutex.", MAL_FAILED_TO_CREATE_MUTEX); } @@ -8702,18 +8733,18 @@ mal_result mal_device_init(mal_context* pContext, mal_device_type type, mal_devi // Each of these semaphores is released internally by the worker thread when the work is completed. The start // semaphore is also used to wake up the worker thread. if (!mal_event_create(pContext, &pDevice->wakeupEvent)) { - mal_mutex_delete(pContext, &pDevice->lock); + mal_mutex_uninit(&pDevice->lock); return mal_post_error(pDevice, "Failed to create worker thread wakeup event.", MAL_FAILED_TO_CREATE_EVENT); } if (!mal_event_create(pContext, &pDevice->startEvent)) { mal_event_delete(pContext, &pDevice->wakeupEvent); - mal_mutex_delete(pContext, &pDevice->lock); + mal_mutex_uninit(&pDevice->lock); return mal_post_error(pDevice, "Failed to create worker thread start event.", MAL_FAILED_TO_CREATE_EVENT); } if (!mal_event_create(pContext, &pDevice->stopEvent)) { mal_event_delete(pContext, &pDevice->startEvent); mal_event_delete(pContext, &pDevice->wakeupEvent); - mal_mutex_delete(pContext, &pDevice->lock); + mal_mutex_uninit(&pDevice->lock); return mal_post_error(pDevice, "Failed to create worker thread stop event.", MAL_FAILED_TO_CREATE_EVENT); } @@ -8849,7 +8880,7 @@ void mal_device_uninit(mal_device* pDevice) mal_event_delete(pDevice->pContext, &pDevice->stopEvent); mal_event_delete(pDevice->pContext, &pDevice->startEvent); mal_event_delete(pDevice->pContext, &pDevice->wakeupEvent); - mal_mutex_delete(pDevice->pContext, &pDevice->lock); + mal_mutex_uninit(&pDevice->lock); #ifdef MAL_ENABLE_WASAPI if (pDevice->pContext->backend == mal_backend_wasapi) { @@ -8919,22 +8950,22 @@ mal_result mal_device_start(mal_device* pDevice) if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_start() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED); mal_result result = MAL_ERROR; - mal_mutex_lock(pDevice->pContext, &pDevice->lock); + mal_mutex_lock(&pDevice->lock); { // Be a bit more descriptive if the device is already started or is already in the process of starting. This is likely // a bug with the application. if (mal_device__get_state(pDevice) == MAL_STATE_STARTING) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_start() called while another thread is already starting it.", MAL_DEVICE_ALREADY_STARTING); } if (mal_device__get_state(pDevice) == MAL_STATE_STARTED) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_start() called for a device that's already started.", MAL_DEVICE_ALREADY_STARTED); } // The device needs to be in a stopped state. If it's not, we just let the caller know the device is busy. if (mal_device__get_state(pDevice) != MAL_STATE_STOPPED) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_start() called while another thread is in the process of stopping it.", MAL_DEVICE_BUSY); } @@ -8957,7 +8988,7 @@ mal_result mal_device_start(mal_device* pDevice) result = pDevice->workResult; } } - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return result; } @@ -8968,22 +8999,22 @@ mal_result mal_device_stop(mal_device* pDevice) if (mal_device__get_state(pDevice) == MAL_STATE_UNINITIALIZED) return mal_post_error(pDevice, "mal_device_stop() called for an uninitialized device.", MAL_DEVICE_NOT_INITIALIZED); mal_result result = MAL_ERROR; - mal_mutex_lock(pDevice->pContext, &pDevice->lock); + mal_mutex_lock(&pDevice->lock); { // Be a bit more descriptive if the device is already stopped or is already in the process of stopping. This is likely // a bug with the application. if (mal_device__get_state(pDevice) == MAL_STATE_STOPPING) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_stop() called while another thread is already stopping it.", MAL_DEVICE_ALREADY_STOPPING); } if (mal_device__get_state(pDevice) == MAL_STATE_STOPPED) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_stop() called for a device that's already stopped.", MAL_DEVICE_ALREADY_STOPPED); } // The device needs to be in a started state. If it's not, we just let the caller know the device is busy. if (mal_device__get_state(pDevice) != MAL_STATE_STARTED) { - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return mal_post_error(pDevice, "mal_device_stop() called while another thread is in the process of starting it.", MAL_DEVICE_BUSY); } @@ -9009,7 +9040,7 @@ mal_result mal_device_stop(mal_device* pDevice) result = MAL_SUCCESS; } } - mal_mutex_unlock(pDevice->pContext, &pDevice->lock); + mal_mutex_unlock(&pDevice->lock); return result; } @@ -10334,9 +10365,10 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) // ================ // // v0.x - 2017-xx-xx +// - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll +// need to update. // - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of // audio data to a different format. -// - Expose the mutex APIs. // // v0.5 - 2017-11-11 // - API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for