blob: 8273309b80255ff2d67bf12c1128959ef298a47e [file] [log] [blame]
Glenn Kasten9b4c8052015-01-06 14:13:13 -08001/*
2 * Copyright (C) 2015 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//#define LOG_NDEBUG 0
18#define LOG_TAG "audio_utils_fifo"
19
Glenn Kasten0ab1d862016-06-20 12:04:56 -070020#include <limits.h>
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070021#include <linux/futex.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080022#include <stdlib.h>
23#include <string.h>
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070024#include <sys/syscall.h>
25
Glenn Kasten9b4c8052015-01-06 14:13:13 -080026#include <audio_utils/fifo.h>
27#include <audio_utils/roundup.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080028#include <cutils/log.h>
Glenn Kasten9b4fe472016-06-13 09:34:57 -070029#include <utils/Errors.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080030
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070031static int sys_futex(void *addr1, int op, int val1, struct timespec *timeout, void *addr2, int val3)
32{
33 return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
34}
35
Glenn Kasten09acf782016-06-17 10:28:05 -070036audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -070037 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070038 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
Glenn Kasten09acf782016-06-17 10:28:05 -070039 mFudgeFactor(mFrameCountP2 - mFrameCount),
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070040 mIsPrivate(true),
Glenn Kasten6d7ad762016-06-15 17:05:54 -070041 mSharedRear(0), mThrottleFront(NULL)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080042{
Glenn Kasten09acf782016-06-17 10:28:05 -070043 // actual upper bound on frameCount will depend on the frame size
Glenn Kasten0ab1d862016-06-20 12:04:56 -070044 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT_MAX));
Glenn Kasten9b4c8052015-01-06 14:13:13 -080045}
46
Glenn Kasten09acf782016-06-17 10:28:05 -070047audio_utils_fifo_base::~audio_utils_fifo_base()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080048{
49}
50
Glenn Kasten09acf782016-06-17 10:28:05 -070051uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070052 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080053{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070054 if (mFudgeFactor) {
55 uint32_t mask = mFrameCountP2 - 1;
56 ALOG_ASSERT((index & mask) < mFrameCount);
57 ALOG_ASSERT(increment <= mFrameCountP2);
58 if ((index & mask) + increment >= mFrameCount) {
59 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080060 }
61 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070062 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080063 return index;
64 } else {
65 return index + increment;
66 }
67}
68
Glenn Kasten09acf782016-06-17 10:28:05 -070069int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070070 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080071{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070072 uint32_t diff = rear - front;
73 if (mFudgeFactor) {
74 uint32_t mask = mFrameCountP2 - 1;
75 uint32_t rearMasked = rear & mask;
76 uint32_t frontMasked = front & mask;
77 if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070078 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070079 }
80 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080081 if (genDiff != 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070082 if (genDiff > mFrameCountP2) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070083 if (lost != NULL) {
84 // TODO provide a more accurate estimate
85 *lost = (genDiff / mFrameCountP2) * mFrameCount;
86 }
87 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070088 }
89 diff -= mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080090 }
91 }
92 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -070093 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070094 if (lost != NULL) {
95 *lost = diff - mFrameCount;
96 }
97 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070098 }
99 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800100}
101
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700102////////////////////////////////////////////////////////////////////////////////
103
Glenn Kasten09acf782016-06-17 10:28:05 -0700104audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer)
105 __attribute__((no_sanitize("integer"))) :
106 audio_utils_fifo_base(frameCount), mFrameSize(frameSize), mBuffer(buffer)
107{
108 // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
109 // be able to distinguish successful and error return values from read and write.
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700110 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
111 frameCount > ((uint32_t) INT_MAX) / frameSize);
Glenn Kasten09acf782016-06-17 10:28:05 -0700112}
113
114audio_utils_fifo::~audio_utils_fifo()
115{
116}
117
118////////////////////////////////////////////////////////////////////////////////
119
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700120audio_utils_fifo_provider::audio_utils_fifo_provider() :
121 mObtained(0)
122{
123}
124
125audio_utils_fifo_provider::~audio_utils_fifo_provider()
126{
127}
128
129////////////////////////////////////////////////////////////////////////////////
130
131audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700132 audio_utils_fifo_provider(), mFifo(fifo), mLocalRear(0),
133 mLowLevelArm(fifo.mFrameCount), mHighLevelTrigger(0), mArmed(false),
134 mEffectiveFrames(fifo.mFrameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700135{
136}
137
138audio_utils_fifo_writer::~audio_utils_fifo_writer()
139{
140}
141
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700142ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count, struct timespec *timeout)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700143 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800144{
Glenn Kasten547a9922016-06-15 13:07:31 -0700145 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700146 ssize_t availToWrite = obtain(iovec, count, timeout);
Glenn Kasten547a9922016-06-15 13:07:31 -0700147 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700148 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
149 iovec[0].mLength * mFifo.mFrameSize);
150 if (iovec[1].mLength > 0) {
151 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
152 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
153 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700154 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700155 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700156 }
157 return availToWrite;
158}
159
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700160ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
161 struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700162 __attribute__((no_sanitize("integer")))
163{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700164 size_t availToWrite;
165 if (mFifo.mThrottleFront != NULL) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700166 uint32_t front;
167 for (;;) {
168 front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
169 std::memory_order_acquire);
170 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
171 if (filled < 0) {
172 mObtained = 0;
173 return (ssize_t) filled;
174 }
175 availToWrite = mEffectiveFrames > (uint32_t) filled ?
176 mEffectiveFrames - (uint32_t) filled : 0;
177 // TODO pull out "count == 0"
178 if (count == 0 || availToWrite > 0 || timeout == NULL ||
179 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
180 break;
181 }
182 int err = sys_futex(mFifo.mThrottleFront,
183 mFifo.mIsPrivate ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, front, timeout, NULL, 0);
184 if (err < 0) {
185 switch (errno) {
186 case EWOULDBLOCK:
187 case EINTR:
188 case ETIMEDOUT:
189 break;
190 default:
191 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
192 break;
193 }
194 }
195 timeout = NULL;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700196 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700197 } else {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700198 availToWrite = mEffectiveFrames;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700199 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800200 if (availToWrite > count) {
201 availToWrite = count;
202 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700203 uint32_t rearMasked = mLocalRear & (mFifo.mFrameCountP2 - 1);
204 size_t part1 = mFifo.mFrameCount - rearMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800205 if (part1 > availToWrite) {
206 part1 = availToWrite;
207 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700208 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700209 iovec[0].mOffset = rearMasked;
210 iovec[0].mLength = part1;
211 iovec[1].mOffset = 0;
212 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700213 mObtained = availToWrite;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800214 return availToWrite;
215}
216
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700217void audio_utils_fifo_writer::release(size_t count)
218 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700219{
220 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700221 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700222 if (mFifo.mThrottleFront != NULL) {
223 uint32_t front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
224 std::memory_order_acquire);
225 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
226 mLocalRear = mFifo.sum(mLocalRear, count);
227 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
228 std::memory_order_release);
229 if (filled >= 0) {
230 if (filled + count <= mLowLevelArm) {
231 mArmed = true;
232 }
233 if (mArmed && filled + count >= mHighLevelTrigger) {
234 int err = sys_futex(&mFifo.mSharedRear,
235 mFifo.mIsPrivate ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
236 INT_MAX /*waiters*/, NULL, NULL, 0);
237 // err is number of processes woken up
238 if (err < 0) {
239 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d", __func__, err, errno);
240 }
241 mArmed = false;
242 }
243 }
244 } else {
245 mLocalRear = mFifo.sum(mLocalRear, count);
246 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
247 std::memory_order_release);
248 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700249 mObtained -= count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700250 }
251}
252
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700253////////////////////////////////////////////////////////////////////////////////
254
255audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700256 audio_utils_fifo_provider(), mFifo(fifo), mLocalFront(0), mSharedFront(0),
257 mHighLevelArm(0), mLowLevelTrigger(mFifo.mFrameCount), mArmed(false)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700258{
259 if (throttlesWriter) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700260 LOG_ALWAYS_FATAL_IF(fifo.mThrottleFront != NULL);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700261 fifo.mThrottleFront = &mSharedFront;
262 }
263}
264
265audio_utils_fifo_reader::~audio_utils_fifo_reader()
266{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700267 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kastena7a0e042016-06-17 10:53:09 -0700268 if (mFifo.mThrottleFront == &mSharedFront) {
269 mFifo.mThrottleFront = NULL;
270 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700271}
272
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700273ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, struct timespec *timeout,
274 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700275 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800276{
Glenn Kasten547a9922016-06-15 13:07:31 -0700277 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700278 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700279 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700280 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
281 iovec[0].mLength * mFifo.mFrameSize);
282 if (iovec[1].mLength > 0) {
283 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
284 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
285 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700286 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700287 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700288 }
289 return availToRead;
290}
291
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700292ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
293 struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700294 __attribute__((no_sanitize("integer")))
295{
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700296 return obtain(iovec, count, timeout, NULL);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700297}
298
299void audio_utils_fifo_reader::release(size_t count)
300 __attribute__((no_sanitize("integer")))
301{
302 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700303 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700304 if (mFifo.mThrottleFront == &mSharedFront) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700305 uint32_t rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
306 std::memory_order_acquire);
307 int32_t filled = mFifo.diff(rear, mLocalFront, NULL /*lost*/);
308 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700309 atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
310 std::memory_order_release);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700311 if (filled >= 0) {
312 if (filled - count >= mHighLevelArm) {
313 mArmed = true;
314 }
315 if (mArmed && filled - count <= mLowLevelTrigger) {
316 int err = sys_futex(&mFifo.mSharedRear,
317 mFifo.mIsPrivate ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
318 1 /*waiters*/, NULL, NULL, 0);
319 // err is number of processes woken up
320 if (err < 0 || err > 1) {
321 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d", __func__, err, errno);
322 }
323 mArmed = false;
324 }
325 }
326 } else {
327 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700328 }
329 mObtained -= count;
330 }
331}
332
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700333ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
334 struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700335 __attribute__((no_sanitize("integer")))
336{
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700337 uint32_t rear;
338 for (;;) {
339 rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
340 std::memory_order_acquire);
341 // TODO pull out "count == 0"
342 if (count == 0 || rear != mLocalFront || timeout == NULL ||
343 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
344 break;
345 }
346 int err = sys_futex(&mFifo.mSharedRear, mFifo.mIsPrivate ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT,
347 rear, timeout, NULL, 0);
348 if (err < 0) {
349 switch (errno) {
350 case EWOULDBLOCK:
351 case EINTR:
352 case ETIMEDOUT:
353 break;
354 default:
355 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
356 break;
357 }
358 }
359 timeout = NULL;
360 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700361 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700362 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700363 if (filled == -EOVERFLOW) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700364 mLocalFront = rear;
365 }
366 mObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700367 return (ssize_t) filled;
368 }
369 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800370 if (availToRead > count) {
371 availToRead = count;
372 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700373 uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
374 size_t part1 = mFifo.mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800375 if (part1 > availToRead) {
376 part1 = availToRead;
377 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700378 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700379 iovec[0].mOffset = frontMasked;
380 iovec[0].mLength = part1;
381 iovec[1].mOffset = 0;
382 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700383 mObtained = availToRead;
Glenn Kasten547a9922016-06-15 13:07:31 -0700384 return availToRead;
385}