// Constructor and destructor
template<typename T> StateQueue<T>::StateQueue() :
- mNext(NULL), mAck(NULL), mCurrent(NULL),
+ mAck(NULL), mCurrent(NULL),
mMutating(&mStates[0]), mExpecting(NULL),
mInMutation(false), mIsDirty(false), mIsInitialized(false)
#ifdef STATE_QUEUE_DUMP
, mObserverDump(&mObserverDummyDump), mMutatorDump(&mMutatorDummyDump)
#endif
{
+ atomic_init(&mNext, 0);
}
template<typename T> StateQueue<T>::~StateQueue()
template<typename T> const T* StateQueue<T>::poll()
{
-#ifdef __LP64__
- const T *next = (const T *) android_atomic_acquire_load64((volatile int64_t *) &mNext);
-#else
- const T *next = (const T *) android_atomic_acquire_load((volatile int32_t *) &mNext);
-#endif
+ const T *next = (const T *) atomic_load_explicit(&mNext, memory_order_acquire);
+
if (next != mCurrent) {
mAck = next; // no additional barrier needed
mCurrent = next;
}
// publish
-#ifdef __LP64__
- android_atomic_release_store64((int64_t) mMutating, (volatile int64_t *) &mNext);
-#else
- android_atomic_release_store((int32_t) mMutating, (volatile int32_t *) &mNext);
-#endif
+ atomic_store_explicit(&mNext, (uintptr_t)mMutating, memory_order_release);
mExpecting = mMutating;
// copy with circular wraparound
#ifndef ANDROID_AUDIO_STATE_QUEUE_H
#define ANDROID_AUDIO_STATE_QUEUE_H
+#include <stdatomic.h>
+
// The state queue template class was originally driven by this use case / requirements:
// There are two threads: a fast mixer, and a normal mixer, and they share state.
// The interesting part of the shared state is a set of active fast tracks,
T mStates[kN]; // written by mutator, read by observer
// "volatile" is meaningless with SMP, but here it indicates that we're using atomic ops
- volatile const T* mNext; // written by mutator to advance next, read by observer
+ atomic_uintptr_t mNext; // written by mutator to advance next, read by observer
volatile const T* mAck; // written by observer to acknowledge advance of next, read by mutator
// only used by observer