blob: d9a200a51872c816d361d777abee7ca53a741e9e [file] [log] [blame]
Glenn Kasten7cc8f542016-12-01 16:12:59 -08001/*
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
Glenn Kasten7225a3d2016-11-30 11:05:32 -080017#include <errno.h>
18#include <limits.h>
Glenn Kasten7cc8f542016-12-01 16:12:59 -080019#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
30void audio_utils_fifo_index::storeRelease(uint32_t value)
31{
32 atomic_store_explicit(&mIndex, value, std::memory_order_release);
33}
34
35int audio_utils_fifo_index::wait(int op, uint32_t expected, const struct timespec *timeout)
36{
37 return sys_futex(&mIndex, op, expected, timeout, NULL, 0);
38}
39
40int audio_utils_fifo_index::wake(int op, int waiters)
41{
42 return sys_futex(&mIndex, op, waiters, NULL, NULL, 0);
43}
Glenn Kasten7225a3d2016-11-30 11:05:32 -080044
Glenn Kasten2f995312016-12-16 12:42:26 -080045uint32_t audio_utils_fifo_index::loadConsume()
46{
47 return atomic_load_explicit(&mIndex, std::memory_order_consume);
48}
49
Glenn Kasten7225a3d2016-11-30 11:05:32 -080050////
51
52RefIndexDeferredStoreReleaseDeferredWake::RefIndexDeferredStoreReleaseDeferredWake(
53 audio_utils_fifo_index& index)
54 : mIndex(index), mValue(0), mWriteback(false), mWaiters(0), mWakeOp(FUTEX_WAIT_PRIVATE)
55{
56}
57
58RefIndexDeferredStoreReleaseDeferredWake::~RefIndexDeferredStoreReleaseDeferredWake()
59{
60 writeback();
61 wakeNowIfNeeded();
62}
63
64void RefIndexDeferredStoreReleaseDeferredWake::set(uint32_t value) {
65 mValue = value;
66 mWriteback = true;
67}
68
69void RefIndexDeferredStoreReleaseDeferredWake::writeback()
70{
71 if (mWriteback) {
72 // TODO When part of a collection, should use relaxed for all but the last writeback
73 mIndex.storeRelease(mValue);
74 mWriteback = false;
75 }
76}
77
78void RefIndexDeferredStoreReleaseDeferredWake::writethrough(uint32_t value) {
79 set(value);
80 writeback();
81}
82
83void RefIndexDeferredStoreReleaseDeferredWake::wakeDeferred(int op, int waiters)
84{
85 if (waiters <= 0) {
86 return;
87 }
88 // default is FUTEX_WAKE_PRIVATE
89 if (op == FUTEX_WAKE) {
90 mWakeOp = FUTEX_WAKE;
91 }
92 if (waiters < INT_MAX - mWaiters) {
93 mWaiters += waiters;
94 } else {
95 mWaiters = INT_MAX;
96 }
97}
98
99void RefIndexDeferredStoreReleaseDeferredWake::wakeNowIfNeeded()
100{
101 if (mWaiters > 0) {
102 mIndex.wake(mWakeOp, mWaiters);
103 mWaiters = 0;
104 mWakeOp = FUTEX_WAKE_PRIVATE;
105 }
106}
107
108void RefIndexDeferredStoreReleaseDeferredWake::wakeNow(int op, int waiters)
109{
110 wakeDeferred(op, waiters);
111 wakeNowIfNeeded();
112}
113
114////
115
116RefIndexCachedLoadAcquireDeferredWait::RefIndexCachedLoadAcquireDeferredWait(
117 audio_utils_fifo_index& index)
118 : mIndex(index), mValue(0), mLoaded(false)
119{
120}
121
122RefIndexCachedLoadAcquireDeferredWait::~RefIndexCachedLoadAcquireDeferredWait()
123{
124}
125
126uint32_t RefIndexCachedLoadAcquireDeferredWait::get()
127{
128 prefetch();
129 return mValue;
130}
131
132void RefIndexCachedLoadAcquireDeferredWait::prefetch()
133{
134 if (!mLoaded) {
135 // TODO When part of a collection, should use relaxed for all but the last load
136 mValue = mIndex.loadAcquire();
137 mLoaded = true;
138 }
139}
140
141void RefIndexCachedLoadAcquireDeferredWait::invalidate()
142{
143 mLoaded = false;
144}
145
146#if 0
147uint32_t RefIndexCachedLoadAcquireDeferredWait::readthrough()
148{
149 invalidate();
150 return get();
151}
152#endif
153
154int RefIndexCachedLoadAcquireDeferredWait::wait(int op, const struct timespec *timeout)
155{
156 if (!mLoaded) {
157 return -EINVAL;
158 }
159 int err = mIndex.wait(op, mValue /*expected*/, timeout);
160 invalidate();
161 return err;
162}