int err = 0;
size_t availToWrite;
if (mFifo.mThrottleFront != NULL) {
+ int retries = kRetries;
uint32_t front;
for (;;) {
front = atomic_load_explicit(&mFifo.mThrottleFront->mIndex, std::memory_order_acquire);
err = sys_futex(&mFifo.mThrottleFront->mIndex, op, front, timeout, NULL, 0);
if (err < 0) {
switch (errno) {
+ case EWOULDBLOCK:
+ // benign race condition with partner, try again
+ if (retries-- > 0) {
+ // bypass the "timeout = NULL;" below
+ continue;
+ }
+ // fall through
case EINTR:
case ETIMEDOUT:
err = -errno;
__attribute__((no_sanitize("integer")))
{
int err = 0;
+ int retries = kRetries;
uint32_t rear;
for (;;) {
rear = atomic_load_explicit(&mFifo.mWriterRear.mIndex,
err = sys_futex(&mFifo.mWriterRear.mIndex, op, rear, timeout, NULL, 0);
if (err < 0) {
switch (errno) {
+ case EWOULDBLOCK:
+ // benign race condition with partner, try again
+ if (retries-- > 0) {
+ // bypass the "timeout = NULL;" below
+ continue;
+ }
+ // fall through
case EINTR:
case ETIMEDOUT:
err = -errno;
* timeout expired, and no frames were available after the timeout.
* \retval -EINTR count is greater than zero, timeout is non-NULL and not {0, 0}, timeout
* was interrupted by a signal, and no frames were available after signal.
+ * \retval -EWOULDBLOCK count is greater than zero, timeout is non-NULL and not {0, 0},
+ * and lost wake-up retries failed. Should usually handle like -EINTR.
*
* Applications should treat all of these as equivalent to zero available frames,
* except they convey extra information as to the cause.
protected:
/** Number of frames obtained at most recent obtain(), less total number of frames released. */
uint32_t mObtained;
+
+ /** Number of times to retry a futex wait fails with EWOULDBLOCK. */
+ static const int kRetries = 2;
};
////////////////////////////////////////////////////////////////////////////////
* timeout expired, and no frames were available after the timeout.
* \retval -EINTR count is greater than zero, timeout is non-NULL and not {0, 0}, timeout
* was interrupted by a signal, and no frames were available after signal.
+ * \retval -EWOULDBLOCK count is greater than zero, timeout is non-NULL and not {0, 0},
+ * and lost wake-up retries failed. Should usually handle like -EINTR.
*/
ssize_t write(const void *buffer, size_t count, const struct timespec *timeout = NULL);
* timeout expired, and no frames were available after the timeout.
* \retval -EINTR count is greater than zero, timeout is non-NULL and not {0, 0}, timeout
* was interrupted by a signal, and no frames were available after signal.
+ * \retval -EWOULDBLOCK count is greater than zero, timeout is non-NULL and not {0, 0},
+ * and lost wake-up retries failed. Should usually handle like -EINTR.
*/
ssize_t read(void *buffer, size_t count, const struct timespec *timeout = NULL,
size_t *lost = NULL);