From 551d34d6f69e7def9590f503f23dad220011f118 Mon Sep 17 00:00:00 2001 From: Aleksandar Donchev Date: Tue, 21 Feb 2017 15:11:15 +0100 Subject: Linux specific TIMERFD implementation as alternative timer mechanism Signed-off-by: Christian Linke --- AudioManagerUtilities/include/CAmSocketHandler.h | 814 ++++++++------- AudioManagerUtilities/src/CAmSocketHandler.cpp | 1172 +++++++++++++--------- CMakeLists.txt | 6 +- cmake/AudioManagerUtilitiesConfig.cmake.in | 1 + cmake/config.cmake.in | 1 + 5 files changed, 1133 insertions(+), 861 deletions(-) diff --git a/AudioManagerUtilities/include/CAmSocketHandler.h b/AudioManagerUtilities/include/CAmSocketHandler.h index 5c3c5ba..7ccfd16 100644 --- a/AudioManagerUtilities/include/CAmSocketHandler.h +++ b/AudioManagerUtilities/include/CAmSocketHandler.h @@ -4,6 +4,7 @@ * Copyright (C) 2012, BMW AG * * \author Christian Linke, christian.linke@bmw.de BMW 2011,2012 + * \author Aleksandar Donchev, aleksander.donchev@partner.bmw.de BMW 2017 * * \copyright * This Source Code Form is subject to the terms of the @@ -17,7 +18,6 @@ #ifndef SOCKETHANDLER_H_ #define SOCKETHANDLER_H_ -#include "audiomanagertypes.h" #include #include #include @@ -25,6 +25,19 @@ #include #include #include +#include +#include +#include "audiomanagertypes.h" + +#ifdef WITH_TIMERFD + +#include +#include +#include +#include +#include + +#endif namespace am { @@ -33,67 +46,79 @@ namespace am #define MAX_TIMERHANDLE INT16_MAX #define MAX_POLLHANDLE INT16_MAX -typedef uint16_t sh_timerHandle_t; //! class TAmShPollFired: public IAmShPollFired { private: @@ -103,14 +128,21 @@ public: public: TAmShPollFired(TClass* instance, void (TClass::*function)(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)) : mInstance(instance), // - mFunction(function) {}; + mFunction(function) + { + } + ; virtual void Call(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) { (*mInstance.*mFunction)(pollfd, handle, userData); - }; + } + ; }; + /** + * template for a callback + */ template class TAmShPollCheck: public IAmShPollCheck { private: @@ -120,367 +152,423 @@ public: public: TAmShPollCheck(TClass* instance, bool (TClass::*function)(const sh_pollHandle_t handle, void* userData)) : mInstance(instance), // - mFunction(function) {}; + mFunction(function) + { + } + ; virtual bool Call(const sh_pollHandle_t handle, void* userData) { return ((*mInstance.*mFunction)(handle, userData)); - }; + } + ; }; - CAmSocketHandler(); - ~CAmSocketHandler(); - - 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); - 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(); - void receiverCallback(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) - { - (void) pollfd; - (void) handle; - (void) userData; - }; - bool checkerCallback(const sh_pollHandle_t handle, void* userData) - { - (void) handle; - (void) userData; - return (false); - }; - - TAmShPollFired receiverCallbackT; - TAmShPollCheck checkerCallbackT; - -private: - - static CAmSocketHandler* mInstance; - int mPipe[2]; - int mDispatchDone; //this starts / stops the mainloop - struct sh_timer_s //! class TAmShPollDispatch: public IAmShPollDispatch { - sh_timerHandle_t handle; //! rListTimerIter; //! mListPollfd_t; //! mListPoll_t; //! class TAmShTimerCallBack: public IAmShTimerCallBack { - timespec result; + private: + TClass* mInstance; + void (TClass::*mFunction)(sh_timerHandle_t handle, void* userData); - if ((a.tv_sec < b.tv_sec) || ((a.tv_sec == b.tv_sec) && (a.tv_nsec <= b.tv_nsec))) + public: + TAmShTimerCallBack(TClass* instance, void (TClass::*function)(sh_timerHandle_t handle, void* userData)) : + IAmShTimerCallBack(), mInstance(instance), // + mFunction(function) { - result.tv_sec = result.tv_nsec = 0; } - else + ; + + virtual void Call(sh_timerHandle_t handle, void* userData) { - result.tv_sec = a.tv_sec - b.tv_sec; - if (a.tv_nsec < b.tv_nsec) - { - result.tv_nsec = a.tv_nsec + MAX_NS - b.tv_nsec; - result.tv_sec--; /* Borrow a second. */ - } - else - { - result.tv_nsec = a.tv_nsec - b.tv_nsec; - } + (*mInstance.*mFunction)(handle, userData); } - return (result); - } + }; /** - * adds timespec values - * @param a - * @param b - * @return the added values + * template for a callback */ - inline timespec timespecAdd(const timespec& a, const timespec& b) + template class TAmShPollPrepare: public IAmShPollPrepare { - timespec result; - result.tv_sec = a.tv_sec + b.tv_sec; - result.tv_nsec = a.tv_nsec + b.tv_nsec; - if (result.tv_nsec >= MAX_NS) + private: + TClass* mInstance; + void (TClass::*mFunction)(const sh_timerHandle_t handle, void* userData); + + public: + TAmShPollPrepare(TClass* instance, void (TClass::*function)(const sh_timerHandle_t handle, void* userData)) : + mInstance(instance), // + mFunction(function) { - result.tv_sec++; - result.tv_nsec = result.tv_nsec - MAX_NS; } - return (result); - } + ; - /** - * comapares timespec values - * @param a - * @param b - * @return - */ - inline int timespecCompare(const timespec& a, const timespec& b) - { - //less - if (a.tv_sec < b.tv_sec) - return (-1); - //greater - else if (a.tv_sec > b.tv_sec) - return (1); - //less - else if (a.tv_nsec < b.tv_nsec) - return (-1); - //greater - else if (a.tv_nsec > b.tv_nsec) - return (1); - //equal - return (0); - } + virtual void Call(const sh_timerHandle_t handle, void* userData) + { + (*mInstance.*mFunction)(handle, userData); + } + ; + }; /** - * functor to return all fired events - * @param a - * @return + * The am::CAmSocketHandler implements a mainloop for the AudioManager. Plugins and different parts of the AudioManager add their filedescriptors to the handler + * to get called on communication of the filedescriptors.\n + * More information can be found here : \ref mainl */ - inline static bool eventFired(const pollfd& a) + class CAmSocketHandler { - return (a.revents == 0 ? false : true); - } + struct sh_poll_s //!Call(a.handle, a.userData)); - } + struct sh_timer_s //!Call(a.handle, a.userData)); - } + typedef std::reverse_iterator rListTimerIter; //! mListPollfd_t; //! mListPoll_t; //!Call(handle, userData); + return false; + } + }; +#endif public: - CAmShCallTimer() {}; - void operator()(sh_timer_s& row); - }; - class CAmShCountdownUp //! mReceiverCallbackT; + TAmShPollCheck mCheckerCallbackT; +#ifdef WITH_TIMERFD + std::list mTimerCallbackT; +#endif + + static CAmSocketHandler* mInstance; + int mPipe[2]; + int mDispatchDone; //this starts / stops the mainloop + + bool fdIsValid(const int fd) const; + + timespec* insertTime(timespec& buffertime); +#ifdef WITH_TIMERFD + am_Error_e createTimeFD(const itimerspec & timeouts, int & fd); + +#else + void timerUp(); + void timerCorrection(); + + /** + * compares countdown values + * @param a + * @param b + * @return true if b greater a + */ + inline static bool compareCountdown(const sh_timer_s& a, const sh_timer_s& b) { - t.countdown = timespecSub(t.countdown, param); + return ((a.countdown.tv_sec == b.countdown.tv_sec) ? (a.countdown.tv_nsec < b.countdown.tv_nsec) : (a.countdown.tv_sec < b.countdown.tv_sec)); } - }; - mListPollfd_t mfdPollingArray; //! mSetPollKeys; //!A set of all used ppoll keys - mListPoll_t mListPoll; //! mSetTimerKeys; //!A set of all used timer keys - std::list mListTimer; //! mListActiveTimer; //! class TAmShTimerCallBack: public IAmShTimerCallBack -{ -private: - TClass* mInstance; - void (TClass::*mFunction)(sh_timerHandle_t handle, void* userData); + /** + * Subtracts b from a + * @param a + * @param b + * @return subtracted value + */ + inline static timespec timespecSub(const timespec& a, const timespec& b) + { + timespec result; -public: - TAmShTimerCallBack(TClass* instance, void (TClass::*function)(sh_timerHandle_t handle, void* userData)) : - mInstance(instance), // - mFunction(function) {}; + if ((a.tv_sec < b.tv_sec) || ((a.tv_sec == b.tv_sec) && (a.tv_nsec <= b.tv_nsec))) + { + result.tv_sec = result.tv_nsec = 0; + } + else + { + result.tv_sec = a.tv_sec - b.tv_sec; + if (a.tv_nsec < b.tv_nsec) + { + result.tv_nsec = a.tv_nsec + MAX_NS - b.tv_nsec; + result.tv_sec--; /* Borrow a second. */ + } + else + { + result.tv_nsec = a.tv_nsec - b.tv_nsec; + } + } + return (result); + } - virtual void Call(sh_timerHandle_t handle, void* userData) - { - (*mInstance.*mFunction)(handle, userData); - } -}; + /** + * adds timespec values + * @param a + * @param b + * @return the added values + */ + inline timespec timespecAdd(const timespec& a, const timespec& b) + { + timespec result; + result.tv_sec = a.tv_sec + b.tv_sec; + result.tv_nsec = a.tv_nsec + b.tv_nsec; + if (result.tv_nsec >= MAX_NS) + { + result.tv_sec++; + result.tv_nsec = result.tv_nsec - MAX_NS; + } + return (result); + } -/** - * template for a callback - */ -template class TAmShPollPrepare: public IAmShPollPrepare -{ -private: - TClass* mInstance; - void (TClass::*mFunction)(const sh_timerHandle_t handle, void* userData); + /** + * comapares timespec values + * @param a + * @param b + * @return + */ + inline int timespecCompare(const timespec& a, const timespec& b) + { + //less + if (a.tv_sec < b.tv_sec) + return (-1); + //greater + else if (a.tv_sec > b.tv_sec) + return (1); + //less + else if (a.tv_nsec < b.tv_nsec) + return (-1); + //greater + else if (a.tv_nsec > b.tv_nsec) + return (1); + //equal + return (0); + } +#endif + /** + * functor to return all fired events + * @param a + * @return + */ + inline static bool eventFired(const pollfd& a) + { + return (a.revents == 0 ? false : true); + } -public: - TAmShPollPrepare(TClass* instance, void (TClass::*function)(const sh_timerHandle_t handle, void* userData)) : - mInstance(instance), // - mFunction(function) {}; + /** + * functor to help find the items that do not need dispatching + * @param a + * @return + */ + inline static bool noDispatching(const sh_poll_s& a) + { + //remove from list of there is no checkCB + if (!a.checkCB) + return (true); + return (!a.checkCB->Call(a.handle, a.userData)); + } - virtual void Call(const sh_timerHandle_t handle, void* userData) - { - (*mInstance.*mFunction)(handle, userData); - }; -}; + /** + * checks if dispatching is already finished + * @param a + * @return + */ + inline static bool dispatchingFinished(const sh_poll_s& a) + { + //remove from list of there is no dispatchCB + if (!a.dispatchCB) + return (true); + return (!a.dispatchCB->Call(a.handle, a.userData)); + } -/**make private, not public - * template for a callback - */ -template class TAmShPollFired: public IAmShPollFired -{ -private: - TClass* mInstance; - void (TClass::*mFunction)(const pollfd pollfd, const sh_pollHandle_t handle, void* userData); + class CAmShCopyPollfd //!< functor to copy filedescriptors into the poll array + { + private: + mListPollfd_t& mArray; + public: + CAmShCopyPollfd(mListPollfd_t& dest) : + mArray(dest) + { + } + void operator()(const sh_poll_s& row); + }; -public: - TAmShPollFired(TClass* instance, void (TClass::*function)(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)) : - mInstance(instance), // - mFunction(function) {}; + class CAmShCallFire //!< functor to call the firecallbacks + { + public: + CAmShCallFire() + { + } + ; + void operator()(sh_poll_s& row); + }; - virtual void Call(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) - { - (*mInstance.*mFunction)(pollfd, handle, userData); - }; -}; + class CAmShCallPrep //!< functor to call the preparation callbacks + { + public: + CAmShCallPrep() + { + } + ; + void operator()(sh_poll_s& row); + }; -/** - * template for a callback - */ -template class TAmShPollCheck: public IAmShPollCheck -{ -private: - TClass* mInstance; - bool (TClass::*mFunction)(const sh_pollHandle_t handle, void* userData); + class CAmShCallTimer //! mSetPollKeys; //!A set of all used ppoll keys + mListPoll_t mListPoll; //! mSetTimerKeys; //!A set of all used timer keys + std::list mListTimer; //! mListActiveTimer; //! class TAmShPollDispatch: public IAmShPollDispatch -{ -private: - TClass* mInstance; - bool (TClass::*mFunction)(const sh_pollHandle_t handle, void* userData); - -public: - TAmShPollDispatch(TClass* instance, bool (TClass::*function)(const sh_pollHandle_t handle, void* userData)) : - mInstance(instance), // - mFunction(function) {}; - - virtual bool Call(const sh_pollHandle_t handle, void* userData) - { - return ((*mInstance.*mFunction)(handle, userData)); - }; -}; } /* namespace am */ #endif /* SOCKETHANDLER_H_ */ diff --git a/AudioManagerUtilities/src/CAmSocketHandler.cpp b/AudioManagerUtilities/src/CAmSocketHandler.cpp index 1092198..56df45c 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 #include #include @@ -32,618 +32,796 @@ #include #include #include "CAmDltWrapper.h" +#include "CAmSocketHandler.h" -namespace am -{ +#ifdef WITH_TIMERFD +#include +#endif -CAmSocketHandler::CAmSocketHandler() : - receiverCallbackT(this, &CAmSocketHandler::receiverCallback),// - checkerCallbackT(this, &CAmSocketHandler::checkerCallback),// - mPipe(), // - mDispatchDone(1),// - mListPoll(), // - mListTimer(), // - mListActiveTimer(), // - mLastInsertedHandle(0), // - mLastInsertedPollHandle(0), // - mRecreatePollfds(true), // - mStartTime() // -{ - if (pipe(mPipe) == -1) - { - 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 - short event = 0; - sh_pollHandle_t handle; - event |= POLLIN; - addFDPoll(mPipe[0], event, NULL, &receiverCallbackT, &checkerCallbackT, NULL, NULL, handle); -} - -CAmSocketHandler::~CAmSocketHandler() +namespace am { - 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. - */ -void CAmSocketHandler::start_listenting() -{ - mDispatchDone = 0; - 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); - - clock_gettime(CLOCK_MONOTONIC, &mStartTime); - while (!mDispatchDone) + CAmSocketHandler::CAmSocketHandler() : + mReceiverCallbackT(this, &CAmSocketHandler::receiverCallback), // + mCheckerCallbackT(this, &CAmSocketHandler::checkerCallback), // +#ifdef WITH_TIMERFD + mTimerCallbackT(), // +#endif + mPipe(), // + mDispatchDone(1), // + mListPoll(), // + mListTimer(), // + mListActiveTimer(), // + mLastInsertedHandle(0), // + mLastInsertedPollHandle(0), // + mRecreatePollfds(true) +#ifndef WITH_TIMERFD + ,mStartTime() // +#endif { - //first we go through the registered filedescriptors and check if someone needs preparation: - std::for_each(mListPoll.begin(), mListPoll.end(), CAmShCallPrep()); - - if (mRecreatePollfds) + if (pipe(mPipe) == -1) { - mfdPollingArray.clear(); - //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)); - mRecreatePollfds = false; + logError("Sockethandler could not create pipe!"); } - timerCorrection(); - - //block until something is on a filedescriptor + //add the pipe to the poll - nothing needs to be proccessed here we just need the pipe to trigger the ppoll + short event = 0; + sh_pollHandle_t handle; + event |= POLLIN; + addFDPoll(mPipe[0], event, NULL, &mReceiverCallbackT, &mCheckerCallbackT, NULL, NULL, handle); + } - timespec buffertime; - if ((pollStatus = ppoll(&mfdPollingArray[0], mfdPollingArray.size(), insertTime(buffertime), &sigmask)) < 0) + CAmSocketHandler::~CAmSocketHandler() + { +#ifdef WITH_TIMERFD + for(auto it: mListTimer) { - if (errno == EINTR) - { - //a signal was received, that means it's time to go... - pollStatus = 0; - } - else - { - logError("SocketHandler::start_listenting ppoll returned with error", errno); - throw std::runtime_error(std::string("SocketHandler::start_listenting ppoll returned with error.")); - } + close(it.fd); } +#endif + close(mPipe[0]); + close(mPipe[1]); + } - if (pollStatus != 0) //only check filedescriptors if there was a change +//todo: maybe have some: give me more time returned? + /** + * start the block listening for filedescriptors. This is the mainloop. + */ + void CAmSocketHandler::start_listenting() + { + mDispatchDone = 0; + 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); +#endif + while (!mDispatchDone) { - //todo: here could be a timer that makes sure naughty plugins return! + //first we go through the registered filedescriptors and check if someone needs preparation: + std::for_each(mListPoll.begin(), mListPoll.end(), CAmShCallPrep()); - //freeze mListPoll by copying it - otherwise we get problems when we want to manipulate it during the next lines - std::list listPoll; - mListPoll_t::iterator listmPollIt; + if (mRecreatePollfds) + { + mfdPollingArray.clear(); + //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)); + mRecreatePollfds = false; + } +#ifndef WITH_TIMERFD + timerCorrection(); +#endif + //block until something is on a filedescriptor - //remove all filedescriptors who did not fire - std::vector::iterator it = mfdPollingArray.begin(); - do + timespec buffertime; + if ((pollStatus = ppoll(&mfdPollingArray[0], mfdPollingArray.size(), insertTime(buffertime), &sigmask)) < 0) { - it = std::find_if(it, mfdPollingArray.end(), eventFired); - if (it != mfdPollingArray.end()) + if (errno == EINTR) { - listmPollIt = mListPoll.begin(); - std::advance(listmPollIt, std::distance(mfdPollingArray.begin(), it)); - listPoll.push_back(*listmPollIt); - listPoll.back().pollfdValue = *it; - it++; + //a signal was received, that means it's time to go... + pollStatus = 0; } - } while (it != mfdPollingArray.end()); + else + { + logError("SocketHandler::start_listenting ppoll returned with error", errno); + throw std::runtime_error(std::string("SocketHandler::start_listenting ppoll returned with error.")); + } + } + + if (pollStatus != 0) //only check filedescriptors if there was a change + { + //todo: here could be a timer that makes sure naughty plugins return! - //stage 1, call firedCB - std::for_each(listPoll.begin(), listPoll.end(), CAmShCallFire()); + //freeze mListPoll by copying it - otherwise we get problems when we want to manipulate it during the next lines + std::list listPoll; + mListPoll_t::iterator listmPollIt; - //stage 2, lets ask around if some dispatching is necessary, the ones who need stay on the list - listPoll.remove_if(noDispatching); + //remove all filedescriptors who did not fire + std::vector::iterator it = mfdPollingArray.begin(); + do + { + it = std::find_if(it, mfdPollingArray.end(), eventFired); + if (it != mfdPollingArray.end()) + { + listmPollIt = mListPoll.begin(); + std::advance(listmPollIt, std::distance(mfdPollingArray.begin(), it)); + listPoll.push_back(*listmPollIt); + listPoll.back().pollfdValue = *it; + it++; + } + } 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.erase(std::remove_if(listPoll.begin(), listPoll.end(), noDispatching), listPoll.end()); + + //stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch.. + do + { + listPoll.erase(std::remove_if(listPoll.begin(), listPoll.end(), dispatchingFinished), listPoll.end()); + } while (!listPoll.empty()); - //stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch.. - do + } +#ifndef WITH_TIMERFD + else //Timerevent { - listPoll.remove_if(dispatchingFinished); - } while (!listPoll.empty()); - + //this was a timer event, we need to take care about the timers + timerUp(); + } +#endif } - else //Timerevent + } + + /** + * exits the loop + */ + void CAmSocketHandler::stop_listening() + { + mDispatchDone = 1; +#ifndef WITH_TIMERFD + //this is for all running timers only - we need to handle the additional offset here + if (!mListActiveTimer.empty()) { - //this was a timer event, we need to take care about the timers - timerUp(); + timespec currentTime, correctionTime; + clock_gettime(CLOCK_MONOTONIC, ¤tTime); + correctionTime = timespecSub(currentTime, mStartTime); + std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime)); } +#endif } -} - -/** - * exits the loop - */ -void CAmSocketHandler::stop_listening() -{ - mDispatchDone = 1; - //this is for all running timers only - we need to handle the additional offset here - if (!mListActiveTimer.empty()) + void CAmSocketHandler::exit_mainloop() { - timespec currentTime, correctionTime; - clock_gettime(CLOCK_MONOTONIC, ¤tTime); - correctionTime = timespecSub(currentTime, mStartTime); - std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime)); - } + //end the while loop + stop_listening(); -} + //fire the ending filedescriptor + int p(1); + ssize_t result = write(mPipe[1], &p, sizeof(p)); + } -/** - * 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) -{ - if (!fdIsValid(fd)) - return (E_NON_EXISTENT); - - //create a new handle for the poll - sh_pollHandle_t lastHandle(mLastInsertedPollHandle); - do + /** + * 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) { - ++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); - - sh_poll_s pollData; - pollData.pollfdValue.fd = fd; - pollData.handle = mLastInsertedPollHandle; - pollData.pollfdValue.events = event; - pollData.pollfdValue.revents = 0; - pollData.userData = userData; - pollData.prepareCB = prepare; - pollData.firedCB = fired; - pollData.checkCB = check; - pollData.dispatchCB = dispatch; - - //add new data to the list - mListPoll.push_back(pollData); - - mRecreatePollfds = true; - - handle = pollData.handle; - return (E_OK); -} + if (!fdIsValid(fd)) + return (E_NON_EXISTENT); -/** - * 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(); + //create a new handle for the poll + sh_pollHandle_t lastHandle(mLastInsertedPollHandle); + do + { + ++mLastInsertedPollHandle; + if (mLastInsertedPollHandle == MAX_POLLHANDLE) + { + mLastInsertedPollHandle = 1; + } + if (mLastInsertedPollHandle == lastHandle) + { + logError("Could not create new polls, too many open!"); + return (E_NOT_POSSIBLE); + } - for (; iterator != mListPoll.end(); ++iterator) + } while (mSetPollKeys.find(mLastInsertedPollHandle) != mSetPollKeys.end()); + + mSetPollKeys.insert(mLastInsertedPollHandle); + + sh_poll_s pollData; + pollData.pollfdValue.fd = fd; + pollData.handle = mLastInsertedPollHandle; + pollData.pollfdValue.events = event; + pollData.pollfdValue.revents = 0; + pollData.userData = userData; + pollData.prepareCB = prepare; + pollData.firedCB = fired; + pollData.checkCB = check; + pollData.dispatchCB = dispatch; + + //add new data to the list + mListPoll.push_back(pollData); + + mRecreatePollfds = true; + + handle = pollData.handle; + return (E_OK); + } + + /** + * removes a filedescriptor from the poll loop + * @param handle + * @return + */ + am_Error_e CAmSocketHandler::removeFDPoll(const sh_pollHandle_t handle) { - if (iterator->handle == handle) + mListPoll_t::iterator iterator = mListPoll.begin(); + + for (; iterator != mListPoll.end(); ++iterator) { - iterator = mListPoll.erase(iterator); - mSetPollKeys.erase(handle); - mRecreatePollfds = true; - return (E_OK); + if (iterator->handle == handle) + { + iterator = mListPoll.erase(iterator); + mSetPollKeys.erase(handle); + mRecreatePollfds = true; + return (E_OK); + } } + return (E_UNKNOWN); } - 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) -{ - assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0))); - assert(callback!=NULL); + /** + * 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; + mListTimer.emplace_back(); + sh_timer_s & timerItem = mListTimer.back(); - //create a new handle for the timer - sh_timerHandle_t lastTimerHandle(mLastInsertedHandle); - do - { - ++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; - timerItem.countdown = timeouts; - timerItem.callback = callback; - timerItem.userData = userData; - - mListTimer.push_back(timerItem); - - //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, ¤tTime); - if (!mDispatchDone) //the mainloop is started - timerItem.countdown = timespecAdd(timeouts, timespecSub(currentTime, mStartTime)); - - mListActiveTimer.push_back(timerItem); - mListActiveTimer.sort(compareCountdown); - return (E_OK); -} +#ifndef WITH_TIMERFD + //create a new handle for the timer + sh_timerHandle_t lastTimerHandle(mLastInsertedHandle); + do + { + ++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); + } -/** - * 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); + }while (mSetTimerKeys.find(mLastInsertedHandle) != mSetTimerKeys.end()); - //stop the current timer - stopTimer(handle); + mSetTimerKeys.insert(mLastInsertedHandle); + handle=mLastInsertedHandle; - std::list::iterator it(mListTimer.begin()); - for (; it != mListTimer.end(); ++it) - { - if (it->handle == handle) + timerItem.countdown = timeouts; + timerItem.callback = callback; + timerItem.userData = userData; + + 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, ¤tTime); + 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.callback = callback; + timerItem.userData = userData; + timerItem.fd = -1; + am_Error_e err = createTimeFD(timerItem.countdown, timerItem.fd); + if (err != E_OK) { - it = mListTimer.erase(it); - mSetTimerKeys.erase(handle); - return (E_OK); + mListTimer.pop_back(); + return err; } + mTimerCallbackT.emplace_back(callback); + + err = addFDPoll(timerItem.fd, POLLIN, NULL, &mTimerCallbackT.back(), &mTimerCallbackT.back(), NULL, NULL, handle); + if (E_OK == err) + { + timerItem.handle = handle; + } + else + { + mTimerCallbackT.pop_back(); + mListTimer.pop_back(); + } + return err; +#endif + } - return (E_UNKNOWN); -} -/** - * 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) -{ - //update the mList .... - sh_timer_s timerItem; - std::list::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin()); - bool found(false); - for (; it != mListTimer.end(); ++it) + /** + * 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) { - if (it->handle == handle) + assert(handle != 0); + + //stop the current timer +#ifdef WITH_TIMERFD + std::list::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::iterator it(mListTimer.begin()); + for (; it != mListTimer.end(); ++it) { - it->countdown = timeouts; - timerItem = *it; - found = true; - break; + if (it->handle == handle) + { + it = mListTimer.erase(it); + mSetTimerKeys.erase(handle); + return (E_OK); + } } + return (E_UNKNOWN); +#endif } - if (!found) + + /** + * 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::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::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin()); + bool found(false); + for (; it != mListTimer.end(); ++it) + { + if (it->handle == handle) + { + it->countdown = timeouts; + timerItem = *it; + found = true; + break; + } + } + if (!found) return (E_NON_EXISTENT); - found = false; + 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; - currentTime.tv_nsec=timeoutsCorrected.tv_nsec=0; - currentTime.tv_sec=timeoutsCorrected.tv_sec=0; - clock_gettime(CLOCK_MONOTONIC, ¤tTime); - if (!mDispatchDone) //the mainloop is started + //we add here the time difference between startTime and currenttime, because this time will be substracted later on in timecorrection + timespec currentTime, timeoutsCorrected; + currentTime.tv_nsec=timeoutsCorrected.tv_nsec=0; + currentTime.tv_sec=timeoutsCorrected.tv_sec=0; + clock_gettime(CLOCK_MONOTONIC, ¤tTime); + if (!mDispatchDone)//the mainloop is started timeoutsCorrected = timespecAdd(timeouts, timespecSub(currentTime, mStartTime)); - for (; activeIt != mListActiveTimer.end(); ++activeIt) - { - if (activeIt->handle == handle) + for (; activeIt != mListActiveTimer.end(); ++activeIt) { - activeIt->countdown = timeoutsCorrected; - found = true; - break; + if (activeIt->handle == handle) + { + activeIt->countdown = timeoutsCorrected; + found = true; + break; + } } - } - if (!found) + if (!found) timerItem.countdown = timeoutsCorrected; - mListActiveTimer.push_back(timerItem); + mListActiveTimer.push_back(timerItem); - mListActiveTimer.sort(compareCountdown); - return (E_OK); -} + mListActiveTimer.sort(compareCountdown); -/** - * 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) -{ - sh_timer_s timerItem; //!::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin()); - bool found(false); - for (; it != mListTimer.end(); ++it) +#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 + */ + am_Error_e CAmSocketHandler::restartTimer(const sh_timerHandle_t handle) { - if (it->handle == handle) +#ifdef WITH_TIMERFD + std::list::iterator it = mListTimer.begin(); + for (; it != mListTimer.end(); ++it) { - timerItem = *it; - found = true; - break; + if (it->handle == handle) + break; } - } - if (!found) + 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; //!::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin()); + bool found(false); + for (; it != mListTimer.end(); ++it) + { + if (it->handle == handle) + { + timerItem = *it; + found = true; + break; + } + } + if (!found) return (E_NON_EXISTENT); - found = false; + 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, ¤tTime); - if (!mDispatchDone) //the mainloop is started - { - timeoutsCorrected = timespecAdd(timerItem.countdown, timespecSub(currentTime, mStartTime)); - timerItem.countdown = timeoutsCorrected; - } + //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, ¤tTime); + if (!mDispatchDone)//the mainloop is started + { + timeoutsCorrected = timespecAdd(timerItem.countdown, timespecSub(currentTime, mStartTime)); + timerItem.countdown = timeoutsCorrected; + } - for (; activeIt != mListActiveTimer.end(); ++activeIt) - { - if (activeIt->handle == handle) + for (; activeIt != mListActiveTimer.end(); ++activeIt) { - activeIt->countdown = timerItem.countdown; - found = true; - break; + if (activeIt->handle == handle) + { + activeIt->countdown = timerItem.countdown; + found = true; + break; + } } - } - if (!found) + if (!found) mListActiveTimer.push_back(timerItem); - mListActiveTimer.sort(compareCountdown); - - return (E_OK); -} + 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 - */ -am_Error_e CAmSocketHandler::stopTimer(const sh_timerHandle_t handle) -{ - //go through the list and remove the timer with the handle - std::list::iterator it(mListActiveTimer.begin()); - for (; it != mListActiveTimer.end(); ++it) + /** + * 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) { - if (it->handle == handle) +#ifdef WITH_TIMERFD + std::list::iterator it = mListTimer.begin(); + for (; it != mListTimer.end(); ++it) { - it = mListActiveTimer.erase(it); - return (E_OK); + if (it->handle == handle) + break; } - } - return (E_NON_EXISTENT); -} + if (it == mListTimer.end()) + return (E_NON_EXISTENT); -/** - * 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(); + itimerspec countdown = it->countdown; + countdown.it_value.tv_nsec = 0; + countdown.it_value.tv_sec = 0; - for (; iterator != mListPoll.end(); ++iterator) - { - if (iterator->handle == handle) + if (timerfd_settime(it->fd, 0, &countdown, NULL)) { - iterator->pollfdValue.events = events; - mRecreatePollfds = true; - return (E_OK); + logError("Failed to set timer duration"); + return E_NOT_POSSIBLE; } +#else + //go through the list and remove the timer with the handle + std::list::iterator it(mListActiveTimer.begin()); + for (; it != mListActiveTimer.end(); ++it) + { + if (it->handle == handle) + { + it = mListActiveTimer.erase(it); + return (E_OK); + } + } + return (E_NON_EXISTENT); +#endif } - return (E_UNKNOWN); -} -/** - * 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); -} + /** + * 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(); -/** - * timer is up. - */ -void CAmSocketHandler::timerUp() -{ - //find out the timedifference to starttime - timespec currentTime, diffTime; - clock_gettime(CLOCK_MONOTONIC, ¤tTime); - diffTime = timespecSub(currentTime, mStartTime); + for (; iterator != mListPoll.end(); ++iterator) + { + if (iterator->handle == handle) + { + iterator->pollfdValue.events = events; + mRecreatePollfds = true; + return (E_OK); + } + } + return (E_UNKNOWN); + } - //now we need to substract the diffTime from all timers and see if they are up - std::list::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownUp(diffTime)); + /** + * 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); + } - //copy all fired timers into a list - std::vector tempList(overflowIter, mListActiveTimer.rend()); +#ifndef WITH_TIMERFD + /** + * timer is up. + */ + void CAmSocketHandler::timerUp() + { + //find out the timedifference to starttime + timespec currentTime, diffTime; + clock_gettime(CLOCK_MONOTONIC, ¤tTime); + diffTime = timespecSub(currentTime, mStartTime); - //erase all fired timers - std::list::iterator it(overflowIter.base()); - mListActiveTimer.erase(mListActiveTimer.begin(), it); + //now we need to substract the diffTime from all timers and see if they are up + std::list::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownUp(diffTime)); - //call the callbacks for the timers - std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer()); -} + //copy all fired timers into a list + std::vector tempList(overflowIter, mListActiveTimer.rend()); -/** - * correct timers and fire the ones who are up - */ -void CAmSocketHandler::timerCorrection() -{ - //get the current time and calculate the correction value - timespec currentTime, correctionTime; - clock_gettime(CLOCK_MONOTONIC, ¤tTime); - correctionTime = timespecSub(currentTime, mStartTime); - mStartTime = currentTime; + //erase all fired timers + std::list::iterator it(overflowIter.base()); + mListActiveTimer.erase(mListActiveTimer.begin(), it); - if (!mListActiveTimer.empty()) + //call the callbacks for the timers + std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer()); + } + + /** + * correct timers and fire the ones who are up + */ + void CAmSocketHandler::timerCorrection() { + //get the current time and calculate the correction value + timespec currentTime, correctionTime; + clock_gettime(CLOCK_MONOTONIC, ¤tTime); + correctionTime = timespecSub(currentTime, mStartTime); + mStartTime = currentTime; - //subtract the correction value from all items in the list - std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime)); + if (!mListActiveTimer.empty()) + { - //find the last occurrence of zero -> timer overflowed - std::list::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownZero()); + //subtract the correction value from all items in the list + std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime)); - //only if a timer overflowed - if (overflowIter != mListActiveTimer.rend()) - { - //copy all timers that need to be called to a new list - std::vector tempList(overflowIter, mListActiveTimer.rend()); + //find the last occurrence of zero -> timer overflowed + std::list::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownZero()); + + //only if a timer overflowed + if (overflowIter != mListActiveTimer.rend()) + { + //copy all timers that need to be called to a new list + std::vector tempList(overflowIter, mListActiveTimer.rend()); - //erase all fired timers - std::list::iterator it(overflowIter.base()); - mListActiveTimer.erase(mListActiveTimer.begin(), it); + //erase all fired timers + std::list::iterator it(overflowIter.base()); + mListActiveTimer.erase(mListActiveTimer.begin(), it); - //call the callbacks for the timers - std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer()); + //call the callbacks for the timers + std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer()); + } + } + } +#endif + /** + * 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::exit_mainloop() -{ - //end the while loop - stop_listening(); +#ifdef WITH_TIMERFD + am_Error_e CAmSocketHandler::createTimeFD(const itimerspec & timeouts, int & fd) + { + fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd <= 0) + { + logError("Failed to create timer"); + return E_NOT_POSSIBLE; + } + if (fcntl(fd, F_SETFL, O_NONBLOCK)) + { + logError("Failed to set to non blocking mode"); + return E_NOT_POSSIBLE; + } - //fire the ending filedescriptor - int p(1); - ssize_t result = write(mPipe[1], &p, sizeof(p)); -} + if (timerfd_settime(fd, 0, &timeouts, NULL)) + { + logError("Failed to set timer duration"); + return E_NOT_POSSIBLE; + } + return E_OK; + } +#endif -/** - * is used to set the pointer for the ppoll command - * @param buffertime - * @return - */ -inline timespec* CAmSocketHandler::insertTime(timespec& buffertime) -{ - if (!mListActiveTimer.empty()) + void CAmSocketHandler::CAmShCallFire::operator()(sh_poll_s& row) { - buffertime = mListActiveTimer.front().countdown; - return (&buffertime); + try + { + row.firedCB->Call(row.pollfdValue, row.handle, row.userData); + } catch (std::exception& e) + { + logError("Sockethandler: Exception in FireCallback,caught", e.what()); + } } - else + + void CAmSocketHandler::CAmShCallPrep::operator()(sh_poll_s& row) { - return (NULL); + if (row.prepareCB) + { + try + { + row.prepareCB->Call(row.handle, row.userData); + } catch (std::exception& e) + { + logError("Sockethandler: Exception in Preparecallback,caught", e.what()); + } + } } -} - -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) -{ - if (row.prepareCB) - { - try - { - row.prepareCB->Call(row.handle, row.userData); - } - catch (std::exception& e) - { - logError("Sockethandler: Exception in Preparecallback,caught",e.what()); - } - } -} -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()); - } -} + 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()); + } + } -void CAmSocketHandler::CAmShCopyPollfd::operator()(const sh_poll_s& row) -{ - pollfd temp = row.pollfdValue; - temp.revents = 0; - mArray.push_back(temp); -} + void CAmSocketHandler::CAmShCopyPollfd::operator()(const sh_poll_s& row) + { + pollfd temp = row.pollfdValue; + temp.revents = 0; + mArray.push_back(temp); + } +#ifndef WITH_TIMERFD bool CAmSocketHandler::CAmShCountdownUp::operator()(const sh_timer_s& row) { - timespec sub = timespecSub(row.countdown, mDiffTime); - if (sub.tv_nsec == 0 && sub.tv_sec == 0) - return (true); - return (false); + timespec sub = timespecSub(row.countdown, mDiffTime); + if (sub.tv_nsec == 0 && sub.tv_sec == 0) + return (true); + 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); + if (row.countdown.tv_nsec == 0 && row.countdown.tv_sec == 0) + return (true); + return (false); } - +#endif } diff --git a/CMakeLists.txt b/CMakeLists.txt index 33433ee..b89daa1 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,10 @@ option ( WITH_SHARED_UTILITIES option ( WITH_SHARED_CORE "Build audio manager core as dynamic library" OFF) - + +option ( WITH_TIMERFD + "Build with the linux specific TIMERFD feature to support timing without using signals" ON) + set(DBUS_SERVICE_PREFIX "org.genivi.audiomanager" CACHE PROPERTY "The dbus service prefix for the AM - only changable for legacy dbus") @@ -219,6 +222,7 @@ message(STATUS "WITH_CAPI_WRAPPER = ${WITH_CAPI_WRAPPER}") message(STATUS "WITH_DBUS_WRAPPER = ${WITH_DBUS_WRAPPER}") message(STATUS "WITH_SHARED_UTILITIES = ${WITH_SHARED_UTILITIES}") message(STATUS "WITH_SHARED_CORE = ${WITH_SHARED_CORE}") +message(STATUS "WITH_TIMERFD = ${WITH_TIMERFD}") message(STATUS "DYNAMIC_ID_BOUNDARY = ${DYNAMIC_ID_BOUNDARY}") message(STATUS "LIB_INSTALL_SUFFIX = ${LIB_INSTALL_SUFFIX}") message(STATUS "TEST_EXECUTABLE_INSTALL_PATH = ${TEST_EXECUTABLE_INSTALL_PATH}") diff --git a/cmake/AudioManagerUtilitiesConfig.cmake.in b/cmake/AudioManagerUtilitiesConfig.cmake.in index acca825..11ebf55 100644 --- a/cmake/AudioManagerUtilitiesConfig.cmake.in +++ b/cmake/AudioManagerUtilitiesConfig.cmake.in @@ -7,6 +7,7 @@ set(WITH_CAPI_WRAPPER "@WITH_CAPI_WRAPPER@") set(WITH_DBUS_WRAPPER "@WITH_DBUS_WRAPPER@") set(WITH_SYSTEMD_WATCHDOG "@WITH_SYSTEMD_WATCHDOG@") set(WITH_DLT "@WITH_DLT@") +set(WITH_TIMERFD "@WITH_TIMERFD@") if(WITH_SYSTEMD_WATCHDOG) diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in index da64732..1501393 100644 --- a/cmake/config.cmake.in +++ b/cmake/config.cmake.in @@ -9,6 +9,7 @@ #cmakedefine WITH_TELNET #cmakedefine GLIB_DBUS_TYPES_TOLERANT #cmakedefine WITH_SYSTEMD_WATCHDOG +#cmakedefine WITH_TIMERFD #cmakedefine DEFAULT_PLUGIN_DIR "@DEFAULT_PLUGIN_DIR@" #cmakedefine DEFAULT_PLUGIN_COMMAND_DIR "@DEFAULT_PLUGIN_COMMAND_DIR@" -- cgit v1.2.1