summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksandar Donchev <Aleksander.Donchev@partner.bmw.de>2017-04-10 14:01:37 +0200
committerChristian Linke <christian.linke@bmw.de>2017-05-02 06:25:51 -0700
commit5abcd3990b5b516a031e21598dac6116a2086749 (patch)
treea829416f2179fffeeac27e3c6d0e6a415c6a1925
parent8f2d32de915abd07dee07de9cbc8b679e947e8ba (diff)
downloadaudiomanager-5abcd3990b5b516a031e21598dac6116a2086749.tar.gz
Signal handling via main loop with signalfd.
Signed-off-by: Christian Linke <christian.linke@bmw.de> Change-Id: I8c4c2c436ac9fcd61c76a21145c731f327cab0c1
-rw-r--r--AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.cpp2
-rw-r--r--AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.h3
-rwxr-xr-xAudioManagerDaemon/src/main.cpp93
-rw-r--r--AudioManagerUtilities/include/CAmSocketHandler.h136
-rw-r--r--AudioManagerUtilities/src/CAmSocketHandler.cpp213
-rw-r--r--AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp143
-rw-r--r--AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.h30
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<IAmDatabaseHandler*>( &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<std::string> plistRoutingPluginDirs;
std::vector<std::string> 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 <signal.h>
#include <vector>
#include <functional>
+#include <sys/signalfd.h>
#include <audiomanagerconfig.h>
#include "audiomanagertypes.h"
@@ -281,50 +282,59 @@ namespace am
}
};
- typedef std::reverse_iterator<sh_timer_s> rListTimerIter; //!<typedef for reverseiterator on timer lists
+ struct sh_signal_s
+ {
+ sh_pollHandle_t handle; //!<handle to uniquely adress a filedesriptor
+ std::function<void(const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData)> callback;
+ void* userData;
+ sh_signal_s() :
+ handle(0), callback(), userData(0)
+ {
+ }
+ };
+ struct sh_identifier_s
+ {
+ std::set<sh_pollHandle_t> 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<sh_timer_s> rListTimerIter; //!<typedef for reverseiterator on timer lists
typedef std::vector<pollfd> VectorListPollfd_t; //!<vector of filedescriptors
typedef std::vector<sh_poll_s> VectorListPoll_t; //!<list for the callbacks
+ typedef std::vector<sh_signal_s> VectorSignalHandlers_t; //!<list for the callbacks
- public:
-
- CAmSocketHandler();
- ~CAmSocketHandler();
+ typedef enum:uint8_t
+ {
+ NO_ERROR = 0u, // OK
+ PIPE_ERROR = 1u, // Pipe error
+ FD_ERROR = 2u, // Invalid file descriptor
+ SFD_ERROR = 4u // Signal file descriptor error
+ } internal_error_codes_e;
+ typedef uint8_t internal_error_codes_t;
- am_Error_e addFDPoll(const int fd, const short event, std::function<void(const sh_pollHandle_t handle, void* userData)> prepare, std::function<void(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)> fired,
- std::function<bool(const sh_pollHandle_t handle, void* userData)> check, std::function<bool(const sh_pollHandle_t handle, void* userData)> 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<void(const sh_timerHandle_t handle, void* userData)> callback, sh_timerHandle_t& handle, void* userData,
+ VectorListPollfd_t mfdPollingArray; //!<the polling array for ppoll
+ sh_identifier_s mSetPollKeys; //!A set of all used ppoll keys
+ VectorListPoll_t mListPoll; //!<list that holds all information for the ppoll
+ sh_identifier_s mSetTimerKeys; //!A set of all used timer keys
+ std::list<sh_timer_s> mListTimer; //!<list of all timers
+ std::list<sh_timer_s> mListActiveTimer; //!<list of all currently active timers
+ sh_identifier_s mSetSignalhandlerKeys; //!A set of all used signal handler keys
+ VectorSignalHandlers_t mSignalHandlers;
+ bool mRecreatePollfds; //!<when this is true, the poll list needs to be recreated
+ internal_error_codes_t mError;
#ifndef WITH_TIMERFD
- const bool __attribute__((__unused__)) repeats = false
-#else
- const bool repeats = false
+ timespec mStartTime; //!<here the actual time is saved for timecorrection
#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();
-
private:
-
- static CAmSocketHandler* mInstance;
- int mPipe[2];
- int mDispatchDone; //this starts / stops the mainloop
-
bool fdIsValid(const int fd) const;
timespec* insertTime(timespec& buffertime);
@@ -462,18 +472,54 @@ namespace am
*/
inline static void callTimer(sh_timer_s& a);
- VectorListPollfd_t mfdPollingArray; //!<the polling array for ppoll
- std::set<sh_pollHandle_t> mSetPollKeys; //!A set of all used ppoll keys
- VectorListPoll_t mListPoll; //!<list that holds all information for the ppoll
- std::set<sh_timerHandle_t> mSetTimerKeys; //!A set of all used timer keys
- std::list<sh_timer_s> mListTimer; //!<list of all timers
- std::list<sh_timer_s> mListActiveTimer; //!<list of all currently active timers
- sh_timerHandle_t mLastInsertedHandle; //!<keeps track of the last inserted timer handle
- sh_pollHandle_t mLastInsertedPollHandle; //!<keeps track of the last inserted poll handle
- bool mRecreatePollfds; //!<when this is true, the poll list needs to be recreated
+ /**
+ * install the signal fd
+ */
+
+ am_Error_e addSignalFd();
+ /**
+ * next handle id
+ * @param std::set handles
+ * @return handle
+ */
+ bool nextHandle(sh_identifier_s & handle);
+
+ public:
+
+ CAmSocketHandler();
+ ~CAmSocketHandler();
+
+ am_Error_e addFDPoll(const int fd, const short event, std::function<void(const sh_pollHandle_t handle, void* userData)> prepare, std::function<void(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)> fired,
+ std::function<bool(const sh_pollHandle_t handle, void* userData)> check, std::function<bool(const sh_pollHandle_t handle, void* userData)> 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<void(const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData)> 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; //!<here the actual time is saved for timecorrection
+ const bool __attribute__((__unused__)) repeats = false
+#else
+ const bool repeats = false
+#endif
+ );
+ am_Error_e addTimer(const timespec & timeouts, std::function<void(const sh_timerHandle_t handle, void* userData)> 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 <features.h>
#include <csignal>
#include <unistd.h>
+
#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]);
}
@@ -214,6 +221,72 @@ namespace am
}
/**
+ * 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
* @param event the event flags
@@ -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);
}
@@ -326,6 +388,50 @@ namespace am
}
/**
+ * 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<void(const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData)> 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
* for an answer via a filedescriptor.
@@ -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<unsigned> & 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<mSignals.size())
+ {
+ std::set<unsigned>::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<unsigned> 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<CAmTimerSockethandlerController> pTimerCallback;
};
+ class CAmTimerSignalHandler: public MockIAmTimerCb
+ {
+ unsigned mIndex;
+ std::set<unsigned> mSignals;
+ CAmSocketHandler *mpSocketHandler;
+ timespec mUpdateTimeout;
+ public:
+ explicit CAmTimerSignalHandler(CAmSocketHandler *SocketHandler, const timespec &timeout, const std::set<unsigned> & signals);
+ virtual ~CAmTimerSignalHandler();
+
+ void timerCallback(sh_timerHandle_t handle, void * userData);
+
+ TAmShTimerCallBack<CAmTimerSignalHandler> pTimerCallback;
+ };
+
class CAmTimer: public MockIAmTimerCb
{
CAmSocketHandler *mpSocketHandler;