Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 538f498b authored by Glenn Kasten's avatar Glenn Kasten
Browse files

Add template class SingleStateQueue

Change-Id: If7e2bc9b2a216524ee9cbb68682e2634933b4973
parent 0c57461f
Loading
Loading
Loading
Loading
+97 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#ifndef SINGLE_STATE_QUEUE_H
#define SINGLE_STATE_QUEUE_H

// Non-blocking single element state queue, or
// Non-blocking single-reader / single-writer multi-word atomic load / store

#include <stdint.h>

namespace android {

template<typename T> class SingleStateQueue {

public:

    class Mutator;
    class Observer;

    struct Shared {
        // needs to be part of a union so don't define constructor or destructor

        friend class Mutator;
        friend class Observer;

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() { }

        // 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);

        // return true if most recent push has been observed
        bool ack();

        // return true if a push with specified sequence number or later has been observed
        bool ack(int32_t sequence);

    private:
        int32_t     mSequence;
        Shared * const mShared;
    };

    class Observer {
    public:
        Observer(Shared *shared);
        /*virtual*/ ~Observer() { }

        // return true if value has changed
        bool poll(T& value);

    private:
        int32_t     mSequence;
        int         mSeed;  // for PRNG
        Shared * const mShared;
    };

#if 0
    SingleStateQueue(void /*Shared*/ *shared);
    /*virtual*/ ~SingleStateQueue() { }

    static size_t size() { return sizeof(Shared); }
#endif

};

}   // namespace android

#endif  // SINGLE_STATE_QUEUE_H
+35 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#ifndef STATIC_AUDIO_TRACK_STATE_H
#define STATIC_AUDIO_TRACK_STATE_H

namespace android {

// Represents a single state of an AudioTrack that was created in static mode (shared memory buffer
// supplied by the client).  This state needs to be communicated from the client to server.  As this
// state is too large to be updated atomically without a mutex, and mutexes aren't allowed here, the
// state is wrapped by a SingleStateQueue.
struct StaticAudioTrackState {
    // do not define constructors, destructors, or virtual methods
    size_t  mLoopStart;
    size_t  mLoopEnd;
    int     mLoopCount;
};

}   // namespace android

#endif  // STATIC_AUDIO_TRACK_STATE_H
+7 −0
Original line number Diff line number Diff line
@@ -53,6 +53,13 @@ LOCAL_SRC_FILES:= \
    SoundPool.cpp \
    SoundPoolThread.cpp

LOCAL_SRC_FILES += ../libnbaio/roundup.c

# for <cutils/atomic-inline.h>
LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
LOCAL_SRC_FILES += SingleStateQueue.cpp
LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'

LOCAL_SHARED_LIBRARIES := \
	libui libcutils libutils libbinder libsonivox libicuuc libexpat \
        libcamera_client libstagefright_foundation \
+107 −0
Original line number Diff line number Diff line
/*
 * 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
+26 −0
Original line number Diff line number Diff line
/*
 * 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 <media/SingleStateQueue.h>
#include <private/media/StaticAudioTrackState.h>

// FIXME hack for gcc

namespace android {

template class SingleStateQueue<StaticAudioTrackState>; // typedef StaticAudioTrackSingleStateQueue

}
Loading