fifo: add index references with caching and deferred operations
The new classes will eventually permit a set of related atomic operations,
wakes, and waits to be grouped together into a single sequence point,
and will allow use of event flags to wait for the "or" of multiple FIFOs.
This is one of a series of CLs to isolate the dependencies.
Test: not ready yet for testing
Change-Id: I2055b7a35721222cd914973cd210f5c0dca7d4ef
diff --git a/audio_utils/fifo_index.cpp b/audio_utils/fifo_index.cpp
index b35319c..ab8292f 100644
--- a/audio_utils/fifo_index.cpp
+++ b/audio_utils/fifo_index.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <errno.h>
+#include <limits.h>
#include <audio_utils/fifo_index.h>
#include <audio_utils/futex.h>
@@ -39,3 +41,117 @@
{
return sys_futex(&mIndex, op, waiters, NULL, NULL, 0);
}
+
+////
+
+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;
+}