diff options
Diffstat (limited to 'AudioManagerUtilities')
-rw-r--r-- | AudioManagerUtilities/include/CAmSocketHandler.h | 814 | ||||
-rw-r--r-- | AudioManagerUtilities/src/CAmSocketHandler.cpp | 1172 |
2 files changed, 1126 insertions, 860 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 <sys/socket.h> #include <stdint.h> #include <sys/poll.h> @@ -25,6 +25,19 @@ #include <map> #include <set> #include <signal.h> +#include <vector> +#include <audiomanagerconfig.h> +#include "audiomanagertypes.h" + +#ifdef WITH_TIMERFD + +#include <stdio.h> +#include <string> +#include <stdexcept> +#include <unistd.h> +#include <fcntl.h> + +#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; //!<this is a handle for a timer to be used with the SocketHandler -typedef uint16_t sh_pollHandle_t; //!<this is a handle for a filedescriptor to be used with the SocketHandler + typedef uint16_t sh_timerHandle_t; //!<this is a handle for a timer to be used with the SocketHandler + typedef uint16_t sh_pollHandle_t; //!<this is a handle for a filedescriptor to be used with the SocketHandler -/** - * prototype for poll prepared callback - */ -class IAmShPollPrepare -{ -public: - virtual void Call(const sh_pollHandle_t handle, void* userData) = 0; - virtual ~IAmShPollPrepare() {}; -}; + /** + * prototype for poll prepared callback + */ + class IAmShPollPrepare + { + public: + virtual void Call(const sh_pollHandle_t handle, void* userData) = 0; + virtual ~IAmShPollPrepare() + { + } + ; + }; -/** - * prototype for poll fired callback - */ -class IAmShPollFired -{ -public: - virtual void Call(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) = 0; - virtual ~ IAmShPollFired() {}; -}; + /** + * prototype for poll fired callback + */ + class IAmShPollFired + { + public: + virtual void Call(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) = 0; + virtual ~ IAmShPollFired() + { + } + ; + }; -/** - * prototype for poll check callback - */ -class IAmShPollCheck -{ -public: - virtual bool Call(const sh_pollHandle_t handle, void* userData) = 0; - virtual ~ IAmShPollCheck() {}; -}; + /** + * prototype for poll check callback + */ + class IAmShPollCheck + { + public: + virtual bool Call(const sh_pollHandle_t handle, void* userData) = 0; + virtual ~ IAmShPollCheck() + { + } + ; + }; -/** - * prototype for dispatch callback - */ -class IAmShPollDispatch -{ -public: - virtual bool Call(const sh_pollHandle_t handle, void* userData) = 0; - virtual ~ IAmShPollDispatch() {}; -}; + /** + * prototype for dispatch callback + */ + class IAmShPollDispatch + { + public: + virtual bool Call(const sh_pollHandle_t handle, void* userData) = 0; + virtual ~ IAmShPollDispatch() + { + } + ; + }; -/** - * prototype for the timer callback - */ -class IAmShTimerCallBack -{ -public: - virtual void Call(const sh_timerHandle_t handle, void* userData) = 0; - virtual ~IAmShTimerCallBack() {}; -}; + /** + * prototype for the timer callback + */ + class IAmShTimerCallBack + { + public: + IAmShTimerCallBack() + { + } + virtual void Call(const sh_timerHandle_t handle, void* userData) = 0; + virtual ~IAmShTimerCallBack() + { + } + }; -/** - * 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 - */ -class CAmSocketHandler -{ -public: + /**make private, not public + * template for a callback + */ template<class TClass> 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 TClass> 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<CAmSocketHandler> receiverCallbackT; - TAmShPollCheck<CAmSocketHandler> checkerCallbackT; - -private: - - static CAmSocketHandler* mInstance; - int mPipe[2]; - int mDispatchDone; //this starts / stops the mainloop - struct sh_timer_s //!<struct that holds information of timers + /** + * template for a callback + */ + template<class TClass> class TAmShPollDispatch: public IAmShPollDispatch { - sh_timerHandle_t handle; //!<the handle of the timer - timespec countdown; //!<the countdown, this value is decreased every time the timer is up - IAmShTimerCallBack* callback; //!<the callbackfunction - void * userData; //!<saves a void pointer together with the rest. - }; + private: + TClass* mInstance; + bool (TClass::*mFunction)(const sh_pollHandle_t handle, void* userData); - typedef std::reverse_iterator<sh_timer_s> rListTimerIter; //!<typedef for reverseiterator on timer lists + public: + TAmShPollDispatch(TClass* instance, bool (TClass::*function)(const sh_pollHandle_t handle, void* userData)) : + mInstance(instance), // + mFunction(function) + { + } + ; - struct sh_poll_s //!<struct that holds information about polls - { - sh_pollHandle_t handle; //!<handle to uniquely adress a filedesriptor - IAmShPollPrepare *prepareCB; //!<pointer to preperation callback - IAmShPollFired *firedCB; //!<pointer to fired callback - IAmShPollCheck *checkCB; //!< pointer to check callback - IAmShPollDispatch *dispatchCB; //!<pointer to dispatch callback - pollfd pollfdValue; //!<the array for polling the filedescriptors - void *userData; //!<userdata saved together with the callback. + virtual bool Call(const sh_pollHandle_t handle, void* userData) + { + return ((*mInstance.*mFunction)(handle, userData)); + } + ; }; - typedef std::vector<pollfd> mListPollfd_t; //!<vector of filedescriptors - typedef std::vector<sh_poll_s> mListPoll_t; //!<list for the callbacks - - bool fdIsValid(const int fd) const; - void timerUp(); - void timerCorrection(); - timespec* insertTime(timespec& buffertime); - - /** - * 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) - { - 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)); - } - /** - * Subtracts b from a - * @param a - * @param b - * @return subtracted value + * template to create the functor for a class */ - inline static timespec timespecSub(const timespec& a, const timespec& b) + template<class TClass> 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 TClass> 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 //!<struct that holds information about polls + { + sh_pollHandle_t handle; //!<handle to uniquely adress a filedesriptor + IAmShPollPrepare *prepareCB; //!<pointer to preperation callback + IAmShPollFired *firedCB; //!<pointer to fired callback + IAmShPollCheck *checkCB; //!< pointer to check callback + IAmShPollDispatch *dispatchCB; //!<pointer to dispatch callback + pollfd pollfdValue; //!<the array for polling the filedescriptors + void *userData; //!<userdata saved together with the callback. + }; - /** - * 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)); - } + struct sh_timer_s //!<struct that holds information of timers + { + sh_timerHandle_t handle; //!<the handle of the timer +#ifdef WITH_TIMERFD + int fd; + itimerspec countdown; //!<the countdown, this value is decreased every time the timer is up +#else + timespec countdown; //!<the countdown, this value is decreased every time the timer is up +#endif + IAmShTimerCallBack* callback; //!<the callbackfunction + void * userData; //!<saves a void pointer together with the rest. + }; - /** - * 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)); - } + typedef std::reverse_iterator<sh_timer_s> rListTimerIter; //!<typedef for reverseiterator on timer lists - 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); - }; + typedef std::vector<pollfd> mListPollfd_t; //!<vector of filedescriptors + typedef std::vector<sh_poll_s> mListPoll_t; //!<list for the callbacks - class CAmShCallFire //!< functor to call the firecallbacks - { - public: - CAmShCallFire() {}; - void operator()(sh_poll_s& row); - }; +#ifdef WITH_TIMERFD + /** + * Wrapper for IAmShTimerCallBack. + * Timerfds are normal file descriptors and therefore they should be added to the handler through the method addFDPoll. + */ + class TAmShPollTimerFired: public IAmShPollFired, public IAmShPollCheck + { + IAmShTimerCallBack* mCallback; + uint64_t mExpirations; + public: + TAmShPollTimerFired(IAmShTimerCallBack * cb) : + mCallback(cb), mExpirations(0) + { + } - class CAmShCallPrep //!< functor to call the preparation callbacks - { - public: - CAmShCallPrep() {}; - void operator()(sh_poll_s& row); - }; + void Call(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) + { + if (read(pollfd.fd, &mExpirations, sizeof(uint64_t)) == -1) + { + //error received...try again + read(pollfd.fd, &mExpirations, sizeof(uint64_t)); + } + } - class CAmShCallTimer //!<functor to call a timer - { + bool Call(const sh_pollHandle_t handle, void* userData) + { + mCallback->Call(handle, userData); + return false; + } + }; +#endif public: - CAmShCallTimer() {}; - void operator()(sh_timer_s& row); - }; - class CAmShCountdownUp //!<functor that checks if a timer is up - { - private: - timespec mDiffTime; - public: - CAmShCountdownUp(const timespec& differenceTime) : mDiffTime(differenceTime) {}; - bool operator()(const sh_timer_s& row); - }; + 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, +#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(); + void receiverCallback(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) + { + (void) pollfd; + (void) handle; + (void) userData; + } - class CAmShCountdownZero //!<functor that checks if a timer is zero - { - public: - CAmShCountdownZero() {}; - bool operator()(const sh_timer_s& row); - }; + bool checkerCallback(const sh_pollHandle_t handle, void* userData) + { + (void) handle; + (void) userData; + return (false); + } - class CAmShSubstractTime //!<functor to easy substract from each countdown value - { private: - timespec param; - public: - CAmShSubstractTime(timespec param) : param(param) {} - inline void operator()(sh_timer_s& t) + TAmShPollFired<CAmSocketHandler> mReceiverCallbackT; + TAmShPollCheck<CAmSocketHandler> mCheckerCallbackT; +#ifdef WITH_TIMERFD + std::list<TAmShPollTimerFired> 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; //!<the polling array for ppoll - std::set<sh_pollHandle_t> mSetPollKeys; //!A set of all used ppoll keys - mListPoll_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 - timespec mStartTime; //!<here the actual time is saved for timecorrection - -}; - -/** - * template to create the functor for a class - */ -template<class TClass> 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 TClass> 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 TClass> 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 TClass> class TAmShPollCheck: public IAmShPollCheck -{ -private: - TClass* mInstance; - bool (TClass::*mFunction)(const sh_pollHandle_t handle, void* userData); + class CAmShCallTimer //!<functor to call a timer + { + public: + CAmShCallTimer() + { + } + ; + void operator()(sh_timer_s& row); + }; -public: - TAmShPollCheck(TClass* instance, bool (TClass::*function)(const sh_pollHandle_t handle, void* userData)) : - mInstance(instance), // - mFunction(function) {}; + class CAmShCountdownUp //!<functor that checks if a timer is up + { + private: + timespec mDiffTime; + public: + CAmShCountdownUp(const timespec& differenceTime) : + mDiffTime(differenceTime) + { + } + ; + bool operator()(const sh_timer_s& row); + }; +#ifndef WITH_TIMERFD + class CAmShCountdownZero //!<functor that checks if a timer is zero + { + public: + CAmShCountdownZero() + {}; + bool operator()(const sh_timer_s& row); + }; - virtual bool Call(const sh_pollHandle_t handle, void* userData) - { - return ((*mInstance.*mFunction)(handle, userData)); + class CAmShSubstractTime //!<functor to easy substract from each countdown value + { + private: + timespec param; + public: + CAmShSubstractTime(timespec param) : param(param) + {} + inline void operator()(sh_timer_s& t) + { + t.countdown = timespecSub(t.countdown, param); + } + }; +#endif + mListPollfd_t mfdPollingArray; //!<the polling array for ppoll + std::set<sh_pollHandle_t> mSetPollKeys; //!A set of all used ppoll keys + mListPoll_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 +#ifndef WITH_TIMERFD + timespec mStartTime; //!<here the actual time is saved for timecorrection +#endif }; -}; -/** - * template for a callback - */ -template<class TClass> 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 <cassert> #include <sys/fcntl.h> #include <sys/errno.h> @@ -32,618 +32,796 @@ #include <csignal> #include <unistd.h> #include "CAmDltWrapper.h" +#include "CAmSocketHandler.h" -namespace am -{ +#ifdef WITH_TIMERFD +#include <sys/timerfd.h> +#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<sh_poll_s> 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<pollfd>::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<sh_poll_s> 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<pollfd>::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<sh_timer_s>::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<sh_timer_s>::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<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) { - 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<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()); + 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; //!<the original timer value - //find the original value - std::list<sh_timer_s>::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<sh_timer_s>::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; //!<the original timer value + //find the original value + std::list<sh_timer_s>::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<sh_timer_s>::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<sh_timer_s>::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<sh_timer_s>::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<sh_timer_s>::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<sh_timer_s> 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<sh_timer_s>::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<sh_timer_s>::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<sh_timer_s> 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<sh_timer_s>::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<sh_timer_s>::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<sh_timer_s> tempList(overflowIter, mListActiveTimer.rend()); + //find the last occurrence of zero -> timer overflowed + std::list<sh_timer_s>::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<sh_timer_s> tempList(overflowIter, mListActiveTimer.rend()); - //erase all fired timers - std::list<sh_timer_s>::iterator it(overflowIter.base()); - mListActiveTimer.erase(mListActiveTimer.begin(), it); + //erase all fired timers + std::list<sh_timer_s>::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 } |