1 /* 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 20 #include <errno.h> 21 #include <limits.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include <audio_utils/clock_nanosleep.h> 26 #include <audio_utils/fifo.h> 27 #include <audio_utils/futex.h> 28 #include <audio_utils/roundup.h> 29 #include <log/log.h> 30 #include <system/audio.h> // FALLTHROUGH_INTENDED 31 #include <utils/Errors.h> 32 33 audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount, 34 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront, 35 audio_utils_fifo_sync sync) 36 __attribute__((no_sanitize("integer"))) : 37 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)), 38 mFudgeFactor(mFrameCountP2 - mFrameCount), 39 // FIXME need an API to configure the sync types 40 mWriterRear(writerRear), mWriterRearSync(sync), 41 mThrottleFront(throttleFront), mThrottleFrontSync(sync), 42 mIsShutdown(false) 43 { 44 // actual upper bound on frameCount will depend on the frame size 45 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT32_MAX)); 46 } 47 48 audio_utils_fifo_base::~audio_utils_fifo_base() 49 { 50 } 51 52 uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment) const 53 __attribute__((no_sanitize("integer"))) 54 { 55 if (mFudgeFactor > 0) { 56 uint32_t mask = mFrameCountP2 - 1; 57 ALOG_ASSERT((index & mask) < mFrameCount); 58 ALOG_ASSERT(increment <= mFrameCountP2); 59 if ((index & mask) + increment >= mFrameCount) { 60 increment += mFudgeFactor; 61 } 62 index += increment; 63 ALOG_ASSERT((index & mask) < mFrameCount); 64 return index; 65 } else { 66 return index + increment; 67 } 68 } 69 70 int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost, bool flush) const 71 __attribute__((no_sanitize("integer"))) 72 { 73 // TODO replace multiple returns by a single return point so this isn't needed 74 if (lost != NULL) { 75 *lost = 0; 76 } 77 if (mIsShutdown) { 78 return -EIO; 79 } 80 uint32_t diff = rear - front; 81 if (mFudgeFactor > 0) { 82 uint32_t mask = mFrameCountP2 - 1; 83 uint32_t rearOffset = rear & mask; 84 uint32_t frontOffset = front & mask; 85 if (rearOffset >= mFrameCount || frontOffset >= mFrameCount) { 86 ALOGE("%s frontOffset=%u rearOffset=%u mFrameCount=%u", 87 __func__, frontOffset, rearOffset, mFrameCount); 88 shutdown(); 89 return -EIO; 90 } 91 // genDiff is the difference between the generation count fields of rear and front, 92 // and is always a multiple of mFrameCountP2. 93 uint32_t genDiff = (rear & ~mask) - (front & ~mask); 94 // It's OK for writer to be one generation beyond reader, 95 // but reader has lost frames if writer is further than one generation beyond. 96 if (genDiff > mFrameCountP2) { 97 if (lost != NULL) { 98 // Calculate the number of lost frames as the raw difference, 99 // less the mFrameCount frames that are still valid and can be read on retry, 100 // less the wasted indices that don't count as true lost frames. 101 *lost = diff - (flush ? 0 : mFrameCount) - mFudgeFactor * (genDiff/mFrameCountP2); 102 } 103 return -EOVERFLOW; 104 } 105 // If writer is one generation beyond reader, skip over the wasted indices. 106 if (genDiff > 0) { 107 diff -= mFudgeFactor; 108 // Note is still possible for diff > mFrameCount. BCD 16 - BCD 1 shows the problem. 109 // genDiff is 16, fudge is 6, decimal diff is 15 = (22 - 1 - 6). 110 // So we need to check diff for overflow one more time. See "if" a few lines below. 111 } 112 } 113 // FIFO should not be overfull 114 if (diff > mFrameCount) { 115 if (lost != NULL) { 116 *lost = diff - (flush ? 0 : mFrameCount); 117 } 118 return -EOVERFLOW; 119 } 120 return (int32_t) diff; 121 } 122 123 void audio_utils_fifo_base::shutdown() const 124 { 125 ALOGE("%s", __func__); 126 mIsShutdown = true; 127 } 128 129 //////////////////////////////////////////////////////////////////////////////// 130 131 audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer, 132 audio_utils_fifo_index& writerRear, audio_utils_fifo_index *throttleFront) 133 __attribute__((no_sanitize("integer"))) : 134 audio_utils_fifo_base(frameCount, writerRear, throttleFront, AUDIO_UTILS_FIFO_SYNC_SHARED), 135 mFrameSize(frameSize), mBuffer(buffer) 136 { 137 // maximum value of frameCount * frameSize is INT32_MAX (2^31 - 1), not 2^31, because we need to 138 // be able to distinguish successful and error return values from read and write. 139 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL || 140 frameCount > ((uint32_t) INT32_MAX) / frameSize); 141 } 142 143 audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer, 144 bool throttlesWriter, audio_utils_fifo_sync sync) : 145 audio_utils_fifo(frameCount, frameSize, buffer, mSingleProcessSharedRear, 146 throttlesWriter ? &mSingleProcessSharedFront : NULL) 147 { 148 LOG_ALWAYS_FATAL_IF(sync == AUDIO_UTILS_FIFO_SYNC_SHARED); 149 } 150 151 audio_utils_fifo::~audio_utils_fifo() 152 { 153 } 154 155 //////////////////////////////////////////////////////////////////////////////// 156 157 audio_utils_fifo_provider::audio_utils_fifo_provider(audio_utils_fifo& fifo) : 158 mFifo(fifo), mObtained(0), mTotalReleased(0) 159 { 160 } 161 162 audio_utils_fifo_provider::~audio_utils_fifo_provider() 163 { 164 } 165 166 //////////////////////////////////////////////////////////////////////////////// 167 168 audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) : 169 audio_utils_fifo_provider(fifo), mLocalRear(0), 170 mArmLevel(fifo.mFrameCount), mTriggerLevel(0), 171 mIsArmed(true), // because initial fill level of zero is < mArmLevel 172 mEffectiveFrames(fifo.mFrameCount) 173 { 174 } 175 176 audio_utils_fifo_writer::~audio_utils_fifo_writer() 177 { 178 } 179 180 ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count, 181 const struct timespec *timeout) 182 __attribute__((no_sanitize("integer"))) 183 { 184 audio_utils_iovec iovec[2]; 185 ssize_t availToWrite = obtain(iovec, count, timeout); 186 if (availToWrite > 0) { 187 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer, 188 iovec[0].mLength * mFifo.mFrameSize); 189 if (iovec[1].mLength > 0) { 190 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize, 191 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize), 192 iovec[1].mLength * mFifo.mFrameSize); 193 } 194 release(availToWrite); 195 } 196 return availToWrite; 197 } 198 199 // iovec == NULL is not part of the public API, but internally it means don't set mObtained 200 ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count, 201 const struct timespec *timeout) 202 __attribute__((no_sanitize("integer"))) 203 { 204 int err = 0; 205 size_t availToWrite; 206 if (mFifo.mThrottleFront != NULL) { 207 int retries = kRetries; 208 for (;;) { 209 uint32_t front = mFifo.mThrottleFrontSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ? 210 mFifo.mThrottleFront->loadSingleThreaded() : 211 mFifo.mThrottleFront->loadAcquire(); 212 // returns -EIO if mIsShutdown 213 int32_t filled = mFifo.diff(mLocalRear, front); 214 if (filled < 0) { 215 // on error, return an empty slice 216 err = filled; 217 availToWrite = 0; 218 break; 219 } 220 availToWrite = mEffectiveFrames > (uint32_t) filled ? 221 mEffectiveFrames - (uint32_t) filled : 0; 222 // TODO pull out "count == 0" 223 if (count == 0 || availToWrite > 0 || timeout == NULL || 224 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) { 225 break; 226 } 227 // TODO add comments 228 // TODO abstract out switch and replace by general sync object 229 // the high level code (synchronization, sleep, futex, iovec) should be completely 230 // separate from the low level code (indexes, available, masking). 231 int op = FUTEX_WAIT; 232 switch (mFifo.mThrottleFrontSync) { 233 case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED: 234 err = -ENOTSUP; 235 break; 236 case AUDIO_UTILS_FIFO_SYNC_SLEEP: 237 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout, 238 NULL /*remain*/); 239 if (err < 0) { 240 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno); 241 err = -errno; 242 } else { 243 err = -ETIMEDOUT; 244 } 245 break; 246 case AUDIO_UTILS_FIFO_SYNC_PRIVATE: 247 op = FUTEX_WAIT_PRIVATE; 248 FALLTHROUGH_INTENDED; 249 case AUDIO_UTILS_FIFO_SYNC_SHARED: 250 if (timeout->tv_sec == LONG_MAX) { 251 timeout = NULL; 252 } 253 err = mFifo.mThrottleFront->wait(op, front, timeout); 254 if (err < 0) { 255 switch (errno) { 256 case EWOULDBLOCK: 257 // Benign race condition with partner: mFifo.mThrottleFront->mIndex 258 // changed value between the earlier atomic_load_explicit() and sys_futex(). 259 // Try to load index again, but give up if we are unable to converge. 260 if (retries-- > 0) { 261 // bypass the "timeout = NULL;" below 262 continue; 263 } 264 FALLTHROUGH_INTENDED; 265 case EINTR: 266 case ETIMEDOUT: 267 err = -errno; 268 break; 269 default: 270 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno); 271 break; 272 } 273 } 274 break; 275 default: 276 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync); 277 break; 278 } 279 timeout = NULL; 280 } 281 } else { 282 if (mFifo.mIsShutdown) { 283 err = -EIO; 284 availToWrite = 0; 285 } else { 286 availToWrite = mEffectiveFrames; 287 } 288 } 289 if (availToWrite > count) { 290 availToWrite = count; 291 } 292 uint32_t rearOffset = mLocalRear & (mFifo.mFrameCountP2 - 1); 293 size_t part1 = mFifo.mFrameCount - rearOffset; 294 if (part1 > availToWrite) { 295 part1 = availToWrite; 296 } 297 size_t part2 = part1 > 0 ? availToWrite - part1 : 0; 298 // return slice 299 if (iovec != NULL) { 300 iovec[0].mOffset = rearOffset; 301 iovec[0].mLength = part1; 302 iovec[1].mOffset = 0; 303 iovec[1].mLength = part2; 304 mObtained = availToWrite; 305 } 306 return availToWrite > 0 ? availToWrite : err; 307 } 308 309 void audio_utils_fifo_writer::release(size_t count) 310 __attribute__((no_sanitize("integer"))) 311 { 312 // no need to do an early check for mIsShutdown, because the extra code executed is harmless 313 if (count > 0) { 314 if (count > mObtained) { 315 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained); 316 mFifo.shutdown(); 317 return; 318 } 319 if (mFifo.mThrottleFront != NULL) { 320 uint32_t front = mFifo.mThrottleFrontSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ? 321 mFifo.mThrottleFront->loadSingleThreaded() : 322 mFifo.mThrottleFront->loadAcquire(); 323 // returns -EIO if mIsShutdown 324 int32_t filled = mFifo.diff(mLocalRear, front); 325 mLocalRear = mFifo.sum(mLocalRear, count); 326 if (mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED) { 327 mFifo.mWriterRear.storeSingleThreaded(mLocalRear); 328 } else { 329 mFifo.mWriterRear.storeRelease(mLocalRear); 330 } 331 // TODO add comments 332 int op = FUTEX_WAKE; 333 switch (mFifo.mWriterRearSync) { 334 case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED: 335 case AUDIO_UTILS_FIFO_SYNC_SLEEP: 336 break; 337 case AUDIO_UTILS_FIFO_SYNC_PRIVATE: 338 op = FUTEX_WAKE_PRIVATE; 339 FALLTHROUGH_INTENDED; 340 case AUDIO_UTILS_FIFO_SYNC_SHARED: 341 if (filled >= 0) { 342 if ((uint32_t) filled < mArmLevel) { 343 mIsArmed = true; 344 } 345 if (mIsArmed && filled + count > mTriggerLevel) { 346 int err = mFifo.mWriterRear.wake(op, INT32_MAX /*waiters*/); 347 // err is number of processes woken up 348 if (err < 0) { 349 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d", 350 __func__, err, errno); 351 } 352 mIsArmed = false; 353 } 354 } 355 break; 356 default: 357 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync); 358 break; 359 } 360 } else { 361 mLocalRear = mFifo.sum(mLocalRear, count); 362 if (mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED) { 363 mFifo.mWriterRear.storeSingleThreaded(mLocalRear); 364 } else { 365 mFifo.mWriterRear.storeRelease(mLocalRear); 366 } 367 } 368 mObtained -= count; 369 mTotalReleased += count; 370 } 371 } 372 373 ssize_t audio_utils_fifo_writer::available() 374 { 375 // iovec == NULL is not part of the public API, but internally it means don't set mObtained 376 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/); 377 } 378 379 void audio_utils_fifo_writer::resize(uint32_t frameCount) 380 { 381 // cap to range [0, mFifo.mFrameCount] 382 if (frameCount > mFifo.mFrameCount) { 383 frameCount = mFifo.mFrameCount; 384 } 385 // if we reduce the effective frame count, update hysteresis points to be within the new range 386 if (frameCount < mEffectiveFrames) { 387 if (mArmLevel > frameCount) { 388 mArmLevel = frameCount; 389 } 390 if (mTriggerLevel > frameCount) { 391 mTriggerLevel = frameCount; 392 } 393 } 394 mEffectiveFrames = frameCount; 395 } 396 397 uint32_t audio_utils_fifo_writer::size() const 398 { 399 return mEffectiveFrames; 400 } 401 402 void audio_utils_fifo_writer::setHysteresis(uint32_t lowLevelArm, uint32_t highLevelTrigger) 403 { 404 // cap to range [0, mEffectiveFrames] 405 if (lowLevelArm > mEffectiveFrames) { 406 lowLevelArm = mEffectiveFrames; 407 } 408 if (highLevelTrigger > mEffectiveFrames) { 409 highLevelTrigger = mEffectiveFrames; 410 } 411 // TODO this is overly conservative; it would be better to arm based on actual fill level 412 if (lowLevelArm > mArmLevel) { 413 mIsArmed = true; 414 } 415 mArmLevel = lowLevelArm; 416 mTriggerLevel = highLevelTrigger; 417 } 418 419 void audio_utils_fifo_writer::getHysteresis(uint32_t *armLevel, uint32_t *triggerLevel) const 420 { 421 *armLevel = mArmLevel; 422 *triggerLevel = mTriggerLevel; 423 } 424 425 //////////////////////////////////////////////////////////////////////////////// 426 427 audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter, 428 bool flush) : 429 audio_utils_fifo_provider(fifo), 430 431 // If we throttle the writer, then initialize our front index to zero so that we see all data 432 // currently in the buffer. 433 // Otherwise, ignore everything currently in the buffer by initializing our front index to the 434 // current value of writer's rear. This avoids an immediate -EOVERFLOW (overrun) in the case 435 // where reader starts out more than one buffer behind writer. The initial catch-up does not 436 // contribute towards the totalLost, totalFlushed, or totalReleased counters. 437 mLocalFront(throttlesWriter ? 0 : mFifo.mWriterRear.loadAcquire()), 438 439 mThrottleFront(throttlesWriter ? mFifo.mThrottleFront : NULL), 440 mFlush(flush), 441 mArmLevel(-1), mTriggerLevel(mFifo.mFrameCount), 442 mIsArmed(true), // because initial fill level of zero is > mArmLevel 443 mTotalLost(0), mTotalFlushed(0) 444 { 445 } 446 447 audio_utils_fifo_reader::~audio_utils_fifo_reader() 448 { 449 // TODO Need a way to pass throttle capability to the another reader, should one reader exit. 450 } 451 452 ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, const struct timespec *timeout, 453 size_t *lost) 454 __attribute__((no_sanitize("integer"))) 455 { 456 audio_utils_iovec iovec[2]; 457 ssize_t availToRead = obtain(iovec, count, timeout, lost); 458 if (availToRead > 0) { 459 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, 460 iovec[0].mLength * mFifo.mFrameSize); 461 if (iovec[1].mLength > 0) { 462 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize), 463 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize, 464 iovec[1].mLength * mFifo.mFrameSize); 465 } 466 release(availToRead); 467 } 468 return availToRead; 469 } 470 471 ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count, 472 const struct timespec *timeout) 473 __attribute__((no_sanitize("integer"))) 474 { 475 return obtain(iovec, count, timeout, NULL /*lost*/); 476 } 477 478 void audio_utils_fifo_reader::release(size_t count) 479 __attribute__((no_sanitize("integer"))) 480 { 481 // no need to do an early check for mIsShutdown, because the extra code executed is harmless 482 if (count > 0) { 483 if (count > mObtained) { 484 ALOGE("%s(count=%zu) > mObtained=%u", __func__, count, mObtained); 485 mFifo.shutdown(); 486 return; 487 } 488 if (mThrottleFront != NULL) { 489 uint32_t rear = mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ? 490 mFifo.mWriterRear.loadSingleThreaded() : mFifo.mWriterRear.loadAcquire(); 491 // returns -EIO if mIsShutdown 492 int32_t filled = mFifo.diff(rear, mLocalFront); 493 mLocalFront = mFifo.sum(mLocalFront, count); 494 if (mFifo.mThrottleFrontSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED) { 495 mThrottleFront->storeSingleThreaded(mLocalFront); 496 } else { 497 mThrottleFront->storeRelease(mLocalFront); 498 } 499 // TODO add comments 500 int op = FUTEX_WAKE; 501 switch (mFifo.mThrottleFrontSync) { 502 case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED: 503 case AUDIO_UTILS_FIFO_SYNC_SLEEP: 504 break; 505 case AUDIO_UTILS_FIFO_SYNC_PRIVATE: 506 op = FUTEX_WAKE_PRIVATE; 507 FALLTHROUGH_INTENDED; 508 case AUDIO_UTILS_FIFO_SYNC_SHARED: 509 if (filled >= 0) { 510 if (filled > mArmLevel) { 511 mIsArmed = true; 512 } 513 if (mIsArmed && filled - count < mTriggerLevel) { 514 int err = mThrottleFront->wake(op, 1 /*waiters*/); 515 // err is number of processes woken up 516 if (err < 0 || err > 1) { 517 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d", 518 __func__, err, errno); 519 } 520 mIsArmed = false; 521 } 522 } 523 break; 524 default: 525 LOG_ALWAYS_FATAL("mFifo.mThrottleFrontSync=%d", mFifo.mThrottleFrontSync); 526 break; 527 } 528 } else { 529 mLocalFront = mFifo.sum(mLocalFront, count); 530 } 531 mObtained -= count; 532 mTotalReleased += count; 533 } 534 } 535 536 // iovec == NULL is not part of the public API, but internally it means don't set mObtained 537 ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count, 538 const struct timespec *timeout, size_t *lost) 539 __attribute__((no_sanitize("integer"))) 540 { 541 int err = 0; 542 int retries = kRetries; 543 uint32_t rear; 544 for (;;) { 545 rear = mFifo.mWriterRearSync == AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED ? 546 mFifo.mWriterRear.loadSingleThreaded() : mFifo.mWriterRear.loadAcquire(); 547 // TODO pull out "count == 0" 548 if (count == 0 || rear != mLocalFront || timeout == NULL || 549 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) { 550 break; 551 } 552 // TODO add comments 553 int op = FUTEX_WAIT; 554 switch (mFifo.mWriterRearSync) { 555 case AUDIO_UTILS_FIFO_SYNC_SINGLE_THREADED: 556 err = -ENOTSUP; 557 break; 558 case AUDIO_UTILS_FIFO_SYNC_SLEEP: 559 err = audio_utils_clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, timeout, 560 NULL /*remain*/); 561 if (err < 0) { 562 LOG_ALWAYS_FATAL_IF(errno != EINTR, "unexpected err=%d errno=%d", err, errno); 563 err = -errno; 564 } else { 565 err = -ETIMEDOUT; 566 } 567 break; 568 case AUDIO_UTILS_FIFO_SYNC_PRIVATE: 569 op = FUTEX_WAIT_PRIVATE; 570 FALLTHROUGH_INTENDED; 571 case AUDIO_UTILS_FIFO_SYNC_SHARED: 572 if (timeout->tv_sec == LONG_MAX) { 573 timeout = NULL; 574 } 575 err = mFifo.mWriterRear.wait(op, rear, timeout); 576 if (err < 0) { 577 switch (errno) { 578 case EWOULDBLOCK: 579 // Benign race condition with partner: mFifo.mWriterRear->mIndex 580 // changed value between the earlier atomic_load_explicit() and sys_futex(). 581 // Try to load index again, but give up if we are unable to converge. 582 if (retries-- > 0) { 583 // bypass the "timeout = NULL;" below 584 continue; 585 } 586 FALLTHROUGH_INTENDED; 587 case EINTR: 588 case ETIMEDOUT: 589 err = -errno; 590 break; 591 default: 592 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno); 593 break; 594 } 595 } 596 break; 597 default: 598 LOG_ALWAYS_FATAL("mFifo.mWriterRearSync=%d", mFifo.mWriterRearSync); 599 break; 600 } 601 timeout = NULL; 602 } 603 size_t ourLost; 604 if (lost == NULL) { 605 lost = &ourLost; 606 } 607 // returns -EIO if mIsShutdown 608 int32_t filled = mFifo.diff(rear, mLocalFront, lost, mFlush); 609 mTotalLost += *lost; 610 mTotalReleased += *lost; 611 if (filled < 0) { 612 if (filled == -EOVERFLOW) { 613 // catch up with writer, but preserve the still valid frames in buffer 614 mLocalFront = rear - (mFlush ? 0 : mFifo.mFrameCountP2 /*sic*/); 615 } 616 // on error, return an empty slice 617 err = filled; 618 filled = 0; 619 } 620 size_t availToRead = (size_t) filled; 621 if (availToRead > count) { 622 availToRead = count; 623 } 624 uint32_t frontOffset = mLocalFront & (mFifo.mFrameCountP2 - 1); 625 size_t part1 = mFifo.mFrameCount - frontOffset; 626 if (part1 > availToRead) { 627 part1 = availToRead; 628 } 629 size_t part2 = part1 > 0 ? availToRead - part1 : 0; 630 // return slice 631 if (iovec != NULL) { 632 iovec[0].mOffset = frontOffset; 633 iovec[0].mLength = part1; 634 iovec[1].mOffset = 0; 635 iovec[1].mLength = part2; 636 mObtained = availToRead; 637 } 638 return availToRead > 0 ? availToRead : err; 639 } 640 641 ssize_t audio_utils_fifo_reader::available() 642 { 643 return available(NULL /*lost*/); 644 } 645 646 ssize_t audio_utils_fifo_reader::available(size_t *lost) 647 { 648 // iovec == NULL is not part of the public API, but internally it means don't set mObtained 649 return obtain(NULL /*iovec*/, SIZE_MAX /*count*/, NULL /*timeout*/, lost); 650 } 651 652 ssize_t audio_utils_fifo_reader::flush(size_t *lost) 653 { 654 audio_utils_iovec iovec[2]; 655 ssize_t ret = obtain(iovec, SIZE_MAX /*count*/, NULL /*timeout*/, lost); 656 if (ret > 0) { 657 size_t flushed = (size_t) ret; 658 release(flushed); 659 mTotalFlushed += flushed; 660 ret = flushed; 661 } 662 return ret; 663 } 664 665 void audio_utils_fifo_reader::setHysteresis(int32_t armLevel, uint32_t triggerLevel) 666 { 667 // cap to range [0, mFifo.mFrameCount] 668 if (armLevel < 0) { 669 armLevel = -1; 670 } else if ((uint32_t) armLevel > mFifo.mFrameCount) { 671 armLevel = mFifo.mFrameCount; 672 } 673 if (triggerLevel > mFifo.mFrameCount) { 674 triggerLevel = mFifo.mFrameCount; 675 } 676 // TODO this is overly conservative; it would be better to arm based on actual fill level 677 if (armLevel < mArmLevel) { 678 mIsArmed = true; 679 } 680 mArmLevel = armLevel; 681 mTriggerLevel = triggerLevel; 682 } 683 684 void audio_utils_fifo_reader::getHysteresis(int32_t *armLevel, uint32_t *triggerLevel) const 685 { 686 *armLevel = mArmLevel; 687 *triggerLevel = mTriggerLevel; 688 } 689