diff options
Diffstat (limited to 'include/media/SingleStateQueue.h')
-rw-r--r-- | include/media/SingleStateQueue.h | 78 |
1 files changed, 66 insertions, 12 deletions
diff --git a/include/media/SingleStateQueue.h b/include/media/SingleStateQueue.h index 04c5fd0..e2e58c5 100644 --- a/include/media/SingleStateQueue.h +++ b/include/media/SingleStateQueue.h @@ -21,6 +21,7 @@ // Non-blocking single-reader / single-writer multi-word atomic load / store #include <stdint.h> +#include <cutils/atomic.h> namespace android { @@ -41,28 +42,47 @@ private: void init() { mAck = 0; mSequence = 0; } volatile int32_t mAck; -#if 0 - int mPad[7]; - // cache line boundary -#endif volatile int32_t mSequence; T mValue; }; class Mutator { public: - Mutator(Shared *shared); - /*virtual*/ ~Mutator() { } + Mutator(Shared *shared) + : mSequence(0), mShared(shared) + { + // exactly one of Mutator and Observer must initialize, currently it is Observer + // shared->init(); + } // push new value onto state queue, overwriting previous value; // returns a sequence number which can be used with ack() - int32_t push(const T& value); + int32_t push(const T& value) + { + Shared *shared = mShared; + int32_t sequence = mSequence; + sequence++; + android_atomic_acquire_store(sequence, &shared->mSequence); + shared->mValue = value; + sequence++; + android_atomic_release_store(sequence, &shared->mSequence); + mSequence = sequence; + // consider signalling a futex here, if we know that observer is waiting + return sequence; + } // return true if most recent push has been observed - bool ack(); + bool ack() const + { + return mShared->mAck - mSequence == 0; + } // return true if a push with specified sequence number or later has been observed - bool ack(int32_t sequence); + bool ack(int32_t sequence) const + { + // this relies on 2's complement rollover to detect an ancient sequence number + return mShared->mAck - sequence >= 0; + } private: int32_t mSequence; @@ -71,11 +91,45 @@ private: class Observer { public: - Observer(Shared *shared); - /*virtual*/ ~Observer() { } + Observer(Shared *shared) + : mSequence(0), mSeed(1), mShared(shared) + { + // exactly one of Mutator and Observer must initialize, currently it is Observer + shared->init(); + } // return true if value has changed - bool poll(T& value); + bool poll(T& value) + { + Shared *shared = mShared; + int32_t before = shared->mSequence; + if (before == mSequence) { + return false; + } + for (int tries = 0; ; ) { + const int MAX_TRIES = 5; + if (before & 1) { + if (++tries >= MAX_TRIES) { + return false; + } + before = shared->mSequence; + } else { + android_memory_barrier(); + T temp = shared->mValue; + int32_t after = android_atomic_release_load(&shared->mSequence); + if (after == before) { + value = temp; + shared->mAck = before; + mSequence = before; + return true; + } + if (++tries >= MAX_TRIES) { + return false; + } + before = after; + } + } + } private: int32_t mSequence; |