Merge "Process write overflow with number of elements" into main
diff --git a/include/fmq/MessageQueueBase.h b/include/fmq/MessageQueueBase.h
index 5a12b5a..8d65108 100644
--- a/include/fmq/MessageQueueBase.h
+++ b/include/fmq/MessageQueueBase.h
@@ -1278,7 +1278,7 @@
* Half of the buffer will be discarded to make space for fast writers and
* reduce chance of repeated overflows. The other half is available to read.
*/
- size_t historyOffset = mDesc->getSize() / 2;
+ size_t historyOffset = getQuantumCount() / 2 * getQuantumSize();
mReadPtr->store(writePtr - historyOffset, std::memory_order_release);
hardware::details::logError("Read failed after an overflow. Resetting read pointer.");
return true;
diff --git a/tests/fmq_unit_tests.cpp b/tests/fmq_unit_tests.cpp
index 6ddec7c..07ed0ce 100644
--- a/tests/fmq_unit_tests.cpp
+++ b/tests/fmq_unit_tests.cpp
@@ -263,6 +263,35 @@
size_t mNumMessagesMax = 0;
};
+TYPED_TEST_CASE(UnsynchronizedOverflowHistoryTestSingleElement, TwoByteUnsyncTypes);
+
+template <typename T>
+class UnsynchronizedOverflowHistoryTestSingleElement : public TestBase<T> {
+ protected:
+ virtual void TearDown() { delete mQueue; }
+
+ virtual void SetUp() {
+ static constexpr size_t kNumElementsInQueue = 1;
+ static constexpr size_t kPayloadSizeBytes = 2;
+ if (T::Setup == SetupType::SINGLE_FD) {
+ mQueue = new (std::nothrow) typename T::MQType(kNumElementsInQueue);
+ } else {
+ android::base::unique_fd ringbufferFd(::ashmem_create_region(
+ "UnsyncHistory", kNumElementsInQueue * kPayloadSizeBytes));
+ mQueue = new (std::nothrow)
+ typename T::MQType(kNumElementsInQueue, false, std::move(ringbufferFd),
+ kNumElementsInQueue * kPayloadSizeBytes);
+ }
+ ASSERT_NE(nullptr, mQueue);
+ ASSERT_TRUE(mQueue->isValid());
+ mNumMessagesMax = mQueue->getQuantumCount();
+ ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
+ }
+
+ typename T::MQType* mQueue = nullptr;
+ size_t mNumMessagesMax = 0;
+};
+
template <typename T>
class BadQueueConfig : public TestBase<T> {};
@@ -1433,3 +1462,30 @@
std::rotate(data.begin(), data.begin() + 1, data.end());
ASSERT_TRUE(std::equal(readData.rbegin(), readData.rend(), data.rbegin()));
}
+
+/*
+ * Verifies a queue of a single element will fail a read after a write overflow
+ * and then recover.
+ */
+TYPED_TEST(UnsynchronizedOverflowHistoryTestSingleElement, ReadAfterOverflow) {
+ constexpr uint16_t kValue = 4;
+ std::vector<uint16_t> data = {kValue};
+
+ // single write/read works normally
+ ASSERT_TRUE(this->mQueue->write(&data[0], 1));
+ uint16_t readDataPlaceholder;
+ ASSERT_TRUE(this->mQueue->read(&readDataPlaceholder, 1));
+ EXPECT_EQ(readDataPlaceholder, kValue);
+
+ // Write more data (first element of the same data) to cause a wrap around
+ ASSERT_TRUE(this->mQueue->write(&data[0], 1));
+ ASSERT_TRUE(this->mQueue->write(&data[0], 1));
+
+ // Attempt a read (this should fail due to how UnsynchronizedWrite works)
+ ASSERT_FALSE(this->mQueue->read(&readDataPlaceholder, 1));
+
+ // Subsequent write/reads should work again
+ ASSERT_TRUE(this->mQueue->write(&data[0], 1));
+ ASSERT_TRUE(this->mQueue->read(&readDataPlaceholder, 1));
+ EXPECT_EQ(readDataPlaceholder, kValue);
+}