event.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. #include "config.h"
  2. #include "AL/alc.h"
  3. #include "AL/al.h"
  4. #include "AL/alext.h"
  5. #include "alMain.h"
  6. #include "alError.h"
  7. #include "ringbuffer.h"
  8. static int EventThread(void *arg)
  9. {
  10. ALCcontext *context = arg;
  11. /* Clear all pending posts on the semaphore. */
  12. while(alsem_trywait(&context->EventSem) == althrd_success)
  13. {
  14. }
  15. while(1)
  16. {
  17. ALbitfieldSOFT enabledevts;
  18. AsyncEvent evt;
  19. if(ll_ringbuffer_read(context->AsyncEvents, (char*)&evt, 1) == 0)
  20. {
  21. alsem_wait(&context->EventSem);
  22. continue;
  23. }
  24. if(!evt.EnumType)
  25. break;
  26. almtx_lock(&context->EventCbLock);
  27. enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire);
  28. if(context->EventCb && (enabledevts&evt.EnumType) == evt.EnumType)
  29. context->EventCb(evt.Type, evt.ObjectId, evt.Param, (ALsizei)strlen(evt.Message),
  30. evt.Message, context->EventParam);
  31. almtx_unlock(&context->EventCbLock);
  32. }
  33. return 0;
  34. }
  35. AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable)
  36. {
  37. ALCcontext *context;
  38. ALbitfieldSOFT enabledevts;
  39. ALbitfieldSOFT flags = 0;
  40. bool isrunning;
  41. ALsizei i;
  42. context = GetContextRef();
  43. if(!context) return;
  44. if(count < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Controlling %d events", count);
  45. if(count == 0) goto done;
  46. if(!types) SETERR_GOTO(context, AL_INVALID_VALUE, done, "NULL pointer");
  47. for(i = 0;i < count;i++)
  48. {
  49. if(types[i] == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT)
  50. flags |= EventType_BufferCompleted;
  51. else if(types[i] == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT)
  52. flags |= EventType_SourceStateChange;
  53. else if(types[i] == AL_EVENT_TYPE_ERROR_SOFT)
  54. flags |= EventType_Error;
  55. else if(types[i] == AL_EVENT_TYPE_PERFORMANCE_SOFT)
  56. flags |= EventType_Performance;
  57. else if(types[i] == AL_EVENT_TYPE_DEPRECATED_SOFT)
  58. flags |= EventType_Deprecated;
  59. else if(types[i] == AL_EVENT_TYPE_DISCONNECTED_SOFT)
  60. flags |= EventType_Disconnected;
  61. else
  62. SETERR_GOTO(context, AL_INVALID_ENUM, done, "Invalid event type 0x%04x", types[i]);
  63. }
  64. almtx_lock(&context->EventThrdLock);
  65. if(enable)
  66. {
  67. if(!context->AsyncEvents)
  68. context->AsyncEvents = ll_ringbuffer_create(63, sizeof(AsyncEvent), false);
  69. enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed);
  70. isrunning = !!enabledevts;
  71. while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts|flags,
  72. almemory_order_acq_rel, almemory_order_acquire) == 0)
  73. {
  74. /* enabledevts is (re-)filled with the current value on failure, so
  75. * just try again.
  76. */
  77. }
  78. if(!isrunning && flags)
  79. althrd_create(&context->EventThread, EventThread, context);
  80. }
  81. else
  82. {
  83. enabledevts = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_relaxed);
  84. isrunning = !!enabledevts;
  85. while(ATOMIC_COMPARE_EXCHANGE_WEAK(&context->EnabledEvts, &enabledevts, enabledevts&~flags,
  86. almemory_order_acq_rel, almemory_order_acquire) == 0)
  87. {
  88. }
  89. if(isrunning && !(enabledevts&~flags))
  90. {
  91. static const AsyncEvent kill_evt = { 0 };
  92. while(ll_ringbuffer_write(context->AsyncEvents, (const char*)&kill_evt, 1) == 0)
  93. althrd_yield();
  94. alsem_post(&context->EventSem);
  95. althrd_join(context->EventThread, NULL);
  96. }
  97. else
  98. {
  99. /* Wait to ensure the event handler sees the changed flags before
  100. * returning.
  101. */
  102. almtx_lock(&context->EventCbLock);
  103. almtx_unlock(&context->EventCbLock);
  104. }
  105. }
  106. almtx_unlock(&context->EventThrdLock);
  107. done:
  108. ALCcontext_DecRef(context);
  109. }
  110. AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam)
  111. {
  112. ALCcontext *context;
  113. context = GetContextRef();
  114. if(!context) return;
  115. almtx_lock(&context->PropLock);
  116. almtx_lock(&context->EventCbLock);
  117. context->EventCb = callback;
  118. context->EventParam = userParam;
  119. almtx_unlock(&context->EventCbLock);
  120. almtx_unlock(&context->PropLock);
  121. ALCcontext_DecRef(context);
  122. }