Add optional retry parameter to EventFlag wait()
am: f1aa0581d5
Change-Id: Ib1deb74426212e02773ccf32e3826a5fec870882
diff --git a/EventFlag.cpp b/EventFlag.cpp
index e391ef2..4d370b0 100644
--- a/EventFlag.cpp
+++ b/EventFlag.cpp
@@ -21,6 +21,7 @@
#include <sys/mman.h>
#include <sys/syscall.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
#include <new>
namespace android {
@@ -130,7 +131,7 @@
* Wait for any of the bits in the bitmask to be set
* and return which bits caused the return.
*/
-status_t EventFlag::wait(uint32_t bitmask, uint32_t* efState, int64_t timeoutNanoSeconds) {
+status_t EventFlag::waitHelper(uint32_t bitmask, uint32_t* efState, int64_t timeoutNanoSeconds) {
/*
* Return early if there are no set bits in bitmask.
*/
@@ -185,6 +186,46 @@
return status;
}
+/*
+ * Wait for any of the bits in the bitmask to be set
+ * and return which bits caused the return. If 'retry'
+ * is true, wait again on a spurious wake-up.
+ */
+status_t EventFlag::wait(uint32_t bitmask,
+ uint32_t* efState,
+ int64_t timeoutNanoSeconds,
+ bool retry) {
+ if (!retry) {
+ return waitHelper(bitmask, efState, timeoutNanoSeconds);
+ }
+
+ bool shouldTimeOut = timeoutNanoSeconds != 0;
+ int64_t prevTimeNs = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
+ status_t status;
+ while (true) {
+ if (shouldTimeOut) {
+ int64_t currentTimeNs = android::elapsedRealtimeNano();
+ /*
+ * Decrement TimeOutNanos to account for the time taken to complete the last
+ * iteration of the while loop.
+ */
+ timeoutNanoSeconds -= currentTimeNs - prevTimeNs;
+ prevTimeNs = currentTimeNs;
+ if (timeoutNanoSeconds <= 0) {
+ status = -ETIMEDOUT;
+ *efState = 0;
+ break;
+ }
+ }
+
+ status = waitHelper(bitmask, efState, timeoutNanoSeconds);
+ if ((status != -EAGAIN) && (status != -EINTR)) {
+ break;
+ }
+ }
+ return status;
+}
+
status_t EventFlag::unmapEventFlagWord(std::atomic<uint32_t>* efWordPtr,
bool* efWordNeedsUnmapping) {
status_t status = NO_ERROR;
diff --git a/include/fmq/EventFlag.h b/include/fmq/EventFlag.h
index f452e10..af18448 100644
--- a/include/fmq/EventFlag.h
+++ b/include/fmq/EventFlag.h
@@ -92,15 +92,20 @@
* @param timeoutNanoSeconds Specifies timeout duration in nanoseconds. It is converted to
* an absolute timeout for the wait according to the CLOCK_MONOTONIC clock.
* @param efState The event flag bits that caused the return from wake.
+ * @param retry If true, retry automatically for a spurious wake. If false,
+ * will return -EINTR or -EAGAIN for a spurious wake.
*
* @return Returns a status_t error code. Likely error codes are
* NO_ERROR if the method is successful, BAD_VALUE due to bad input
* parameters, TIMED_OUT if the wait timedout as per the timeout
* parameter, -EAGAIN or -EINTR to indicate that the caller needs to invoke
- * wait() again.
+ * wait() again. -EAGAIN or -EINTR error codes will not be returned if
+ * 'retry' is true since the method will retry waiting in that case.
*/
- status_t wait(uint32_t bitmask, uint32_t* efState, int64_t timeOutNanoSeconds = 0);
-
+ status_t wait(uint32_t bitmask,
+ uint32_t* efState,
+ int64_t timeOutNanoSeconds = 0,
+ bool retry = false);
private:
bool mEfWordNeedsUnmapping = false;
std::atomic<uint32_t>* mEfWordPtr = nullptr;
@@ -124,12 +129,19 @@
EventFlag(const EventFlag& other) = delete;
/*
+ * Wait for any of the bits in the bit mask to be set.
+ */
+ status_t waitHelper(uint32_t bitmask, uint32_t* efState, int64_t timeOutNanoSeconds);
+
+ /*
* Utility method to unmap the event flag word.
*/
static status_t unmapEventFlagWord(std::atomic<uint32_t>* efWordPtr,
bool* efWordNeedsUnmapping);
+
/*
- * Utility method to convert timeout duration to an absolute value.
+ * Utility method to convert timeout duration to an absolute CLOCK_MONOTONIC
+ * clock time which is required by futex syscalls.
*/
inline void addNanosecondsToCurrentTime(int64_t nanoseconds, struct timespec* timeAbs);
~EventFlag();
diff --git a/include/fmq/MessageQueue.h b/include/fmq/MessageQueue.h
index 5045787..b8a4c2f 100644
--- a/include/fmq/MessageQueue.h
+++ b/include/fmq/MessageQueue.h
@@ -761,19 +761,23 @@
}
bool shouldTimeOut = timeOutNanos != 0;
- int64_t prevTimeNs = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
+ int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
- bool endWait = false;
- while (endWait == false) {
- /* It is not require to adjust 'timeOutNanos' if 'shouldTimeOut' is true */
+ while (true) {
+ /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
if (shouldTimeOut) {
+ /*
+ * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
+ * to Nanoseconds)
+ */
int64_t currentTimeNs = android::elapsedRealtimeNano();
/*
- * Decrement TimeOutNanos to account for the time taken to complete the last
+ * Decrement 'timeOutNanos' to account for the time taken to complete the last
* iteration of the while loop.
*/
- timeOutNanos -= currentTimeNs - prevTimeNs;
- prevTimeNs = currentTimeNs;
+ timeOutNanos -= currentTimeNs - prevTimeNanos;
+ prevTimeNanos = currentTimeNs;
+
if (timeOutNanos <= 0) {
/*
* Attempt write in case a context switch happened outside of
@@ -789,44 +793,27 @@
* notification.
*/
uint32_t efState = 0;
- status_t status = evFlag->wait(readNotification, &efState, timeOutNanos);
- switch (status) {
- case android::NO_ERROR:
- /*
- * If wait() returns NO_ERROR, break and check efState.
- */
- break;
- case android::TIMED_OUT:
- /*
- * If wait() returns android::TIMEDOUT, break out of the while loop
- * and return false;
- */
- endWait = true;
- continue;
- case -EAGAIN:
- case -EINTR:
- /*
- * For errors -EAGAIN and -EINTR, go back to wait.
- */
- continue;
- default:
- /*
- * Throw an error for any other error code since it is unexpected.
- */
+ status_t status = evFlag->wait(readNotification,
+ &efState,
+ timeOutNanos,
+ true /* retry on spurious wake */);
- endWait = true;
- ALOGE("Unexpected error code from EventFlag Wait %d", status);
- continue;
+ if (status != android::TIMED_OUT && status != android::NO_ERROR) {
+ ALOGE("Unexpected error code from EventFlag Wait write %d", status);
+ break;
+ }
+
+ if (status == android::TIMED_OUT) {
+ break;
}
/*
- * If the wake() was not due to the readNotification bit or if
- * there is still insufficient space to write to the FMQ,
+ * If there is still insufficient space to write to the FMQ,
* keep waiting for another readNotification.
*/
if ((efState & readNotification) && write(data, count)) {
result = true;
- endWait = true;
+ break;
}
}
@@ -889,19 +876,22 @@
}
bool shouldTimeOut = timeOutNanos != 0;
- int64_t prevTimeNs = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
+ int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
- bool endWait = false;
- while (endWait == false) {
- /* It is not require to adjust 'timeOutNanos' if 'shouldTimeOut' is true */
+ while (true) {
+ /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
if (shouldTimeOut) {
+ /*
+ * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
+ * to Nanoseconds)
+ */
int64_t currentTimeNs = android::elapsedRealtimeNano();
/*
- * Decrement TimeOutNanos to account for the time taken to complete the last
+ * Decrement 'timeOutNanos' to account for the time taken to complete the last
* iteration of the while loop.
*/
- timeOutNanos -= currentTimeNs - prevTimeNs;
- prevTimeNs = currentTimeNs;
+ timeOutNanos -= currentTimeNs - prevTimeNanos;
+ prevTimeNanos = currentTimeNs;
if (timeOutNanos <= 0) {
/*
@@ -918,44 +908,27 @@
* notification.
*/
uint32_t efState = 0;
- status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos);
- switch (status) {
- case android::NO_ERROR:
- /*
- * If wait() returns NO_ERROR, break and check efState.
- */
- break;
- case android::TIMED_OUT:
- /*
- * If wait() returns android::TIMEDOUT, break out of the while loop
- * and return false;
- */
- endWait = true;
- continue;
- case -EAGAIN:
- case -EINTR:
- /*
- * For errors -EAGAIN and -EINTR, go back to wait.
- */
- continue;
- default:
- /*
- * Throw an error for any other error code since it is unexpected.
- */
+ status_t status = evFlag->wait(writeNotification,
+ &efState,
+ timeOutNanos,
+ true /* retry on spurious wake */);
- endWait = true;
- ALOGE("Unexpected error code from EventFlag Wait %d", status);
- continue;
+ if (status != android::TIMED_OUT && status != android::NO_ERROR) {
+ ALOGE("Unexpected error code from EventFlag Wait status %d", status);
+ break;
+ }
+
+ if (status == android::TIMED_OUT) {
+ break;
}
/*
- * If the wake() was not due to the writeNotification bit being set
- * or if the data in FMQ is still insufficient, go back to waiting
+ * If the data in FMQ is still insufficient, go back to waiting
* for another write notification.
*/
if ((efState & writeNotification) && read(data, count)) {
result = true;
- endWait = true;
+ break;
}
}