summaryrefslogtreecommitdiff
path: root/AudioManagerUtilities/src/CAmSocketHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'AudioManagerUtilities/src/CAmSocketHandler.cpp')
-rw-r--r--AudioManagerUtilities/src/CAmSocketHandler.cpp925
1 files changed, 678 insertions, 247 deletions
diff --git a/AudioManagerUtilities/src/CAmSocketHandler.cpp b/AudioManagerUtilities/src/CAmSocketHandler.cpp
index 1092198..7b0fc5d 100644
--- a/AudioManagerUtilities/src/CAmSocketHandler.cpp
+++ b/AudioManagerUtilities/src/CAmSocketHandler.cpp
@@ -15,13 +15,13 @@
*
*
* \author Christian Linke, christian.linke@bmw.de BMW 2011,2012
+ * \author Aleksandar Donchev, aleksander.donchev@partner.bmw.de BMW 2017
*
* \file CAmSocketHandler.cpp
* For further information see http://www.genivi.org/.
*
*/
-#include "CAmSocketHandler.h"
#include <cassert>
#include <sys/fcntl.h>
#include <sys/errno.h>
@@ -31,80 +31,111 @@
#include <features.h>
#include <csignal>
#include <unistd.h>
+
#include "CAmDltWrapper.h"
+#include "CAmSocketHandler.h"
+
+#ifdef WITH_TIMERFD
+#include <sys/timerfd.h>
+#endif
namespace am
{
CAmSocketHandler::CAmSocketHandler() :
- receiverCallbackT(this, &CAmSocketHandler::receiverCallback),//
- checkerCallbackT(this, &CAmSocketHandler::checkerCallback),//
mPipe(), //
- mDispatchDone(1),//
- mListPoll(), //
- mListTimer(), //
- mListActiveTimer(), //
- mLastInsertedHandle(0), //
- mLastInsertedPollHandle(0), //
- mRecreatePollfds(true), //
- mStartTime() //
+ mDispatchDone(true), //
+ mSetPollKeys(MAX_POLLHANDLE), //
+ mListPoll(), //
+ mSetTimerKeys(MAX_TIMERHANDLE),
+ mListTimer(), //
+ mListActiveTimer(), //
+ mSetSignalhandlerKeys(MAX_POLLHANDLE), //
+ mSignalHandlers(), //
+ mRecreatePollfds(true),
+ mInternalCodes(internal_codes_e::NO_ERROR),
+ mSignalFdHandle(0)
+#ifndef WITH_TIMERFD
+,mStartTime() //
+#endif
{
if (pipe(mPipe) == -1)
{
+ mInternalCodes = internal_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, &receiverCallbackT, &checkerCallbackT, NULL, NULL, handle);
+ if (addFDPoll(mPipe[0], event, NULL, [](const pollfd pollfd, const sh_pollHandle_t, void*)
+ {}, [](const sh_pollHandle_t, void*)
+ { return (false);}, NULL, NULL, handle) != E_OK)
+ mInternalCodes |= internal_codes_e::FD_ERROR;
}
CAmSocketHandler::~CAmSocketHandler()
{
- close(mPipe[0]);
- close(mPipe[1]);
+ for (auto it : mListPoll)
+ {
+ close(it.pollfdValue.fd);
+ }
+ close(mPipe[0]);
+ close(mPipe[1]);
}
//todo: maybe have some: give me more time returned?
/**
- * start the block listening for filedescriptors. This is the mainloop.
- */
+ * start the block listening for filedescriptors. This is the mainloop.
+ */
void CAmSocketHandler::start_listenting()
{
- mDispatchDone = 0;
+ mDispatchDone = false;
int16_t pollStatus;
- //prepare the signalmask
- sigset_t sigmask;
- sigemptyset(&sigmask);
- sigaddset(&sigmask, SIGINT);
- sigaddset(&sigmask, SIGQUIT);
- sigaddset(&sigmask, SIGTERM);
- sigaddset(&sigmask, SIGHUP);
- sigaddset(&sigmask, SIGQUIT);
-
+#ifndef WITH_TIMERFD
clock_gettime(CLOCK_MONOTONIC, &mStartTime);
- while (!mDispatchDone)
+#endif
+ timespec buffertime;
+
+ std::list<sh_poll_s> listPoll;
+ VectorListPoll_t cloneListPoll;
+ VectorListPoll_t::iterator listmPollIt;
+ VectorListPollfd_t::iterator itMfdPollingArray;
+ VectorListPollfd_t fdPollingArray; //!<the polling array for ppoll
+
+ auto preparePollfd = [&](const sh_poll_s& row)
{
- //first we go through the registered filedescriptors and check if someone needs preparation:
- std::for_each(mListPoll.begin(), mListPoll.end(), CAmShCallPrep());
+ CAmSocketHandler::prepare((sh_poll_s&)row);
+ pollfd temp = row.pollfdValue;
+ temp.revents = 0;
+ fdPollingArray.push_back(temp);
+ };
+ while (!mDispatchDone)
+ {
if (mRecreatePollfds)
{
- mfdPollingArray.clear();
+ fdPollingArray.clear();
+ //freeze mListPoll by copying it - otherwise we get problems when we want to manipulate it during the next lines
+ cloneListPoll = mListPoll;
//there was a change in the setup, so we need to recreate the fdarray from the list
- std::for_each(mListPoll.begin(), mListPoll.end(), CAmShCopyPollfd(mfdPollingArray));
+ std::for_each(cloneListPoll.begin(), cloneListPoll.end(), preparePollfd);
mRecreatePollfds = false;
}
+ else
+ {
+ //first we go through the registered filedescriptors and check if someone needs preparation:
+ std::for_each(cloneListPoll.begin(), cloneListPoll.end(), CAmSocketHandler::prepare);
+ }
+#ifndef WITH_TIMERFD
timerCorrection();
-
+#endif
//block until something is on a filedescriptor
- timespec buffertime;
- if ((pollStatus = ppoll(&mfdPollingArray[0], mfdPollingArray.size(), insertTime(buffertime), &sigmask)) < 0)
+ if ((pollStatus = ppoll(&fdPollingArray[0], fdPollingArray.size(), insertTime(buffertime), NULL)) < 0)
{
if (errno == EINTR)
{
@@ -121,112 +152,223 @@ void CAmSocketHandler::start_listenting()
if (pollStatus != 0) //only check filedescriptors if there was a change
{
//todo: here could be a timer that makes sure naughty plugins return!
-
- //freeze mListPoll by copying it - otherwise we get problems when we want to manipulate it during the next lines
- std::list<sh_poll_s> listPoll;
- mListPoll_t::iterator listmPollIt;
-
- //remove all filedescriptors who did not fire
- std::vector<pollfd>::iterator it = mfdPollingArray.begin();
- do
+ listPoll.clear();
+ //stage 0+1, call firedCB
+ for (itMfdPollingArray = fdPollingArray.begin(); itMfdPollingArray != fdPollingArray.end(); itMfdPollingArray++)
{
- it = std::find_if(it, mfdPollingArray.end(), eventFired);
- if (it != mfdPollingArray.end())
- {
- listmPollIt = mListPoll.begin();
- std::advance(listmPollIt, std::distance(mfdPollingArray.begin(), it));
+ if (CAmSocketHandler::eventFired(*itMfdPollingArray))
+ {
+ listmPollIt = cloneListPoll.begin();
+ std::advance(listmPollIt, std::distance(fdPollingArray.begin(), itMfdPollingArray));
+
listPoll.push_back(*listmPollIt);
- listPoll.back().pollfdValue = *it;
- it++;
+ CAmSocketHandler::fire(*listmPollIt);
}
- } while (it != mfdPollingArray.end());
-
- //stage 1, call firedCB
- std::for_each(listPoll.begin(), listPoll.end(), CAmShCallFire());
-
+ }
+
//stage 2, lets ask around if some dispatching is necessary, the ones who need stay on the list
- listPoll.remove_if(noDispatching);
+ listPoll.remove_if(CAmSocketHandler::noDispatching);
//stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch..
do
{
- listPoll.remove_if(dispatchingFinished);
+ listPoll.remove_if(CAmSocketHandler::dispatchingFinished);
} while (!listPoll.empty());
}
+#ifndef WITH_TIMERFD
else //Timerevent
{
//this was a timer event, we need to take care about the timers
+ //find out the timedifference to starttime
timerUp();
}
+#endif
}
}
/**
- * exits the loop
- */
+ * exits the loop
+ */
void CAmSocketHandler::stop_listening()
{
- mDispatchDone = 1;
-
+ mDispatchDone = true;
+#ifndef WITH_TIMERFD
//this is for all running timers only - we need to handle the additional offset here
if (!mListActiveTimer.empty())
{
timespec currentTime, correctionTime;
clock_gettime(CLOCK_MONOTONIC, &currentTime);
correctionTime = timespecSub(currentTime, mStartTime);
- std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime));
+ std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), [&correctionTime](sh_timer_s& t)
+ { t.countdown = timespecSub(t.countdown, correctionTime);});
}
+#endif
+}
+
+void CAmSocketHandler::exit_mainloop()
+{
+ //end the while loop
+ stop_listening();
+
+ //fire the ending filedescriptor
+ int p(1);
+ ssize_t result = write(mPipe[1], &p, sizeof(p));
+}
+bool CAmSocketHandler::fatalErrorOccurred()
+{
+ return ((mInternalCodes&internal_codes_e::PIPE_ERROR)>0)||((mInternalCodes&internal_codes_e::FD_ERROR)>0);
+}
+
+am_Error_e CAmSocketHandler::getFDPollData(const sh_pollHandle_t handle, sh_poll_s & outPollData)
+{
+ VectorListPoll_t::iterator iterator = mListPoll.begin();
+ for (; iterator != mListPoll.end(); ++iterator)
+ {
+ if (iterator->handle == handle)
+ {
+ outPollData = *iterator;
+ return (E_OK);
+ }
+ }
+ return (E_UNKNOWN);
}
/**
- * Adds a filedescriptor to the polling loop
- * @param fd the filedescriptor
- * @param event the event flags
- * @param prepare a callback that is called before the loop is entered
- * @param fired a callback that is called when the filedescriptor needs to be read
- * @param check a callback that is called to check if further actions are neccessary
- * @param dispatch a callback that is called to dispatch the received data
- * @param userData a pointer to userdata that is always passed around
- * @param handle the handle of this poll
- * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid
- */
-am_Error_e CAmSocketHandler::addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void *userData, sh_pollHandle_t & handle)
+ * Adds a signal handler filedescriptor to the polling loop
+ *
+ */
+am_Error_e CAmSocketHandler::listenToSignals(const std::vector<uint8_t> & listSignals)
+{
+ int fdErr;
+ uint8_t addedSignals = 0;
+ sigset_t sigset;
+
+ if(0==listSignals.size())
+ {
+ logWarning("Empty signal list!");
+ return (E_NOT_POSSIBLE);
+ }
+
+ /* 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);
+ }
+
+ for(uint8_t itSignal : listSignals)
+ {
+ fdErr = sigaddset(&sigset, itSignal);
+ if (fdErr != 0)
+ logWarning("Could not add", itSignal);
+ else
+ addedSignals++;
+ }
+
+ if(0==addedSignals)
+ {
+ logWarning("None of the signals were added!");
+ return (E_NOT_POSSIBLE);
+ }
+
+ /* 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);
+ }
+
+ int signalHandlerFd;
+ if(mSignalFdHandle)
+ {
+ sh_poll_s sgPollData;
+ if(E_OK!=getFDPollData(mSignalFdHandle, sgPollData))
+ {
+ removeFDPoll(mSignalFdHandle);
+ mSignalFdHandle = 0;
+ }
+ else
+ {
+ int signalHandlerFd = signalfd(sgPollData.pollfdValue.fd, &sigset, 0);
+ if (signalHandlerFd == -1)
+ {
+ logError("Could not update signal fd!");
+ return (E_NOT_POSSIBLE);
+ }
+ return E_OK;
+ }
+ }
+
+ if(0==mSignalFdHandle)
+ {
+ /* Create the signalfd */
+ 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));
+
+ /* Notify all listeners */
+ 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. */
+ am_Error_e shFdError = addFDPoll(signalHandlerFd, POLLIN | POLLERR | POLLHUP, NULL, actionPoll, [](const sh_pollHandle_t, void*)
+ { return (false);}, NULL, NULL, mSignalFdHandle);
+ return shFdError;
+ }
+}
+
+/**
+ * Adds a filedescriptor to the polling loop
+ * @param fd the filedescriptor
+ * @param event the event flags
+ * @param prepare a std::function that is called before the loop is entered
+ * @param fired a std::function that is called when the filedescriptor needs to be read
+ * @param check a std::function that is called to check if further actions are neccessary
+ * @param dispatch a std::function that is called to dispatch the received data
+ * @param userData a pointer to userdata that is always passed around
+ * @param handle the handle of this poll
+ * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid
+ */
+
+am_Error_e CAmSocketHandler::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)
{
if (!fdIsValid(fd))
return (E_NON_EXISTENT);
-
- //create a new handle for the poll
- sh_pollHandle_t lastHandle(mLastInsertedPollHandle);
- do
+
+ //create a new handle for the poll
+ if (!nextHandle(mSetPollKeys))
{
- ++mLastInsertedPollHandle;
- if (mLastInsertedPollHandle == MAX_POLLHANDLE)
- {
- mLastInsertedPollHandle = 1;
- }
- if (mLastInsertedPollHandle==lastHandle)
- {
- logError(__func__,"Could not create new polls, too many open!");
- return (am_Error_e::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.userData = userData;
pollData.prepareCB = prepare;
pollData.firedCB = fired;
pollData.checkCB = check;
pollData.dispatchCB = dispatch;
-
+ pollData.userData = userData;
//add new data to the list
mListPoll.push_back(pollData);
@@ -234,23 +376,56 @@ am_Error_e CAmSocketHandler::addFDPoll(const int fd, const short event, IAmShPol
handle = pollData.handle;
return (E_OK);
+
}
/**
- * removes a filedescriptor from the poll loop
- * @param handle
- * @return
- */
+ * Adds a filedescriptor to the polling loop
+ * @param fd the filedescriptor
+ * @param event the event flags
+ * @param prepare a callback that is called before the loop is entered
+ * @param fired a callback that is called when the filedescriptor needs to be read
+ * @param check a callback that is called to check if further actions are neccessary
+ * @param dispatch a callback that is called to dispatch the received data
+ * @param userData a pointer to userdata that is always passed around
+ * @param handle the handle of this poll
+ * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid
+ */
+am::am_Error_e CAmSocketHandler::addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void *userData, sh_pollHandle_t & handle)
+{
+
+ std::function<void(const sh_pollHandle_t handle, void* userData)> prepareCB; //preperation callback
+ std::function<void(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)> firedCB; //fired callback
+ std::function<bool(const sh_pollHandle_t handle, void* userData)> checkCB; //check callback
+ std::function<bool(const sh_pollHandle_t handle, void* userData)> dispatchCB; //check callback
+
+ if (prepare)
+ prepareCB = std::bind(&IAmShPollPrepare::Call, prepare, std::placeholders::_1, std::placeholders::_2);
+ if (fired)
+ firedCB = std::bind(&IAmShPollFired::Call, fired, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
+ if (check)
+ checkCB = std::bind(&IAmShPollCheck::Call, check, std::placeholders::_1, std::placeholders::_2);
+ if (dispatch)
+ dispatchCB = std::bind(&IAmShPollDispatch::Call, dispatch, std::placeholders::_1, std::placeholders::_2);
+
+ return addFDPoll(fd, event, prepareCB, firedCB, checkCB, dispatchCB, userData, handle);
+}
+
+/**
+ * removes a filedescriptor from the poll loop
+ * @param handle
+ * @return
+ */
am_Error_e CAmSocketHandler::removeFDPoll(const sh_pollHandle_t handle)
{
- mListPoll_t::iterator iterator = mListPoll.begin();
+ VectorListPoll_t::iterator iterator = mListPoll.begin();
for (; iterator != mListPoll.end(); ++iterator)
{
if (iterator->handle == handle)
{
iterator = mListPoll.erase(iterator);
- mSetPollKeys.erase(handle);
+ mSetPollKeys.pollHandles.erase(handle);
mRecreatePollfds = true;
return (E_OK);
}
@@ -259,93 +434,232 @@ am_Error_e CAmSocketHandler::removeFDPoll(const sh_pollHandle_t handle)
}
/**
- * 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.
- * One time timer. If you need again a timer, you need to add a new timer in the callback of the old one.
- * @param timeouts timeouts time until the callback is fired
- * @param callback callback the callback
- * @param handle handle the handle that is created for the timer is returned. Can be used to remove the timer
- * @param userData pointer always passed with the call
- * @return E_OK in case of success
- */
-am_Error_e CAmSocketHandler::addTimer(const timespec timeouts, IAmShTimerCallBack* callback, sh_timerHandle_t& handle, void * userData)
+ * 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.
+ * One time timer. If you need again a timer, you need to add a new timer in the callback of the old one.
+ * @param timeouts timeouts time until the callback is fired
+ * @param callback callback the callback
+ * @param handle handle the handle that is created for the timer is returned. Can be used to remove the timer
+ * @param userData pointer always passed with the call
+ * @return E_OK in case of success
+ */
+
+am_Error_e CAmSocketHandler::addTimer(const timespec & timeouts, IAmShTimerCallBack* callback, sh_timerHandle_t& handle, void * userData, const bool repeats)
{
- assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0)));
assert(callback!=NULL);
- sh_timer_s timerItem;
+ std::function<void(const sh_timerHandle_t handle, void* userData)> callbackFunc;
+ callbackFunc = std::bind(&IAmShTimerCallBack::Call, callback, std::placeholders::_1, std::placeholders::_2);
+ return addTimer(timeouts, callbackFunc, handle, userData, repeats);
+}
+
+am_Error_e CAmSocketHandler::addTimer(const timespec & timeouts, std::function<void(const sh_timerHandle_t handle, void* userData)> callback, sh_timerHandle_t& handle, void * userData, const bool repeats)
+{
+ assert(!((timeouts.tv_sec == 0) && (timeouts.tv_nsec == 0)));
+
+ mListTimer.emplace_back();
+ sh_timer_s & timerItem = mListTimer.back();
+
+#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(__func__,"Could not create new timers, too many open!");
- return (am_Error_e::E_NOT_POSSIBLE);
- }
-
- } while (mSetTimerKeys.find(mLastInsertedHandle) != mSetTimerKeys.end());
-
- mSetTimerKeys.insert(mLastInsertedHandle);
- handle=mLastInsertedHandle;
- timerItem.handle = handle;
+ 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;
timerItem.userData = userData;
- mListTimer.push_back(timerItem);
+ timerItem.handle = handle;
//we add here the time difference between startTime and currenttime, because this time will be substracted later on in timecorrection
timespec currentTime;
clock_gettime(CLOCK_MONOTONIC, &currentTime);
- if (!mDispatchDone) //the mainloop is started
- timerItem.countdown = timespecAdd(timeouts, timespecSub(currentTime, mStartTime));
-
+ if (!mDispatchDone)//the mainloop is started
+ timerItem.countdown = timespecAdd(timeouts, timespecSub(currentTime, mStartTime));
+ mListTimer.push_back(timerItem);
mListActiveTimer.push_back(timerItem);
mListActiveTimer.sort(compareCountdown);
return (E_OK);
+
+#else
+ timerItem.countdown.it_value = timeouts;
+ if (repeats)
+ timerItem.countdown.it_interval = timeouts;
+ else
+ {
+ timespec zero;
+ zero.tv_sec = 0;
+ zero.tv_nsec = 0;
+ timerItem.countdown.it_interval = zero;
+ }
+
+ timerItem.fd = -1;
+ timerItem.userData = userData;
+ am_Error_e err = createTimeFD(timerItem.countdown, timerItem.fd);
+ if (err != E_OK)
+ {
+ mListTimer.pop_back();
+ return err;
+ }
+
+ static auto actionPoll = [](const pollfd pollfd, const sh_pollHandle_t handle, void* userData)
+ {
+ uint64_t mExpirations;
+ if (read(pollfd.fd, &mExpirations, sizeof(uint64_t)) == -1)
+ {
+ //error received...try again
+ read(pollfd.fd, &mExpirations, sizeof(uint64_t));
+ }
+ };
+
+ err = addFDPoll(timerItem.fd, POLLIN, NULL, actionPoll, [callback](const sh_pollHandle_t handle, void* userData)->bool
+ {
+ callback(handle, userData);
+ return false;
+ },
+ NULL, userData, handle);
+ if (E_OK == err)
+ {
+ timerItem.handle = handle;
+ }
+ else
+ {
+ mListTimer.pop_back();
+ }
+ return err;
+#endif
+
}
/**
- * removes a timer from the list of timers
- * @param handle the handle to the timer
- * @return E_OK in case of success, E_UNKNOWN if timer was not found.
- */
+ * removes a timer from the list of timers
+ * @param handle the handle to the timer
+ * @return E_OK in case of success, E_UNKNOWN if timer was not found.
+ */
am_Error_e CAmSocketHandler::removeTimer(const sh_timerHandle_t handle)
{
- assert(handle!=0);
+ assert(handle != 0);
//stop the current timer
- stopTimer(handle);
+#ifdef WITH_TIMERFD
+ std::list<sh_timer_s>::iterator it = mListTimer.begin();
+ for (; it != mListTimer.end(); ++it)
+ {
+ if (it->handle == handle)
+ break;
+ }
+ if (it == mListTimer.end())
+ return (E_NON_EXISTENT);
+ close(it->fd);
+ mListTimer.erase(it);
+ return removeFDPoll(handle);
+#else
+ stopTimer(handle);
std::list<sh_timer_s>::iterator it(mListTimer.begin());
for (; it != mListTimer.end(); ++it)
{
if (it->handle == handle)
{
it = mListTimer.erase(it);
- mSetTimerKeys.erase(handle);
+ mSetTimerKeys.pollHandles.erase(handle);
return (E_OK);
}
}
return (E_UNKNOWN);
+#endif
}
/**
- * restarts a timer and updates with a new interva
- * @param handle handle to the timer
- * @param timeouts new timout time
- * @return E_OK on success, E_NON_EXISTENT if the handle was not found
- */
-am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const timespec timeouts)
+ * restarts a timer and updates with a new interva
+ * @param handle handle to the timer
+ * @param timeouts new timout time
+ * @return E_OK on success, E_NON_EXISTENT if the handle was not found
+ */
+am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const timespec & timeouts)
{
+#ifdef WITH_TIMERFD
+ std::list<sh_timer_s>::iterator it = mListTimer.begin();
+ for (; it != mListTimer.end(); ++it)
+ {
+ if (it->handle == handle)
+ break;
+ }
+ if (it == mListTimer.end())
+ return (E_NON_EXISTENT);
+
+ if (it->countdown.it_interval.tv_nsec != 0 || it->countdown.it_interval.tv_sec != 0)
+ it->countdown.it_interval = timeouts;
+ it->countdown.it_value = timeouts;
+
+ if (!fdIsValid(it->fd))
+ {
+ am_Error_e err = createTimeFD(it->countdown, it->fd);
+ if (err != E_OK)
+ return err;
+ }
+ else
+ {
+ if (timerfd_settime(it->fd, 0, &it->countdown, NULL))
+ {
+ logError("Failed to set timer duration");
+ return E_NOT_POSSIBLE;
+ }
+ }
+#else
+
//update the mList ....
sh_timer_s timerItem;
std::list<sh_timer_s>::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin());
@@ -361,7 +675,7 @@ am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const ti
}
}
if (!found)
- return (E_NON_EXISTENT);
+ return (E_NON_EXISTENT);
found = false;
@@ -370,8 +684,8 @@ am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const ti
currentTime.tv_nsec=timeoutsCorrected.tv_nsec=0;
currentTime.tv_sec=timeoutsCorrected.tv_sec=0;
clock_gettime(CLOCK_MONOTONIC, &currentTime);
- if (!mDispatchDone) //the mainloop is started
- timeoutsCorrected = timespecAdd(timeouts, timespecSub(currentTime, mStartTime));
+ if (!mDispatchDone)//the mainloop is started
+ timeoutsCorrected = timespecAdd(timeouts, timespecSub(currentTime, mStartTime));
for (; activeIt != mListActiveTimer.end(); ++activeIt)
{
@@ -384,20 +698,48 @@ am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const ti
}
if (!found)
- timerItem.countdown = timeoutsCorrected;
+ timerItem.countdown = timeoutsCorrected;
mListActiveTimer.push_back(timerItem);
mListActiveTimer.sort(compareCountdown);
+
+#endif
return (E_OK);
}
/**
- * restarts a timer with the original value
- * @param handle
- * @return E_OK on success, E_NON_EXISTENT if the handle was not found
- */
+ * restarts a timer with the original value
+ * @param handle
+ * @return E_OK on success, E_NON_EXISTENT if the handle was not found
+ */
am_Error_e CAmSocketHandler::restartTimer(const sh_timerHandle_t handle)
{
+#ifdef WITH_TIMERFD
+ std::list<sh_timer_s>::iterator it = mListTimer.begin();
+ for (; it != mListTimer.end(); ++it)
+ {
+ if (it->handle == handle)
+ break;
+ }
+ if (it == mListTimer.end())
+ return (E_NON_EXISTENT);
+
+ if (!fdIsValid(it->fd))
+ {
+ am_Error_e err = createTimeFD(it->countdown, it->fd);
+ if (err != E_OK)
+ return err;
+ }
+ else
+ {
+ if (timerfd_settime(it->fd, 0, &it->countdown, NULL))
+ {
+ logError("Failed to set timer duration");
+ return E_NOT_POSSIBLE;
+ }
+ }
+#else
+
sh_timer_s timerItem; //!<the original timer value
//find the original value
std::list<sh_timer_s>::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin());
@@ -412,14 +754,14 @@ am_Error_e CAmSocketHandler::restartTimer(const sh_timerHandle_t handle)
}
}
if (!found)
- return (E_NON_EXISTENT);
+ return (E_NON_EXISTENT);
found = false;
//we add here the time difference between startTime and currenttime, because this time will be substracted later on in timecorrection
timespec currentTime, timeoutsCorrected;
clock_gettime(CLOCK_MONOTONIC, &currentTime);
- if (!mDispatchDone) //the mainloop is started
+ if (!mDispatchDone)//the mainloop is started
{
timeoutsCorrected = timespecAdd(timerItem.countdown, timespecSub(currentTime, mStartTime));
timerItem.countdown = timeoutsCorrected;
@@ -436,20 +778,41 @@ am_Error_e CAmSocketHandler::restartTimer(const sh_timerHandle_t handle)
}
if (!found)
- mListActiveTimer.push_back(timerItem);
+ mListActiveTimer.push_back(timerItem);
mListActiveTimer.sort(compareCountdown);
-
+#endif
return (E_OK);
}
/**
- * stops a timer
- * @param handle
- * @return E_OK on success, E_NON_EXISTENT if the handle was not found
- */
+ * stops a timer
+ * @param handle
+ * @return E_OK on success, E_NON_EXISTENT if the handle was not found
+ */
am_Error_e CAmSocketHandler::stopTimer(const sh_timerHandle_t handle)
{
+#ifdef WITH_TIMERFD
+ std::list<sh_timer_s>::iterator it = mListTimer.begin();
+ for (; it != mListTimer.end(); ++it)
+ {
+ if (it->handle == handle)
+ break;
+ }
+ if (it == mListTimer.end())
+ return (E_NON_EXISTENT);
+
+ itimerspec countdown = it->countdown;
+ countdown.it_value.tv_nsec = 0;
+ countdown.it_value.tv_sec = 0;
+
+ if (timerfd_settime(it->fd, 0, &countdown, NULL))
+ {
+ logError("Failed to set timer duration");
+ return E_NOT_POSSIBLE;
+ }
+ return (E_OK);
+#else
//go through the list and remove the timer with the handle
std::list<sh_timer_s>::iterator it(mListActiveTimer.begin());
for (; it != mListActiveTimer.end(); ++it)
@@ -461,17 +824,18 @@ am_Error_e CAmSocketHandler::stopTimer(const sh_timerHandle_t handle)
}
}
return (E_NON_EXISTENT);
+#endif
}
/**
- * updates the eventFlags of a poll
- * @param handle
- * @param events
- * @return @return E_OK on succsess, E_NON_EXISTENT if fd was not found
- */
+ * updates the eventFlags of a poll
+ * @param handle
+ * @param events
+ * @return @return E_OK on succsess, E_NON_EXISTENT if fd was not found
+ */
am_Error_e CAmSocketHandler::updateEventFlags(const sh_pollHandle_t handle, const short events)
{
- mListPoll_t::iterator iterator = mListPoll.begin();
+ VectorListPoll_t::iterator iterator = mListPoll.begin();
for (; iterator != mListPoll.end(); ++iterator)
{
@@ -486,27 +850,36 @@ am_Error_e CAmSocketHandler::updateEventFlags(const sh_pollHandle_t handle, cons
}
/**
- * checks if a filedescriptor is validCAmShSubstractTime
- * @param fd the filedescriptor
- * @return true if the fd is valid
- */
+ * checks if a filedescriptor is validCAmShSubstractTime
+ * @param fd the filedescriptor
+ * @return true if the fd is valid
+ */
bool CAmSocketHandler::fdIsValid(const int fd) const
{
return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
}
+#ifndef WITH_TIMERFD
/**
- * timer is up.
- */
+ * timer is up.
+ */
void CAmSocketHandler::timerUp()
{
//find out the timedifference to starttime
- timespec currentTime, diffTime;
+ static timespec currentTime, diffTime;
clock_gettime(CLOCK_MONOTONIC, &currentTime);
diffTime = timespecSub(currentTime, mStartTime);
+ static auto countdownUp = [&](const sh_timer_s& row)->bool
+ {
+ timespec sub = timespecSub(row.countdown, diffTime);
+ if (sub.tv_nsec == 0 && sub.tv_sec == 0)
+ return (true);
+ return (false);
+ };
+
//now we need to substract the diffTime from all timers and see if they are up
- std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownUp(diffTime));
+ std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), countdownUp);
//copy all fired timers into a list
std::vector<sh_timer_s> tempList(overflowIter, mListActiveTimer.rend());
@@ -516,28 +889,40 @@ void CAmSocketHandler::timerUp()
mListActiveTimer.erase(mListActiveTimer.begin(), it);
//call the callbacks for the timers
- std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer());
+ std::for_each(tempList.begin(), tempList.end(), CAmSocketHandler::callTimer);
}
/**
- * correct timers and fire the ones who are up
- */
+ * correct timers and fire the ones who are up
+ */
void CAmSocketHandler::timerCorrection()
{
//get the current time and calculate the correction value
- timespec currentTime, correctionTime;
+ static timespec currentTime, correctionTime;
clock_gettime(CLOCK_MONOTONIC, &currentTime);
correctionTime = timespecSub(currentTime, mStartTime);
mStartTime = currentTime;
+ static auto countdownZero = [](const sh_timer_s& row)->bool
+ {
+ if (row.countdown.tv_nsec == 0 && row.countdown.tv_sec == 0)
+ return (true);
+ return (false);
+ };
+
+ static auto substractTime = [&](sh_timer_s& t)
+ {
+ t.countdown = timespecSub(t.countdown, correctionTime);
+ };
+
if (!mListActiveTimer.empty())
{
//subtract the correction value from all items in the list
- std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime));
+ std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), substractTime);
//find the last occurrence of zero -> timer overflowed
- std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownZero());
+ std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), countdownZero);
//only if a timer overflowed
if (overflowIter != mListActiveTimer.rend())
@@ -550,100 +935,146 @@ void CAmSocketHandler::timerCorrection()
mListActiveTimer.erase(mListActiveTimer.begin(), it);
//call the callbacks for the timers
- std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer());
+ std::for_each(tempList.begin(), tempList.end(), CAmSocketHandler::callTimer);
}
}
}
+#endif
-void CAmSocketHandler::exit_mainloop()
+/**
+ * prepare for poll
+ */
+void CAmSocketHandler::prepare(am::CAmSocketHandler::sh_poll_s& row)
{
- //end the while loop
- stop_listening();
+ if (row.prepareCB)
+ {
+ try
+ {
+ row.prepareCB(row.handle, row.userData);
+ } catch (std::exception& e)
+ {
+ logError("Sockethandler: Exception in Preparecallback,caught", e.what());
+ }
+ }
+}
- //fire the ending filedescriptor
- int p(1);
- ssize_t result = write(mPipe[1], &p, sizeof(p));
+/**
+ * fire callback
+ */
+void CAmSocketHandler::fire(sh_poll_s& a)
+{
+ try
+ {
+ a.firedCB(a.pollfdValue, a.handle, a.userData);
+ } catch (std::exception& e)
+ {
+ logError("Sockethandler: Exception in Preparecallback,caught", e.what());
+ }
}
/**
- * is used to set the pointer for the ppoll command
- * @param buffertime
- * @return
- */
+ * should disptach
+ */
+bool CAmSocketHandler::noDispatching(const sh_poll_s& a)
+{
+ //remove from list of there is no checkCB
+ if (nullptr == a.checkCB)
+ return (true);
+ return (!a.checkCB(a.handle, a.userData));
+}
+
+/**
+ * disptach
+ */
+bool CAmSocketHandler::dispatchingFinished(const sh_poll_s& a)
+{
+ //remove from list of there is no dispatchCB
+ if (nullptr == a.dispatchCB)
+ return (true);
+ return (!a.dispatchCB(a.handle, a.userData));
+}
+
+/**
+ * event triggered
+ */
+bool CAmSocketHandler::eventFired(const pollfd& a)
+{
+ return (a.revents == 0 ? false : true);
+}
+
+/**
+ * is used to set the pointer for the ppoll command
+ * @param buffertime
+ * @return
+ */
inline timespec* CAmSocketHandler::insertTime(timespec& buffertime)
{
+#ifndef WITH_TIMERFD
if (!mListActiveTimer.empty())
{
buffertime = mListActiveTimer.front().countdown;
return (&buffertime);
}
else
+#endif
{
return (NULL);
}
}
-void CAmSocketHandler::CAmShCallFire::operator()(sh_poll_s& row)
-{
- try
- {
- row.firedCB->Call(row.pollfdValue, row.handle, row.userData);
- }
- catch (std::exception& e)
- {
- logError("Sockethandler: Exception in FireCallback,caught",e.what());
- }
-}
-
-void CAmSocketHandler::CAmShCallPrep::operator()(sh_poll_s& row)
+#ifdef WITH_TIMERFD
+am_Error_e CAmSocketHandler::createTimeFD(const itimerspec & timeouts, int & fd)
{
- if (row.prepareCB)
- {
- try
- {
- row.prepareCB->Call(row.handle, row.userData);
- }
- catch (std::exception& e)
- {
- logError("Sockethandler: Exception in Preparecallback,caught",e.what());
- }
- }
-}
+ fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
+ if (fd <= 0)
+ {
+ logError("Failed to create timer");
+ return E_NOT_POSSIBLE;
+ }
-void CAmSocketHandler::CAmShCallTimer::operator()(sh_timer_s& row)
-{
- try
- {
- row.callback->Call(row.handle, row.userData);
- }
- catch (std::exception& e)
- {
- logError("Sockethandler: Exception in Timercallback,caught",e.what());
- }
+ if (timerfd_settime(fd, 0, &timeouts, NULL))
+ {
+ logError("Failed to set timer duration");
+ return E_NOT_POSSIBLE;
+ }
+ return E_OK;
}
+#endif
-void CAmSocketHandler::CAmShCopyPollfd::operator()(const sh_poll_s& row)
+void CAmSocketHandler::callTimer(sh_timer_s& a)
{
- pollfd temp = row.pollfdValue;
- temp.revents = 0;
- mArray.push_back(temp);
+ try
+ {
+ a.callback(a.handle, a.userData);
+ } catch (std::exception& e)
+ {
+ logError("Sockethandler: Exception in Timercallback,caught", e.what());
+ }
}
-bool CAmSocketHandler::CAmShCountdownUp::operator()(const sh_timer_s& row)
+bool CAmSocketHandler::nextHandle(sh_identifier_s & handle)
{
- timespec sub = timespecSub(row.countdown, mDiffTime);
- if (sub.tv_nsec == 0 && sub.tv_sec == 0)
- return (true);
- return (false);
-}
+ //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);
+ }
-bool CAmSocketHandler::CAmShCountdownZero::operator()(const sh_timer_s& row)
-{
- if (row.countdown.tv_nsec == 0 && row.countdown.tv_sec == 0)
- return (true);
- return (false);
-}
+ } while (handle.pollHandles.find(handle.lastUsedID) != handle.pollHandles.end());
+ handle.pollHandles.insert(handle.lastUsedID);
+
+ return (true);
+}
}