CARingBuffer implementation question
CARingBuffer implementation question
- Subject: CARingBuffer implementation question
- From: Per Bull Holmen <email@hidden>
- Date: Sun, 22 May 2011 19:12:13 +0200
Hi
Sorry for the long post. I'm wondering about an implementation detail
in CARingBuffer. The part I don't understand is regarding getting and
setting the time bounds for the buffer. In the version I have on my
HD, the time bounds are set with this code:
void CARingBuffer::SetTimeBounds(SampleTime startTime, SampleTime endTime)
{
UInt32 nextPtr = mTimeBoundsQueuePtr + 1;
UInt32 index = nextPtr & kGeneralRingTimeBoundsQueueMask;
mTimeBoundsQueue[index].mStartTime = startTime;
mTimeBoundsQueue[index].mEndTime = endTime;
mTimeBoundsQueue[index].mUpdateCounter = nextPtr;
CAAtomicCompareAndSwap32Barrier(mTimeBoundsQueuePtr,
mTimeBoundsQueuePtr + 1, (SInt32*)&mTimeBoundsQueuePtr);
}
So, the time bounds (start time, stop time) are held in a TimeBounds
structure, and there's a 32 slots queue holding one such structure in
each position. Only one slot in this queue is active at any moment.
One member variable, mTimeBoundsQueuePtr tells the application which
slot is currently active, that is, holding the currently valid
TimeBounds structure. Each time the time bounds are being updated, the
data in the next slot (after the active slot) is being changed to the
new time bounds values, and when the change is finished, the next slot
is atomically set to active.
In addition, the TimeBounds structure includes a member for the
corresponding value of mTimeBoundsQueuePtr, which is an always
increasing absolute value, while the actual index in the time bounds
queue is computed by using only the last 5 bits of this value. So far,
everything OK.
The time bounds are read with this code:
CARingBufferError CARingBuffer::GetTimeBounds(SampleTime &startTime,
SampleTime &endTime)
{
for (int i=0; i<8; ++i) // fail after a few tries.
{
x UInt32 curPtr = mTimeBoundsQueuePtr;
UInt32 index = curPtr & kGeneralRingTimeBoundsQueueMask;
CARingBuffer::TimeBounds* bounds = mTimeBoundsQueue + index;
startTime = bounds->mStartTime;
endTime = bounds->mEndTime;
y UInt32 newPtr = bounds->mUpdateCounter;
* if (newPtr == curPtr)
return kCARingBufferError_OK;
}
return kCARingBufferError_CPUOverload;
}
The asterix marks the part I don't understand. Here, after reading the
current time bounds information, we check if the associated value of
mTimeBoundsQueuePtr equals the value used when finding the slot in the
time bounds queue (line marked with an x). If the check fails, we try
again. But how could the check fail? If the time bounds were being
updated between the line marked with an x and the line marked with a y
(as a result of another thread writing to the buffer), then the new
mTimeBoundsQueuePtr would point to a different slot in the queue than
the one we were reading from, and the check would still succeed,
wouldn't it? The only possibility I can imagine (with no experience
with lockless concurrent programming) is that the time bounds were
updated 32 times or more between line x and line y. In that case the
check would fail, is this the reason for the extra check?
Also, I could imagine a situation where mTimeBoundsQueuePtr was
atomically updated by CARingBuffer::SetTimeBounds, but the new time
bounds data still wasn't flushed into memory. In that case the check
would fail, but I would think the memory barrier in
CAAtomicCompareAndSwap32Barrier would make that impossible?
The reason I'm asking, is that I've implemented similar functionality
myself in an AudioUnit, but without this check. Just wondering if
there's something I don't understand that could go wrong.
Per
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden