From 5abcd3990b5b516a031e21598dac6116a2086749 Mon Sep 17 00:00:00 2001 From: Aleksandar Donchev Date: Mon, 10 Apr 2017 14:01:37 +0200 Subject: Signal handling via main loop with signalfd. Signed-off-by: Christian Linke Change-Id: I8c4c2c436ac9fcd61c76a21145c731f327cab0c1 --- .../test/AmMapHandlerTest/CAmMapHandlerTest.cpp | 2 +- .../test/AmMapHandlerTest/CAmMapHandlerTest.h | 3 +- AudioManagerDaemon/src/main.cpp | 93 ++++----- AudioManagerUtilities/include/CAmSocketHandler.h | 136 ++++++++----- AudioManagerUtilities/src/CAmSocketHandler.cpp | 213 ++++++++++++++++----- .../AmSocketHandlerTest/CAmSocketHandlerTest.cpp | 143 +++++++++++++- .../AmSocketHandlerTest/CAmSocketHandlerTest.h | 30 +++ 7 files changed, 468 insertions(+), 152 deletions(-) diff --git a/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.cpp b/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.cpp index fe2f68a..7b11af1 100644 --- a/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.cpp +++ b/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.cpp @@ -47,10 +47,10 @@ TCLAP::SwitchArg enableDebug ("V","logDlt","print DLT logs to stdout or dlt-daem CAmMapBasicTest::CAmMapBasicTest() : + pSocketHandler(),// pDatabaseHandler(), // plistRoutingPluginDirs(), // plistCommandPluginDirs(), // - pSocketHandler(),// pRoutingSender(plistRoutingPluginDirs,dynamic_cast( &pDatabaseHandler )), // pCommandSender(plistCommandPluginDirs, &pSocketHandler), // pRoutingInterfaceBackdoor(), // diff --git a/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.h b/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.h index 32add3d..fc4b023 100644 --- a/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.h +++ b/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.h @@ -54,13 +54,14 @@ public: CAmMapBasicTest(); ~CAmMapBasicTest(); CAmSocketHandler pSocketHandler; + CAmDatabaseHandlerMap pDatabaseHandler; std::vector plistRoutingPluginDirs; std::vector plistCommandPluginDirs; CAmRoutingSender pRoutingSender; CAmCommandSender pCommandSender; IAmRoutingBackdoor pRoutingInterfaceBackdoor; IAmCommandBackdoor pCommandInterfaceBackdoor; - CAmDatabaseHandlerMap pDatabaseHandler; + CAmControlSender pControlSender; CAmRouter pRouter; CAmControlReceiver pControlReceiver; diff --git a/AudioManagerDaemon/src/main.cpp b/AudioManagerDaemon/src/main.cpp index 26d7cea..4e8ca47 100755 --- a/AudioManagerDaemon/src/main.cpp +++ b/AudioManagerDaemon/src/main.cpp @@ -179,45 +179,6 @@ void printCmdInformation() exit(0); } -/** - * the signal handler - * @param sig - * @param siginfo - * @param context - */ -static void signalHandler(int sig, siginfo_t *siginfo, void *context) -{ - (void) sig; - (void) siginfo; - (void) context; - logInfo("signal handler was called, signal",sig); - - switch (sig) - { - /*ctl +c lets call direct controllerRundown, because we might be blocked at the moment. - But there is the risk of interrupting something important */https://asc.bmwgroup.net/wiki/display/MGUROTO/Lastest+and+greatest - case SIGINT: - CAmControlSender::CallsetControllerRundown(sig); - break; - - /* huch- we are getting killed. Better take the fast but risky way: */ - case SIGQUIT: - CAmControlSender::CallsetControllerRundown(sig); - break; - - /* more friendly here assuming systemd wants to stop us, so we can use the mainloop */ - case SIGTERM: - CAmControlSender::CallsetControllerRundownSafe(sig); - break; - - /* looks friendly, too, so lets take the long run */ - case SIGHUP: - CAmControlSender::CallsetControllerRundownSafe(sig); - break; - default: - break; - } -} void mainProgram(int argc, char *argv[]) { @@ -255,6 +216,45 @@ void mainProgram(int argc, char *argv[]) //Instantiate all classes. Keep in same order ! CAmSocketHandler iSocketHandler; + if(iSocketHandler.fatalErrorOccurred()) + { + throw std::runtime_error(std::string("CAmSocketHandler: Could not create pipe or file descriptor is invalid.")); + } + //Register signal handler + sh_pollHandle_t signalHandler; + iSocketHandler.addSignalHandler([&](const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData){ + + unsigned sig = info.ssi_signo; + unsigned user = info.ssi_uid; + + logInfo("signal handler was called from user", user, "with signal ",sig); + + switch (sig) + { + /*ctl +c lets call direct controllerRundown, because we might be blocked at the moment. + But there is the risk of interrupting something important */ + case SIGINT: + CAmControlSender::CallsetControllerRundown(sig); + break; + + /* huch- we are getting killed. Better take the fast but risky way: */ + case SIGQUIT: + CAmControlSender::CallsetControllerRundown(sig); + break; + + /* more friendly here assuming systemd wants to stop us, so we can use the mainloop */ + case SIGTERM: + CAmControlSender::CallsetControllerRundownSafe(sig); + break; + + /* looks friendly, too, so lets take the long run */ + case SIGHUP: + CAmControlSender::CallsetControllerRundownSafe(sig); + break; + default: + break; + } + },signalHandler,NULL); if(commandPluginDir.isSet()) { @@ -364,21 +364,6 @@ int main(int argc, char *argv[], char** envp) listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR)); listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR)); - //now the signal handler: - struct sigaction signalAction; - memset(&signalAction, '\0', sizeof(signalAction)); - signalAction.sa_sigaction = &signalHandler; - signalAction.sa_flags = SA_SIGINFO; - sigaction(SIGINT, &signalAction, NULL); - sigaction(SIGQUIT, &signalAction, NULL); - sigaction(SIGTERM, &signalAction, NULL); - sigaction(SIGHUP, &signalAction, NULL); - - struct sigaction signalChildAction; - memset(&signalChildAction, '\0', sizeof(signalChildAction)); - signalChildAction.sa_flags = SA_NOCLDWAIT; - sigaction(SIGCHLD, &signalChildAction, NULL); - //register new out of memory handler std::set_new_handler(&OutOfMemoryHandler); diff --git a/AudioManagerUtilities/include/CAmSocketHandler.h b/AudioManagerUtilities/include/CAmSocketHandler.h index 4519c0c..c2a1aa3 100644 --- a/AudioManagerUtilities/include/CAmSocketHandler.h +++ b/AudioManagerUtilities/include/CAmSocketHandler.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "audiomanagertypes.h" @@ -281,50 +282,59 @@ namespace am } }; - typedef std::reverse_iterator rListTimerIter; //! callback; + void* userData; + sh_signal_s() : + handle(0), callback(), userData(0) + { + } + }; + struct sh_identifier_s + { + std::set pollHandles; + uint16_t limit; + uint16_t lastUsedID; + sh_identifier_s(const uint16_t pollLimit = UINT16_MAX) : + pollHandles(), limit(pollLimit), lastUsedID(0) + { + } + }; + + typedef std::reverse_iterator rListTimerIter; //! VectorListPollfd_t; //! VectorListPoll_t; //! VectorSignalHandlers_t; //! prepare, std::function fired, - std::function check, std::function dispatch, void* userData, sh_pollHandle_t& handle); + int mPipe[2]; + int mDispatchDone; //this starts / stops the mainloop - am_Error_e addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void* userData, sh_pollHandle_t& handle); - am_Error_e removeFDPoll(const sh_pollHandle_t handle); - am_Error_e updateEventFlags(const sh_pollHandle_t handle, const short events); - am_Error_e addTimer(const timespec & timeouts, IAmShTimerCallBack* callback, sh_timerHandle_t& handle, void * userData, -#ifndef WITH_TIMERFD - const bool __attribute__((__unused__)) repeats = false -#else - const bool repeats = false -#endif - ); - am_Error_e addTimer(const timespec & timeouts, std::function callback, sh_timerHandle_t& handle, void* userData, + VectorListPollfd_t mfdPollingArray; //! mListTimer; //! mListActiveTimer; //! mSetPollKeys; //!A set of all used ppoll keys - VectorListPoll_t mListPoll; //! mSetTimerKeys; //!A set of all used timer keys - std::list mListTimer; //! mListActiveTimer; //! prepare, std::function fired, + std::function check, std::function dispatch, void* userData, sh_pollHandle_t& handle); + + am_Error_e addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void* userData, sh_pollHandle_t& handle); + am_Error_e removeFDPoll(const sh_pollHandle_t handle); + am_Error_e updateEventFlags(const sh_pollHandle_t handle, const short events); + am_Error_e addSignalHandler(std::function callback, sh_pollHandle_t& handle, void * userData); + am_Error_e removeSignalHandler(const sh_pollHandle_t handle); + am_Error_e addTimer(const timespec & timeouts, IAmShTimerCallBack* callback, sh_timerHandle_t& handle, void * userData, #ifndef WITH_TIMERFD - timespec mStartTime; //! callback, sh_timerHandle_t& handle, void* userData, +#ifndef WITH_TIMERFD + const bool __attribute__((__unused__)) repeats = false +#else + const bool repeats = false #endif + ); + am_Error_e removeTimer(const sh_timerHandle_t handle); + am_Error_e restartTimer(const sh_timerHandle_t handle); + am_Error_e updateTimer(const sh_timerHandle_t handle, const timespec & timeouts); + am_Error_e stopTimer(const sh_timerHandle_t handle); + void start_listenting(); + void stop_listening(); + void exit_mainloop(); + + bool fatalErrorOccurred() { return ((mError&internal_error_codes_e::PIPE_ERROR)>0)||((mError&internal_error_codes_e::FD_ERROR)>0); } }; } /* namespace am */ diff --git a/AudioManagerUtilities/src/CAmSocketHandler.cpp b/AudioManagerUtilities/src/CAmSocketHandler.cpp index 44c041e..7c6fb9f 100644 --- a/AudioManagerUtilities/src/CAmSocketHandler.cpp +++ b/AudioManagerUtilities/src/CAmSocketHandler.cpp @@ -31,6 +31,7 @@ #include #include #include + #include "CAmDltWrapper.h" #include "CAmSocketHandler.h" @@ -44,38 +45,44 @@ namespace am CAmSocketHandler::CAmSocketHandler() : mPipe(), // mDispatchDone(1), // + mfdPollingArray(), // + mSetPollKeys(MAX_POLLHANDLE), // mListPoll(), // + mSetTimerKeys(MAX_TIMERHANDLE), mListTimer(), // mListActiveTimer(), // - mLastInsertedHandle(0), // - mLastInsertedPollHandle(0), // - mRecreatePollfds(true) + mSetSignalhandlerKeys(MAX_POLLHANDLE), // + mSignalHandlers(), // + mRecreatePollfds(true), + mError(internal_error_codes_e::NO_ERROR) #ifndef WITH_TIMERFD ,mStartTime() // #endif { if (pipe(mPipe) == -1) { + mError = internal_error_codes_e::PIPE_ERROR; logError("Sockethandler could not create pipe!"); } - //add the pipe to the poll - nothing needs to be proccessed here we just need the pipe to trigger the ppoll + //add the pipe to the poll - nothing needs to be processed here we just need the pipe to trigger the ppoll short event = 0; sh_pollHandle_t handle; event |= POLLIN; - addFDPoll(mPipe[0], event, NULL, [](const pollfd pollfd, const sh_pollHandle_t, void*) + if (addFDPoll(mPipe[0], event, NULL, [](const pollfd pollfd, const sh_pollHandle_t, void*) {}, [](const sh_pollHandle_t, void*) - { return (false);}, NULL, NULL, handle); + { return (false);}, NULL, NULL, handle) != E_OK) + mError |= internal_error_codes_e::FD_ERROR; + if (addSignalFd() != E_OK) + mError |= internal_error_codes_e::SFD_ERROR; } CAmSocketHandler::~CAmSocketHandler() { -#ifdef WITH_TIMERFD - for (auto it : mListTimer) + for (auto it : mListPoll) { - close(it.fd); + close(it.pollfdValue.fd); } -#endif close(mPipe[0]); close(mPipe[1]); } @@ -213,6 +220,72 @@ namespace am ssize_t result = write(mPipe[1], &p, sizeof(p)); } + /** + * Adds a signal handler filedescriptor to the polling loop + * + */ + am_Error_e CAmSocketHandler::addSignalFd() + { + sh_pollHandle_t handle; + int fdErr; + sigset_t sigset; + + /* Create a sigset of all the signals that we're interested in */ + fdErr = sigemptyset(&sigset); + if (fdErr != 0) + { + logError("Could not create sigset!"); + return (E_NOT_POSSIBLE); + } + fdErr = sigaddset(&sigset, SIGINT); + if (fdErr != 0) + logWarning("Could not add SIGINT"); + fdErr = sigaddset(&sigset, SIGHUP); + if (fdErr != 0) + logWarning("Could not add SIGHUP"); + fdErr = sigaddset(&sigset, SIGQUIT); + if (fdErr != 0) + logWarning("Could not add SIGQUIT"); + fdErr = sigaddset(&sigset, SIGTERM); + if (fdErr != 0) + logWarning("Could not add SIGTERM"); + fdErr = sigaddset(&sigset, SIGCHLD); + if (fdErr != 0) + logWarning("Could not add SIGCHLD"); + + /* We must block the signals in order for signalfd to receive them */ + fdErr = sigprocmask(SIG_BLOCK, &sigset, NULL); + if (fdErr != 0) + { + logError("Could not block signals! They must be blocked in order to receive them!"); + return (E_NOT_POSSIBLE); + } + + /* Create the signalfd */ + int signalHandlerFd = signalfd(-1, &sigset, 0); + if (signalHandlerFd == -1) + { + logError("Could not open signal fd!"); + return (E_NOT_POSSIBLE); + } + + auto actionPoll = [this](const pollfd pollfd, const sh_pollHandle_t, void*) + { + const VectorSignalHandlers_t & signalHandlers = mSignalHandlers; + /* We have a valid signal, read the info from the fd */ + struct signalfd_siginfo info; + ssize_t bytes = read(pollfd.fd, &info, sizeof(info)); + assert(bytes == sizeof(info)); + + /* We have a valid signal, read the info from the fd */ + for(auto it: signalHandlers) + it.callback(it.handle, info, it.userData); + }; + /* We're going to add the signal fd through addFDPoll. At this point we don't have any signal listeners. */ + return addFDPoll(signalHandlerFd, POLLIN | POLLERR | POLLHUP, NULL, actionPoll, [](const sh_pollHandle_t, void*) + { return (false);}, NULL, NULL, handle); + } + /** * Adds a filedescriptor to the polling loop * @param fd the filedescriptor @@ -234,27 +307,15 @@ namespace am return (E_NON_EXISTENT); //create a new handle for the poll - sh_pollHandle_t lastHandle(mLastInsertedPollHandle); - do + if (!nextHandle(mSetPollKeys)) { - ++mLastInsertedPollHandle; - if (mLastInsertedPollHandle == MAX_POLLHANDLE) - { - mLastInsertedPollHandle = 1; - } - if (mLastInsertedPollHandle == lastHandle) - { - logError("Could not create new polls, too many open!"); - return (E_NOT_POSSIBLE); - } - - } while (mSetPollKeys.find(mLastInsertedPollHandle) != mSetPollKeys.end()); - - mSetPollKeys.insert(mLastInsertedPollHandle); + logError("Could not create new polls, too many open!"); + return (E_NOT_POSSIBLE); + } sh_poll_s pollData; pollData.pollfdValue.fd = fd; - pollData.handle = mLastInsertedPollHandle; + pollData.handle = mSetPollKeys.lastUsedID; pollData.pollfdValue.events = event; pollData.pollfdValue.revents = 0; pollData.prepareCB = prepare; @@ -269,6 +330,7 @@ namespace am handle = pollData.handle; return (E_OK); + } /** @@ -317,7 +379,7 @@ namespace am if (iterator->handle == handle) { iterator = mListPoll.erase(iterator); - mSetPollKeys.erase(handle); + mSetPollKeys.pollHandles.erase(handle); mRecreatePollfds = true; return (E_OK); } @@ -325,6 +387,50 @@ namespace am return (E_UNKNOWN); } + /** + * Adds a callback for any signals + * @param callback + * @param handle the handle of this poll + * @param userData a pointer to userdata that is always passed around + * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid + */ + am_Error_e CAmSocketHandler::addSignalHandler(std::function callback, sh_pollHandle_t& handle, void * userData) + { + if (!nextHandle(mSetSignalhandlerKeys)) + { + logError("Could not create new polls, too many open!"); + return (E_NOT_POSSIBLE); + } + + mSignalHandlers.emplace_back(); + mSignalHandlers.back().callback = callback; + mSignalHandlers.back().handle = mSetSignalhandlerKeys.lastUsedID; + mSignalHandlers.back().userData = userData; + handle = mSetSignalhandlerKeys.lastUsedID; + + return E_OK; + } + + /** + * removes a signal handler from the list + * @param handle is signal handler id + * @return E_OK in case of success, E_UNKNOWN if the handler was not found. + */ + am_Error_e CAmSocketHandler::removeSignalHandler(const sh_pollHandle_t handle) + { + VectorSignalHandlers_t::iterator it(mSignalHandlers.begin()); + for (; it != mSignalHandlers.end(); ++it) + { + if (it->handle == handle) + { + it = mSignalHandlers.erase(it); + mSetSignalhandlerKeys.pollHandles.erase(handle); + return (E_OK); + } + } + return (E_UNKNOWN); + } + /** * adds a timer to the list of timers. The callback will be fired when the timer is up. * This is not a high precise timer, it is very coarse. It is meant to be used for timeouts when waiting @@ -356,25 +462,14 @@ namespace am #ifndef WITH_TIMERFD //create a new handle for the timer - sh_timerHandle_t lastTimerHandle(mLastInsertedHandle); - do + if (!nextHandle(mSetTimerKeys)) { - ++mLastInsertedHandle; - if (mLastInsertedHandle == MAX_TIMERHANDLE) - { - mLastInsertedHandle = 1; - } - if (lastTimerHandle==mLastInsertedHandle) - { - logError("Could not create new timers, too many open!"); - mListTimer.pop_back(); - return (E_NOT_POSSIBLE); - } - - }while (mSetTimerKeys.find(mLastInsertedHandle) != mSetTimerKeys.end()); - - mSetTimerKeys.insert(mLastInsertedHandle); - handle=mLastInsertedHandle; + logError("Could not create new timers, too many open!"); + mListTimer.pop_back(); + return (E_NOT_POSSIBLE); + } + //create a new handle for the timer + handle = mSetTimerKeys.lastUsedID; timerItem.countdown = timeouts; timerItem.callback = callback; @@ -473,7 +568,7 @@ namespace am if (it->handle == handle) { it = mListTimer.erase(it); - mSetTimerKeys.erase(handle); + mSetTimerKeys.pollHandles.erase(handle); return (E_OK); } } @@ -911,5 +1006,29 @@ namespace am } } + bool CAmSocketHandler::nextHandle(sh_identifier_s & handle) + { + //create a new handle for the poll + const sh_pollHandle_t lastHandle(handle.lastUsedID); + do + { + ++handle.lastUsedID; + if (handle.lastUsedID == handle.limit) + { + handle.lastUsedID = 1; + } + if (handle.lastUsedID == lastHandle) + { + logError("Could not create new polls, too many open!"); + return (false); + } + + } while (handle.pollHandles.find(handle.lastUsedID) != handle.pollHandles.end()); + + handle.pollHandles.insert(handle.lastUsedID); + + return (true); + } + } diff --git a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp index d443c89..af21f90 100644 --- a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp +++ b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp @@ -80,6 +80,35 @@ void am::CAmTimerSockethandlerController::timerCallback(sh_timerHandle_t handle, mpSocketHandler->stop_listening(); } +CAmTimerSignalHandler::CAmTimerSignalHandler(CAmSocketHandler *myHandler, const timespec &timeout, const std::set & signals) : + MockIAmTimerCb(), mIndex(0), mSignals(signals), mpSocketHandler(myHandler), mUpdateTimeout(timeout), pTimerCallback(this, &CAmTimerSignalHandler::timerCallback) +{ + +} + +am::CAmTimerSignalHandler::~CAmTimerSignalHandler() +{ +} + +void am::CAmTimerSignalHandler::timerCallback(sh_timerHandle_t handle, void* userData) +{ + MockIAmTimerCb::timerCallback(handle, userData); + if(mIndex::iterator it = mSignals.begin(); + std::advance(it, mIndex); + kill(getpid(), *it); + mIndex++; + +#ifndef WITH_TIMERFD + mpSocketHandler->updateTimer( handle, mUpdateTimeout); +#endif + } + else + mpSocketHandler->stop_listening(); + +} + CAmTimer::CAmTimer(CAmSocketHandler *myHandler, const timespec &timeout, const int32_t repeats) : MockIAmTimerCb(), mpSocketHandler(myHandler), mUpdateTimeout(timeout), pTimerCallback(this, &CAmTimer::timerCallback), mRepeats(repeats) { @@ -178,6 +207,7 @@ void* playWithUnixSocketServer(void* data) TEST(CAmSocketHandlerTest, timersOneshot) { CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); timespec timeoutTime; timeoutTime.tv_sec = 1; timeoutTime.tv_nsec = 0; @@ -194,7 +224,11 @@ TEST(CAmSocketHandlerTest, timersOneshot) sh_timerHandle_t handle; myHandler.addTimer(timeoutTime, &testCallback1.pTimerCallback, handle, &userData); - +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 3); +#endif EXPECT_CALL(testCallback1,timerCallback(handle,&userData)).Times(1); timespec timeout4; @@ -203,6 +237,11 @@ TEST(CAmSocketHandlerTest, timersOneshot) CAmTimerSockethandlerController testCallback4(&myHandler, timeout4); myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 2); +#else + ASSERT_EQ(handle, 4); +#endif EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); myHandler.start_listenting(); } @@ -210,6 +249,7 @@ TEST(CAmSocketHandlerTest, timersOneshot) TEST(CAmSocketHandlerTest, timersStop) { CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); timespec timeoutTime; timeoutTime.tv_sec = 1; timeoutTime.tv_nsec = 0; @@ -226,7 +266,11 @@ TEST(CAmSocketHandlerTest, timersStop) sh_timerHandle_t handle; myHandler.addTimer(timeoutTime, &testCallback1.pTimerCallback, handle, &userData, true); - +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 3); +#endif EXPECT_CALL(testCallback1,timerCallback(handle,&userData)).Times(4); timespec timeout4; @@ -235,6 +279,11 @@ TEST(CAmSocketHandlerTest, timersStop) CAmTimerSockethandlerController testCallback4(&myHandler, timeout4); myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 2); +#else + ASSERT_EQ(handle, 4); +#endif EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); myHandler.start_listenting(); } @@ -242,6 +291,8 @@ TEST(CAmSocketHandlerTest, timersStop) TEST(CAmSocketHandlerTest, timersGeneral) { CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); + timespec timeoutTime; timeoutTime.tv_sec = 1; timeoutTime.tv_nsec = 0; @@ -258,7 +309,11 @@ TEST(CAmSocketHandlerTest, timersGeneral) sh_timerHandle_t handle; myHandler.addTimer(timeoutTime, &testCallback1.pTimerCallback, handle, &userData, true); - +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 3); +#endif EXPECT_CALL(testCallback1,timerCallback(handle,&userData)).Times(4); //+1 because of measurment timespec timeout4; @@ -267,6 +322,11 @@ TEST(CAmSocketHandlerTest, timersGeneral) CAmTimerSockethandlerController testCallback4(&myHandler, timeout4); myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 2); +#else + ASSERT_EQ(handle, 4); +#endif EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); myHandler.start_listenting(); } @@ -274,7 +334,7 @@ TEST(CAmSocketHandlerTest, timersGeneral) TEST(CAmSocketHandlerTest,playWithTimers) { CAmSocketHandler myHandler; - + ASSERT_FALSE(myHandler.fatalErrorOccurred()); timespec timeoutTime, timeout2, timeout3, timeout4; timeoutTime.tv_sec = 1; timeoutTime.tv_nsec = 34000000; @@ -293,20 +353,93 @@ TEST(CAmSocketHandlerTest,playWithTimers) sh_timerHandle_t handle; myHandler.addTimer(timeoutTime, &testCallback1.pTimerCallback, handle, NULL, true); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 3); +#endif EXPECT_CALL(testCallback1,timerCallback(handle,NULL)).Times(AnyNumber()); myHandler.addTimer(timeout2, &testCallback2.pTimerCallback, handle, NULL, true); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 2); +#else + ASSERT_EQ(handle, 4); +#endif EXPECT_CALL(testCallback2,timerCallback(handle,NULL)).Times(AnyNumber()); myHandler.addTimer(timeout3, &testCallback3.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 3); +#else + ASSERT_EQ(handle, 5); +#endif EXPECT_CALL(testCallback3,timerCallback(handle,NULL)).Times(2); //+1 because of measurment myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 4); +#else + ASSERT_EQ(handle, 6); +#endif EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); myHandler.start_listenting(); } +TEST(CAmSocketHandlerTest, signalHandler) +{ + CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); + sh_pollHandle_t signalHandler1, signalHandler2; + MockIAmSignalHandler mock; + std::string userData = "User data"; + myHandler.addSignalHandler([&](const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData) + { + unsigned sig = info.ssi_signo; + mock.signalHandlerAction(handle, sig, userData); +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT + unsigned user = info.ssi_uid; + std::cout<<"signal handler was called from user "<< user << " with signal " << sig << std::endl; +#endif + }, signalHandler1, &userData); + ASSERT_EQ(signalHandler1, 1); + myHandler.addSignalHandler([&](const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData) + { + unsigned sig = info.ssi_signo; + mock.signalHandlerAction(handle, sig, userData); + #ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT + unsigned user = info.ssi_uid; + std::cout<<"signal handler was called from user "<< user << " with signal " << sig << std::endl; + #endif + }, signalHandler2, &userData); + ASSERT_EQ(signalHandler2, 2); + timespec timeout4; + timeout4.tv_nsec = 200000000; + timeout4.tv_sec = 0; + std::set signals; + signals.insert(SIGHUP); + signals.insert(SIGINT); + signals.insert(SIGTERM); + signals.insert(SIGQUIT); + + CAmTimerSignalHandler testCallback4(&myHandler, timeout4, signals); + sh_timerHandle_t handle; + + myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL, true); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 3); +#endif + EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(signals.size()+1); + for(auto it: signals) + EXPECT_CALL(mock,signalHandlerAction(signalHandler1,it,&userData)).Times(1); + for(auto it: signals) + EXPECT_CALL(mock,signalHandlerAction(signalHandler2,it,&userData)).Times(1); + myHandler.start_listenting(); +} + TEST(CAmSocketHandlerTest,playWithUNIXSockets) { pthread_t serverThread; @@ -314,6 +447,7 @@ TEST(CAmSocketHandlerTest,playWithUNIXSockets) int socket_; CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); CAmSamplePlugin::sockType_e type = CAmSamplePlugin::UNIX; CAmSamplePlugin myplugin(&myHandler, type); @@ -360,6 +494,7 @@ TEST(CAmSocketHandlerTest,playWithSockets) int socket_; CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); CAmSamplePlugin::sockType_e type = CAmSamplePlugin::INET; CAmSamplePlugin myplugin(&myHandler, type); diff --git a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.h b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.h index 63f79cf..d38f8c1 100644 --- a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.h +++ b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.h @@ -47,6 +47,15 @@ namespace am virtual void timerCallback(sh_timerHandle_t handle, void * userData)=0; }; + class IAmSignalHandler + { + public: + virtual ~IAmSignalHandler() + { + } + virtual void signalHandlerAction(const sh_pollHandle_t handle, const unsigned sig, void* userData)=0; + }; + class IAmSocketHandlerCb { public: @@ -65,6 +74,12 @@ namespace am void(sh_timerHandle_t handle, void *userData)); }; + class MockIAmSignalHandler: public IAmSignalHandler + { + public: + MOCK_METHOD3(signalHandlerAction, void (const sh_pollHandle_t handle, const unsigned sig, void* userData)); + }; + class MockSocketHandlerCb: public IAmSocketHandlerCb { public: @@ -116,6 +131,21 @@ namespace am TAmShTimerCallBack pTimerCallback; }; + class CAmTimerSignalHandler: public MockIAmTimerCb + { + unsigned mIndex; + std::set mSignals; + CAmSocketHandler *mpSocketHandler; + timespec mUpdateTimeout; + public: + explicit CAmTimerSignalHandler(CAmSocketHandler *SocketHandler, const timespec &timeout, const std::set & signals); + virtual ~CAmTimerSignalHandler(); + + void timerCallback(sh_timerHandle_t handle, void * userData); + + TAmShTimerCallBack pTimerCallback; + }; + class CAmTimer: public MockIAmTimerCb { CAmSocketHandler *mpSocketHandler; -- cgit v1.2.1