You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
892 lines
30 KiB
892 lines
30 KiB
/* |
|
* Copyright (C) 2016 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include <gtest/gtest.h> |
|
#ifndef GTEST_IS_THREADSAFE |
|
#error "GTest did not detect pthread library." |
|
#endif |
|
|
|
#include <android/hardware/tests/msgq/1.0/ITestMsgQ.h> |
|
#include <fmq/EventFlag.h> |
|
#include <fmq/MessageQueue.h> |
|
#include <hidl/ServiceManagement.h> |
|
|
|
// libutils: |
|
using android::OK; |
|
using android::sp; |
|
using android::status_t; |
|
|
|
// generated |
|
using android::hardware::tests::msgq::V1_0::ITestMsgQ; |
|
|
|
// libhidl |
|
using android::hardware::kSynchronizedReadWrite; |
|
using android::hardware::kUnsynchronizedWrite; |
|
using android::hardware::MessageQueue; |
|
using android::hardware::MQDescriptorSync; |
|
using android::hardware::MQDescriptorUnsync; |
|
using android::hardware::details::waitForHwService; |
|
|
|
typedef MessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync; |
|
typedef MessageQueue<uint16_t, kUnsynchronizedWrite> MessageQueueUnsync; |
|
|
|
static sp<ITestMsgQ> waitGetTestService() { |
|
// waitForHwService is required because ITestMsgQ is not in manifest.xml. |
|
// "Real" HALs shouldn't be doing this. |
|
waitForHwService(ITestMsgQ::descriptor, "default"); |
|
return ITestMsgQ::getService(); |
|
} |
|
|
|
class UnsynchronizedWriteClientMultiProcess : public ::testing::Test { |
|
protected: |
|
void getQueue(MessageQueueUnsync** fmq, sp<ITestMsgQ>* service, bool setupQueue) { |
|
*service = waitGetTestService(); |
|
*fmq = nullptr; |
|
if (*service == nullptr) return; |
|
if (!(*service)->isRemote()) return; |
|
(*service)->getFmqUnsyncWrite(setupQueue, |
|
[fmq](bool ret, const MQDescriptorUnsync<uint16_t>& in) { |
|
ASSERT_TRUE(ret); |
|
*fmq = new (std::nothrow) MessageQueueUnsync(in); |
|
}); |
|
} |
|
}; |
|
|
|
class SynchronizedReadWriteClient : public ::testing::Test { |
|
protected: |
|
virtual void TearDown() { |
|
delete mQueue; |
|
} |
|
|
|
virtual void SetUp() { |
|
mService = waitGetTestService(); |
|
ASSERT_NE(mService, nullptr); |
|
ASSERT_TRUE(mService->isRemote()); |
|
mService->configureFmqSyncReadWrite([this]( |
|
bool ret, const MQDescriptorSync<uint16_t>& in) { |
|
ASSERT_TRUE(ret); |
|
mQueue = new (std::nothrow) MessageQueueSync(in); |
|
}); |
|
ASSERT_NE(nullptr, mQueue); |
|
ASSERT_TRUE(mQueue->isValid()); |
|
mNumMessagesMax = mQueue->getQuantumCount(); |
|
} |
|
|
|
sp<ITestMsgQ> mService; |
|
MessageQueueSync* mQueue = nullptr; |
|
size_t mNumMessagesMax = 0; |
|
}; |
|
|
|
class UnsynchronizedWriteClient : public ::testing::Test { |
|
protected: |
|
virtual void TearDown() { |
|
delete mQueue; |
|
} |
|
|
|
virtual void SetUp() { |
|
mService = waitGetTestService(); |
|
ASSERT_NE(mService, nullptr); |
|
ASSERT_TRUE(mService->isRemote()); |
|
mService->getFmqUnsyncWrite(true /* configureFmq */, |
|
[this](bool ret, const MQDescriptorUnsync<uint16_t>& in) { |
|
ASSERT_TRUE(ret); |
|
mQueue = new (std::nothrow) MessageQueueUnsync(in); |
|
}); |
|
ASSERT_NE(nullptr, mQueue); |
|
ASSERT_TRUE(mQueue->isValid()); |
|
mNumMessagesMax = mQueue->getQuantumCount(); |
|
} |
|
|
|
sp<ITestMsgQ> mService; |
|
MessageQueueUnsync* mQueue = nullptr; |
|
size_t mNumMessagesMax = 0; |
|
}; |
|
|
|
/* |
|
* Utility function to verify data read from the fast message queue. |
|
*/ |
|
bool verifyData(uint16_t* data, size_t count) { |
|
for (size_t i = 0; i < count; i++) { |
|
if (data[i] != i) return false; |
|
} |
|
return true; |
|
} |
|
|
|
/* |
|
* Utility function to initialize data to be written to the FMQ |
|
*/ |
|
inline void initData(uint16_t* data, size_t count) { |
|
for (size_t i = 0; i < count; i++) { |
|
data[i] = i; |
|
} |
|
} |
|
|
|
/* |
|
* Verify that for an unsynchronized flavor of FMQ, multiple readers |
|
* can recover from a write overflow condition. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClientMultiProcess, MultipleReadersAfterOverflow) { |
|
const size_t dataLen = 16; |
|
|
|
pid_t pid; |
|
/* creating first reader process */ |
|
if ((pid = fork()) == 0) { |
|
sp<ITestMsgQ> testService; |
|
MessageQueueUnsync* queue = nullptr; |
|
getQueue(&queue, &testService, true /* setupQueue */); |
|
ASSERT_NE(testService, nullptr); |
|
ASSERT_TRUE(testService->isRemote()); |
|
ASSERT_NE(queue, nullptr); |
|
ASSERT_TRUE(queue->isValid()); |
|
|
|
size_t numMessagesMax = queue->getQuantumCount(); |
|
|
|
// The following two writes will cause a write overflow. |
|
auto ret = testService->requestWriteFmqUnsync(numMessagesMax); |
|
ASSERT_TRUE(ret.isOk()); |
|
ASSERT_TRUE(ret); |
|
|
|
ret = testService->requestWriteFmqUnsync(1); |
|
ASSERT_TRUE(ret.isOk()); |
|
ASSERT_TRUE(ret); |
|
|
|
// The following read should fail due to the overflow. |
|
std::vector<uint16_t> readData(numMessagesMax); |
|
ASSERT_FALSE(queue->read(&readData[0], numMessagesMax)); |
|
|
|
/* |
|
* Request another write to verify that the reader can recover from the |
|
* overflow condition. |
|
*/ |
|
ASSERT_LT(dataLen, numMessagesMax); |
|
ret = testService->requestWriteFmqUnsync(dataLen); |
|
ASSERT_TRUE(ret.isOk()); |
|
ASSERT_TRUE(ret); |
|
|
|
// Verify that the read is successful. |
|
ASSERT_TRUE(queue->read(&readData[0], dataLen)); |
|
ASSERT_TRUE(verifyData(&readData[0], dataLen)); |
|
|
|
delete queue; |
|
exit(0); |
|
} |
|
|
|
ASSERT_GT(pid, 0 /* parent should see PID greater than 0 for a good fork */); |
|
|
|
int status; |
|
// wait for the first reader process to exit. |
|
ASSERT_EQ(pid, waitpid(pid, &status, 0 /* options */)); |
|
|
|
// creating second reader process. |
|
if ((pid = fork()) == 0) { |
|
sp<ITestMsgQ> testService; |
|
MessageQueueUnsync* queue = nullptr; |
|
|
|
getQueue(&queue, &testService, false /* setupQueue */); |
|
ASSERT_NE(testService, nullptr); |
|
ASSERT_TRUE(testService->isRemote()); |
|
ASSERT_NE(queue, nullptr); |
|
ASSERT_TRUE(queue->isValid()); |
|
|
|
// This read should fail due to the write overflow. |
|
std::vector<uint16_t> readData(dataLen); |
|
ASSERT_FALSE(queue->read(&readData[0], dataLen)); |
|
|
|
/* |
|
* Request another write to verify that the process that recover from |
|
* the overflow condition. |
|
*/ |
|
auto ret = testService->requestWriteFmqUnsync(dataLen); |
|
ASSERT_TRUE(ret.isOk()); |
|
ASSERT_TRUE(ret); |
|
|
|
// verify that the read is successful. |
|
ASSERT_TRUE(queue->read(&readData[0], dataLen)); |
|
ASSERT_TRUE(verifyData(&readData[0], dataLen)); |
|
|
|
delete queue; |
|
exit(0); |
|
} |
|
|
|
ASSERT_GT(pid, 0 /* parent should see PID greater than 0 for a good fork */); |
|
ASSERT_EQ(pid, waitpid(pid, &status, 0 /* options */)); |
|
} |
|
|
|
/* |
|
* Test that basic blocking works using readBlocking()/writeBlocking() APIs |
|
* using the EventFlag object owned by FMQ. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, BlockingReadWrite1) { |
|
const size_t dataLen = 64; |
|
uint16_t data[dataLen] = {0}; |
|
|
|
/* |
|
* Request service to perform a blocking read. This call is oneway and will |
|
* return immediately. |
|
*/ |
|
mService->requestBlockingRead(dataLen); |
|
bool ret = mQueue->writeBlocking(data, |
|
dataLen, |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), |
|
5000000000 /* timeOutNanos */); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Test that basic blocking works using readBlocking()/writeBlocking() APIs |
|
* using the EventFlag object owned by FMQ and using the default EventFlag |
|
* notification bit mask. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, BlockingReadWrite2) { |
|
const size_t dataLen = 64; |
|
std::vector<uint16_t> data(mNumMessagesMax); |
|
|
|
/* |
|
* Request service to perform a blocking read using default EventFlag |
|
* notification bit mask. This call is oneway and will |
|
* return immediately. |
|
*/ |
|
mService->requestBlockingReadDefaultEventFlagBits(dataLen); |
|
|
|
/* Cause a context switch to allow service to block */ |
|
sched_yield(); |
|
|
|
bool ret = mQueue->writeBlocking(&data[0], |
|
dataLen); |
|
ASSERT_TRUE(ret); |
|
|
|
/* |
|
* If the blocking read was successful, another write of size |
|
* mNumMessagesMax will succeed. |
|
*/ |
|
ret = mQueue->writeBlocking(&data[0], mNumMessagesMax, 5000000000 /* timeOutNanos */); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Test that repeated blocking reads and writes work using readBlocking()/writeBlocking() APIs |
|
* using the EventFlag object owned by FMQ. |
|
* Each write operation writes the same amount of data as a single read |
|
* operation. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat1) { |
|
const size_t dataLen = 64; |
|
uint16_t data[dataLen] = {0}; |
|
|
|
/* |
|
* Request service to perform a blocking read. This call is oneway and will |
|
* return immediately. |
|
*/ |
|
const size_t writeCount = 1024; |
|
mService->requestBlockingReadRepeat(dataLen, writeCount); |
|
|
|
for (size_t i = 0; i < writeCount; i++) { |
|
bool ret = mQueue->writeBlocking( |
|
data, |
|
dataLen, |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), |
|
5000000000 /* timeOutNanos */); |
|
ASSERT_TRUE(ret); |
|
} |
|
} |
|
|
|
/* |
|
* Test that repeated blocking reads and writes work using readBlocking()/writeBlocking() APIs |
|
* using the EventFlag object owned by FMQ. Each read operation reads twice the |
|
* amount of data as a single write. |
|
* |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat2) { |
|
const size_t dataLen = 64; |
|
uint16_t data[dataLen] = {0}; |
|
|
|
/* |
|
* Request service to perform a blocking read. This call is oneway and will |
|
* return immediately. |
|
*/ |
|
const size_t writeCount = 1024; |
|
mService->requestBlockingReadRepeat(dataLen*2, writeCount/2); |
|
|
|
for (size_t i = 0; i < writeCount; i++) { |
|
bool ret = mQueue->writeBlocking( |
|
data, |
|
dataLen, |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), |
|
5000000000 /* timeOutNanos */); |
|
ASSERT_TRUE(ret); |
|
} |
|
} |
|
|
|
/* |
|
* Test that basic blocking works using readBlocking()/writeBlocking() APIs |
|
* using the EventFlag object owned by FMQ. Each write operation writes twice |
|
* the amount of data as a single read. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, BlockingReadWriteRepeat3) { |
|
const size_t dataLen = 64; |
|
uint16_t data[dataLen] = {0}; |
|
|
|
/* |
|
* Request service to perform a blocking read. This call is oneway and will |
|
* return immediately. |
|
*/ |
|
size_t writeCount = 1024; |
|
mService->requestBlockingReadRepeat(dataLen/2, writeCount*2); |
|
|
|
for (size_t i = 0; i < writeCount; i++) { |
|
bool ret = mQueue->writeBlocking( |
|
data, |
|
dataLen, |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY), |
|
5000000000 /* timeOutNanos */); |
|
ASSERT_TRUE(ret); |
|
} |
|
} |
|
|
|
/* |
|
* Test that writeBlocking()/readBlocking() APIs do not block on |
|
* attempts to write/read 0 messages and return true. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, BlockingReadWriteZeroMessages) { |
|
uint16_t data = 0; |
|
|
|
/* |
|
* Trigger a blocking write for zero messages with no timeout. |
|
*/ |
|
bool ret = mQueue->writeBlocking( |
|
&data, |
|
0, |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY)); |
|
ASSERT_TRUE(ret); |
|
|
|
/* |
|
* Trigger a blocking read for zero messages with no timeout. |
|
*/ |
|
ret = mQueue->readBlocking(&data, |
|
0, |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_FULL), |
|
static_cast<uint32_t>(ITestMsgQ::EventFlagBits::FMQ_NOT_EMPTY)); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Request mService to write a small number of messages |
|
* to the FMQ. Read and verify data. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, SmallInputReaderTest1) { |
|
const size_t dataLen = 16; |
|
ASSERT_LE(dataLen, mNumMessagesMax); |
|
bool ret = mService->requestWriteFmqSync(dataLen); |
|
ASSERT_TRUE(ret); |
|
uint16_t readData[dataLen] = {}; |
|
ASSERT_TRUE(mQueue->read(readData, dataLen)); |
|
ASSERT_TRUE(verifyData(readData, dataLen)); |
|
} |
|
|
|
/* |
|
* Request mService to write a small number of messages |
|
* to the FMQ. Read and verify each message using |
|
* beginRead/Commit read APIs. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, SmallInputReaderTest2) { |
|
const size_t dataLen = 16; |
|
ASSERT_LE(dataLen, mNumMessagesMax); |
|
auto ret = mService->requestWriteFmqSync(dataLen); |
|
|
|
ASSERT_TRUE(ret.isOk()); |
|
ASSERT_TRUE(ret); |
|
|
|
MessageQueueSync::MemTransaction tx; |
|
ASSERT_TRUE(mQueue->beginRead(dataLen, &tx)); |
|
|
|
auto first = tx.getFirstRegion(); |
|
auto second = tx.getSecondRegion(); |
|
size_t firstRegionLength = first.getLength(); |
|
|
|
for (size_t i = 0; i < dataLen; i++) { |
|
if (i < firstRegionLength) { |
|
ASSERT_EQ(i, *(first.getAddress() + i)); |
|
} else { |
|
ASSERT_EQ(i, *(second.getAddress() + i - firstRegionLength)); |
|
} |
|
} |
|
|
|
ASSERT_TRUE(mQueue->commitRead(dataLen)); |
|
} |
|
|
|
/* |
|
* Write a small number of messages to FMQ. Request |
|
* mService to read and verify that the write was succesful. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, SmallInputWriterTest1) { |
|
const size_t dataLen = 16; |
|
ASSERT_LE(dataLen, mNumMessagesMax); |
|
size_t originalCount = mQueue->availableToWrite(); |
|
uint16_t data[dataLen]; |
|
initData(data, dataLen); |
|
ASSERT_TRUE(mQueue->write(data, dataLen)); |
|
bool ret = mService->requestReadFmqSync(dataLen); |
|
ASSERT_TRUE(ret); |
|
size_t availableCount = mQueue->availableToWrite(); |
|
ASSERT_EQ(originalCount, availableCount); |
|
} |
|
|
|
/* |
|
* Write a small number of messages to FMQ using the beginWrite()/CommitWrite() |
|
* APIs. Request mService to read and verify that the write was succesful. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, SmallInputWriterTest2) { |
|
const size_t dataLen = 16; |
|
ASSERT_LE(dataLen, mNumMessagesMax); |
|
size_t originalCount = mQueue->availableToWrite(); |
|
uint16_t data[dataLen]; |
|
initData(data, dataLen); |
|
|
|
MessageQueueSync::MemTransaction tx; |
|
ASSERT_TRUE(mQueue->beginWrite(dataLen, &tx)); |
|
|
|
auto first = tx.getFirstRegion(); |
|
auto second = tx.getSecondRegion(); |
|
|
|
size_t firstRegionLength = first.getLength(); |
|
uint16_t* firstBaseAddress = first.getAddress(); |
|
uint16_t* secondBaseAddress = second.getAddress(); |
|
|
|
for (size_t i = 0; i < dataLen; i++) { |
|
if (i < firstRegionLength) { |
|
*(firstBaseAddress + i) = i; |
|
} else { |
|
*(secondBaseAddress + i - firstRegionLength) = i; |
|
} |
|
} |
|
|
|
ASSERT_TRUE(mQueue->commitWrite(dataLen)); |
|
|
|
auto ret = mService->requestReadFmqSync(dataLen); |
|
ASSERT_TRUE(ret.isOk()); |
|
ASSERT_TRUE(ret); |
|
size_t availableCount = mQueue->availableToWrite(); |
|
ASSERT_EQ(originalCount, availableCount); |
|
} |
|
|
|
/* |
|
* Verify that the FMQ is empty and read fails when it is empty. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, ReadWhenEmpty) { |
|
ASSERT_EQ(0UL, mQueue->availableToRead()); |
|
const size_t numMessages = 2; |
|
ASSERT_LE(numMessages, mNumMessagesMax); |
|
uint16_t readData[numMessages]; |
|
ASSERT_FALSE(mQueue->read(readData, numMessages)); |
|
} |
|
|
|
/* |
|
* Verify FMQ is empty. |
|
* Write enough messages to fill it. |
|
* Verify availableToWrite() method returns is zero. |
|
* Try writing another message and verify that |
|
* the attempted write was unsuccesful. Request mService |
|
* to read and verify the messages in the FMQ. |
|
*/ |
|
|
|
TEST_F(SynchronizedReadWriteClient, WriteWhenFull) { |
|
std::vector<uint16_t> data(mNumMessagesMax); |
|
initData(&data[0], mNumMessagesMax); |
|
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); |
|
ASSERT_EQ(0UL, mQueue->availableToWrite()); |
|
ASSERT_FALSE(mQueue->write(&data[0], 1)); |
|
bool ret = mService->requestReadFmqSync(mNumMessagesMax); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Verify FMQ is empty. |
|
* Request mService to write data equal to queue size. |
|
* Read and verify data in mQueue. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, LargeInputTest1) { |
|
bool ret = mService->requestWriteFmqSync(mNumMessagesMax); |
|
ASSERT_TRUE(ret); |
|
std::vector<uint16_t> readData(mNumMessagesMax); |
|
ASSERT_TRUE(mQueue->read(&readData[0], mNumMessagesMax)); |
|
ASSERT_TRUE(verifyData(&readData[0], mNumMessagesMax)); |
|
} |
|
|
|
/* |
|
* Request mService to write more than maximum number of messages to the FMQ. |
|
* Verify that the write fails. Verify that availableToRead() method |
|
* still returns 0 and verify that attempt to read fails. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, LargeInputTest2) { |
|
ASSERT_EQ(0UL, mQueue->availableToRead()); |
|
const size_t numMessages = 2048; |
|
ASSERT_GT(numMessages, mNumMessagesMax); |
|
bool ret = mService->requestWriteFmqSync(numMessages); |
|
ASSERT_FALSE(ret); |
|
uint16_t readData; |
|
ASSERT_EQ(0UL, mQueue->availableToRead()); |
|
ASSERT_FALSE(mQueue->read(&readData, 1)); |
|
} |
|
|
|
/* |
|
* Write until FMQ is full. |
|
* Verify that the number of messages available to write |
|
* is equal to mNumMessagesMax. |
|
* Verify that another write attempt fails. |
|
* Request mService to read. Verify read count. |
|
*/ |
|
|
|
TEST_F(SynchronizedReadWriteClient, LargeInputTest3) { |
|
std::vector<uint16_t> data(mNumMessagesMax); |
|
initData(&data[0], mNumMessagesMax); |
|
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); |
|
ASSERT_EQ(0UL, mQueue->availableToWrite()); |
|
ASSERT_FALSE(mQueue->write(&data[0], 1)); |
|
|
|
bool ret = mService->requestReadFmqSync(mNumMessagesMax); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Confirm that the FMQ is empty. Request mService to write to FMQ. |
|
* Do multiple reads to empty FMQ and verify data. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, MultipleRead) { |
|
const size_t chunkSize = 100; |
|
const size_t chunkNum = 5; |
|
const size_t numMessages = chunkSize * chunkNum; |
|
ASSERT_LE(numMessages, mNumMessagesMax); |
|
size_t availableToRead = mQueue->availableToRead(); |
|
size_t expectedCount = 0; |
|
ASSERT_EQ(expectedCount, availableToRead); |
|
bool ret = mService->requestWriteFmqSync(numMessages); |
|
ASSERT_TRUE(ret); |
|
uint16_t readData[numMessages] = {}; |
|
for (size_t i = 0; i < chunkNum; i++) { |
|
ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize)); |
|
} |
|
ASSERT_TRUE(verifyData(readData, numMessages)); |
|
} |
|
|
|
/* |
|
* Write to FMQ in bursts. |
|
* Request mService to read data. Verify the read was successful. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, MultipleWrite) { |
|
const size_t chunkSize = 100; |
|
const size_t chunkNum = 5; |
|
const size_t numMessages = chunkSize * chunkNum; |
|
ASSERT_LE(numMessages, mNumMessagesMax); |
|
uint16_t data[numMessages]; |
|
initData(&data[0], numMessages); |
|
|
|
for (size_t i = 0; i < chunkNum; i++) { |
|
ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize)); |
|
} |
|
bool ret = mService->requestReadFmqSync(numMessages); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Write enough messages into the FMQ to fill half of it. |
|
* Request mService to read back the same. |
|
* Write mNumMessagesMax messages into the queue. This should cause a |
|
* wrap around. Request mService to read and verify the data. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, ReadWriteWrapAround) { |
|
size_t numMessages = mNumMessagesMax / 2; |
|
std::vector<uint16_t> data(mNumMessagesMax); |
|
initData(&data[0], mNumMessagesMax); |
|
ASSERT_TRUE(mQueue->write(&data[0], numMessages)); |
|
bool ret = mService->requestReadFmqSync(numMessages); |
|
ASSERT_TRUE(ret); |
|
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); |
|
ret = mService->requestReadFmqSync(mNumMessagesMax); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Use beginWrite/commitWrite/getSlot APIs to test wrap arounds are handled |
|
* correctly. |
|
* Write enough messages into the FMQ to fill half of it |
|
* and read back the same. |
|
* Write mNumMessagesMax messages into the queue. This will cause a |
|
* wrap around. Read and verify the data. |
|
*/ |
|
TEST_F(SynchronizedReadWriteClient, ReadWriteWrapAround2) { |
|
size_t numMessages = mNumMessagesMax / 2; |
|
std::vector<uint16_t> data(mNumMessagesMax); |
|
initData(&data[0], mNumMessagesMax); |
|
ASSERT_TRUE(mQueue->write(&data[0], numMessages)); |
|
auto ret = mService->requestReadFmqSync(numMessages); |
|
|
|
ASSERT_TRUE(ret.isOk()); |
|
ASSERT_TRUE(ret); |
|
|
|
/* |
|
* The next write and read will have to deal with with wrap arounds. |
|
*/ |
|
MessageQueueSync::MemTransaction tx; |
|
ASSERT_TRUE(mQueue->beginWrite(mNumMessagesMax, &tx)); |
|
|
|
ASSERT_EQ(tx.getFirstRegion().getLength() + tx.getSecondRegion().getLength(), mNumMessagesMax); |
|
|
|
for (size_t i = 0; i < mNumMessagesMax; i++) { |
|
uint16_t* ptr = tx.getSlot(i); |
|
*ptr = data[i]; |
|
} |
|
|
|
ASSERT_TRUE(mQueue->commitWrite(mNumMessagesMax)); |
|
|
|
ret = mService->requestReadFmqSync(mNumMessagesMax); |
|
|
|
ASSERT_TRUE(ret.isOk()); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Request mService to write a small number of messages |
|
* to the FMQ. Read and verify data. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, SmallInputReaderTest1) { |
|
const size_t dataLen = 16; |
|
ASSERT_LE(dataLen, mNumMessagesMax); |
|
bool ret = mService->requestWriteFmqUnsync(dataLen); |
|
ASSERT_TRUE(ret); |
|
uint16_t readData[dataLen] = {}; |
|
ASSERT_TRUE(mQueue->read(readData, dataLen)); |
|
ASSERT_TRUE(verifyData(readData, dataLen)); |
|
} |
|
|
|
/* |
|
* Write a small number of messages to FMQ. Request |
|
* mService to read and verify that the write was succesful. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, SmallInputWriterTest1) { |
|
const size_t dataLen = 16; |
|
ASSERT_LE(dataLen, mNumMessagesMax); |
|
uint16_t data[dataLen]; |
|
initData(data, dataLen); |
|
ASSERT_TRUE(mQueue->write(data, dataLen)); |
|
bool ret = mService->requestReadFmqUnsync(dataLen); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Verify that the FMQ is empty and read fails when it is empty. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, ReadWhenEmpty) { |
|
ASSERT_EQ(0UL, mQueue->availableToRead()); |
|
const size_t numMessages = 2; |
|
ASSERT_LE(numMessages, mNumMessagesMax); |
|
uint16_t readData[numMessages]; |
|
ASSERT_FALSE(mQueue->read(readData, numMessages)); |
|
} |
|
|
|
/* |
|
* Verify FMQ is empty. |
|
* Write enough messages to fill it. |
|
* Verify availableToWrite() method returns is zero. |
|
* Try writing another message and verify that |
|
* the attempted write was successful. Request mService |
|
* to read the messages in the FMQ and verify that it is unsuccesful. |
|
*/ |
|
|
|
TEST_F(UnsynchronizedWriteClient, WriteWhenFull) { |
|
std::vector<uint16_t> data(mNumMessagesMax); |
|
initData(&data[0], mNumMessagesMax); |
|
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); |
|
ASSERT_EQ(0UL, mQueue->availableToWrite()); |
|
ASSERT_TRUE(mQueue->write(&data[0], 1)); |
|
bool ret = mService->requestReadFmqUnsync(mNumMessagesMax); |
|
ASSERT_FALSE(ret); |
|
} |
|
|
|
/* |
|
* Verify FMQ is empty. |
|
* Request mService to write data equal to queue size. |
|
* Read and verify data in mQueue. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, LargeInputTest1) { |
|
bool ret = mService->requestWriteFmqUnsync(mNumMessagesMax); |
|
ASSERT_TRUE(ret); |
|
std::vector<uint16_t> data(mNumMessagesMax); |
|
ASSERT_TRUE(mQueue->read(&data[0], mNumMessagesMax)); |
|
ASSERT_TRUE(verifyData(&data[0], mNumMessagesMax)); |
|
} |
|
|
|
/* |
|
* Request mService to write more than maximum number of messages to the FMQ. |
|
* Verify that the write fails. Verify that availableToRead() method |
|
* still returns 0 and verify that attempt to read fails. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, LargeInputTest2) { |
|
ASSERT_EQ(0UL, mQueue->availableToRead()); |
|
const size_t numMessages = mNumMessagesMax + 1; |
|
bool ret = mService->requestWriteFmqUnsync(numMessages); |
|
ASSERT_FALSE(ret); |
|
uint16_t readData; |
|
ASSERT_EQ(0UL, mQueue->availableToRead()); |
|
ASSERT_FALSE(mQueue->read(&readData, 1)); |
|
} |
|
|
|
/* |
|
* Write until FMQ is full. |
|
* Verify that the number of messages available to write |
|
* is equal to mNumMessagesMax. |
|
* Verify that another write attempt is succesful. |
|
* Request mService to read. Verify that read is unsuccessful. |
|
* Perform another write and verify that the read is succesful |
|
* to check if the reader process can recover from the error condition. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, LargeInputTest3) { |
|
std::vector<uint16_t> data(mNumMessagesMax); |
|
initData(&data[0], mNumMessagesMax); |
|
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); |
|
ASSERT_EQ(0UL, mQueue->availableToWrite()); |
|
ASSERT_TRUE(mQueue->write(&data[0], 1)); |
|
|
|
bool ret = mService->requestReadFmqUnsync(mNumMessagesMax); |
|
ASSERT_FALSE(ret); |
|
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); |
|
|
|
ret = mService->requestReadFmqUnsync(mNumMessagesMax); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Confirm that the FMQ is empty. Request mService to write to FMQ. |
|
* Do multiple reads to empty FMQ and verify data. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, MultipleRead) { |
|
const size_t chunkSize = 100; |
|
const size_t chunkNum = 5; |
|
const size_t numMessages = chunkSize * chunkNum; |
|
ASSERT_LE(numMessages, mNumMessagesMax); |
|
size_t availableToRead = mQueue->availableToRead(); |
|
size_t expectedCount = 0; |
|
ASSERT_EQ(expectedCount, availableToRead); |
|
bool ret = mService->requestWriteFmqUnsync(numMessages); |
|
ASSERT_TRUE(ret); |
|
uint16_t readData[numMessages] = {}; |
|
for (size_t i = 0; i < chunkNum; i++) { |
|
ASSERT_TRUE(mQueue->read(readData + i * chunkSize, chunkSize)); |
|
} |
|
ASSERT_TRUE(verifyData(readData, numMessages)); |
|
} |
|
|
|
/* |
|
* Write to FMQ in bursts. |
|
* Request mService to read data, verify that it was successful. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, MultipleWrite) { |
|
const size_t chunkSize = 100; |
|
const size_t chunkNum = 5; |
|
const size_t numMessages = chunkSize * chunkNum; |
|
ASSERT_LE(numMessages, mNumMessagesMax); |
|
uint16_t data[numMessages]; |
|
initData(data, numMessages); |
|
for (size_t i = 0; i < chunkNum; i++) { |
|
ASSERT_TRUE(mQueue->write(data + i * chunkSize, chunkSize)); |
|
} |
|
bool ret = mService->requestReadFmqUnsync(numMessages); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Write enough messages into the FMQ to fill half of it. |
|
* Request mService to read back the same. |
|
* Write mNumMessagesMax messages into the queue. This should cause a |
|
* wrap around. Request mService to read and verify the data. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, ReadWriteWrapAround) { |
|
size_t numMessages = mNumMessagesMax / 2; |
|
std::vector<uint16_t> data(mNumMessagesMax); |
|
initData(&data[0], mNumMessagesMax); |
|
ASSERT_TRUE(mQueue->write(&data[0], numMessages)); |
|
bool ret = mService->requestReadFmqUnsync(numMessages); |
|
ASSERT_TRUE(ret); |
|
ASSERT_TRUE(mQueue->write(&data[0], mNumMessagesMax)); |
|
ret = mService->requestReadFmqUnsync(mNumMessagesMax); |
|
ASSERT_TRUE(ret); |
|
} |
|
|
|
/* |
|
* Request mService to write a small number of messages |
|
* to the FMQ. Read and verify data from two threads configured |
|
* as readers to the FMQ. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, SmallInputMultipleReaderTest) { |
|
auto desc = mQueue->getDesc(); |
|
std::unique_ptr<MessageQueue<uint16_t, kUnsynchronizedWrite>> mQueue2( |
|
new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>(*desc)); |
|
ASSERT_NE(nullptr, mQueue2.get()); |
|
|
|
const size_t dataLen = 16; |
|
ASSERT_LE(dataLen, mNumMessagesMax); |
|
|
|
bool ret = mService->requestWriteFmqUnsync(dataLen); |
|
ASSERT_TRUE(ret); |
|
|
|
pid_t pid; |
|
if ((pid = fork()) == 0) { |
|
/* child process */ |
|
uint16_t readData[dataLen] = {}; |
|
ASSERT_TRUE(mQueue2->read(readData, dataLen)); |
|
ASSERT_TRUE(verifyData(readData, dataLen)); |
|
exit(0); |
|
} else { |
|
ASSERT_GT(pid, |
|
0 /* parent should see PID greater than 0 for a good fork */); |
|
uint16_t readData[dataLen] = {}; |
|
ASSERT_TRUE(mQueue->read(readData, dataLen)); |
|
ASSERT_TRUE(verifyData(readData, dataLen)); |
|
} |
|
} |
|
|
|
/* |
|
* Request mService to write into the FMQ until it is full. |
|
* Request mService to do another write and verify it is successful. |
|
* Use two reader processes to read and verify that both fail. |
|
*/ |
|
TEST_F(UnsynchronizedWriteClient, OverflowNotificationTest) { |
|
auto desc = mQueue->getDesc(); |
|
std::unique_ptr<MessageQueue<uint16_t, kUnsynchronizedWrite>> mQueue2( |
|
new (std::nothrow) MessageQueue<uint16_t, kUnsynchronizedWrite>(*desc)); |
|
ASSERT_NE(nullptr, mQueue2.get()); |
|
|
|
bool ret = mService->requestWriteFmqUnsync(mNumMessagesMax); |
|
ASSERT_TRUE(ret); |
|
ret = mService->requestWriteFmqUnsync(1); |
|
ASSERT_TRUE(ret); |
|
|
|
pid_t pid; |
|
if ((pid = fork()) == 0) { |
|
/* child process */ |
|
std::vector<uint16_t> readData(mNumMessagesMax); |
|
ASSERT_FALSE(mQueue2->read(&readData[0], mNumMessagesMax)); |
|
exit(0); |
|
} else { |
|
ASSERT_GT(pid, 0/* parent should see PID greater than 0 for a good fork */); |
|
std::vector<uint16_t> readData(mNumMessagesMax); |
|
ASSERT_FALSE(mQueue->read(&readData[0], mNumMessagesMax)); |
|
} |
|
}
|
|
|