Hi,
Let's assume for the discussion that
Winecoreaudio/mmdevdrv.c: ca_in_buffer_cb(...) { OSSpinLockLock(&This->lock); list_add_tail(&This->avail_buffers, &buf->entry); This->inbuf_frames += buffer->mAudioDataByteSize / This->fmt->nBlockAlign; OSSpinLockUnlock(&This->lock); } really is causing deadlocks and leads to bogus code like releasing locks mid-function to call other functions that may take the lock too: OSSpinLockUnlock(&This->lock); sc = AudioQueueFlush(This->aqueue); sc = AudioQueuePause(This->aqueue); OSSpinLockLock(&This->lock); -- alas allowing any other thread to enter mmdevdrv in between. (I'll have to perform more checks this week-end). For reference, see bug #29657.
I thought about using lock-free data structures:
a) MacOS lock-free FIFO b) MS' InterlockedPushEntrySList c) other schemes
a) MacOS' lock-free FIFO: MacOS OSAtomicFifoEnqueue is only available with Lion, which rules it out. http://developer.apple.com/library/mac/#documentation/DriversKernelHardware/...
b) MS' InterlockedPushEntrySList: That is implemented in dlls/ntdll/rtl.c However, I presumably can't call that from within the MacOS callback, because the cross-library call might get logged by +relay, and that's a no-no within the native callback (RunLoop) execution context.
Work-around: copy&paste that function into winecoreaudio I don't like that much but do you have a better idea?
c) other schemes: Assuming list elements are returned in the order we sent them out, we don't need to enqueue them and instead could set a bit or use InterlockedIncrement (like the MCI does with winmm headers).
Is there any other suggestion that comes to mind?
IMHO, ca_in_buffer_cb doesn't need a transaction around enqueue+inbuf. Enqueue and inbuf+= could be performed separately, inbuf+= could even be deferred to GetCurrentPadding, leaving one single operation left to do within the MacOS callback.
Regards, Jörg Höhle