/** * SPDX license identifier: MPL-2.0 * * 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 * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with * this file, You can obtain one at http://mozilla.org/MPL/2.0/. * * \file CAmSocketHandler.h * For further information see http://www.genivi.org/. */ #ifndef SOCKETHANDLER_H_ #define SOCKETHANDLER_H_ #include #include #include #include #include #include #include #include #include #include "audiomanagertypes.h" #ifdef WITH_TIMERFD #include #include #include #include #include #endif namespace am { #define MAX_NS 1000000000L #define MAX_TIMERHANDLE INT16_MAX #define MAX_POLLHANDLE INT16_MAX typedef uint16_t sh_timerHandle_t; //! class TAmShPollFired: public IAmShPollFired { private: TClass* mInstance; void (TClass::*mFunction)(const pollfd pollfd, const sh_pollHandle_t handle, void* userData); public: TAmShPollFired(TClass* instance, void (TClass::*function)(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)) : mInstance(instance), // 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: TClass* mInstance; bool (TClass::*mFunction)(const sh_pollHandle_t handle, void* userData); public: TAmShPollCheck(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)); } ; }; /** * template for a callback */ template 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)); } ; }; /** * template to create the functor for a class */ template class TAmShTimerCallBack: public IAmShTimerCallBack { private: TClass* mInstance; void (TClass::*mFunction)(sh_timerHandle_t handle, void* userData); public: TAmShTimerCallBack(TClass* instance, void (TClass::*function)(sh_timerHandle_t handle, void* userData)) : IAmShTimerCallBack(), mInstance(instance), // mFunction(function) { } ; virtual void Call(sh_timerHandle_t handle, void* userData) { (*mInstance.*mFunction)(handle, userData); } }; /** * template for a callback */ template class TAmShPollPrepare: public IAmShPollPrepare { 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) { } ; virtual void Call(const sh_timerHandle_t handle, void* userData) { (*mInstance.*mFunction)(handle, userData); } ; }; /** * 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 { struct sh_poll_s //! rListTimerIter; //! mListPollfd_t; //! mListPoll_t; //!Call(handle, userData); return false; } }; #endif public: 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; } bool checkerCallback(const sh_pollHandle_t handle, void* userData) { (void) handle; (void) userData; return (false); } private: TAmShPollFired 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) { 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 */ inline static timespec timespecSub(const timespec& a, const timespec& b) { timespec result; 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); } /** * 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); } /** * 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); } /** * 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)); } /** * 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)); } 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); }; class CAmShCallFire //!< functor to call the firecallbacks { public: CAmShCallFire() { } ; void operator()(sh_poll_s& row); }; class CAmShCallPrep //!< functor to call the preparation callbacks { public: CAmShCallPrep() { } ; void operator()(sh_poll_s& row); }; 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; //!