Commit 34a2294f authored by David Reid's avatar David Reid

Add support for configuring the priority of the worker thread.

parent 93fe66b7
...@@ -351,6 +351,19 @@ typedef void (* mal_proc)(); ...@@ -351,6 +351,19 @@ typedef void (* mal_proc)();
typedef struct mal_context mal_context; typedef struct mal_context mal_context;
typedef struct mal_device mal_device; typedef struct mal_device mal_device;
// Thread priorties should be ordered such that the default priority of the worker thread is 0.
typedef enum
{
mal_thread_priority_idle = -5,
mal_thread_priority_lowest = -4,
mal_thread_priority_low = -3,
mal_thread_priority_normal = -2,
mal_thread_priority_high = -1,
mal_thread_priority_highest = 0,
mal_thread_priority_realtime = 1,
mal_thread_priority_default = 0
} mal_thread_priority;
typedef struct typedef struct
{ {
mal_context* pContext; mal_context* pContext;
...@@ -745,6 +758,7 @@ typedef struct ...@@ -745,6 +758,7 @@ typedef struct
typedef struct typedef struct
{ {
mal_log_proc onLog; mal_log_proc onLog;
mal_thread_priority threadPriority;
struct struct
{ {
...@@ -1097,6 +1111,11 @@ struct mal_context ...@@ -1097,6 +1111,11 @@ struct mal_context
mal_proc pthread_cond_destroy; mal_proc pthread_cond_destroy;
mal_proc pthread_cond_wait; mal_proc pthread_cond_wait;
mal_proc pthread_cond_signal; mal_proc pthread_cond_signal;
mal_proc pthread_attr_init;
mal_proc pthread_attr_destroy;
mal_proc pthread_attr_setschedpolicy;
mal_proc pthread_attr_getschedparam;
mal_proc pthread_attr_setschedparam;
} posix; } posix;
#endif #endif
int _unused; int _unused;
...@@ -2566,15 +2585,29 @@ mal_proc mal_dlsym(mal_handle handle, const char* symbol) ...@@ -2566,15 +2585,29 @@ mal_proc mal_dlsym(mal_handle handle, const char* symbol)
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#ifdef MAL_WIN32 #ifdef MAL_WIN32
mal_result mal_thread_create__win32(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) static int mal_thread_priority_to_win32(mal_thread_priority priority)
{ {
(void)pContext; switch (priority) {
case mal_thread_priority_idle: return THREAD_PRIORITY_IDLE;
case mal_thread_priority_lowest: return THREAD_PRIORITY_LOWEST;
case mal_thread_priority_low: return THREAD_PRIORITY_BELOW_NORMAL;
case mal_thread_priority_normal: return THREAD_PRIORITY_NORMAL;
case mal_thread_priority_high: return THREAD_PRIORITY_ABOVE_NORMAL;
case mal_thread_priority_highest: return THREAD_PRIORITY_HIGHEST;
case mal_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL;
default: return mal_thread_priority_normal;
}
}
mal_result mal_thread_create__win32(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData)
{
pThread->win32.hThread = CreateThread(NULL, 0, entryProc, pData, 0, NULL); pThread->win32.hThread = CreateThread(NULL, 0, entryProc, pData, 0, NULL);
if (pThread->win32.hThread == NULL) { if (pThread->win32.hThread == NULL) {
return MAL_FAILED_TO_CREATE_THREAD; return MAL_FAILED_TO_CREATE_THREAD;
} }
SetThreadPriority((HANDLE)pThread->win32.hThread, mal_thread_priority_to_win32(pContext->config.threadPriority));
return MAL_SUCCESS; return MAL_SUCCESS;
} }
...@@ -2647,6 +2680,8 @@ mal_bool32 mal_event_signal__win32(mal_event* pEvent) ...@@ -2647,6 +2680,8 @@ mal_bool32 mal_event_signal__win32(mal_event* pEvent)
#ifdef MAL_POSIX #ifdef MAL_POSIX
#include <sched.h>
typedef int (* mal_pthread_create_proc)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); typedef int (* mal_pthread_create_proc)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
typedef int (* mal_pthread_join_proc)(pthread_t thread, void **retval); typedef int (* mal_pthread_join_proc)(pthread_t thread, void **retval);
typedef int (* mal_pthread_mutex_init_proc)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr); typedef int (* mal_pthread_mutex_init_proc)(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr);
...@@ -2657,10 +2692,67 @@ typedef int (* mal_pthread_cond_init_proc)(pthread_cond_t *__restrict __cond, co ...@@ -2657,10 +2692,67 @@ typedef int (* mal_pthread_cond_init_proc)(pthread_cond_t *__restrict __cond, co
typedef int (* mal_pthread_cond_destroy_proc)(pthread_cond_t *__cond); typedef int (* mal_pthread_cond_destroy_proc)(pthread_cond_t *__cond);
typedef int (* mal_pthread_cond_signal_proc)(pthread_cond_t *__cond); typedef int (* mal_pthread_cond_signal_proc)(pthread_cond_t *__cond);
typedef int (* mal_pthread_cond_wait_proc)(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex); typedef int (* mal_pthread_cond_wait_proc)(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex);
typedef int (* mal_pthread_attr_init_proc)(pthread_attr_t *attr);
typedef int (* mal_pthread_attr_destroy_proc)(pthread_attr_t *attr);
typedef int (* mal_pthread_attr_setschedpolicy_proc)(pthread_attr_t *attr, int policy);
typedef int (* mal_pthread_attr_getschedparam_proc)(const pthread_attr_t *attr, struct sched_param *param);
typedef int (* mal_pthread_attr_setschedparam_proc)(pthread_attr_t *attr, const struct sched_param *param);
mal_bool32 mal_thread_create__posix(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData) mal_bool32 mal_thread_create__posix(mal_context* pContext, mal_thread* pThread, mal_thread_entry_proc entryProc, void* pData)
{ {
int result = ((mal_pthread_create_proc)pContext->posix.pthread_create)(&pThread->posix.thread, NULL, entryProc, pData); pthread_attr_t* pAttr = NULL;
// Try setting the thread priority. It's not critical if anything fails here.
pthread_attr_t attr;
if (((mal_pthread_attr_init_proc)pContext->posix.pthread_attr_init)(&attr) == 0) {
int scheduler = -1;
if (pContext->config.threadPriority == mal_thread_priority_idle) {
#ifdef SCHED_IDLE
if (((mal_pthread_attr_setschedpolicy_proc)pContext->posix.pthread_attr_setschedpolicy)(&attr, SCHED_IDLE) == 0) {
scheduler = SCHED_IDLE;
}
#endif
} else if (pContext->config.threadPriority == mal_thread_priority_realtime) {
#ifdef SCHED_FIFO
if (((mal_pthread_attr_setschedpolicy_proc)pContext->posix.pthread_attr_setschedpolicy)(&attr, SCHED_FIFO) == 0) {
scheduler = SCHED_FIFO;
}
#endif
} else {
scheduler = sched_getscheduler(0);
}
if (scheduler != -1) {
int priorityMin = sched_get_priority_min(scheduler);
int priorityMax = sched_get_priority_max(scheduler);
int priorityStep = (priorityMax - priorityMin) / 7; // 7 = number of priorities supported by mini_al.
struct sched_param sched;
if (((mal_pthread_attr_getschedparam_proc)pContext->posix.pthread_attr_getschedparam)(&attr, &sched) == 0) {
if (pContext->config.threadPriority == mal_thread_priority_idle) {
sched.sched_priority = priorityMin;
} else if (pContext->config.threadPriority == mal_thread_priority_realtime) {
sched.sched_priority = priorityMax;
} else {
sched.sched_priority += ((int)pContext->config.threadPriority + 5) * priorityStep; // +5 because the lowest priority is -5.
if (sched.sched_priority < priorityMin) {
sched.sched_priority = priorityMin;
}
if (sched.sched_priority > priorityMax) {
sched.sched_priority = priorityMax;
}
}
if (((mal_pthread_attr_setschedparam_proc)pContext->posix.pthread_attr_setschedparam)(&attr, &sched) == 0) {
pAttr = &attr;
}
}
}
((mal_pthread_attr_destroy_proc)pContext->posix.pthread_attr_destroy)(&attr);
}
int result = ((mal_pthread_create_proc)pContext->posix.pthread_create)(&pThread->posix.thread, pAttr, entryProc, pData);
if (result != 0) { if (result != 0) {
return MAL_FAILED_TO_CREATE_THREAD; return MAL_FAILED_TO_CREATE_THREAD;
} }
...@@ -2892,14 +2984,7 @@ mal_bool32 mal_event_signal(mal_event* pEvent) ...@@ -2892,14 +2984,7 @@ mal_bool32 mal_event_signal(mal_event* pEvent)
} }
#if defined(_MSC_VER) mal_uint32 mal_get_best_sample_rate_within_range(mal_uint32 sampleRateMin, mal_uint32 sampleRateMax)
#pragma warning(push)
#pragma warning(disable:4505)
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
static mal_uint32 mal_get_best_sample_rate_within_range(mal_uint32 sampleRateMin, mal_uint32 sampleRateMax)
{ {
// Normalize the range in case we were given something stupid. // Normalize the range in case we were given something stupid.
if (sampleRateMin < MAL_MIN_SAMPLE_RATE) { if (sampleRateMin < MAL_MIN_SAMPLE_RATE) {
...@@ -2927,11 +3012,6 @@ static mal_uint32 mal_get_best_sample_rate_within_range(mal_uint32 sampleRateMin ...@@ -2927,11 +3012,6 @@ static mal_uint32 mal_get_best_sample_rate_within_range(mal_uint32 sampleRateMin
mal_assert(MAL_FALSE); mal_assert(MAL_FALSE);
return 0; return 0;
} }
#if defined(_MSC_VER)
#pragma warning(pop)
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
// Posts a log message. // Posts a log message.
...@@ -12232,6 +12312,11 @@ mal_result mal_context_init_backend_apis__nix(mal_context* pContext) ...@@ -12232,6 +12312,11 @@ mal_result mal_context_init_backend_apis__nix(mal_context* pContext)
pContext->posix.pthread_cond_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_destroy"); pContext->posix.pthread_cond_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_destroy");
pContext->posix.pthread_cond_wait = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_wait"); pContext->posix.pthread_cond_wait = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_wait");
pContext->posix.pthread_cond_signal = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_signal"); pContext->posix.pthread_cond_signal = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_cond_signal");
pContext->posix.pthread_attr_init = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_attr_init");
pContext->posix.pthread_attr_destroy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_attr_destroy");
pContext->posix.pthread_attr_setschedpolicy = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_attr_setschedpolicy");
pContext->posix.pthread_attr_getschedparam = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_attr_getschedparam");
pContext->posix.pthread_attr_setschedparam = (mal_proc)mal_dlsym(pContext->posix.pthreadSO, "pthread_attr_setschedparam");
#else #else
pContext->posix.pthread_create = (mal_proc)pthread_create; pContext->posix.pthread_create = (mal_proc)pthread_create;
pContext->posix.pthread_join = (mal_proc)pthread_join; pContext->posix.pthread_join = (mal_proc)pthread_join;
...@@ -12243,6 +12328,11 @@ mal_result mal_context_init_backend_apis__nix(mal_context* pContext) ...@@ -12243,6 +12328,11 @@ mal_result mal_context_init_backend_apis__nix(mal_context* pContext)
pContext->posix.pthread_cond_destroy = (mal_proc)pthread_cond_destroy; pContext->posix.pthread_cond_destroy = (mal_proc)pthread_cond_destroy;
pContext->posix.pthread_cond_wait = (mal_proc)pthread_cond_wait; pContext->posix.pthread_cond_wait = (mal_proc)pthread_cond_wait;
pContext->posix.pthread_cond_signal = (mal_proc)pthread_cond_signal; pContext->posix.pthread_cond_signal = (mal_proc)pthread_cond_signal;
pContext->posix.pthread_attr_init = (mal_proc)pthread_attr_init;
pContext->posix.pthread_attr_destroy = (mal_proc)pthread_attr_destroy;
pContext->posix.pthread_attr_setschedpolicy = (mal_proc)pthread_attr_setschedpolicy;
pContext->posix.pthread_attr_getschedparam = (mal_proc)pthread_attr_getschedparam;
pContext->posix.pthread_attr_setschedparam = (mal_proc)pthread_attr_setschedparam;
#endif #endif
return MAL_SUCCESS; return MAL_SUCCESS;
...@@ -16017,6 +16107,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count) ...@@ -16017,6 +16107,7 @@ void mal_pcm_f32_to_s32(int* pOut, const float* pIn, unsigned int count)
// - Add support for JACK. // - Add support for JACK.
// - Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no // - Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no
// longer required to build mini_al. // longer required to build mini_al.
// - Add support for configuring the priority of the worker thread.
// - Introduce the notion of default device configurations. A default config uses the same configuration // - Introduce the notion of default device configurations. A default config uses the same configuration
// as the backend's internal device, and as such results in a pass-through data transmission pipeline. // as the backend's internal device, and as such results in a pass-through data transmission pipeline.
// - Add support for passing in NULL for the device config in mal_device_init(), which uses a default // - Add support for passing in NULL for the device config in mal_device_init(), which uses a default
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment