Construct AsyncEvent objects directly in the ringbuffer
This commit is contained in:
+19
@@ -2465,6 +2465,25 @@ ALCcontext_struct::~ALCcontext_struct()
|
||||
}
|
||||
TRACE("Freed " SZFMT " listener property object%s\n", count, (count==1)?"":"s");
|
||||
|
||||
count = 0;
|
||||
auto evt_vec = ll_ringbuffer_get_read_vector(AsyncEvents);
|
||||
while(evt_vec.first.len > 0)
|
||||
{
|
||||
reinterpret_cast<AsyncEvent*>(evt_vec.first.buf)->~AsyncEvent();
|
||||
evt_vec.first.buf += sizeof(AsyncEvent);
|
||||
evt_vec.first.len -= 1;
|
||||
++count;
|
||||
}
|
||||
while(evt_vec.second.len > 0)
|
||||
{
|
||||
reinterpret_cast<AsyncEvent*>(evt_vec.second.buf)->~AsyncEvent();
|
||||
evt_vec.second.buf += sizeof(AsyncEvent);
|
||||
evt_vec.second.len -= 1;
|
||||
++count;
|
||||
}
|
||||
if(count > 0)
|
||||
TRACE("Destructed " SZFMT " orphaned event%s\n", count, (count==1)?"":"s");
|
||||
|
||||
delete AsyncEvents;
|
||||
AsyncEvents = nullptr;
|
||||
|
||||
|
||||
+27
-15
@@ -293,12 +293,14 @@ void SendSourceStoppedEvent(ALCcontext *context, ALuint id)
|
||||
ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)};
|
||||
if(!(enabledevt&EventType_SourceStateChange)) return;
|
||||
|
||||
AsyncEvent evt{EventType_SourceStateChange};
|
||||
evt.u.srcstate.id = id;
|
||||
evt.u.srcstate.state = AL_STOPPED;
|
||||
auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first;
|
||||
if(evt_data.len < 1) return;
|
||||
|
||||
if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1)
|
||||
context->EventSem.post();
|
||||
AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_SourceStateChange}};
|
||||
evt->u.srcstate.id = id;
|
||||
evt->u.srcstate.state = AL_STOPPED;
|
||||
ll_ringbuffer_write_advance(context->AsyncEvents, 1);
|
||||
context->EventSem.post();
|
||||
}
|
||||
|
||||
|
||||
@@ -394,6 +396,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force)
|
||||
}
|
||||
|
||||
state = props->State;
|
||||
props->State = nullptr;
|
||||
|
||||
if(state == slot->Params.mEffectState)
|
||||
{
|
||||
@@ -402,21 +405,23 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force)
|
||||
* 0 refs since the current params also hold a reference).
|
||||
*/
|
||||
DecrementRef(&state->mRef);
|
||||
props->State = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, replace it and send off the old one with a release
|
||||
* event.
|
||||
*/
|
||||
AsyncEvent evt{EventType_ReleaseEffectState};
|
||||
evt.u.mEffectState = slot->Params.mEffectState;
|
||||
|
||||
EffectState *oldstate{slot->Params.mEffectState};
|
||||
slot->Params.mEffectState = state;
|
||||
props->State = nullptr;
|
||||
|
||||
if(LIKELY(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) != 0))
|
||||
auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first;
|
||||
if(LIKELY(evt_data.len > 0))
|
||||
{
|
||||
AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_ReleaseEffectState}};
|
||||
evt->u.mEffectState = oldstate;
|
||||
ll_ringbuffer_write_advance(context->AsyncEvents, 1);
|
||||
context->EventSem.post();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If writing the event failed, the queue was probably full.
|
||||
@@ -424,7 +429,7 @@ bool CalcEffectSlotParams(ALeffectslot *slot, ALCcontext *context, bool force)
|
||||
* eventually be cleaned up sometime later (not ideal, but
|
||||
* better than blocking or leaking).
|
||||
*/
|
||||
props->State = evt.u.mEffectState;
|
||||
props->State = oldstate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1828,9 +1833,16 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...)
|
||||
while(ctx)
|
||||
{
|
||||
const ALbitfieldSOFT enabledevt{ctx->EnabledEvts.load(std::memory_order_acquire)};
|
||||
if((enabledevt&EventType_Disconnected) &&
|
||||
ll_ringbuffer_write(ctx->AsyncEvents, &evt, 1) == 1)
|
||||
ctx->EventSem.post();
|
||||
if((enabledevt&EventType_Disconnected))
|
||||
{
|
||||
auto evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first;
|
||||
if(evt_data.len > 0)
|
||||
{
|
||||
new (evt_data.buf) AsyncEvent{evt};
|
||||
ll_ringbuffer_write_advance(ctx->AsyncEvents, 1);
|
||||
ctx->EventSem.post();
|
||||
}
|
||||
}
|
||||
|
||||
std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire),
|
||||
[ctx](ALvoice *voice) -> void
|
||||
|
||||
+8
-4
@@ -721,11 +721,15 @@ ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsize
|
||||
ALbitfieldSOFT enabledevt{Context->EnabledEvts.load(std::memory_order_acquire)};
|
||||
if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted))
|
||||
{
|
||||
AsyncEvent evt{EventType_BufferCompleted};
|
||||
evt.u.bufcomp.id = SourceID;
|
||||
evt.u.bufcomp.count = buffers_done;
|
||||
if(ll_ringbuffer_write(Context->AsyncEvents, &evt, 1) == 1)
|
||||
auto evt_data = ll_ringbuffer_get_write_vector(Context->AsyncEvents).first;
|
||||
if(evt_data.len > 0)
|
||||
{
|
||||
AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_BufferCompleted}};
|
||||
evt->u.bufcomp.id = SourceID;
|
||||
evt->u.bufcomp.count = buffers_done;
|
||||
ll_ringbuffer_write_advance(Context->AsyncEvents, 1);
|
||||
Context->EventSem.post();
|
||||
}
|
||||
}
|
||||
|
||||
return isplaying;
|
||||
|
||||
@@ -687,16 +687,18 @@ void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state)
|
||||
ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)};
|
||||
if(!(enabledevt&EventType_SourceStateChange)) return;
|
||||
|
||||
AsyncEvent evt{EventType_SourceStateChange};
|
||||
evt.u.srcstate.id = id;
|
||||
evt.u.srcstate.state = state;
|
||||
|
||||
/* The mixer may have queued a state change that's not yet been processed,
|
||||
* and we don't want state change messages to occur out of order, so send
|
||||
* it through the async queue to ensure proper ordering.
|
||||
*/
|
||||
if(ll_ringbuffer_write(context->AsyncEvents, &evt, 1) == 1)
|
||||
context->EventSem.post();
|
||||
auto evt_data = ll_ringbuffer_get_write_vector(context->AsyncEvents).first;
|
||||
if(evt_data.len < 1) return;
|
||||
|
||||
AsyncEvent *evt{new (evt_data.buf) AsyncEvent{EventType_SourceStateChange}};
|
||||
evt->u.srcstate.id = id;
|
||||
evt->u.srcstate.state = state;
|
||||
ll_ringbuffer_write_advance(context->AsyncEvents, 1);
|
||||
context->EventSem.post();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+30
-5
@@ -18,10 +18,10 @@
|
||||
static int EventThread(ALCcontext *context)
|
||||
{
|
||||
bool quitnow{false};
|
||||
AsyncEvent evt{};
|
||||
while(LIKELY(!quitnow))
|
||||
{
|
||||
if(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) == 0)
|
||||
auto evt_data = ll_ringbuffer_get_read_vector(context->AsyncEvents).first;
|
||||
if(evt_data.len == 0)
|
||||
{
|
||||
context->EventSem.wait();
|
||||
continue;
|
||||
@@ -29,6 +29,22 @@ static int EventThread(ALCcontext *context)
|
||||
|
||||
std::lock_guard<std::mutex> _{context->EventCbLock};
|
||||
do {
|
||||
auto &evt = *reinterpret_cast<AsyncEvent*>(evt_data.buf);
|
||||
evt_data.buf += sizeof(AsyncEvent);
|
||||
evt_data.len -= 1;
|
||||
/* This automatically destructs the event object and advances the
|
||||
* ringbuffer's read offset at the end of scope.
|
||||
*/
|
||||
const struct EventAutoDestructor {
|
||||
AsyncEvent &evt;
|
||||
ll_ringbuffer *ring;
|
||||
~EventAutoDestructor()
|
||||
{
|
||||
evt.~AsyncEvent();
|
||||
ll_ringbuffer_read_advance(ring, 1);
|
||||
}
|
||||
} _{evt, context->AsyncEvents};
|
||||
|
||||
quitnow = evt.EnumType == EventType_KillThread;
|
||||
if(UNLIKELY(quitnow)) break;
|
||||
|
||||
@@ -73,7 +89,7 @@ static int EventThread(ALCcontext *context)
|
||||
static_cast<ALsizei>(strlen(evt.u.user.msg)), evt.u.user.msg,
|
||||
context->EventParam
|
||||
);
|
||||
} while(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) != 0);
|
||||
} while(evt_data.len != 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -94,8 +110,17 @@ void StartEventThrd(ALCcontext *ctx)
|
||||
void StopEventThrd(ALCcontext *ctx)
|
||||
{
|
||||
static constexpr AsyncEvent kill_evt{EventType_KillThread};
|
||||
while(ll_ringbuffer_write(ctx->AsyncEvents, &kill_evt, 1) == 0)
|
||||
std::this_thread::yield();
|
||||
ll_ringbuffer_data evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first;
|
||||
if(evt_data.len == 0)
|
||||
{
|
||||
do {
|
||||
std::this_thread::yield();
|
||||
evt_data = ll_ringbuffer_get_write_vector(ctx->AsyncEvents).first;
|
||||
} while(evt_data.len == 0);
|
||||
}
|
||||
new (evt_data.buf) AsyncEvent{kill_evt};
|
||||
ll_ringbuffer_write_advance(ctx->AsyncEvents, 1);
|
||||
|
||||
ctx->EventSem.post();
|
||||
if(ctx->EventThread.joinable())
|
||||
ctx->EventThread.join();
|
||||
|
||||
Reference in New Issue
Block a user