9 #include "ringbuffer.h"
12 static int EventThread(void *arg
)
14 ALCcontext
*context
= arg
;
16 /* Clear all pending posts on the semaphore. */
17 while(alsem_trywait(&context
->EventSem
) == althrd_success
)
23 ALbitfieldSOFT enabledevts
;
26 if(ll_ringbuffer_read(context
->AsyncEvents
, (char*)&evt
, 1) == 0)
28 alsem_wait(&context
->EventSem
);
34 almtx_lock(&context
->EventCbLock
);
35 enabledevts
= ATOMIC_LOAD(&context
->EnabledEvts
, almemory_order_acquire
);
36 if(context
->EventCb
&& (enabledevts
&evt
.EnumType
) == evt
.EnumType
)
37 context
->EventCb(evt
.Type
, evt
.ObjectId
, evt
.Param
, (ALsizei
)strlen(evt
.Message
),
38 evt
.Message
, context
->EventParam
);
39 almtx_unlock(&context
->EventCbLock
);
44 AL_API
void AL_APIENTRY
alEventControlSOFT(ALsizei count
, const ALenum
*types
, ALboolean enable
)
47 ALbitfieldSOFT enabledevts
;
48 ALbitfieldSOFT flags
= 0;
52 context
= GetContextRef();
55 if(count
< 0) SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Controlling %d events", count
);
56 if(count
== 0) goto done
;
57 if(!types
) SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "NULL pointer");
59 for(i
= 0;i
< count
;i
++)
61 if(types
[i
] == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT
)
62 flags
|= EventType_BufferCompleted
;
63 else if(types
[i
] == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
)
64 flags
|= EventType_SourceStateChange
;
65 else if(types
[i
] == AL_EVENT_TYPE_ERROR_SOFT
)
66 flags
|= EventType_Error
;
67 else if(types
[i
] == AL_EVENT_TYPE_PERFORMANCE_SOFT
)
68 flags
|= EventType_Performance
;
69 else if(types
[i
] == AL_EVENT_TYPE_DEPRECATED_SOFT
)
70 flags
|= EventType_Deprecated
;
71 else if(types
[i
] == AL_EVENT_TYPE_DISCONNECTED_SOFT
)
72 flags
|= EventType_Disconnected
;
74 SETERR_GOTO(context
, AL_INVALID_ENUM
, done
, "Invalid event type 0x%04x", types
[i
]);
77 almtx_lock(&context
->EventThrdLock
);
80 if(!context
->AsyncEvents
)
81 context
->AsyncEvents
= ll_ringbuffer_create(63, sizeof(AsyncEvent
), false);
82 enabledevts
= ATOMIC_LOAD(&context
->EnabledEvts
, almemory_order_relaxed
);
83 isrunning
= !!enabledevts
;
84 while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context
->EnabledEvts
, &enabledevts
, enabledevts
|flags
,
85 almemory_order_acq_rel
, almemory_order_acquire
) == 0)
87 /* enabledevts is (re-)filled with the current value on failure, so
91 if(!isrunning
&& flags
)
92 althrd_create(&context
->EventThread
, EventThread
, context
);
96 enabledevts
= ATOMIC_LOAD(&context
->EnabledEvts
, almemory_order_relaxed
);
97 isrunning
= !!enabledevts
;
98 while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context
->EnabledEvts
, &enabledevts
, enabledevts
&~flags
,
99 almemory_order_acq_rel
, almemory_order_acquire
) == 0)
102 if(isrunning
&& !(enabledevts
&~flags
))
104 static const AsyncEvent kill_evt
= { 0 };
105 while(ll_ringbuffer_write(context
->AsyncEvents
, (const char*)&kill_evt
, 1) == 0)
107 alsem_post(&context
->EventSem
);
108 althrd_join(context
->EventThread
, NULL
);
112 /* Wait to ensure the event handler sees the changed flags before
115 almtx_lock(&context
->EventCbLock
);
116 almtx_unlock(&context
->EventCbLock
);
119 almtx_unlock(&context
->EventThrdLock
);
122 ALCcontext_DecRef(context
);
125 AL_API
void AL_APIENTRY
alEventCallbackSOFT(ALEVENTPROCSOFT callback
, void *userParam
)
129 context
= GetContextRef();
132 almtx_lock(&context
->PropLock
);
133 almtx_lock(&context
->EventCbLock
);
134 context
->EventCb
= callback
;
135 context
->EventParam
= userParam
;
136 almtx_unlock(&context
->EventCbLock
);
137 almtx_unlock(&context
->PropLock
);
139 ALCcontext_DecRef(context
);