Get rid of the last ATOMIC macro uses
[openal-soft.git] / OpenAL32 / event.cpp
blob0491c7c6b8a278cbdb0a20b7634f5ae38bfe5600
2 #include "config.h"
4 #include <algorithm>
6 #include "AL/alc.h"
7 #include "AL/al.h"
8 #include "AL/alext.h"
10 #include "alMain.h"
11 #include "alcontext.h"
12 #include "alError.h"
13 #include "alAuxEffectSlot.h"
14 #include "ringbuffer.h"
15 #include "threads.h"
18 static int EventThread(ALCcontext *context)
20 bool quitnow{false};
21 while(LIKELY(!quitnow))
23 AsyncEvent evt;
24 if(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) == 0)
26 alsem_wait(&context->EventSem);
27 continue;
30 std::lock_guard<std::mutex> _{context->EventCbLock};
31 do {
32 quitnow = evt.EnumType == EventType_KillThread;
33 if(UNLIKELY(quitnow)) break;
35 if(evt.EnumType == EventType_ReleaseEffectState)
37 evt.u.mEffectState->DecRef();
38 continue;
41 ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_acquire)};
42 if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType)
43 context->EventCb(evt.u.user.type, evt.u.user.id, evt.u.user.param,
44 (ALsizei)strlen(evt.u.user.msg), evt.u.user.msg, context->EventParam
46 } while(ll_ringbuffer_read(context->AsyncEvents, &evt, 1) != 0);
48 return 0;
51 void StartEventThrd(ALCcontext *ctx)
53 try {
54 ctx->EventThread = std::thread(EventThread, ctx);
56 catch(std::exception& e) {
57 ERR("Failed to start event thread: %s\n", e.what());
59 catch(...) {
60 ERR("Failed to start event thread! Expect problems.\n");
64 void StopEventThrd(ALCcontext *ctx)
66 static constexpr AsyncEvent kill_evt = ASYNC_EVENT(EventType_KillThread);
67 while(ll_ringbuffer_write(ctx->AsyncEvents, &kill_evt, 1) == 0)
68 althrd_yield();
69 alsem_post(&ctx->EventSem);
70 if(ctx->EventThread.joinable())
71 ctx->EventThread.join();
74 AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable)
76 ContextRef context{GetContextRef()};
77 if(UNLIKELY(!context)) return;
79 if(count < 0) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "Controlling %d events", count);
80 if(count == 0) return;
81 if(!types) SETERR_RETURN(context.get(), AL_INVALID_VALUE,, "NULL pointer");
83 ALbitfieldSOFT flags{0};
84 const ALenum *types_end = types+count;
85 auto bad_type = std::find_if_not(types, types_end,
86 [&flags](ALenum type) noexcept -> bool
88 if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT)
89 flags |= EventType_BufferCompleted;
90 else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT)
91 flags |= EventType_SourceStateChange;
92 else if(type == AL_EVENT_TYPE_ERROR_SOFT)
93 flags |= EventType_Error;
94 else if(type == AL_EVENT_TYPE_PERFORMANCE_SOFT)
95 flags |= EventType_Performance;
96 else if(type == AL_EVENT_TYPE_DEPRECATED_SOFT)
97 flags |= EventType_Deprecated;
98 else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT)
99 flags |= EventType_Disconnected;
100 else
101 return false;
102 return true;
105 if(bad_type != types_end)
106 SETERR_RETURN(context.get(), AL_INVALID_ENUM,, "Invalid event type 0x%04x", *bad_type);
108 if(enable)
110 ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)};
111 while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts|flags,
112 std::memory_order_acq_rel, std::memory_order_acquire) == 0)
114 /* enabledevts is (re-)filled with the current value on failure, so
115 * just try again.
119 else
121 ALbitfieldSOFT enabledevts{context->EnabledEvts.load(std::memory_order_relaxed)};
122 while(context->EnabledEvts.compare_exchange_weak(enabledevts, enabledevts&~flags,
123 std::memory_order_acq_rel, std::memory_order_acquire) == 0)
126 /* Wait to ensure the event handler sees the changed flags before
127 * returning.
129 std::lock_guard<std::mutex>{context->EventCbLock};
133 AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam)
135 ContextRef context{GetContextRef()};
136 if(UNLIKELY(!context)) return;
138 std::lock_guard<almtx_t> _{context->PropLock};
139 std::lock_guard<std::mutex> __{context->EventCbLock};
140 context->EventCb = callback;
141 context->EventParam = userParam;