aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2018-02-01 18:09:16 -0800
committerChris Robinson <[email protected]>2018-02-01 18:20:14 -0800
commite240351d81105e233f02d006f6bf42d03c0dd09b (patch)
treecfa0d4b2f59bae0ed1ba44a220ba0a9ecdb8f97b
parent4ec31291c0de9334f6715edc13bf2d28ea884eb0 (diff)
Use a semaphore to signal the event handler
Semaphores allow for semi-persistent signals, compared to a condition variable which requires a mutex for proper detection. A semaphore can be 'post'ed after writing some data on one thread, and another thread will be able to recognize it quickly even if the post occured in between checking for data and waiting. This more correctly fixes a race condition with events since the mixer shouldn't be using mutexes, and arbitrary wake-ups just to make sure an event wasn't missed was quite inefficient.
-rw-r--r--Alc/ALc.c5
-rw-r--r--Alc/mixer.c2
-rw-r--r--OpenAL32/Include/alMain.h2
-rw-r--r--OpenAL32/event.c19
4 files changed, 9 insertions, 19 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index 632e1f18..8ed10ac6 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -2613,7 +2613,7 @@ static ALvoid InitContext(ALCcontext *Context)
ATOMIC_FLAG_TEST_AND_SET(&Context->PropsClean, almemory_order_relaxed);
ATOMIC_INIT(&Context->DeferUpdates, AL_FALSE);
almtx_init(&Context->EventThrdLock, almtx_plain);
- alcnd_init(&Context->EventCnd);
+ alsem_init(&Context->EventSem, 0);
Context->AsyncEvents = NULL;
ATOMIC_INIT(&Context->EnabledEvts, 0);
almtx_init(&Context->EventCbLock, almtx_plain);
@@ -2753,12 +2753,13 @@ static void FreeContext(ALCcontext *context)
while(ll_ringbuffer_write_space(context->AsyncEvents) == 0)
althrd_yield();
ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1);
+ alsem_post(&context->EventSem);
althrd_join(context->EventThread, NULL);
}
almtx_destroy(&context->EventCbLock);
almtx_destroy(&context->EventThrdLock);
- alcnd_destroy(&context->EventCnd);
+ alsem_destroy(&context->EventSem);
ll_ringbuffer_free(context->AsyncEvents);
context->AsyncEvents = NULL;
diff --git a/Alc/mixer.c b/Alc/mixer.c
index 31e94974..c34284d5 100644
--- a/Alc/mixer.c
+++ b/Alc/mixer.c
@@ -754,7 +754,7 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, 0, "Buffer completed"
);
} while(--buffers_done > 0);
- alcnd_signal(&Context->EventCnd);
+ alsem_post(&Context->EventSem);
}
return isplaying;
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index e7a95eef..bc5a27c8 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -675,7 +675,7 @@ struct ALCcontext_struct {
almtx_t EventThrdLock;
althrd_t EventThread;
- alcnd_t EventCnd;
+ alsem_t EventSem;
struct ll_ringbuffer *AsyncEvents;
ATOMIC(ALbitfieldSOFT) EnabledEvts;
almtx_t EventCbLock;
diff --git a/OpenAL32/event.c b/OpenAL32/event.c
index ff53d7d8..38c12d98 100644
--- a/OpenAL32/event.c
+++ b/OpenAL32/event.c
@@ -13,7 +13,6 @@ static int EventThread(void *arg)
{
ALCcontext *context = arg;
- almtx_lock(&context->EventCbLock);
while(1)
{
AsyncEvent evt;
@@ -21,30 +20,19 @@ static int EventThread(void *arg)
if(ll_ringbuffer_read_space(context->AsyncEvents) == 0)
{
- /* Wait 50ms before checking again. Because events are delivered
- * asynchronously by the mixer, it's possible for one to be written
- * in between checking for a readable element and sleeping. So to
- * ensure events don't get left to go stale in the ringbuffer, we
- * need to keep checking regardless of being signaled.
- */
- struct timespec ts;
- altimespec_get(&ts, AL_TIME_UTC);
- ts.tv_nsec += 50000000;
- ts.tv_sec += ts.tv_nsec/1000000000;
- ts.tv_nsec %= 1000000000;
- alcnd_timedwait(&context->EventCnd, &context->EventCbLock, &ts);
+ alsem_wait(&context->EventSem);
continue;
}
ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1);
if(!evt.EnumType) break;
- /* Should check the actual type is enabled here too. */
+ almtx_lock(&context->EventCbLock);
enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire);
if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType)
context->EventCb(evt.Type, evt.ObjectId, evt.Param, (ALsizei)strlen(evt.Message),
evt.Message, context->EventParam);
+ almtx_unlock(&context->EventCbLock);
}
- almtx_unlock(&context->EventCbLock);
return 0;
}
@@ -114,6 +102,7 @@ AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, A
while(ll_ringbuffer_write_space(context->AsyncEvents) == 0)
althrd_yield();
ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1);
+ alsem_post(&context->EventSem);
althrd_join(context->EventThread, NULL);
}
else