/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <new> #include <cutils/atomic.h> #include <cutils/atomic-inline.h> // for android_memory_barrier() #include <media/SingleStateQueue.h> namespace android { template<typename T> SingleStateQueue<T>::Mutator::Mutator(Shared *shared) : mSequence(0), mShared((Shared *) shared) { // exactly one of Mutator and Observer must initialize, currently it is Observer //shared->init(); } template<typename T> int32_t SingleStateQueue<T>::Mutator::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; } template<typename T> bool SingleStateQueue<T>::Mutator::ack() { return mShared->mAck - mSequence == 0; } template<typename T> bool SingleStateQueue<T>::Mutator::ack(int32_t sequence) { // this relies on 2's complement rollover to detect an ancient sequence number return mShared->mAck - sequence >= 0; } template<typename T> SingleStateQueue<T>::Observer::Observer(Shared *shared) : mSequence(0), mSeed(1), mShared((Shared *) shared) { // exactly one of Mutator and Observer must initialize, currently it is Observer shared->init(); } template<typename T> bool SingleStateQueue<T>::Observer::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; } } } #if 0 template<typename T> SingleStateQueue<T>::SingleStateQueue(void /*Shared*/ *shared) { ((Shared *) shared)->init(); } #endif } // namespace android // hack for gcc #ifdef SINGLE_STATE_QUEUE_INSTANTIATIONS #include SINGLE_STATE_QUEUE_INSTANTIATIONS #endif