blob: 54d9d3e0e3ac0fdfd6f46241470e1866d7b46f47 [file] [log] [blame]
/*
* Copyright (C) 2016 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 <errno.h>
#include <limits.h>
#include <audio_utils/fifo_index.h>
#include <audio_utils/futex.h>
// These are not implemented within <audio_utils/fifo_index.h>
// so that we don't expose futex.
uint32_t audio_utils_fifo_index::loadAcquire()
{
return atomic_load_explicit(&mIndex, std::memory_order_acquire);
}
// FIXME should inline this, so that writer_T can also inline it
void audio_utils_fifo_index::storeRelease(uint32_t value)
{
atomic_store_explicit(&mIndex, value, std::memory_order_release);
}
int audio_utils_fifo_index::wait(int op, uint32_t expected, const struct timespec *timeout)
{
return sys_futex(&mIndex, op, expected, timeout, NULL, 0);
}
int audio_utils_fifo_index::wake(int op, int waiters)
{
return sys_futex(&mIndex, op, waiters, NULL, NULL, 0);
}
uint32_t audio_utils_fifo_index::loadConsume()
{
return atomic_load_explicit(&mIndex, std::memory_order_consume);
}
////
RefIndexDeferredStoreReleaseDeferredWake::RefIndexDeferredStoreReleaseDeferredWake(
audio_utils_fifo_index& index)
: mIndex(index), mValue(0), mWriteback(false), mWaiters(0), mWakeOp(FUTEX_WAIT_PRIVATE)
{
}
RefIndexDeferredStoreReleaseDeferredWake::~RefIndexDeferredStoreReleaseDeferredWake()
{
writeback();
wakeNowIfNeeded();
}
void RefIndexDeferredStoreReleaseDeferredWake::set(uint32_t value) {
mValue = value;
mWriteback = true;
}
void RefIndexDeferredStoreReleaseDeferredWake::writeback()
{
if (mWriteback) {
// TODO When part of a collection, should use relaxed for all but the last writeback
mIndex.storeRelease(mValue);
mWriteback = false;
}
}
void RefIndexDeferredStoreReleaseDeferredWake::writethrough(uint32_t value) {
set(value);
writeback();
}
void RefIndexDeferredStoreReleaseDeferredWake::wakeDeferred(int op, int waiters)
{
if (waiters <= 0) {
return;
}
// default is FUTEX_WAKE_PRIVATE
if (op == FUTEX_WAKE) {
mWakeOp = FUTEX_WAKE;
}
if (waiters < INT_MAX - mWaiters) {
mWaiters += waiters;
} else {
mWaiters = INT_MAX;
}
}
void RefIndexDeferredStoreReleaseDeferredWake::wakeNowIfNeeded()
{
if (mWaiters > 0) {
mIndex.wake(mWakeOp, mWaiters);
mWaiters = 0;
mWakeOp = FUTEX_WAKE_PRIVATE;
}
}
void RefIndexDeferredStoreReleaseDeferredWake::wakeNow(int op, int waiters)
{
wakeDeferred(op, waiters);
wakeNowIfNeeded();
}
////
RefIndexCachedLoadAcquireDeferredWait::RefIndexCachedLoadAcquireDeferredWait(
audio_utils_fifo_index& index)
: mIndex(index), mValue(0), mLoaded(false)
{
}
RefIndexCachedLoadAcquireDeferredWait::~RefIndexCachedLoadAcquireDeferredWait()
{
}
uint32_t RefIndexCachedLoadAcquireDeferredWait::get()
{
prefetch();
return mValue;
}
void RefIndexCachedLoadAcquireDeferredWait::prefetch()
{
if (!mLoaded) {
// TODO When part of a collection, should use relaxed for all but the last load
mValue = mIndex.loadAcquire();
mLoaded = true;
}
}
void RefIndexCachedLoadAcquireDeferredWait::invalidate()
{
mLoaded = false;
}
#if 0
uint32_t RefIndexCachedLoadAcquireDeferredWait::readthrough()
{
invalidate();
return get();
}
#endif
int RefIndexCachedLoadAcquireDeferredWait::wait(int op, const struct timespec *timeout)
{
if (!mLoaded) {
return -EINVAL;
}
int err = mIndex.wait(op, mValue /*expected*/, timeout);
invalidate();
return err;
}