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
25 // FIXME should inline these, so that writer_T can also inline it
26
loadSingleThreaded()27 uint32_t audio_utils_fifo_index::loadSingleThreaded()
28 {
29 // TODO Should be a read from simple non-atomic variable
30 return atomic_load_explicit(&mIndex, std::memory_order_relaxed);
31 }
32
loadAcquire()33 uint32_t audio_utils_fifo_index::loadAcquire()
34 {
35 return atomic_load_explicit(&mIndex, std::memory_order_acquire);
36 }
37
storeSingleThreaded(uint32_t value)38 void audio_utils_fifo_index::storeSingleThreaded(uint32_t value)
39 {
40 // TODO Should be a write to simple non-atomic variable
41 atomic_store_explicit(&mIndex, value, std::memory_order_relaxed);
42 }
43
storeRelease(uint32_t value)44 void audio_utils_fifo_index::storeRelease(uint32_t value)
45 {
46 atomic_store_explicit(&mIndex, value, std::memory_order_release);
47 }
48
wait(int op,uint32_t expected,const struct timespec * timeout)49 int audio_utils_fifo_index::wait(int op, uint32_t expected, const struct timespec *timeout)
50 {
51 return sys_futex(&mIndex, op, expected, timeout, NULL, 0);
52 }
53
wake(int op,int waiters)54 int audio_utils_fifo_index::wake(int op, int waiters)
55 {
56 return sys_futex(&mIndex, op, waiters, NULL, NULL, 0);
57 }
58
59 // ----------------------------------------------------------------------------
60
61 #if 0 // TODO not currently used, review this code later: bug 150627616
62
63 RefIndexDeferredStoreReleaseDeferredWake::RefIndexDeferredStoreReleaseDeferredWake(
64 audio_utils_fifo_index& index)
65 : mIndex(index), mValue(0), mWriteback(false), mWaiters(0), mWakeOp(FUTEX_WAIT_PRIVATE)
66 {
67 }
68
69 RefIndexDeferredStoreReleaseDeferredWake::~RefIndexDeferredStoreReleaseDeferredWake()
70 {
71 writeback();
72 wakeNowIfNeeded();
73 }
74
75 void RefIndexDeferredStoreReleaseDeferredWake::set(uint32_t value) {
76 mValue = value;
77 mWriteback = true;
78 }
79
80 void RefIndexDeferredStoreReleaseDeferredWake::writeback()
81 {
82 if (mWriteback) {
83 // TODO When part of a collection, should use relaxed for all but the last writeback
84 mIndex.storeRelease(mValue);
85 mWriteback = false;
86 }
87 }
88
89 void RefIndexDeferredStoreReleaseDeferredWake::writethrough(uint32_t value) {
90 set(value);
91 writeback();
92 }
93
94 void RefIndexDeferredStoreReleaseDeferredWake::wakeDeferred(int op, int waiters)
95 {
96 if (waiters <= 0) {
97 return;
98 }
99 // default is FUTEX_WAKE_PRIVATE
100 if (op == FUTEX_WAKE) {
101 mWakeOp = FUTEX_WAKE;
102 }
103 if (waiters < INT_MAX - mWaiters) {
104 mWaiters += waiters;
105 } else {
106 mWaiters = INT_MAX;
107 }
108 }
109
110 void RefIndexDeferredStoreReleaseDeferredWake::wakeNowIfNeeded()
111 {
112 if (mWaiters > 0) {
113 mIndex.wake(mWakeOp, mWaiters);
114 mWaiters = 0;
115 mWakeOp = FUTEX_WAKE_PRIVATE;
116 }
117 }
118
119 void RefIndexDeferredStoreReleaseDeferredWake::wakeNow(int op, int waiters)
120 {
121 wakeDeferred(op, waiters);
122 wakeNowIfNeeded();
123 }
124
125 ////
126
127 RefIndexCachedLoadAcquireDeferredWait::RefIndexCachedLoadAcquireDeferredWait(
128 audio_utils_fifo_index& index)
129 : mIndex(index), mValue(0), mLoaded(false)
130 {
131 }
132
133 RefIndexCachedLoadAcquireDeferredWait::~RefIndexCachedLoadAcquireDeferredWait()
134 {
135 }
136
137 uint32_t RefIndexCachedLoadAcquireDeferredWait::get()
138 {
139 prefetch();
140 return mValue;
141 }
142
143 void RefIndexCachedLoadAcquireDeferredWait::prefetch()
144 {
145 if (!mLoaded) {
146 // TODO When part of a collection, should use relaxed for all but the last load
147 mValue = mIndex.loadAcquire();
148 mLoaded = true;
149 }
150 }
151
152 void RefIndexCachedLoadAcquireDeferredWait::invalidate()
153 {
154 mLoaded = false;
155 }
156
157 #if 0
158 uint32_t RefIndexCachedLoadAcquireDeferredWait::readthrough()
159 {
160 invalidate();
161 return get();
162 }
163 #endif
164
165 int RefIndexCachedLoadAcquireDeferredWait::wait(int op, const struct timespec *timeout)
166 {
167 if (!mLoaded) {
168 return -EINVAL;
169 }
170 int err = mIndex.wait(op, mValue /*expected*/, timeout);
171 invalidate();
172 return err;
173 }
174
175 #endif // 0
176