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
)
24 ALbitfieldSOFT enabledevts
;
26 if(ll_ringbuffer_read_space(context
->AsyncEvents
) == 0)
28 alsem_wait(&context
->EventSem
);
31 ll_ringbuffer_read(context
->AsyncEvents
, (char*)&evt
, 1);
32 if(!evt
.EnumType
) break;
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 flags
= 0;
50 context
= GetContextRef();
53 if(count
< 0) SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "Controlling %d events", count
);
54 if(count
== 0) goto done
;
55 if(!types
) SETERR_GOTO(context
, AL_INVALID_VALUE
, done
, "NULL pointer");
57 for(i
= 0;i
< count
;i
++)
59 if(types
[i
] == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT
)
60 flags
|= EventType_BufferCompleted
;
61 else if(types
[i
] == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
)
62 flags
|= EventType_SourceStateChange
;
63 else if(types
[i
] == AL_EVENT_TYPE_ERROR_SOFT
)
64 flags
|= EventType_Error
;
65 else if(types
[i
] == AL_EVENT_TYPE_PERFORMANCE_SOFT
)
66 flags
|= EventType_Performance
;
67 else if(types
[i
] == AL_EVENT_TYPE_DEPRECATED_SOFT
)
68 flags
|= EventType_Deprecated
;
69 else if(types
[i
] == AL_EVENT_TYPE_DISCONNECTED_SOFT
)
70 flags
|= EventType_Disconnected
;
72 SETERR_GOTO(context
, AL_INVALID_ENUM
, done
, "Invalid event type 0x%04x", types
[i
]);
77 ALbitfieldSOFT enabledevts
;
79 almtx_lock(&context
->EventThrdLock
);
80 if(!context
->AsyncEvents
)
81 context
->AsyncEvents
= ll_ringbuffer_create(64, sizeof(AsyncEvent
));
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
);
93 almtx_unlock(&context
->EventThrdLock
);
97 ALbitfieldSOFT enabledevts
;
99 almtx_lock(&context
->EventThrdLock
);
100 enabledevts
= ATOMIC_LOAD(&context
->EnabledEvts
, almemory_order_relaxed
);
101 isrunning
= !!enabledevts
;
102 while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context
->EnabledEvts
, &enabledevts
, enabledevts
&~flags
,
103 almemory_order_acq_rel
, almemory_order_acquire
) == 0)
106 if(isrunning
&& !(enabledevts
&~flags
))
108 static const AsyncEvent kill_evt
= { 0 };
109 while(ll_ringbuffer_write_space(context
->AsyncEvents
) == 0)
111 ll_ringbuffer_write(context
->AsyncEvents
, (const char*)&kill_evt
, 1);
112 alsem_post(&context
->EventSem
);
113 althrd_join(context
->EventThread
, NULL
);
117 /* Wait to ensure the event handler sees the changed flags before
120 almtx_lock(&context
->EventCbLock
);
121 almtx_unlock(&context
->EventCbLock
);
123 almtx_unlock(&context
->EventThrdLock
);
127 ALCcontext_DecRef(context
);
130 AL_API
void AL_APIENTRY
alEventCallbackSOFT(ALEVENTPROCSOFT callback
, void *userParam
)
134 context
= GetContextRef();
137 almtx_lock(&context
->EventCbLock
);
138 context
->EventCb
= callback
;
139 context
->EventParam
= userParam
;
140 almtx_unlock(&context
->EventCbLock
);
142 ALCcontext_DecRef(context
);