summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AudioManagerUtilities/src/CAmSocketHandler.cpp16
-rw-r--r--AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp75
2 files changed, 87 insertions, 4 deletions
diff --git a/AudioManagerUtilities/src/CAmSocketHandler.cpp b/AudioManagerUtilities/src/CAmSocketHandler.cpp
index 1e7db6a..e5752b4 100644
--- a/AudioManagerUtilities/src/CAmSocketHandler.cpp
+++ b/AudioManagerUtilities/src/CAmSocketHandler.cpp
@@ -40,9 +40,9 @@
#include <sys/timerfd.h>
#endif
+#define END_EVENT (UINT64_MAX >> 1)
#define SHPOLL_IS_ACTIVE(state) (!(state == poll_states_e::REMOVE || state == poll_states_e::CLOSE))
-
namespace am
{
@@ -72,7 +72,7 @@ CAmSocketHandler::CAmSocketHandler() :
ssize_t bytes = read(pollfd.fd, &events, sizeof(events));
if (bytes == sizeof(events))
{
- if (events == UINT64_MAX-1)
+ if (events >= END_EVENT)
{
for (auto & elem : mMapShPoll)
{
@@ -80,6 +80,7 @@ CAmSocketHandler::CAmSocketHandler() :
elem.second.state = poll_states_e::UNINIT;
}
mDispatchDone = true;
+ }
return;
}
@@ -145,7 +146,14 @@ void CAmSocketHandler::start_listenting()
// fallthrough
case poll_states_e::REMOVE:
- fdPollIt = fdPollingArray.erase(fdPollIt);
+ /* The first check is needed for the restart behavior were an element is marked
+ * as removed but not part of the polling array - which is stored on heap.
+ * The second check is needed in case a map element was inserted newly but was
+ * directly marked after as REMOVE but in between there was no sync. of the
+ * polling array processed.
+ */
+ if (fdPollIt != fdPollingArray.end() && fdPollIt->fd == elem.pollfdValue.fd)
+ fdPollIt = fdPollingArray.erase(fdPollIt);
it = mMapShPoll.erase(it);
continue;
@@ -246,7 +254,7 @@ void CAmSocketHandler::exit_mainloop()
stop_listening();
//fire the ending filedescriptor
- const uint64_t events = UINT64_MAX-1;
+ const uint64_t events = END_EVENT;
if (write(mEventFd, &events, sizeof(events)) < 0)
{
//Failed to write to event fd...
diff --git a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp
index 085c3b1..a31ccf4 100644
--- a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp
+++ b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp
@@ -30,6 +30,7 @@
#include <fcntl.h>
#include <sys/un.h>
#include <sys/poll.h>
+#include <sys/eventfd.h>
#include "CAmDltWrapper.h"
#include "CAmSocketHandler.h"
@@ -56,6 +57,12 @@ struct TestUserData
float f;
};
+struct TestStressUserData
+{
+ CAmSocketHandler &socket;
+ std::vector<sh_pollHandle_t> &handles;
+};
+
MockIAmSignalHandler *pMockSignalHandler = NULL;
static void signalHandler(int sig, siginfo_t *siginfo, void *context)
{
@@ -308,6 +315,22 @@ void* threadCallbackUnixSocketAndTimers(void* data)
return sendTestData(sock, (struct sockaddr*)&servAddr, sizeof(servAddr), 500000);
}
+void* threadRaceFd(void* pData)
+{
+ struct TestStressUserData data = *(struct TestStressUserData*)pData;
+ usleep(50000);
+ auto elem = data.handles.begin();
+ std::advance(elem, data.handles.size() / 2);
+ data.socket.removeFDPoll(*elem, sh_rmv_e::RMV_N_CLS);
+ data.handles.erase(elem);
+}
+void* threadEnd(void* pData)
+{
+ struct TestStressUserData data = *(struct TestStressUserData*)pData;
+ usleep(1000000);
+ data.socket.exit_mainloop();
+}
+
TEST(CAmSocketHandlerTest, stressTestUnixSocketAndTimers)
{
@@ -345,6 +368,58 @@ TEST(CAmSocketHandlerTest, stressTestUnixSocketAndTimers)
shutdown(socket_, SHUT_RDWR);
}
+
+TEST(CAmSocketHandlerTest, fdStressTest)
+{
+ CAmSocketHandler myHandler;
+ ASSERT_FALSE(myHandler.fatalErrorOccurred());
+
+ //Check unkonw systemd fd ids
+ sh_pollHandle_t handle;
+ EXPECT_EQ(myHandler.addFDPoll(100, 0, NULL, NULL, NULL, NULL, NULL, handle), E_NON_EXISTENT);
+
+ int fd(-1);
+ std::vector<sh_pollHandle_t> handles(10);
+ for (auto& hndl : handles)
+ {
+ fd = eventfd(0, 0);
+ ASSERT_EQ(myHandler.addFDPoll(fd, POLL_IN, NULL, NULL, NULL, NULL, NULL, hndl), E_OK);
+ }
+
+ // remove/add check
+ ASSERT_EQ(myHandler.addFDPoll(fd, POLL_IN, NULL, NULL, NULL, NULL, NULL, handles.back()), E_ALREADY_EXISTS);
+ ASSERT_EQ(myHandler.removeFDPoll(handles.back()), E_OK);
+ ASSERT_EQ(myHandler.addFDPoll(fd, POLL_IN, NULL, NULL, NULL, NULL, NULL, handles.back()), E_OK);
+
+ // create a copy to check if all handles are removed
+ std::vector<sh_pollHandle_t> handlesCheckup(handles);
+
+ while (handles.size())
+ {
+ pthread_t tid1, tid2;
+
+ // this removes an element before starting the socket handler and we
+ // erase the last handle
+ myHandler.removeFDPoll(handles.back(), sh_rmv_e::RMV_N_CLS);
+ handles.erase(handles.end()-1);
+
+ TestStressUserData data = {myHandler, handles};
+ pthread_create(&tid1, NULL, threadEnd, &data);
+
+ // erase the handle in the middle
+ pthread_create(&tid2, NULL, threadRaceFd, &data);
+
+ myHandler.start_listenting();
+
+ pthread_join(tid2, NULL);
+ pthread_join(tid1, NULL);
+ }
+
+ // now do the check
+ for (auto& hndl : handlesCheckup)
+ EXPECT_EQ(myHandler.removeFDPoll(hndl), E_UNKNOWN) << "Handle " << hndl << " not correctly removed before";
+}
+
TEST(CAmSocketHandlerTest, timersOneshot)
{
CAmSocketHandler myHandler;