1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <errno.h> 18#include <limits.h> 19#include <audio_utils/fifo_index.h> 20#include <audio_utils/futex.h> 21 22// These are not implemented within <audio_utils/fifo_index.h> 23// so that we don't expose futex. 24 25uint32_t audio_utils_fifo_index::loadAcquire() 26{ 27 return atomic_load_explicit(&mIndex, std::memory_order_acquire); 28} 29 30// FIXME should inline this, so that writer32 can also inline it 31void audio_utils_fifo_index::storeRelease(uint32_t value) 32{ 33 atomic_store_explicit(&mIndex, value, std::memory_order_release); 34} 35 36int audio_utils_fifo_index::wait(int op, uint32_t expected, const struct timespec *timeout) 37{ 38 return sys_futex(&mIndex, op, expected, timeout, NULL, 0); 39} 40 41int audio_utils_fifo_index::wake(int op, int waiters) 42{ 43 return sys_futex(&mIndex, op, waiters, NULL, NULL, 0); 44} 45 46uint32_t audio_utils_fifo_index::loadConsume() 47{ 48 return atomic_load_explicit(&mIndex, std::memory_order_consume); 49} 50 51//// 52 53RefIndexDeferredStoreReleaseDeferredWake::RefIndexDeferredStoreReleaseDeferredWake( 54 audio_utils_fifo_index& index) 55 : mIndex(index), mValue(0), mWriteback(false), mWaiters(0), mWakeOp(FUTEX_WAIT_PRIVATE) 56{ 57} 58 59RefIndexDeferredStoreReleaseDeferredWake::~RefIndexDeferredStoreReleaseDeferredWake() 60{ 61 writeback(); 62 wakeNowIfNeeded(); 63} 64 65void RefIndexDeferredStoreReleaseDeferredWake::set(uint32_t value) { 66 mValue = value; 67 mWriteback = true; 68} 69 70void RefIndexDeferredStoreReleaseDeferredWake::writeback() 71{ 72 if (mWriteback) { 73 // TODO When part of a collection, should use relaxed for all but the last writeback 74 mIndex.storeRelease(mValue); 75 mWriteback = false; 76 } 77} 78 79void RefIndexDeferredStoreReleaseDeferredWake::writethrough(uint32_t value) { 80 set(value); 81 writeback(); 82} 83 84void RefIndexDeferredStoreReleaseDeferredWake::wakeDeferred(int op, int waiters) 85{ 86 if (waiters <= 0) { 87 return; 88 } 89 // default is FUTEX_WAKE_PRIVATE 90 if (op == FUTEX_WAKE) { 91 mWakeOp = FUTEX_WAKE; 92 } 93 if (waiters < INT_MAX - mWaiters) { 94 mWaiters += waiters; 95 } else { 96 mWaiters = INT_MAX; 97 } 98} 99 100void RefIndexDeferredStoreReleaseDeferredWake::wakeNowIfNeeded() 101{ 102 if (mWaiters > 0) { 103 mIndex.wake(mWakeOp, mWaiters); 104 mWaiters = 0; 105 mWakeOp = FUTEX_WAKE_PRIVATE; 106 } 107} 108 109void RefIndexDeferredStoreReleaseDeferredWake::wakeNow(int op, int waiters) 110{ 111 wakeDeferred(op, waiters); 112 wakeNowIfNeeded(); 113} 114 115//// 116 117RefIndexCachedLoadAcquireDeferredWait::RefIndexCachedLoadAcquireDeferredWait( 118 audio_utils_fifo_index& index) 119 : mIndex(index), mValue(0), mLoaded(false) 120{ 121} 122 123RefIndexCachedLoadAcquireDeferredWait::~RefIndexCachedLoadAcquireDeferredWait() 124{ 125} 126 127uint32_t RefIndexCachedLoadAcquireDeferredWait::get() 128{ 129 prefetch(); 130 return mValue; 131} 132 133void RefIndexCachedLoadAcquireDeferredWait::prefetch() 134{ 135 if (!mLoaded) { 136 // TODO When part of a collection, should use relaxed for all but the last load 137 mValue = mIndex.loadAcquire(); 138 mLoaded = true; 139 } 140} 141 142void RefIndexCachedLoadAcquireDeferredWait::invalidate() 143{ 144 mLoaded = false; 145} 146 147#if 0 148uint32_t RefIndexCachedLoadAcquireDeferredWait::readthrough() 149{ 150 invalidate(); 151 return get(); 152} 153#endif 154 155int RefIndexCachedLoadAcquireDeferredWait::wait(int op, const struct timespec *timeout) 156{ 157 if (!mLoaded) { 158 return -EINVAL; 159 } 160 int err = mIndex.wait(op, mValue /*expected*/, timeout); 161 invalidate(); 162 return err; 163} 164