diff options
author | GENIVI Audio Manager Maintainer <genivi-maint-audiomanager@smtp1.genivi.org> | 2017-08-22 14:50:37 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-22 14:50:37 +0200 |
commit | f620be8a774f966fbd76ca8892a39ce28037a213 (patch) | |
tree | 9baabfbf751e85d0980f74e55e8332f6e20c379f | |
parent | 8f2387e42641c7c2b967553a4c578f0e87549fb6 (diff) | |
parent | be63615585049aa4045f13e91291d64b0a9ed5a3 (diff) | |
download | audiomanager-f620be8a774f966fbd76ca8892a39ce28037a213.tar.gz |
Merge pull request #16 from GENIVI/utility_updates
Utility updates
26 files changed, 3215 insertions, 1510 deletions
diff --git a/AudioManagerCore/include/CAmCommandSender.h b/AudioManagerCore/include/CAmCommandSender.h index caa72ad..2f7daec 100644 --- a/AudioManagerCore/include/CAmCommandSender.h +++ b/AudioManagerCore/include/CAmCommandSender.h @@ -88,7 +88,7 @@ private: std::vector<std::string> mListLibraryNames; //!< list of all library names. This information is used for getListPlugins. CAmCommandReceiver *mCommandReceiver; - CAmSerializer mSerializer; + V2::CAmSerializer mSerializer; }; diff --git a/AudioManagerCore/src/CAmCommandReceiver.cpp b/AudioManagerCore/src/CAmCommandReceiver.cpp index 0c6338a..ccf9612 100644 --- a/AudioManagerCore/src/CAmCommandReceiver.cpp +++ b/AudioManagerCore/src/CAmCommandReceiver.cpp @@ -120,7 +120,7 @@ am_Error_e CAmCommandReceiver::setMainSourceSoundProperty(const am_MainSoundProp am_Error_e CAmCommandReceiver::setSystemProperty(const am_SystemProperty_s & property) { - logInfo(__METHOD_NAME__,"type=", property.type, "soundPropertyValue=", property.value); + logInfo(__METHOD_NAME__,"type=", property.type, "systemPropertyValue=", property.value); return (mControlSender->hookUserSetSystemProperty(property)); } diff --git a/AudioManagerCore/src/CAmCommandSender.cpp b/AudioManagerCore/src/CAmCommandSender.cpp index ea0d749..6626bdb 100644 --- a/AudioManagerCore/src/CAmCommandSender.cpp +++ b/AudioManagerCore/src/CAmCommandSender.cpp @@ -163,10 +163,10 @@ CAmCommandSender::CAmCommandSender(const std::vector<std::string>& listOfPluginD } dboNewMainConnection = [&](const am_MainConnectionType_s& mainConnection) { - mSerializer.asyncCall<CAmCommandSender, const am_MainConnectionType_s>(this, &CAmCommandSender::cbNewMainConnection, mainConnection); + mSerializer.asyncCall(this, &CAmCommandSender::cbNewMainConnection, mainConnection); }; dboRemovedMainConnection = [&](const am_mainConnectionID_t mainConnection) { - mSerializer.asyncCall<CAmCommandSender, const am_mainConnectionID_t>(this, &CAmCommandSender::cbRemovedMainConnection, mainConnection); + mSerializer.asyncCall(this, &CAmCommandSender::cbRemovedMainConnection, mainConnection); }; dboNewSink = [&](const am_Sink_s& sink) { if (sink.visible) @@ -178,7 +178,8 @@ CAmCommandSender::CAmCommandSender(const std::vector<std::string>& listOfPluginD s.sinkClassID = sink.sinkClassID; s.sinkID = sink.sinkID; s.volume = sink.mainVolume; - mSerializer.asyncCall<CAmCommandSender, const am_SinkType_s>(this, &CAmCommandSender::cbNewSink, s); + typedef void(CAmCommandSender::*TMeth)(am::am_SinkType_s) ; + mSerializer.asyncCall<CAmCommandSender, TMeth, am::am_SinkType_s>(this, &CAmCommandSender::cbNewSink, s); } }; dboNewSource = [&](const am_Source_s& source) { @@ -189,64 +190,65 @@ CAmCommandSender::CAmCommandSender(const std::vector<std::string>& listOfPluginD s.name = source.name; s.sourceClassID = source.sourceClassID; s.sourceID = source.sourceID; - mSerializer.asyncCall<CAmCommandSender, const am_SourceType_s>(this, &CAmCommandSender::cbNewSource, s); + typedef void(CAmCommandSender::*TMeth)(am::am_SourceType_s) ; + mSerializer.asyncCall<CAmCommandSender, TMeth, am::am_SourceType_s>(this, &CAmCommandSender::cbNewSource, s); } }; dboRemovedSink = [&](const am_sinkID_t sinkID, const bool visible) { if (visible) - mSerializer.asyncCall<CAmCommandSender, const am_sinkID_t>(this, &CAmCommandSender::cbRemovedSink, sinkID); + mSerializer.asyncCall(this, &CAmCommandSender::cbRemovedSink, sinkID); }; dboRemovedSource = [&](const am_sourceID_t sourceID, const bool visible) { if (visible) - mSerializer.asyncCall<CAmCommandSender, const am_sourceID_t>(this, &CAmCommandSender::cbRemovedSource, sourceID); + mSerializer.asyncCall(this, &CAmCommandSender::cbRemovedSource, sourceID); }; dboNumberOfSinkClassesChanged = [&]() { - mSerializer.asyncCall<CAmCommandSender>(this, &CAmCommandSender::cbNumberOfSinkClassesChanged); + mSerializer.asyncCall(this, &CAmCommandSender::cbNumberOfSinkClassesChanged); }; dboNumberOfSourceClassesChanged = [&]() { - mSerializer.asyncCall<CAmCommandSender>(this, &CAmCommandSender::cbNumberOfSourceClassesChanged); + mSerializer.asyncCall(this, &CAmCommandSender::cbNumberOfSourceClassesChanged); }; dboMainConnectionStateChanged = [&](const am_mainConnectionID_t connectionID, const am_ConnectionState_e connectionState) { - mSerializer.asyncCall<CAmCommandSender, const am_connectionID_t, const am_ConnectionState_e>(this, &CAmCommandSender::cbMainConnectionStateChanged, connectionID, connectionState); + mSerializer.asyncCall(this, &CAmCommandSender::cbMainConnectionStateChanged, connectionID, connectionState); }; dboMainSinkSoundPropertyChanged = [&](const am_sinkID_t sinkID, const am_MainSoundProperty_s& SoundProperty) { - mSerializer.asyncCall<CAmCommandSender, const am_sinkID_t, const am_MainSoundProperty_s>(this, &CAmCommandSender::cbMainSinkSoundPropertyChanged, sinkID, SoundProperty); + mSerializer.asyncCall(this, &CAmCommandSender::cbMainSinkSoundPropertyChanged, sinkID, SoundProperty); }; dboMainSourceSoundPropertyChanged = [&](const am_sourceID_t sourceID, const am_MainSoundProperty_s& SoundProperty) { - mSerializer.asyncCall<CAmCommandSender, const am_sourceID_t, const am_MainSoundProperty_s>(this, &CAmCommandSender::cbMainSourceSoundPropertyChanged, sourceID, SoundProperty); + mSerializer.asyncCall(this, &CAmCommandSender::cbMainSourceSoundPropertyChanged, sourceID, SoundProperty); }; dboSinkAvailabilityChanged = [&](const am_sinkID_t sinkID, const am_Availability_s & availability) { - mSerializer.asyncCall<CAmCommandSender, const am_sinkID_t, const am_Availability_s>(this, &CAmCommandSender::cbSinkAvailabilityChanged, sinkID, availability); + mSerializer.asyncCall(this, &CAmCommandSender::cbSinkAvailabilityChanged, sinkID, availability); }; dboSourceAvailabilityChanged = [&](const am_sourceID_t sourceID, const am_Availability_s & availability) { - mSerializer.asyncCall<CAmCommandSender, const am_sourceID_t, const am_Availability_s>(this, &CAmCommandSender::cbSourceAvailabilityChanged, sourceID, availability); + mSerializer.asyncCall(this, &CAmCommandSender::cbSourceAvailabilityChanged, sourceID, availability); }; dboVolumeChanged = [&](const am_sinkID_t sinkID, const am_mainVolume_t volume) { - mSerializer.asyncCall<CAmCommandSender, const am_sinkID_t, const am_mainVolume_t>(this, &CAmCommandSender::cbVolumeChanged, sinkID, volume); + mSerializer.asyncCall(this, &CAmCommandSender::cbVolumeChanged, sinkID, volume); }; dboSinkMuteStateChanged = [&](const am_sinkID_t sinkID, const am_MuteState_e muteState) { - mSerializer.asyncCall<CAmCommandSender, const am_sinkID_t, const am_MuteState_e>(this, &CAmCommandSender::cbSinkMuteStateChanged, sinkID, muteState); + mSerializer.asyncCall(this, &CAmCommandSender::cbSinkMuteStateChanged, sinkID, muteState); }; dboSystemPropertyChanged = [&](const am_SystemProperty_s& SystemProperty) { - mSerializer.asyncCall<CAmCommandSender, const am_SystemProperty_s>(this, &CAmCommandSender::cbSystemPropertyChanged, SystemProperty); + mSerializer.asyncCall(this, &CAmCommandSender::cbSystemPropertyChanged, SystemProperty); }; dboTimingInformationChanged = [&](const am_mainConnectionID_t mainConnection, const am_timeSync_t time) { - mSerializer.asyncCall<CAmCommandSender, const am_mainConnectionID_t, const am_timeSync_t>(this, &CAmCommandSender::cbTimingInformationChanged, mainConnection, time); + mSerializer.asyncCall(this, &CAmCommandSender::cbTimingInformationChanged, mainConnection, time); }; dboSinkUpdated = [&](const am_sinkID_t sinkID, const am_sinkClass_t sinkClassID, const std::vector<am_MainSoundProperty_s>& listMainSoundProperties, const bool visible) { if (visible) - mSerializer.asyncCall<CAmCommandSender, const am_sinkID_t, const am_sinkClass_t, const std::vector<am_MainSoundProperty_s> >(this, &CAmCommandSender::cbSinkUpdated, sinkID, sinkClassID, listMainSoundProperties); + mSerializer.asyncCall(this, &CAmCommandSender::cbSinkUpdated, sinkID, sinkClassID, listMainSoundProperties); }; dboSourceUpdated = [&](const am_sourceID_t sourceID, const am_sourceClass_t sourceClassID, const std::vector<am_MainSoundProperty_s>& listMainSoundProperties, const bool visible) { if (visible) - mSerializer.asyncCall<CAmCommandSender, const am_sourceID_t, const am_sourceClass_t, const std::vector<am_MainSoundProperty_s> >(this, &CAmCommandSender::cbSinkUpdated, sourceID, sourceClassID, listMainSoundProperties); + mSerializer.asyncCall(this, &CAmCommandSender::cbSinkUpdated, sourceID, sourceClassID, listMainSoundProperties); }; dboSinkMainNotificationConfigurationChanged = [&](const am_sinkID_t sinkID, const am_NotificationConfiguration_s mainNotificationConfiguration) { - mSerializer.asyncCall<CAmCommandSender, const am_sinkID_t, const am_NotificationConfiguration_s> (this, &CAmCommandSender::cbSinkMainNotificationConfigurationChanged, sinkID, mainNotificationConfiguration); + mSerializer.asyncCall(this, &CAmCommandSender::cbSinkMainNotificationConfigurationChanged, sinkID, mainNotificationConfiguration); }; dboSourceMainNotificationConfigurationChanged = [&](const am_sourceID_t sourceID, const am_NotificationConfiguration_s mainNotificationConfiguration) { - mSerializer.asyncCall<CAmCommandSender, const am_sourceID_t, const am_NotificationConfiguration_s>(this, &CAmCommandSender::cbSourceMainNotificationConfigurationChanged, sourceID, mainNotificationConfiguration); + mSerializer.asyncCall(this, &CAmCommandSender::cbSourceMainNotificationConfigurationChanged, sourceID, mainNotificationConfiguration); }; } diff --git a/AudioManagerCore/src/CAmDatabaseHandlerMap.cpp b/AudioManagerCore/src/CAmDatabaseHandlerMap.cpp index 48ef37b..cc95d28 100644 --- a/AudioManagerCore/src/CAmDatabaseHandlerMap.cpp +++ b/AudioManagerCore/src/CAmDatabaseHandlerMap.cpp @@ -3393,22 +3393,20 @@ am_Error_e CAmDatabaseHandlerMap::enumerateConverters(std::function<void(const a bool CAmDatabaseHandlerMap::registerObserver(IAmDatabaseObserver * iObserver) { assert(iObserver!=NULL); - if (std::find(mDatabaseObservers.begin(), mDatabaseObservers.end(), - iObserver) == mDatabaseObservers.end()) { - mDatabaseObservers.push_back( - dynamic_cast<AmDatabaseObserverCallbacks*>(iObserver)), dynamic_cast<AmDatabaseObserverCallbacks*>(iObserver)->mpDatabaseHandler = - nullptr; + if (std::find(mDatabaseObservers.begin(), mDatabaseObservers.end(), iObserver) == mDatabaseObservers.end()) + { + mDatabaseObservers.push_back(static_cast<AmDatabaseObserverCallbacks*>(iObserver)); + static_cast<AmDatabaseObserverCallbacks*>(iObserver)->mpDatabaseHandler = this; return true; } return false; } bool CAmDatabaseHandlerMap::unregisterObserver(IAmDatabaseObserver * iObserver) { assert(iObserver!=NULL); - auto it = std::find(mDatabaseObservers.begin(), mDatabaseObservers.end(), - iObserver); + auto it = std::find(mDatabaseObservers.begin(), mDatabaseObservers.end(), iObserver); if (it != mDatabaseObservers.end()) { - mDatabaseObservers.erase(it), dynamic_cast<AmDatabaseObserverCallbacks*>(iObserver)->mpDatabaseHandler = - nullptr; + mDatabaseObservers.erase(it); + static_cast<AmDatabaseObserverCallbacks*>(iObserver)->mpDatabaseHandler = nullptr; return true; } return false; diff --git a/AudioManagerCore/test/AmControlInterfaceTest/CMakeLists.txt b/AudioManagerCore/test/AmControlInterfaceTest/CMakeLists.txt index f2636a8..b1a0dae 100644 --- a/AudioManagerCore/test/AmControlInterfaceTest/CMakeLists.txt +++ b/AudioManagerCore/test/AmControlInterfaceTest/CMakeLists.txt @@ -37,6 +37,7 @@ add_executable(AmControlInterfaceTest ${CONTROL_INTERFACE_SRCS_CXX}) TARGET_LINK_LIBRARIES(AmControlInterfaceTest ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} AudioManagerCore ) diff --git a/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.cpp b/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.cpp index fe2f68a..7b11af1 100644 --- a/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.cpp +++ b/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.cpp @@ -47,10 +47,10 @@ TCLAP::SwitchArg enableDebug ("V","logDlt","print DLT logs to stdout or dlt-daem CAmMapBasicTest::CAmMapBasicTest() : + pSocketHandler(),// pDatabaseHandler(), // plistRoutingPluginDirs(), // plistCommandPluginDirs(), // - pSocketHandler(),// pRoutingSender(plistRoutingPluginDirs,dynamic_cast<IAmDatabaseHandler*>( &pDatabaseHandler )), // pCommandSender(plistCommandPluginDirs, &pSocketHandler), // pRoutingInterfaceBackdoor(), // diff --git a/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.h b/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.h index 32add3d..fc4b023 100644 --- a/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.h +++ b/AudioManagerCore/test/AmMapHandlerTest/CAmMapHandlerTest.h @@ -54,13 +54,14 @@ public: CAmMapBasicTest(); ~CAmMapBasicTest(); CAmSocketHandler pSocketHandler; + CAmDatabaseHandlerMap pDatabaseHandler; std::vector<std::string> plistRoutingPluginDirs; std::vector<std::string> plistCommandPluginDirs; CAmRoutingSender pRoutingSender; CAmCommandSender pCommandSender; IAmRoutingBackdoor pRoutingInterfaceBackdoor; IAmCommandBackdoor pCommandInterfaceBackdoor; - CAmDatabaseHandlerMap pDatabaseHandler; + CAmControlSender pControlSender; CAmRouter pRouter; CAmControlReceiver pControlReceiver; diff --git a/AudioManagerCore/test/AmMapHandlerTest/CMakeLists.txt b/AudioManagerCore/test/AmMapHandlerTest/CMakeLists.txt index 41c62c7..5a74cba 100644 --- a/AudioManagerCore/test/AmMapHandlerTest/CMakeLists.txt +++ b/AudioManagerCore/test/AmMapHandlerTest/CMakeLists.txt @@ -36,6 +36,7 @@ ADD_EXECUTABLE( AmMapHandlerTest ${DATABASE_SRCS_CXX}) TARGET_LINK_LIBRARIES( AmMapHandlerTest ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} AudioManagerCore ) diff --git a/AudioManagerCore/test/AmRouterMapTest/CMakeLists.txt b/AudioManagerCore/test/AmRouterMapTest/CMakeLists.txt index dc2732c..c4a5968 100644 --- a/AudioManagerCore/test/AmRouterMapTest/CMakeLists.txt +++ b/AudioManagerCore/test/AmRouterMapTest/CMakeLists.txt @@ -34,6 +34,7 @@ ADD_EXECUTABLE( AmRouterMapTest ${ROUTINGMAP_SRCS_CXX}) TARGET_LINK_LIBRARIES(AmRouterMapTest ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} AudioManagerCore ) diff --git a/AudioManagerCore/test/AmRouterTest/CMakeLists.txt b/AudioManagerCore/test/AmRouterTest/CMakeLists.txt index 89094c8..d866032 100644 --- a/AudioManagerCore/test/AmRouterTest/CMakeLists.txt +++ b/AudioManagerCore/test/AmRouterTest/CMakeLists.txt @@ -35,6 +35,7 @@ ADD_EXECUTABLE( AmRouterTest ${ROUTING_SRCS_CXX}) TARGET_LINK_LIBRARIES(AmRouterTest ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} AudioManagerCore ) diff --git a/AudioManagerCore/test/AmRoutingInterfaceTest/CMakeLists.txt b/AudioManagerCore/test/AmRoutingInterfaceTest/CMakeLists.txt index 6d47c15..369c536 100644 --- a/AudioManagerCore/test/AmRoutingInterfaceTest/CMakeLists.txt +++ b/AudioManagerCore/test/AmRoutingInterfaceTest/CMakeLists.txt @@ -38,6 +38,7 @@ ADD_TEST(AmRoutingInterfaceTest AmRoutingInterfaceTest) TARGET_LINK_LIBRARIES(AmRoutingInterfaceTest ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} AudioManagerCore ) diff --git a/AudioManagerDaemon/src/main.cpp b/AudioManagerDaemon/src/main.cpp index 26d7cea..5c0582e 100755 --- a/AudioManagerDaemon/src/main.cpp +++ b/AudioManagerDaemon/src/main.cpp @@ -195,7 +195,7 @@ static void signalHandler(int sig, siginfo_t *siginfo, void *context) switch (sig) { /*ctl +c lets call direct controllerRundown, because we might be blocked at the moment. - But there is the risk of interrupting something important */https://asc.bmwgroup.net/wiki/display/MGUROTO/Lastest+and+greatest + But there is the risk of interrupting something important */ case SIGINT: CAmControlSender::CallsetControllerRundown(sig); break; @@ -204,21 +204,12 @@ static void signalHandler(int sig, siginfo_t *siginfo, void *context) case SIGQUIT: CAmControlSender::CallsetControllerRundown(sig); break; - - /* more friendly here assuming systemd wants to stop us, so we can use the mainloop */ - case SIGTERM: - CAmControlSender::CallsetControllerRundownSafe(sig); - break; - - /* looks friendly, too, so lets take the long run */ - case SIGHUP: - CAmControlSender::CallsetControllerRundownSafe(sig); - break; default: break; } } + void mainProgram(int argc, char *argv[]) { @@ -255,6 +246,39 @@ void mainProgram(int argc, char *argv[]) //Instantiate all classes. Keep in same order ! CAmSocketHandler iSocketHandler; + if(iSocketHandler.fatalErrorOccurred()) + { + throw std::runtime_error(std::string("CAmSocketHandler: Could not create pipe or file descriptor is invalid.")); + } + + if( E_OK!=iSocketHandler.listenToSignals({SIGHUP, SIGTERM, SIGCHLD}) ) + { + logWarning("CAmSocketHandler failed to register itself as signal handler."); + } + //Register signal handler + sh_pollHandle_t signalHandler; + iSocketHandler.addSignalHandler([&](const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData){ + + unsigned sig = info.ssi_signo; + unsigned user = info.ssi_uid; + + logInfo("signal handler was called from user", user, "with signal ",sig); + + switch (sig) + { + /* more friendly here assuming systemd wants to stop us, so we can use the mainloop */ + case SIGTERM: + CAmControlSender::CallsetControllerRundownSafe(sig); + break; + + /* looks friendly, too, so lets take the long run */ + case SIGHUP: + CAmControlSender::CallsetControllerRundownSafe(sig); + break; + default: + break; + } + },signalHandler,NULL); if(commandPluginDir.isSet()) { @@ -364,21 +388,14 @@ int main(int argc, char *argv[], char** envp) listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR)); listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR)); - //now the signal handler: + //critical signals are registered here: struct sigaction signalAction; memset(&signalAction, '\0', sizeof(signalAction)); signalAction.sa_sigaction = &signalHandler; signalAction.sa_flags = SA_SIGINFO; sigaction(SIGINT, &signalAction, NULL); sigaction(SIGQUIT, &signalAction, NULL); - sigaction(SIGTERM, &signalAction, NULL); - sigaction(SIGHUP, &signalAction, NULL); - - struct sigaction signalChildAction; - memset(&signalChildAction, '\0', sizeof(signalChildAction)); - signalChildAction.sa_flags = SA_NOCLDWAIT; - sigaction(SIGCHLD, &signalChildAction, NULL); - + //register new out of memory handler std::set_new_handler(&OutOfMemoryHandler); diff --git a/AudioManagerUtilities/include/CAmSerializer.h b/AudioManagerUtilities/include/CAmSerializer.h index b0cd70e..6bd6143 100644 --- a/AudioManagerUtilities/include/CAmSerializer.h +++ b/AudioManagerUtilities/include/CAmSerializer.h @@ -1,10 +1,10 @@ /** * SPDX license identifier: MPL-2.0 * - * Copyright (C) 2012, BMW AG + * Copyright (C) 2012-2017, BMW AG * * \author Christian Linke, christian.linke@bmw.de BMW 2011,2012 - * \author Alesksandar Donchev, aleksander.donchev@partner.bmw.de BMW 2015 + * \author Alesksandar Donchev, aleksander.donchev@partner.bmw.de BMW 2015, 2017 * * \copyright * This Source Code Form is subject to the terms of the @@ -27,779 +27,1192 @@ #include "CAmDltWrapper.h" #include "CAmSocketHandler.h" -/** - * todo: performance improvement we could implement a memory pool that is more efficient here and avoids - * allocation and deallocation times. +/*! + * \brief Helper structures used within std::bind for automatically identification of all placeholders. */ - -namespace am +template<std::size_t ... Is> +struct indices { -/** - * magic class that does the serialization of functions calls - * The constructor must be called within the main threadcontext, after that using the - * overloaded template function call will serialize all calls and call them within the - * main thread context.\n - * More details can be found here: \ref util - * \warning asynchronous calls may be used in the mainthread context, but if you want to use synchronous calls make sure that you use one - * instance of this class per thread otherwise you could be lost in never returning calls.\n - * Examples of the usage can be found in IAmCommandReceiverShadow of the ControlPlugin or IAmRoutingReceiverShadow of the - * PluginRoutingInterfaceAsync. - * - */ -class CAmSerializer -{ -private: - - /** - * Prototype for a delegate - */ - class CAmDelegate - { - public: - - typedef enum:bool { - SyncCallType = false, - AsyncCallType = true - } CallType; - - virtual ~CAmDelegate() - {}; - virtual CallType call(int* pipe)=0; - - }; - - /** - * Prototype for a delegate with variadic template arguments in conjunction with the following class. - */ - template <class Class, typename Method, typename Tuple, bool Done, int Total, int... N> - class CAmDelegateAsyncImpl : public CAmDelegate - { - Class mInstance; - Method mMethod; - Tuple mArguments; - public: - friend class CAmSerializer; - static void call(Class instance, Method method, Tuple && arguments) - { - CAmDelegateAsyncImpl<Class, Method, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(instance, method, std::forward<Tuple>(arguments)); - } - - CAmDelegateAsyncImpl(Class instance, Method method, Tuple && arguments) - { - mInstance = instance; - mMethod = method; - mArguments = std::move(arguments); - } - - CallType call(int* pipe) - { - (void) pipe; - call(mInstance, mMethod, std::forward<Tuple>(mArguments)); - return (AsyncCallType); - }; - }; - - /** - * Prototype for a delegate with variadic template arguments. - */ - template <class Class, typename Method, typename Tuple, int Total, int... N> - class CAmDelegateAsyncImpl<Class, Method, Tuple, true, Total, N...> : public CAmDelegate - { - Class mInstance; - Method mMethod; - Tuple mArguments; - public: - friend class CAmSerializer; - static void call(Class instance, Method method, Tuple && t) - { - (*instance.*method)(std::get<N>(std::forward<Tuple>(t))...); - } - - CAmDelegateAsyncImpl(Class instance, Method method, Tuple && arguments) - { - mInstance = instance; - mMethod = method; - mArguments = std::move(arguments); - } - - CallType call(int* pipe) - { - (void) pipe; - call(mInstance, mMethod, std::forward<Tuple>(mArguments)); - return (AsyncCallType); - }; - }; - - /** - * Prototype for a delegate with variadic template arguments in conjunction with the following class. - */ - template <class Class, typename Method, typename Return, typename Tuple, bool Done, int Total, int... N> - class CAmDelegateSyncImpl : public CAmDelegate - { - Class mInstance; - Method mMethod; - Tuple mArguments; - Return mReturn; - public: - friend class CAmSerializer; - static void call(Class instance,Method method, Return & result, Tuple && arguments) - { - CAmDelegateSyncImpl<Class, Method, Return, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(instance, method, result, std::forward<Tuple>(arguments)); - } - - CAmDelegateSyncImpl(Class instance, Method method, Tuple && arguments) - { - mInstance = instance; - mMethod = method; - mArguments = std::move(arguments); - } - - CallType call(int* pipe) - { - call(mInstance, mMethod, mReturn, std::forward<Tuple>(mArguments)); - ssize_t result(-1); - result = write(pipe[1], this, sizeof(this)); - if (result == -1) - logError("CAmSerializer: Problem writing into pipe! Error No:",errno); - return (SyncCallType); - }; - }; - - /** - * Prototype for a delegate with variadic template arguments. - */ - template <class Class, typename Method, typename Return, typename Tuple, int Total, int... N> - class CAmDelegateSyncImpl<Class, Method, Return, Tuple, true, Total, N...> : public CAmDelegate - { - Class mInstance; - Method mMethod; - Tuple mArguments; - Return mReturn; - public: - friend class CAmSerializer; - static void call(Class instance, Method method, Return & result, Tuple && t) - { - result = (*instance.*method)(std::get<N>(t)...); - } - - CAmDelegateSyncImpl(Class instance, Method method, Tuple && arguments) - { - mInstance = instance; - mMethod = method; - mArguments = std::move(arguments); - } - - CallType call(int* pipe) - { - call(mInstance, mMethod, mReturn, std::forward<Tuple>(mArguments)); - ssize_t result(-1); - result = write(pipe[1], this, sizeof(this)); - if (result == -1) - logError("CAmSerializer: Problem writing into pipe! Error No:",errno); - return (SyncCallType); - }; - }; - - typedef CAmDelegate* CAmDelegagePtr; //!< pointer to a delegate - -public: - /** - * instantiates a async delegate with given arguments and sends the delegate pointer over the pipe - */ - template <typename Class, typename Method, typename Tuple> - void doAsyncCall(Class intsance, Method method, Tuple & arguments) - { - typedef typename std::decay<Tuple>::type ttype; - typedef CAmDelegateAsyncImpl<Class, Method, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value> AsyncDelegate; - AsyncDelegate *pImp = new AsyncDelegate(intsance, method, std::forward<Tuple>(arguments)); - send(pImp); - //Do not delete the pointer. It will be deleted automatically later. - } - - /** - * instantiates a sync delegate with given arguments and sends the delegate pointer over the pipe - */ - template <typename Class, typename Method, typename Return, typename Tuple> - void doSyncCall(Class intsance, Method method, Return & result, Tuple & arguments) - { - typedef typename std::decay<Tuple>::type ttype; - typedef CAmDelegateSyncImpl<Class, Method, Return, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value> SyncDelegate; - SyncDelegate *pImp = new SyncDelegate(intsance, method, std::forward<Tuple>(arguments)); - send(pImp); - int numReads; - SyncDelegate *p = NULL; - if ((numReads = read(mReturnPipe[0], &p, sizeof(p))) == -1) - { - logError("CAmSerializer::doSyncCall could not read pipe!"); - throw std::runtime_error("CAmSerializer Could not read pipe!"); - } - result = std::move(pImp->mReturn); - arguments = std::move(pImp->mArguments); - //Delete the pointer. - delete pImp; - } -private: - - /** - * rings the line of the pipe and adds the delegate pointer to the queue - * @param p delegate pointer - */ - inline void send(CAmDelegagePtr p) - { - if (write(mPipe[1], &p, sizeof(p)) == -1) - { - throw std::runtime_error("could not write to pipe !"); - } - } - - int mPipe[2]; //!< the pipe - int mReturnPipe[2]; //!< pipe handling returns - sh_pollHandle_t mHandle; - CAmSocketHandler* mpSocketHandler; - std::deque<CAmDelegagePtr> mListDelegatePoiters; //!< intermediate queue to store the pipe results - -public: - - /** - * get the size of delegate pointers - */ - int getListDelegatePoiters() - { - return mListDelegatePoiters.size(); - } - - /** - * calls a function with variadic arguments threadsafe - * @param instance the instance of the class that shall be called - * @param function the function that shall be called as member function pointer. - * @param output variable. - * @tparam TClass the type of the Class to be called - * @tparam TRet the type of the result - * @tparam TArgs argument list - * \section ex Example: - * @code - * class MyGreatClass - * { - * public: - * int AGreatMethod(int x); - * } - * CAmSerializer serial(&Sockethandler); - * MyGreatClass anInstance; - * int result; - * serial.syncCall<MyGreatClass, int, int>(&anInstance,&MyGreatClass::AGreatMethod, result, 100); - * @endcode - */ - template<class TClass, class TRet, class ... TArgs> - void syncCall(TClass* instance, TRet (TClass::*method)(TArgs ...), TRet & result, TArgs & ... arguments) - { - auto t = std::make_tuple(arguments...); - doSyncCall(instance, method, result, t); - std::tie(arguments...) = t; - } - - /** - * calls a function with variadic arguments threadsafe - * @param instance the instance of the class that shall be called - * @param function the function that shall be called as member function pointer. - * @tparam TClass the type of the Class to be called - * @tparam TRet the type of the result - * @tparam TArgs argument list - * \section ex Example: - * @code - * class MyGreatClass - * { - * public: - * int AGreatMethod(int x); - * } - * CAmSerializer serial(&Sockethandler); - * MyGreatClass anInstance; - * serial.asyncCall<MyGreatClass, void, int>(&anInstance,&MyGreatClass::AGreatMethod, 100); - * @endcode - */ - template<class TClass, class TRet, class ... TArgs> - void asyncCall(TClass* instance, TRet (TClass::*method)(TArgs ...), TArgs & ... arguments) - { - auto t = std::make_tuple(arguments...); - doAsyncCall(instance, method, t); - } - - /** - * calls a function with no arguments threadsafe - * @param instance the instance of the class that shall be called - * @param function the function that shall be called as memberfunction pointer. - * @tparam TClass1 the type of the Class to be called - * \section ex Example: - * @code - * class myClass - * { - * public: - * void myfunction(); - * } - * CAmSerializer serial(&Sockethandler); - * myClass instanceMyClass; - * serial<CommandSender>(&instanceMyClass,&myClass::myfunction); - * @endcode - */ - template<class TClass> - void asyncCall(TClass* instance, void (TClass::*function)()) - { - auto t = std::make_tuple(); - doAsyncCall(instance, function, t); - } - - /** - * calls a function with one arguments asynchronously threadsafe - * @param instance the instance of the class that shall be called - * @param function the function that shall be called as memberfunction pointer. - * @param argument the argument - * @tparam TClass1 the type of the Class to be called - * @tparam Targ the type of the argument to be called - * \section ex Example: - * @code - * class myClass - * { - * public: - * void myfunction(int k); - * } - * CAmSerializer serial(&Sockethandler); - * myClass instanceMyClass; - * serial<CommandSender,int>(&instanceMyClass,&myClass::myfunction,k); - * @endcode - * - */ - template<class TClass1, class Targ> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ), Targ argument) - { - auto t = std::make_tuple(argument); - doAsyncCall(instance, function, t); - } - - /** - * calls a function with one argument called by reference asynchronously threadsafe - * @param instance the instance of the class that shall be called - * @param function the function that shall be called as memberfunction pointer. - * @param argument the argument - * @tparam TClass1 the type of the Class to be called - * @tparam Targ the type of the argument to be called - * \section ex Example: - * @code - * class myClass - * { - * public: - * void myfunction(int k); - * } - * CAmSerializer serial(&Sockethandler); - * myClass instanceMyClass; - * serial<CommandSender,int>(&instanceMyClass,&myClass::myfunction,k); - * @endcode - * - */ - template<class TClass1, class Targ> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ&), Targ& argument) - { - auto t = std::make_tuple(argument); - doAsyncCall(instance, function, t); - } - - /** - * calls a function with two arguments asynchronously threadsafe. for more see asyncCall with one argument - * @param instance pointer to the instance of the class - * @param function memberfunction poitner - * @param argument the first argument - * @param argument1 the second argument - * @tparam TClass1 the type of the Class to be called - * @tparam Targ the type of the argument to be called - * @tparam Targ1 the type of the first argument to be called - */ - template<class TClass1, class Targ, class Targ1> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1 argument1), Targ argument, Targ1 argument1) - { - auto t = std::make_tuple(argument,argument1); - doAsyncCall(instance, function, t); - } - - /** - * calls a function with two arguments asynchronously threadsafe, first argument is a reference. for more see asyncCall with one argument - * @param instance pointer to the instance of the class - * @param function memberfunction poitner - * @param argument the first argument - * @param argument1 the second argument - * @tparam TClass1 the type of the Class to be called - * @tparam Targ the type of the argument to be called - * @tparam Targ1 the type of the first argument to be called - */ - template<class TClass1, class Targ, class Targ1> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1 argument1), Targ& argument, Targ1 argument1) - { - auto t = std::make_tuple(argument,argument1); - doAsyncCall(instance, function, t); - } - - /** - * calls a function with two arguments asynchronously threadsafe, second argument is a reference. for more see asyncCall with one argument - * @param instance pointer to the instance of the class - * @param function memberfunction poitner - * @param argument the first argument - * @param argument1 the second argument - * @tparam TClass1 the type of the Class to be called - * @tparam Targ the type of the argument to be called - * @tparam Targ1 the type of the first argument to be called - */ - template<class TClass1, class Targ, class Targ1> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1& argument1), Targ argument, Targ1& argument1) - { - auto t = std::make_tuple(argument,argument1); - doAsyncCall(instance, function, t); - } - - /** - * calls a function with two arguments asynchronously threadsafe, both arguments are references. for more see asyncCall with one argument - * @param instance pointer to the instance of the class - * @param function memberfunction poitner - * @param argument the first argument - * @param argument1 the second argument - * @tparam TClass1 the type of the Class to be called - * @tparam Targ the type of the argument to be called - * @tparam Targ1 the type of the first argument to be called - */ - template<class TClass1, class Targ, class Targ1> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1& argument1), Targ& argument, Targ1& argument1) - { - auto t = std::make_tuple(argument,argument1); - doAsyncCall(instance, function, t); - } - - /** - * calls a function with three arguments asynchronously threadsafe. for more see other asycCall - */ - template<class TClass1, class Targ, class Targ1, class Targ2> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1 argument1, Targ2 argument2), Targ argument, Targ1 argument1, Targ2 argument2) - { - auto t = std::make_tuple(argument,argument1, argument2); - doAsyncCall(instance, function, t); - } - - /** - * calls a function with three arguments asynchronously threadsafe. for more see other asycCall - */ - template<class TClass1, class Targ, class Targ1, class Targ2> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1 argument1, Targ2 argument2), Targ& argument, Targ1 argument1, Targ2 argument2) - { - auto t = std::make_tuple(argument,argument1, argument2); - doAsyncCall(instance, function, t); - } - - - /** - * calls a function with three arguments asynchronously threadsafe. for more see other asycCall - */ - template<class TClass1, class Targ, class Targ1, class Targ2> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1& argument1, Targ2 argument2), Targ argument, Targ1& argument1, Targ2 argument2) - { - auto t = std::make_tuple(argument,argument1, argument2); - doAsyncCall(instance, function, t); - } - - /** - * calls a function with three arguments asynchronously threadsafe. for more see other asycCall - */ - template<class TClass1, class Targ, class Targ1, class Targ2> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1 argument1, Targ2& argument2), Targ argument, Targ1 argument1, Targ2& argument2) - { - auto t = std::make_tuple(argument,argument1, argument2); - doAsyncCall(instance, function, t); - } +}; - /** - * calls a function with three arguments asynchronously threadsafe. for more see other asycCall - */ - template<class TClass1, class Targ, class Targ1, class Targ2> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1& argument1, Targ2& argument2), Targ argument, Targ1& argument1, Targ2& argument2) - { - auto t = std::make_tuple(argument,argument1, argument2); - doAsyncCall(instance, function, t); - } +template<std::size_t N, std::size_t ... Is> +struct build_indices: build_indices<N - 1, N - 1, Is...> +{ +}; - /** - * calls a function with three arguments asynchronously threadsafe. for more see other asycCall - */ - template<class TClass1, class Targ, class Targ1, class Targ2> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1& argument1, Targ2& argument2), Targ& argument, Targ1& argument1, Targ2& argument2) - { - auto t = std::make_tuple(argument,argument1, argument2); - doAsyncCall(instance, function, t); - } +template<std::size_t ... Is> +struct build_indices<0, Is...> : indices<Is...> +{ +}; - /** - * calls a function with three arguments asynchronously threadsafe. for more see other asycCall - */ - template<class TClass1, class Targ, class Targ1, class Targ2> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1& argument1, Targ2 argument2), Targ& argument, Targ1& argument1, Targ2 argument2) - { - auto t = std::make_tuple(argument,argument1, argument2); - doAsyncCall(instance, function, t); - } +template<int I> struct placeholder +{ +}; - /** - * calls a function with three arguments asynchronously threadsafe. for more see other asycCall - */ - template<class TClass1, class Targ, class Targ1, class Targ2> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1 argument1, Targ2& argument2), Targ& argument, Targ1 argument1, Targ2& argument2) +namespace std +{ + template<int I> + struct is_placeholder<::placeholder<I>> : std::integral_constant<int, I> { - auto t = std::make_tuple(argument,argument1, argument2); - doAsyncCall(instance, function, t); - } + }; +} - /** - * calls a function with four arguments asynchronously threadsafe. for more see other asycCall - */ - template<class TClass1, class Targ, class Targ1, class Targ2, class Targ3> - void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1 argument1, Targ2 argument2, Targ3 argument3), Targ argument, Targ1 argument1, Targ2 argument2, Targ3 argument3) - { - auto t = std::make_tuple(argument,argument1, argument2,argument3); - doAsyncCall(instance, function, t); - } +#if defined(__GNUC__) +# define DEPRECATED(MSG) __attribute__ ((__deprecated__((#MSG)))) +#else +# define DEPRECATED(MSG) +#endif +namespace am +{ /** - * calls a synchronous function with no arguments threadsafe - * @param instance the instance of the class that shall be called - * @param function the function that shall be called as memberfunction pointer. - * @param retVal the return parameter, no const allowed ! - * @tparam TClass1 the type of the class to be called - * @tparam TretVal the type of the return parameter - * \section ex Example: - * @code - * class myClass - * { - * public: - * am_Error_e myfunction(); - * } - * CAmSerializer serial(&Sockethandler); - * myClass instanceMyClass; - * am_Error_e error; - * serial<CommandSender,am_Error_e>(&instanceMyClass,&myClass::myfunction, error); - * @endcode - * All arguments given to synchronous functions must be non-const since the results of the operations will be written back to the arguments. + * magic class that does the serialization of functions calls + * The constructor must be called within the main threadcontext, after that using the + * overloaded template function call will serialize all calls and call them within the + * main thread context.\n + * More details can be found here: \ref util + * \warning asynchronous calls may be used in the mainthread context, but if you want to use synchronous calls make sure that you use one + * instance of this class per thread otherwise you could be lost in never returning calls.\n + * Examples of the usage can be found in IAmCommandReceiverShadow of the ControlPlugin or IAmRoutingReceiverShadow of the + * PluginRoutingInterfaceAsync. * */ - template<class TClass1, class TretVal> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(), TretVal& retVal) - { - auto t = std::make_tuple(); - doSyncCall(instance, function, retVal, t); - } - - /** - * calls a function with one argument synchronous threadsafe - * @param instance the instance of the class that shall be called - * @param function the function that shall be called as memberfunction pointer. - * @param retVal the return parameter, no const allowed ! - * @param argument the argument, no const allowed ! - * @tparam TClass1 the type of the class to be called - * @tparam TretVal the type of the return parameter - * @tparam TargCall the type of the argument like in the function to be called. here all references and const must be - * respected! - * @tparam Targ the type of the argument, here no const and no references allowed ! - * \section ex Example: - * @code - * class myClass - * { - * public: - * am_Error_e myfunction(int k); - * } - * CAmSerializer serial(&Sockethandler); - * myClass instanceMyClass; - * am_Error_e error; - * int l; - * serial<CommandSender,am_Error_e,int>(&instanceMyClass,&myClass::myfunction,error,l); - * @endcode - * All arguments given to synchronous functions must be non-const since the results of the operations will be written back to the arguments. - */ - template<class TClass1, class TretVal, class TargCall, class Targ> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall), TretVal& retVal, Targ& argument) - { - auto t = std::make_tuple(argument); - doSyncCall(instance, function, retVal, t); - std::tie(argument) = t; - } - - /** - * calls a function with one argument synchronous threadsafe for const functions. For more see syncCall with one argument - */ - template<class TClass1, class TretVal, class TargCall, class Targ> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall) const, TretVal& retVal, Targ& argument) - { - auto t = std::make_tuple(argument); - doSyncCall(instance, function, retVal, t); - std::tie(argument) = t; - } - - /** - * calls a function with two arguments synchronously threadsafe. For more see syncCall with one argument - */ - template<class TClass1, class TretVal, class TargCall, class Targ1Call, class Targ, class Targ1> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, Targ1Call), TretVal& retVal, Targ& argument, Targ1& argument1) - { - auto t = std::make_tuple(argument, argument1); - doSyncCall(instance, function, retVal, t); - std::tie(argument, argument1) = t; - } - /** - * calls a function with two arguments synchronously threadsafe const. For more see syncCall with one argument - */ - template<class TClass1, class TretVal, class TargCall, class Targ1Call, class Targ, class Targ1> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, Targ1Call) const, TretVal& retVal, Targ& argument, Targ1& argument1) - { - auto t = std::make_tuple(argument, argument1); - doSyncCall(instance, function, retVal, t); - std::tie(argument, argument1) = t; - } - - /** - * calls a function with three arguments synchronously threadsafe. for more see syncCall with one argument - */ - template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class Targ, class Targ1, class Targ2> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2), TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2) - { - auto t = std::make_tuple(argument, argument1, argument2); - doSyncCall(instance, function, retVal, t); - std::tie(argument, argument1,argument2) = t; - } - - /** - * calls a const function with three arguments synchronously threadsafe. for more see syncCall with one argument - */ - template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class Targ, class Targ1, class Targ2> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2) const, TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2) - { - auto t = std::make_tuple(argument, argument1, argument2); - doSyncCall(instance, function, retVal, t); - std::tie(argument, argument1,argument2) = t; - } - - /** - * calls a function with four arguments synchronously threadsafe. for more see syncCall with one argument - */ - template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class TargCall3, class Targ, class Targ1, class Targ2, class Targ3> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2, TargCall3), TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2, Targ3& argument3) - { - auto t = std::make_tuple(argument, argument1, argument2, argument3); - doSyncCall(instance, function, retVal, t); - std::tie(argument, argument1,argument2, argument3) = t; - } /** - * calls a function with five arguments synchronously threadsafe. for more see syncCall with one argument + * \defgroup Deprecated Obsolete class! + * @{ */ - template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class TargCall3, class TargCall4, class Targ, class Targ1, class Targ2, class Targ3, class Targ4> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2, TargCall3, TargCall4), TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2, Targ3& argument3, Targ4& argument4) - { - auto t = std::make_tuple(argument, argument1, argument2, argument3, argument4); - doSyncCall(instance, function, retVal, t); - std::tie(argument, argument1,argument2, argument3, argument4) = t; - } - /** - * calls a function with six arguments synchronously threadsafe. for more see syncCall with one argument - */ - template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class TargCall3, class TargCall4, class TargCall5, class Targ, class Targ1, class Targ2, class Targ3, class Targ4, class Targ5> - void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2, TargCall3, TargCall4, TargCall5), TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2, Targ3& argument3, Targ4& argument4, Targ5& argument5) - { - auto t = std::make_tuple(argument, argument1, argument2, argument3, argument4, argument5); - doSyncCall(instance, function, retVal, t); - std::tie(argument, argument1,argument2, argument3, argument4, argument5) = t; - } - - /** - * receiver callback for sockethandling, for more, see CAmSocketHandler - */ - void receiverCallback(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) + namespace V1 { - (void) handle; - (void) userData; - int numReads; - CAmDelegagePtr listPointers[3]; - if ((numReads = read(pollfd.fd, &listPointers, sizeof(listPointers))) == -1) + class CAmSerializer { - logError("CAmSerializer::receiverCallback could not read pipe!"); - throw std::runtime_error("CAmSerializer Could not read pipe!"); - } - mListDelegatePoiters.assign(listPointers, listPointers + (numReads / sizeof(CAmDelegagePtr))); - } - - /** - * checker callback for sockethandling, for more, see CAmSocketHandler - */ - bool checkerCallback(const sh_pollHandle_t handle, void* userData) + private: + + /** + * Prototype for a delegate + */ + class CAmDelegate + { + public: + + typedef enum + :bool + { + SyncCallType = false, AsyncCallType = true + } CallType; + + virtual ~CAmDelegate() + { + } + ; + virtual CallType call(int* pipe)=0; + + }; + + /** + * Prototype for a delegate with variadic template arguments in conjunction with the following class. + */ + template<class Class, typename Method, typename Tuple, bool Done, int Total, int ... N> + class CAmDelegateAsyncImpl: public CAmDelegate + { + Class mInstance; + Method mMethod; + Tuple mArguments; + public: + friend class CAmSerializer; + static void call(Class instance, Method method, Tuple && arguments) + { + CAmDelegateAsyncImpl<Class, Method, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(instance, method, std::forward<Tuple>(arguments)); + } + + CAmDelegateAsyncImpl(Class instance, Method method, Tuple && arguments) + { + mInstance = instance; + mMethod = method; + mArguments = std::move(arguments); + } + + CallType call(int* pipe) + { + (void) pipe; + call(mInstance, mMethod, std::forward<Tuple>(mArguments)); + return (AsyncCallType); + } + ; + }; + + /** + * Prototype for a delegate with variadic template arguments. + */ + template<class Class, typename Method, typename Tuple, int Total, int ... N> + class CAmDelegateAsyncImpl<Class, Method, Tuple, true, Total, N...> : public CAmDelegate + { + Class mInstance; + Method mMethod; + Tuple mArguments; + public: + friend class CAmSerializer; + static void call(Class instance, Method method, Tuple && t) + { + (*instance.*method)(std::get<N>(std::forward<Tuple>(t))...); + } + + CAmDelegateAsyncImpl(Class instance, Method method, Tuple && arguments) + { + mInstance = instance; + mMethod = method; + mArguments = std::move(arguments); + } + + CallType call(int* pipe) + { + (void) pipe; + call(mInstance, mMethod, std::forward<Tuple>(mArguments)); + return (AsyncCallType); + } + ; + }; + + /** + * Prototype for a delegate with variadic template arguments in conjunction with the following class. + */ + template<class Class, typename Method, typename Return, typename Tuple, bool Done, int Total, int ... N> + class CAmDelegateSyncImpl: public CAmDelegate + { + Class mInstance; + Method mMethod; + Tuple mArguments; + Return mReturn; + public: + friend class CAmSerializer; + static void call(Class instance, Method method, Return & result, Tuple && arguments) + { + CAmDelegateSyncImpl<Class, Method, Return, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(instance, method, result, std::forward<Tuple>(arguments)); + } + + CAmDelegateSyncImpl(Class instance, Method method, Tuple && arguments) + { + mInstance = instance; + mMethod = method; + mArguments = std::move(arguments); + } + + CallType call(int* pipe) + { + call(mInstance, mMethod, mReturn, std::forward<Tuple>(mArguments)); + ssize_t result(-1); + result = write(pipe[1], this, sizeof(this)); + if (result == -1) + logError("CAmSerializer: Problem writing into pipe! Error No:", errno); + return (SyncCallType); + } + ; + }; + + /** + * Prototype for a delegate with variadic template arguments. + */ + template<class Class, typename Method, typename Return, typename Tuple, int Total, int ... N> + class CAmDelegateSyncImpl<Class, Method, Return, Tuple, true, Total, N...> : public CAmDelegate + { + Class mInstance; + Method mMethod; + Tuple mArguments; + Return mReturn; + public: + friend class CAmSerializer; + static void call(Class instance, Method method, Return & result, Tuple && t) + { + result = (*instance.*method)(std::get<N>(t)...); + } + + CAmDelegateSyncImpl(Class instance, Method method, Tuple && arguments) + { + mInstance = instance; + mMethod = method; + mArguments = std::move(arguments); + } + + CallType call(int* pipe) + { + call(mInstance, mMethod, mReturn, std::forward<Tuple>(mArguments)); + ssize_t result(-1); + result = write(pipe[1], this, sizeof(this)); + if (result == -1) + logError("CAmSerializer: Problem writing into pipe! Error No:", errno); + return (SyncCallType); + } + ; + }; + + typedef CAmDelegate* CAmDelegagePtr; //!< pointer to a delegate + + public: + /** + * instantiates a async delegate with given arguments and sends the delegate pointer over the pipe + */ + template<typename Class, typename Method, typename Tuple> + void doAsyncCall(Class intsance, Method method, Tuple & arguments) + { + typedef typename std::decay<Tuple>::type ttype; + typedef CAmDelegateAsyncImpl<Class, Method, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value> AsyncDelegate; + AsyncDelegate *pImp = new AsyncDelegate(intsance, method, std::forward<Tuple>(arguments)); + send(pImp); + //Do not delete the pointer. It will be deleted automatically later. + } + + /** + * instantiates a sync delegate with given arguments and sends the delegate pointer over the pipe + */ + template<typename Class, typename Method, typename Return, typename Tuple> + void doSyncCall(Class intsance, Method method, Return & result, Tuple & arguments) + { + typedef typename std::decay<Tuple>::type ttype; + typedef CAmDelegateSyncImpl<Class, Method, Return, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value> SyncDelegate; + SyncDelegate *pImp = new SyncDelegate(intsance, method, std::forward<Tuple>(arguments)); + send(pImp); + int numReads; + SyncDelegate *p = NULL; + if ((numReads = read(mReturnPipe[0], &p, sizeof(p))) == -1) + { + logError("CAmSerializer::doSyncCall could not read pipe!"); + throw std::runtime_error("CAmSerializer Could not read pipe!"); + } + result = std::move(pImp->mReturn); + arguments = std::move(pImp->mArguments); + //Delete the pointer. + delete pImp; + } + private: + + /** + * rings the line of the pipe and adds the delegate pointer to the queue + * @param p delegate pointer + */ + inline void send(CAmDelegagePtr p) + { + if (write(mPipe[1], &p, sizeof(p)) == -1) + { + throw std::runtime_error("could not write to pipe !"); + } + } + + int mPipe[2]; //!< the pipe + int mReturnPipe[2]; //!< pipe handling returns + sh_pollHandle_t mHandle; + CAmSocketHandler* mpSocketHandler; + std::deque<CAmDelegagePtr> mListDelegatePoiters; //!< intermediate queue to store the pipe results + + public: + + /** + * get the size of delegate pointers + */ + int getListDelegatePoiters() + { + return mListDelegatePoiters.size(); + } + + /** + * calls a function with variadic arguments threadsafe + * @param instance the instance of the class that shall be called + * @param function the function that shall be called as member function pointer. + * @param output variable. + * @tparam TClass the type of the Class to be called + * @tparam TRet the type of the result + * @tparam TArgs argument list + * \section ex Example: + * @code + * class MyGreatClass + * { + * public: + * int AGreatMethod(int x); + * } + * CAmSerializer serial(&Sockethandler); + * MyGreatClass anInstance; + * int result; + * serial.syncCall<MyGreatClass, int, int>(&anInstance,&MyGreatClass::AGreatMethod, result, 100); + * @endcode + */ + template<class TClass, class TRet, class ... TArgs> + void syncCall(TClass* instance, TRet (TClass::*method)(TArgs ...), TRet & result, TArgs & ... arguments) + { + auto t = std::make_tuple(arguments...); + doSyncCall(instance, method, result, t); + std::tie(arguments...) = t; + } + + /** + * calls a function with variadic arguments threadsafe + * @param instance the instance of the class that shall be called + * @param function the function that shall be called as member function pointer. + * @tparam TClass the type of the Class to be called + * @tparam TRet the type of the result + * @tparam TArgs argument list + * \section ex Example: + * @code + * class MyGreatClass + * { + * public: + * int AGreatMethod(int x); + * } + * CAmSerializer serial(&Sockethandler); + * MyGreatClass anInstance; + * serial.asyncCall<MyGreatClass, void, int>(&anInstance,&MyGreatClass::AGreatMethod, 100); + * @endcode + */ + template<class TClass, class TRet, class ... TArgs> + void asyncCall(TClass* instance, TRet (TClass::*method)(TArgs ...), TArgs & ... arguments) + { + auto t = std::make_tuple(arguments...); + doAsyncCall(instance, method, t); + } + + /** + * calls a function with no arguments threadsafe + * @param instance the instance of the class that shall be called + * @param function the function that shall be called as memberfunction pointer. + * @tparam TClass1 the type of the Class to be called + * \section ex Example: + * @code + * class myClass + * { + * public: + * void myfunction(); + * } + * CAmSerializer serial(&Sockethandler); + * myClass instanceMyClass; + * serial<CommandSender>(&instanceMyClass,&myClass::myfunction); + * @endcode + */ + template<class TClass> + void asyncCall(TClass* instance, void (TClass::*function)()) + { + auto t = std::make_tuple(); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with one arguments asynchronously threadsafe + * @param instance the instance of the class that shall be called + * @param function the function that shall be called as memberfunction pointer. + * @param argument the argument + * @tparam TClass1 the type of the Class to be called + * @tparam Targ the type of the argument to be called + * \section ex Example: + * @code + * class myClass + * { + * public: + * void myfunction(int k); + * } + * CAmSerializer serial(&Sockethandler); + * myClass instanceMyClass; + * serial<CommandSender,int>(&instanceMyClass,&myClass::myfunction,k); + * @endcode + * + */ + template<class TClass1, class Targ> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ), Targ argument) + { + auto t = std::make_tuple(argument); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with one argument called by reference asynchronously threadsafe + * @param instance the instance of the class that shall be called + * @param function the function that shall be called as memberfunction pointer. + * @param argument the argument + * @tparam TClass1 the type of the Class to be called + * @tparam Targ the type of the argument to be called + * \section ex Example: + * @code + * class myClass + * { + * public: + * void myfunction(int k); + * } + * CAmSerializer serial(&Sockethandler); + * myClass instanceMyClass; + * serial<CommandSender,int>(&instanceMyClass,&myClass::myfunction,k); + * @endcode + * + */ + template<class TClass1, class Targ> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ&), Targ& argument) + { + auto t = std::make_tuple(argument); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with two arguments asynchronously threadsafe. for more see asyncCall with one argument + * @param instance pointer to the instance of the class + * @param function memberfunction poitner + * @param argument the first argument + * @param argument1 the second argument + * @tparam TClass1 the type of the Class to be called + * @tparam Targ the type of the argument to be called + * @tparam Targ1 the type of the first argument to be called + */ + template<class TClass1, class Targ, class Targ1> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1 argument1), Targ argument, Targ1 argument1) + { + auto t = std::make_tuple(argument, argument1); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with two arguments asynchronously threadsafe, first argument is a reference. for more see asyncCall with one argument + * @param instance pointer to the instance of the class + * @param function memberfunction poitner + * @param argument the first argument + * @param argument1 the second argument + * @tparam TClass1 the type of the Class to be called + * @tparam Targ the type of the argument to be called + * @tparam Targ1 the type of the first argument to be called + */ + template<class TClass1, class Targ, class Targ1> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1 argument1), Targ& argument, Targ1 argument1) + { + auto t = std::make_tuple(argument, argument1); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with two arguments asynchronously threadsafe, second argument is a reference. for more see asyncCall with one argument + * @param instance pointer to the instance of the class + * @param function memberfunction poitner + * @param argument the first argument + * @param argument1 the second argument + * @tparam TClass1 the type of the Class to be called + * @tparam Targ the type of the argument to be called + * @tparam Targ1 the type of the first argument to be called + */ + template<class TClass1, class Targ, class Targ1> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1& argument1), Targ argument, Targ1& argument1) + { + auto t = std::make_tuple(argument, argument1); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with two arguments asynchronously threadsafe, both arguments are references. for more see asyncCall with one argument + * @param instance pointer to the instance of the class + * @param function memberfunction poitner + * @param argument the first argument + * @param argument1 the second argument + * @tparam TClass1 the type of the Class to be called + * @tparam Targ the type of the argument to be called + * @tparam Targ1 the type of the first argument to be called + */ + template<class TClass1, class Targ, class Targ1> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1& argument1), Targ& argument, Targ1& argument1) + { + auto t = std::make_tuple(argument, argument1); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with three arguments asynchronously threadsafe. for more see other asycCall + */ + template<class TClass1, class Targ, class Targ1, class Targ2> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1 argument1, Targ2 argument2), Targ argument, Targ1 argument1, Targ2 argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with three arguments asynchronously threadsafe. for more see other asycCall + */ + template<class TClass1, class Targ, class Targ1, class Targ2> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1 argument1, Targ2 argument2), Targ& argument, Targ1 argument1, Targ2 argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with three arguments asynchronously threadsafe. for more see other asycCall + */ + template<class TClass1, class Targ, class Targ1, class Targ2> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1& argument1, Targ2 argument2), Targ argument, Targ1& argument1, Targ2 argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with three arguments asynchronously threadsafe. for more see other asycCall + */ + template<class TClass1, class Targ, class Targ1, class Targ2> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1 argument1, Targ2& argument2), Targ argument, Targ1 argument1, Targ2& argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with three arguments asynchronously threadsafe. for more see other asycCall + */ + template<class TClass1, class Targ, class Targ1, class Targ2> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1& argument1, Targ2& argument2), Targ argument, Targ1& argument1, Targ2& argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with three arguments asynchronously threadsafe. for more see other asycCall + */ + template<class TClass1, class Targ, class Targ1, class Targ2> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1& argument1, Targ2& argument2), Targ& argument, Targ1& argument1, Targ2& argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with three arguments asynchronously threadsafe. for more see other asycCall + */ + template<class TClass1, class Targ, class Targ1, class Targ2> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1& argument1, Targ2 argument2), Targ& argument, Targ1& argument1, Targ2 argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with three arguments asynchronously threadsafe. for more see other asycCall + */ + template<class TClass1, class Targ, class Targ1, class Targ2> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ& argument, Targ1 argument1, Targ2& argument2), Targ& argument, Targ1 argument1, Targ2& argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doAsyncCall(instance, function, t); + } + + /** + * calls a function with four arguments asynchronously threadsafe. for more see other asycCall + */ + template<class TClass1, class Targ, class Targ1, class Targ2, class Targ3> + void asyncCall(TClass1* instance, void (TClass1::*function)(Targ argument, Targ1 argument1, Targ2 argument2, Targ3 argument3), Targ argument, Targ1 argument1, Targ2 argument2, Targ3 argument3) + { + auto t = std::make_tuple(argument, argument1, argument2, argument3); + doAsyncCall(instance, function, t); + } + + /** + * calls a synchronous function with no arguments threadsafe + * @param instance the instance of the class that shall be called + * @param function the function that shall be called as memberfunction pointer. + * @param retVal the return parameter, no const allowed ! + * @tparam TClass1 the type of the class to be called + * @tparam TretVal the type of the return parameter + * \section ex Example: + * @code + * class myClass + * { + * public: + * am_Error_e myfunction(); + * } + * CAmSerializer serial(&Sockethandler); + * myClass instanceMyClass; + * am_Error_e error; + * serial<CommandSender,am_Error_e>(&instanceMyClass,&myClass::myfunction, error); + * @endcode + * All arguments given to synchronous functions must be non-const since the results of the operations will be written back to the arguments. + * + */ + template<class TClass1, class TretVal> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(), TretVal& retVal) + { + auto t = std::make_tuple(); + doSyncCall(instance, function, retVal, t); + } + + /** + * calls a function with one argument synchronous threadsafe + * @param instance the instance of the class that shall be called + * @param function the function that shall be called as memberfunction pointer. + * @param retVal the return parameter, no const allowed ! + * @param argument the argument, no const allowed ! + * @tparam TClass1 the type of the class to be called + * @tparam TretVal the type of the return parameter + * @tparam TargCall the type of the argument like in the function to be called. here all references and const must be + * respected! + * @tparam Targ the type of the argument, here no const and no references allowed ! + * \section ex Example: + * @code + * class myClass + * { + * public: + * am_Error_e myfunction(int k); + * } + * CAmSerializer serial(&Sockethandler); + * myClass instanceMyClass; + * am_Error_e error; + * int l; + * serial<CommandSender,am_Error_e,int>(&instanceMyClass,&myClass::myfunction,error,l); + * @endcode + * All arguments given to synchronous functions must be non-const since the results of the operations will be written back to the arguments. + */ + template<class TClass1, class TretVal, class TargCall, class Targ> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall), TretVal& retVal, Targ& argument) + { + auto t = std::make_tuple(argument); + doSyncCall(instance, function, retVal, t); + std::tie(argument) = t; + } + + /** + * calls a function with one argument synchronous threadsafe for const functions. For more see syncCall with one argument + */ + template<class TClass1, class TretVal, class TargCall, class Targ> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall) const, TretVal& retVal, Targ& argument) + { + auto t = std::make_tuple(argument); + doSyncCall(instance, function, retVal, t); + std::tie(argument) = t; + } + + /** + * calls a function with two arguments synchronously threadsafe. For more see syncCall with one argument + */ + template<class TClass1, class TretVal, class TargCall, class Targ1Call, class Targ, class Targ1> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, Targ1Call), TretVal& retVal, Targ& argument, Targ1& argument1) + { + auto t = std::make_tuple(argument, argument1); + doSyncCall(instance, function, retVal, t); + std::tie(argument, argument1) = t; + } + /** + * calls a function with two arguments synchronously threadsafe const. For more see syncCall with one argument + */ + template<class TClass1, class TretVal, class TargCall, class Targ1Call, class Targ, class Targ1> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, Targ1Call) const, TretVal& retVal, Targ& argument, Targ1& argument1) + { + auto t = std::make_tuple(argument, argument1); + doSyncCall(instance, function, retVal, t); + std::tie(argument, argument1) = t; + } + + /** + * calls a function with three arguments synchronously threadsafe. for more see syncCall with one argument + */ + template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class Targ, class Targ1, class Targ2> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2), TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doSyncCall(instance, function, retVal, t); + std::tie(argument, argument1, argument2) = t; + } + + /** + * calls a const function with three arguments synchronously threadsafe. for more see syncCall with one argument + */ + template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class Targ, class Targ1, class Targ2> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2) const, TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2) + { + auto t = std::make_tuple(argument, argument1, argument2); + doSyncCall(instance, function, retVal, t); + std::tie(argument, argument1, argument2) = t; + } + + /** + * calls a function with four arguments synchronously threadsafe. for more see syncCall with one argument + */ + template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class TargCall3, class Targ, class Targ1, class Targ2, class Targ3> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2, TargCall3), TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2, Targ3& argument3) + { + auto t = std::make_tuple(argument, argument1, argument2, argument3); + doSyncCall(instance, function, retVal, t); + std::tie(argument, argument1, argument2, argument3) = t; + } + + /** + * calls a function with five arguments synchronously threadsafe. for more see syncCall with one argument + */ + template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class TargCall3, class TargCall4, class Targ, class Targ1, class Targ2, class Targ3, class Targ4> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2, TargCall3, TargCall4), TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2, Targ3& argument3, Targ4& argument4) + { + auto t = std::make_tuple(argument, argument1, argument2, argument3, argument4); + doSyncCall(instance, function, retVal, t); + std::tie(argument, argument1, argument2, argument3, argument4) = t; + } + + /** + * calls a function with six arguments synchronously threadsafe. for more see syncCall with one argument + */ + template<class TClass1, class TretVal, class TargCall, class TargCall1, class TargCall2, class TargCall3, class TargCall4, class TargCall5, class Targ, class Targ1, class Targ2, class Targ3, class Targ4, class Targ5> + void syncCall(TClass1* instance, TretVal (TClass1::*function)(TargCall, TargCall1, TargCall2, TargCall3, TargCall4, TargCall5), TretVal& retVal, Targ& argument, Targ1& argument1, Targ2& argument2, Targ3& argument3, + Targ4& argument4, Targ5& argument5) + { + auto t = std::make_tuple(argument, argument1, argument2, argument3, argument4, argument5); + doSyncCall(instance, function, retVal, t); + std::tie(argument, argument1, argument2, argument3, argument4, argument5) = t; + } + + /** + * receiver callback for sockethandling, for more, see CAmSocketHandler + */ + void receiverCallback(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) + { + (void) handle; + (void) userData; + int numReads; + CAmDelegagePtr listPointers[3]; + if ((numReads = read(pollfd.fd, &listPointers, sizeof(listPointers))) == -1) + { + logError("CAmSerializer::receiverCallback could not read pipe!"); + throw std::runtime_error("CAmSerializer Could not read pipe!"); + } + mListDelegatePoiters.assign(listPointers, listPointers + (numReads / sizeof(CAmDelegagePtr))); + } + + /** + * checker callback for sockethandling, for more, see CAmSocketHandler + */ + bool checkerCallback(const sh_pollHandle_t handle, void* userData) + { + (void) handle; + (void) userData; + if (mListDelegatePoiters.empty()) + return (false); + return (true); + } + + /** + * dispatcher callback for sockethandling, for more, see CAmSocketHandler + */ + bool dispatcherCallback(const sh_pollHandle_t handle, void* userData) + { + (void) handle; + (void) userData; + CAmDelegagePtr delegatePoiter = mListDelegatePoiters.front(); + mListDelegatePoiters.pop_front(); + if (delegatePoiter->call(mReturnPipe)) + delete delegatePoiter; + if (mListDelegatePoiters.empty()) + return (false); + return (true); + } + + TAmShPollFired<CAmSerializer> receiverCallbackT; + TAmShPollDispatch<CAmSerializer> dispatcherCallbackT; + TAmShPollCheck<CAmSerializer> checkerCallbackT; + + /** + * The constructor must be called in the mainthread context ! + * @param iSocketHandler pointer to the CAmSocketHandler + */ + CAmSerializer(CAmSocketHandler *iSocketHandler) : + mPipe(), // + mReturnPipe(), // + mHandle(), + mpSocketHandler(iSocketHandler), + mListDelegatePoiters(), // + receiverCallbackT(this, &CAmSerializer::receiverCallback), // + dispatcherCallbackT(this, &CAmSerializer::dispatcherCallback), // + checkerCallbackT(this, &CAmSerializer::checkerCallback) + { + assert(NULL!=iSocketHandler); + + if (pipe(mPipe) == -1) + { + logError("CAmSerializer could not create pipe!"); + throw std::runtime_error("CAmSerializer Could not open pipe!"); + } + + if (pipe(mReturnPipe) == -1) + { + logError("CAmSerializer could not create mReturnPipe!"); + throw std::runtime_error("CAmSerializer Could not open mReturnPipe!"); + } + + short event = 0; + event |= POLLIN; + mpSocketHandler->addFDPoll(mPipe[0], event, NULL, &receiverCallbackT, &checkerCallbackT, &dispatcherCallbackT, NULL, mHandle); + } + + ~CAmSerializer() + { + mpSocketHandler->removeFDPoll(mHandle); + close(mPipe[0]); + close(mPipe[1]); + close(mReturnPipe[0]); + close(mReturnPipe[1]); + } + }; + + } /* namespace V1 */ + + /**@}*/ + + namespace V2 { - (void) handle; - (void) userData; - if (mListDelegatePoiters.empty()) - return (false); - return (true); - } - - /** - * dispatcher callback for sockethandling, for more, see CAmSocketHandler - */ - bool dispatcherCallback(const sh_pollHandle_t handle, void* userData) - { - (void) handle; - (void) userData; - CAmDelegagePtr delegatePoiter = mListDelegatePoiters.front(); - mListDelegatePoiters.pop_front(); - if (delegatePoiter->call(mReturnPipe)) - delete delegatePoiter; - if (mListDelegatePoiters.empty()) - return (false); - return (true); - } - - TAmShPollFired<CAmSerializer> receiverCallbackT; - TAmShPollDispatch<CAmSerializer> dispatcherCallbackT; - TAmShPollCheck<CAmSerializer> checkerCallbackT; - - /** - * The constructor must be called in the mainthread context ! - * @param iSocketHandler pointer to the CAmSocketHandler - */ - CAmSerializer(CAmSocketHandler *iSocketHandler) : - mPipe(), // - mReturnPipe(),// - mHandle(), - mpSocketHandler(iSocketHandler), - mListDelegatePoiters(), // - receiverCallbackT(this, &CAmSerializer::receiverCallback), // - dispatcherCallbackT(this, &CAmSerializer::dispatcherCallback), // - checkerCallbackT(this, &CAmSerializer::checkerCallback) - { - assert(NULL!=iSocketHandler); - - if (pipe(mPipe) == -1) - { - logError("CAmSerializer could not create pipe!"); - throw std::runtime_error("CAmSerializer Could not open pipe!"); - } - - if (pipe(mReturnPipe) == -1) + class CAmSerializer { - logError("CAmSerializer could not create mReturnPipe!"); - throw std::runtime_error("CAmSerializer Could not open mReturnPipe!"); - } - - short event = 0; - event |= POLLIN; - mpSocketHandler->addFDPoll(mPipe[0], event, NULL, &receiverCallbackT, &checkerCallbackT, &dispatcherCallbackT, NULL, mHandle); - } + /** + * Prototype for a delegate + */ + class CAmDelegate + { + public: + typedef enum + :bool + { + SyncCallType = false, AsyncCallType = true + } CallType; + + virtual ~CAmDelegate() + { + } + ; + virtual CallType call(int* pipe)=0; + }; + + /** + * Prototype for a delegate with variadic template arguments. + */ + template<class TInvocation> + class CAmDelegateAsyncImpl: public CAmDelegate + { + TInvocation mInvocation; + public: + friend class CAmSerializer; + CAmDelegateAsyncImpl(TInvocation && invocation) : + mInvocation(std::move(invocation)) + { + } + + CallType call(int* pipe) + { + (void) pipe; + mInvocation(); + return (AsyncCallType); + } + ; + }; + + template<class TInvocation, class TRet> + class CAmDelegateSyncImpl: public CAmDelegate + { + TInvocation mInvocation; + TRet & mReturn; + public: + friend class CAmSerializer; + CAmDelegateSyncImpl(TInvocation && invocation, TRet && ret) : + mInvocation(std::move(invocation)), mReturn(ret) + { + } + + CallType call(int* pipe) + { + mReturn = mInvocation(); + ssize_t result(-1); + result = write(pipe[1], this, sizeof(this)); + if (result == -1) + logError("CAmSerializer: Problem writing into pipe! Error No:", errno); + return (SyncCallType); + } + ; + }; + + template<class TInvocation> + class CAmDelegateSyncVoidImpl: public CAmDelegate + { + TInvocation mInvocation; + public: + friend class CAmSerializer; + CAmDelegateSyncVoidImpl(TInvocation && invocation) : + mInvocation(std::move(invocation)) + { + } + + CallType call(int* pipe) + { + mInvocation(); + ssize_t result(-1); + result = write(pipe[1], this, sizeof(this)); + if (result == -1) + logError("CAmSerializer: Problem writing into pipe! Error No:", errno); + return (SyncCallType); + } + ; + }; + + typedef CAmDelegate* CAmDelegagePtr; //!< pointer to a delegate + + void sendSync(CAmDelegagePtr pDelegate) + { + send(pDelegate); + int numReads; + CAmDelegagePtr *p = NULL; + if ((numReads = read(mReturnPipe[0], &p, sizeof(p))) == -1) + { + logError("CAmSerializer::doSyncCall could not read pipe!"); + throw std::runtime_error("CAmSerializer Could not read pipe!"); + } + } + + /** + * rings the line of the pipe and adds the delegate pointer to the queue + * @param p delegate pointer + */ + inline void send(CAmDelegagePtr p) + { + if (write(mPipe[1], &p, sizeof(p)) == -1) + { + throw std::runtime_error("could not write to pipe !"); + } + } + + int mPipe[2]; //!< the pipe + int mReturnPipe[2]; //!< pipe handling returns + sh_pollHandle_t mHandle; + CAmSocketHandler* mpSocketHandler; + std::deque<CAmDelegagePtr> mListDelegatePointers; //!< intermediate queue to store the pipe results + + public: + + /** + * get the size of delegate pointers + */ + size_t getListDelegatePointers() + { + return mListDelegatePointers.size(); + } + + /** + * calls a function with variadic arguments threadsafe + * @param invocation is a type is produced by std::bind + * \section ex Example: + * @code + * CAmSerializer serial(&Sockethandler); + * serial.asyncInvocation(std::bind([]()->bool{return true;})); + * @endcode + */ + template<class TFunc> + void asyncInvocation(TFunc invocation) + { + static_assert(std::is_bind_expression<TFunc>::value,"The type is not produced by std::bind"); + typedef CAmDelegateAsyncImpl<TFunc> AsyncDelegate; + AsyncDelegate *pImp = new AsyncDelegate(std::forward<TFunc>(invocation)); + send(pImp); + //Do not delete the pointer. It will be deleted automatically later. + } + + /** + * calls a function with variadic arguments threadsafe + * @param instance the instance of the class that shall be called + * @param function the function that shall be called as member function pointer. + * @tparam TClass the type of the Class to be called + * @tparam TRet the type of the result + * @tparam TArgs argument list + * \section ex Example: + * @code + * class AClass + * { + * public: + * void instanceMethod(int x); + * } + * CAmSerializer serial(&Sockethandler); + * AClass anInstance; + * serial.asyncCall(&anInstance,&AClass::instanceMethod, 100); + * @endcode + */ + template<class TClass, class TMeth, class TRet, class ... TArgs> + void asyncCall(TClass* instance, TMeth method, TArgs && ... arguments) + { + auto invocation = std::bind(method, instance, std::forward<TArgs>(arguments)...); + asyncInvocation(invocation); + } + + template<class TClass, class TMeth, class ... TArgs> + void asyncCall(TClass* instance, TMeth method, TArgs && ... arguments) + { + auto invocation = std::bind(method, instance, std::forward<TArgs>(arguments)...); + asyncInvocation(invocation); + } + + /** + * calls a function with variadic arguments threadsafe + * @param invocation is a type is produced by std::bind + * @param result from type TRet + * \section ex Example: + * @code + * CAmSerializer serial(&Sockethandler); + * bool result; + * serial.syncCall(std::bind([]()->bool{return true;}), result); + * @endcode + */ + template<class TFunc, class TRet> + void syncInvocation(TFunc invocation, TRet && result) + { + static_assert(std::is_bind_expression<TFunc>::value,"The type is not produced by std::bind"); + + typedef CAmDelegateSyncImpl<TFunc, TRet> SyncDelegate; + + SyncDelegate *pImp = new SyncDelegate(std::forward<TFunc>(invocation), std::forward<TRet>(result)); + sendSync(pImp); + //Delete the pointer. + delete pImp; + } + + /** + * calls a function with variadic arguments threadsafe + * @param invocation is a type produced by std::bind + * \section ex Example: + * @code + * CAmSerializer serial(&Sockethandler); + * serial.syncCall(std::bind([]()->bool{return true;})); + * @endcode + */ + template<class TFunc> + void syncInvocation(TFunc invocation) + { + static_assert(std::is_bind_expression<TFunc>::value,"The type is not produced by std::bind"); + + typedef CAmDelegateSyncVoidImpl<TFunc> SyncDelegate; + + SyncDelegate *pImp = new SyncDelegate(std::forward<TFunc>(invocation)); + sendSync(pImp); + //Delete the pointer. + delete pImp; + } + /** + * calls a function with variadic arguments threadsafe + * @param instance the instance of the class that shall be called + * @param function the function that shall be called as member function pointer. + * @param output variable. + * @tparam TClass the type of the Class to be called + * @tparam TRet the type of the result + * @tparam TArgs argument list + * \section ex Example: + * @code + * class AClass + * { + * public: + * int instanceMethod(int x); + * } + * CAmSerializer serial(&Sockethandler); + * AClass anInstance; + * int result; + * serial.syncCall(&anInstance,&AClass::instanceMethod, result, 100); + * @endcode + */ + template<class TClass, class TMeth, class TRet, class ... TArgs> + void syncCall(TClass* instance, TMeth method, TRet & result, TArgs && ... arguments) + { + auto invocation = std::bind(method, instance, std::ref(arguments)...); + syncInvocation(invocation, result); + } + + template<class TClass, class TMeth, class ... TArgs> + void syncCall(TClass* instance, TMeth method, TArgs && ... arguments) + { + auto invocation = std::bind(method, instance, std::ref(arguments)...); + syncInvocation(invocation); + } + + /** + * receiver callback for sockethandling, for more, see CAmSocketHandler + */ + void receiverCallback(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) + { + (void) handle; + (void) userData; + int numReads; + CAmDelegagePtr listPointers[3]; + if ((numReads = read(pollfd.fd, &listPointers, sizeof(listPointers))) == -1) + { + logError("CAmSerializer::receiverCallback could not read pipe!"); + throw std::runtime_error("CAmSerializer Could not read pipe!"); + } + mListDelegatePointers.assign(listPointers, listPointers + (numReads / sizeof(CAmDelegagePtr))); + } + + /** + * checker callback for sockethandling, for more, see CAmSocketHandler + */ + bool checkerCallback(const sh_pollHandle_t handle, void* userData) + { + (void) handle; + (void) userData; + if (mListDelegatePointers.empty()) + return (false); + return (true); + } + + /** + * dispatcher callback for sockethandling, for more, see CAmSocketHandler + */ + bool dispatcherCallback(const sh_pollHandle_t handle, void* userData) + { + (void) handle; + (void) userData; + CAmDelegagePtr delegatePoiter = mListDelegatePointers.front(); + mListDelegatePointers.pop_front(); + if (delegatePoiter->call(mReturnPipe)) + delete delegatePoiter; + if (mListDelegatePointers.empty()) + return (false); + return (true); + } + + TAmShPollFired<CAmSerializer> receiverCallbackT; + TAmShPollDispatch<CAmSerializer> dispatcherCallbackT; + TAmShPollCheck<CAmSerializer> checkerCallbackT; + + /** + * The constructor must be called in the mainthread context ! + * @param iSocketHandler pointer to the CAmSocketHandler + */ + CAmSerializer(CAmSocketHandler *iSocketHandler) : + mPipe(), // + mReturnPipe(), // + mHandle(), + mpSocketHandler(iSocketHandler), + mListDelegatePointers(), // + receiverCallbackT(this, &CAmSerializer::receiverCallback), // + dispatcherCallbackT(this, &CAmSerializer::dispatcherCallback), // + checkerCallbackT(this, &CAmSerializer::checkerCallback) + { + assert(NULL!=iSocketHandler); + + if (pipe(mPipe) == -1) + { + logError("CAmSerializer could not create pipe!"); + throw std::runtime_error("CAmSerializer Could not open pipe!"); + } + + if (pipe(mReturnPipe) == -1) + { + logError("CAmSerializer could not create mReturnPipe!"); + throw std::runtime_error("CAmSerializer Could not open mReturnPipe!"); + } + + short event = 0; + event |= POLLIN; + mpSocketHandler->addFDPoll(mPipe[0], event, NULL, &receiverCallbackT, &checkerCallbackT, &dispatcherCallbackT, NULL, mHandle); + } + + ~CAmSerializer() + { + mpSocketHandler->removeFDPoll(mHandle); + close(mPipe[0]); + close(mPipe[1]); + close(mReturnPipe[0]); + close(mReturnPipe[1]); + } + }; + } /* namespace V2 */ + + typedef V1::CAmSerializer CAmSerializer DEPRECATED("You should use V2::CAmSerializer instead!"); - ~CAmSerializer() - { - mpSocketHandler->removeFDPoll(mHandle); - close(mPipe[0]); - close(mPipe[1]); - close(mReturnPipe[0]); - close(mReturnPipe[1]); - } -}; } /* namespace am */ #endif /* CAMSERIALIZER_H_ */ diff --git a/AudioManagerUtilities/include/CAmSocketHandler.h b/AudioManagerUtilities/include/CAmSocketHandler.h index 5c3c5ba..717f792 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,190 +25,309 @@ #include <map> #include <set> #include <signal.h> +#include <vector> +#include <functional> +#include <sys/signalfd.h> +#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 { #define MAX_NS 1000000000L -#define MAX_TIMERHANDLE INT16_MAX -#define MAX_POLLHANDLE INT16_MAX +#define MAX_TIMERHANDLE UINT16_MAX +#define MAX_POLLHANDLE UINT16_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 sh_pollHandle_t sh_timerHandle_t; //!<this is a handle for a timer to be used with the SocketHandler /** - * prototype for poll prepared callback - */ + * prototype for poll prepared callback + */ class IAmShPollPrepare { public: virtual void Call(const sh_pollHandle_t handle, void* userData) = 0; - virtual ~IAmShPollPrepare() {}; + virtual ~IAmShPollPrepare() {} }; /** - * prototype for poll fired callback - */ + * prototype for poll fired callback + */ class IAmShPollFired { public: virtual void Call(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) = 0; - virtual ~ IAmShPollFired() {}; + virtual ~ IAmShPollFired() {} }; /** - * prototype for poll check callback - */ + * prototype for poll check callback + */ class IAmShPollCheck { public: virtual bool Call(const sh_pollHandle_t handle, void* userData) = 0; - virtual ~ IAmShPollCheck() {}; + virtual ~ IAmShPollCheck() {} }; /** - * prototype for dispatch callback - */ + * prototype for dispatch callback + */ class IAmShPollDispatch { public: virtual bool Call(const sh_pollHandle_t handle, void* userData) = 0; - virtual ~ IAmShPollDispatch() {}; + virtual ~ IAmShPollDispatch() {} }; /** - * prototype for the timer callback - */ + * prototype for the timer callback + */ class IAmShTimerCallBack { public: + IAmShTimerCallBack(){}; virtual void Call(const sh_timerHandle_t handle, void* userData) = 0; - virtual ~IAmShTimerCallBack() {}; + 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 +/**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); + public: - template<class TClass> class TAmShPollFired: public IAmShPollFired + 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) { - private: - TClass* mInstance; - void (TClass::*mFunction)(const pollfd pollfd, const sh_pollHandle_t handle, void* userData); + (*mInstance.*mFunction)(pollfd, handle, userData); + } +}; - public: - TAmShPollFired(TClass* instance, void (TClass::*function)(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)) : - mInstance(instance), // - mFunction(function) {}; +/** + * template for a callback + */ +template<class TClass> class TAmShPollCheck: public IAmShPollCheck +{ +private: + TClass* mInstance; + bool (TClass::*mFunction)(const sh_pollHandle_t handle, void* userData); - virtual void Call(const pollfd pollfd, const sh_pollHandle_t handle, void* userData) - { - (*mInstance.*mFunction)(pollfd, handle, userData); - }; - }; +public: + TAmShPollCheck(TClass* instance, bool (TClass::*function)(const sh_pollHandle_t handle, void* userData)) : + mInstance(instance), // + mFunction(function) + {} - template<class TClass> class TAmShPollCheck: public IAmShPollCheck + virtual bool Call(const sh_pollHandle_t handle, void* userData) { - private: - TClass* mInstance; - bool (TClass::*mFunction)(const sh_pollHandle_t handle, void* userData); + return ((*mInstance.*mFunction)(handle, userData)); + } +}; - public: - TAmShPollCheck(TClass* instance, bool (TClass::*function)(const sh_pollHandle_t handle, void* userData)) : - mInstance(instance), // - mFunction(function) {}; +/** + * template for a callback + */ +template<class TClass> class TAmShPollDispatch: public IAmShPollDispatch +{ +private: + TClass* mInstance; + bool (TClass::*mFunction)(const sh_pollHandle_t handle, void* userData); - virtual bool Call(const sh_pollHandle_t handle, void* userData) - { - return ((*mInstance.*mFunction)(handle, userData)); - }; - }; +public: + TAmShPollDispatch(TClass* instance, bool (TClass::*function)(const sh_pollHandle_t handle, void* userData)) : + mInstance(instance), // + mFunction(function) + {} - CAmSocketHandler(); - ~CAmSocketHandler(); + virtual bool Call(const sh_pollHandle_t handle, void* userData) + { + return ((*mInstance.*mFunction)(handle, userData)); + } +}; - 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); - }; +/** + * 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); - TAmShPollFired<CAmSocketHandler> receiverCallbackT; - TAmShPollCheck<CAmSocketHandler> checkerCallbackT; +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 TClass> class TAmShPollPrepare: public IAmShPollPrepare +{ private: + TClass* mInstance; + void (TClass::*mFunction)(const sh_pollHandle_t handle, void* userData); + +public: + TAmShPollPrepare(TClass* instance, void (TClass::*function)(const sh_pollHandle_t handle, void* userData)) : + mInstance(instance), // + mFunction(function) + {} + + virtual void Call(const sh_pollHandle_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 //!<struct that holds information about polls + { + sh_pollHandle_t handle; //!<handle to uniquely adress a filedesriptor + pollfd pollfdValue; //!<the array for polling the filedescriptors + std::function<void(const sh_pollHandle_t handle, void* userData)> prepareCB; //preperation callback + std::function<void(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)> firedCB; //fired callback + std::function<bool(const sh_pollHandle_t handle, void* userData)> checkCB; //check callback + std::function<bool(const sh_pollHandle_t handle, void* userData)> dispatchCB; //dispatch callback + void* userData; + + sh_poll_s() : + handle(0), pollfdValue(), prepareCB(), firedCB(), checkCB(), dispatchCB(), userData(0) + {} + }; - static CAmSocketHandler* mInstance; - int mPipe[2]; - int mDispatchDone; //this starts / stops the mainloop struct sh_timer_s //!<struct that holds information of timers { - sh_timerHandle_t handle; //!<the handle of the timer + 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 - IAmShTimerCallBack* callback; //!<the callbackfunction - void * userData; //!<saves a void pointer together with the rest. +#endif + std::function<void(const sh_timerHandle_t handle, void* userData)> callback; //timer callback + void* userData; + sh_timer_s() : + handle(0) +#ifdef WITH_TIMERFD + , fd(0) +#endif + , countdown(), callback(), userData(0) + {} }; - typedef std::reverse_iterator<sh_timer_s> rListTimerIter; //!<typedef for reverseiterator on timer lists - - struct sh_poll_s //!<struct that holds information about polls + struct sh_signal_s { 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. + std::function<void(const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData)> callback; + void* userData; + sh_signal_s() : + handle(0), callback(), userData(0) + {} + }; + + struct sh_identifier_s + { + std::set<sh_pollHandle_t> pollHandles; + uint16_t limit; + uint16_t lastUsedID; + sh_identifier_s(const uint16_t pollLimit = UINT16_MAX) : + pollHandles(), limit(pollLimit), lastUsedID(0) + {} }; - typedef std::vector<pollfd> mListPollfd_t; //!<vector of filedescriptors - typedef std::vector<sh_poll_s> mListPoll_t; //!<list for the callbacks + typedef std::reverse_iterator<sh_timer_s> rListTimerIter; //!<typedef for reverseiterator on timer lists + typedef std::vector<pollfd> VectorListPollfd_t; //!<vector of filedescriptors + typedef std::vector<sh_poll_s> VectorListPoll_t; //!<list for the callbacks + typedef std::vector<sh_signal_s> VectorSignalHandlers_t; //!<list for the callbacks + + typedef enum:uint8_t + { + NO_ERROR = 0u, // OK + PIPE_ERROR = 1u, // Pipe error + FD_ERROR = 2u, // Invalid file descriptor + SFD_ERROR = 4u, + } internal_codes_e; + typedef uint8_t internal_codes_t; + int mPipe[2]; + bool mDispatchDone; //this starts / stops the mainloop + + sh_identifier_s mSetPollKeys; //!A set of all used ppoll keys + VectorListPoll_t mListPoll; //!<list that holds all information for the ppoll + sh_identifier_s mSetTimerKeys; //!A set of all used timer keys + std::list<sh_timer_s> mListTimer; //!<list of all timers + std::list<sh_timer_s> mListActiveTimer; //!<list of all currently active timers + sh_identifier_s mSetSignalhandlerKeys; //!A set of all used signal handler keys + VectorSignalHandlers_t mSignalHandlers; + bool mRecreatePollfds; //!<when this is true, the poll list needs to be recreated + internal_codes_t mInternalCodes; + sh_pollHandle_t mSignalFdHandle; +#ifndef WITH_TIMERFD + timespec mStartTime; //!<here the actual time is saved for timecorrection +#endif +private: 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(); - timespec* insertTime(timespec& buffertime); /** - * compares countdown values - * @param a - * @param b - * @return true if b greater a - */ + * 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 - */ + * Subtracts b from a + * @param a + * @param b + * @return subtracted value + */ inline static timespec timespecSub(const timespec& a, const timespec& b) { timespec result; @@ -234,11 +353,11 @@ private: } /** - * adds timespec values - * @param a - * @param b - * @return the added values - */ + * adds timespec values + * @param a + * @param b + * @return the added values + */ inline timespec timespecAdd(const timespec& a, const timespec& b) { timespec result; @@ -253,234 +372,123 @@ private: } /** - * comapares timespec values - * @param a - * @param b - * @return - */ + * 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); + return (-1); //greater else if (a.tv_sec > b.tv_sec) - return (1); + return (1); //less else if (a.tv_nsec < b.tv_nsec) - return (-1); + return (-1); //greater else if (a.tv_nsec > b.tv_nsec) - return (1); + 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 prepare all fire events + * @param a + * @return + */ + inline static void prepare(sh_poll_s& row); /** - * 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)); - } + * functor to return all fired events + * @param a + * @return + */ + inline static void fire(sh_poll_s& a); /** - * 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 //!<functor to call a timer - { - 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); - }; - - class CAmShCountdownZero //!<functor that checks if a timer is zero - { - public: - CAmShCountdownZero() {}; - bool operator()(const sh_timer_s& row); - }; - - 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); - } - }; - - 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); - -public: - TAmShTimerCallBack(TClass* instance, void (TClass::*function)(sh_timerHandle_t handle, void* userData)) : - mInstance(instance), // - mFunction(function) {}; + * functor to return all fired events + * @param a + * @return + */ + inline static bool eventFired(const pollfd& a); - virtual void Call(sh_timerHandle_t handle, void* userData) - { - (*mInstance.*mFunction)(handle, userData); - } -}; - -/** - * template for a callback - */ -template<class TClass> 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) {}; + /** + * functor to help find the items that do not need dispatching + * @param a + * @return + */ + inline static bool noDispatching(const sh_poll_s& a); - 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); -/**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); + /** + * timer fire callback + * @param a + * @return + */ + inline static void callTimer(sh_timer_s& a); + /** + * next handle id + * @param std::set handles + * @return handle + */ + bool nextHandle(sh_identifier_s & handle); + + am_Error_e getFDPollData(const sh_pollHandle_t handle, sh_poll_s & outPollData); + 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 TClass> 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) {}; + CAmSocketHandler(); + ~CAmSocketHandler(); + + /** + * install the signal fd + */ + am_Error_e listenToSignals(const std::vector<uint8_t> & listSignals); + + am_Error_e addFDPoll(const int fd, const short event, std::function<void(const sh_pollHandle_t handle, void* userData)> prepare, std::function<void(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)> fired, + std::function<bool(const sh_pollHandle_t handle, void* userData)> check, std::function<bool(const sh_pollHandle_t handle, void* userData)> dispatch, void* userData, sh_pollHandle_t& handle); - virtual bool Call(const sh_pollHandle_t handle, void* userData) - { - return ((*mInstance.*mFunction)(handle, userData)); - }; + am_Error_e addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void* userData, sh_pollHandle_t& handle); + am_Error_e removeFDPoll(const sh_pollHandle_t handle); + am_Error_e updateEventFlags(const sh_pollHandle_t handle, const short events); + am_Error_e addSignalHandler(std::function<void(const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData)> callback, sh_pollHandle_t& handle, void * userData); + am_Error_e removeSignalHandler(const sh_pollHandle_t handle); + am_Error_e addTimer(const timespec & timeouts, IAmShTimerCallBack* callback, sh_timerHandle_t& handle, void * userData, +#ifndef WITH_TIMERFD + const bool __attribute__((__unused__)) repeats = false +#else + const bool repeats = false +#endif + ); + am_Error_e addTimer(const timespec & timeouts, std::function<void(const sh_timerHandle_t handle, void* userData)> callback, sh_timerHandle_t& handle, void* userData, +#ifndef WITH_TIMERFD + const bool __attribute__((__unused__)) repeats = false +#else + const bool repeats = false +#endif + ); + am_Error_e removeTimer(const sh_timerHandle_t handle); + am_Error_e restartTimer(const sh_timerHandle_t handle); + am_Error_e updateTimer(const sh_timerHandle_t handle, const timespec & timeouts); + am_Error_e stopTimer(const sh_timerHandle_t handle); + void start_listenting(); + void stop_listening(); + void exit_mainloop(); + + bool fatalErrorOccurred(); }; -/** - * 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..7b0fc5d 100644 --- a/AudioManagerUtilities/src/CAmSocketHandler.cpp +++ b/AudioManagerUtilities/src/CAmSocketHandler.cpp @@ -15,13 +15,13 @@ * * * \author Christian Linke, christian.linke@bmw.de BMW 2011,2012 + * \author Aleksandar Donchev, aleksander.donchev@partner.bmw.de BMW 2017 * * \file CAmSocketHandler.cpp * For further information see http://www.genivi.org/. * */ -#include "CAmSocketHandler.h" #include <cassert> #include <sys/fcntl.h> #include <sys/errno.h> @@ -31,80 +31,111 @@ #include <features.h> #include <csignal> #include <unistd.h> + #include "CAmDltWrapper.h" +#include "CAmSocketHandler.h" + +#ifdef WITH_TIMERFD +#include <sys/timerfd.h> +#endif namespace am { CAmSocketHandler::CAmSocketHandler() : - receiverCallbackT(this, &CAmSocketHandler::receiverCallback),// - checkerCallbackT(this, &CAmSocketHandler::checkerCallback),// mPipe(), // - mDispatchDone(1),// - mListPoll(), // - mListTimer(), // - mListActiveTimer(), // - mLastInsertedHandle(0), // - mLastInsertedPollHandle(0), // - mRecreatePollfds(true), // - mStartTime() // + mDispatchDone(true), // + mSetPollKeys(MAX_POLLHANDLE), // + mListPoll(), // + mSetTimerKeys(MAX_TIMERHANDLE), + mListTimer(), // + mListActiveTimer(), // + mSetSignalhandlerKeys(MAX_POLLHANDLE), // + mSignalHandlers(), // + mRecreatePollfds(true), + mInternalCodes(internal_codes_e::NO_ERROR), + mSignalFdHandle(0) +#ifndef WITH_TIMERFD +,mStartTime() // +#endif { if (pipe(mPipe) == -1) { + mInternalCodes = internal_codes_e::PIPE_ERROR; logError("Sockethandler could not create pipe!"); } - //add the pipe to the poll - nothing needs to be proccessed here we just need the pipe to trigger the ppoll + //add the pipe to the poll - nothing needs to be processed here we just need the pipe to trigger the ppoll short event = 0; sh_pollHandle_t handle; event |= POLLIN; - addFDPoll(mPipe[0], event, NULL, &receiverCallbackT, &checkerCallbackT, NULL, NULL, handle); + if (addFDPoll(mPipe[0], event, NULL, [](const pollfd pollfd, const sh_pollHandle_t, void*) + {}, [](const sh_pollHandle_t, void*) + { return (false);}, NULL, NULL, handle) != E_OK) + mInternalCodes |= internal_codes_e::FD_ERROR; } CAmSocketHandler::~CAmSocketHandler() { - close(mPipe[0]); - close(mPipe[1]); + for (auto it : mListPoll) + { + close(it.pollfdValue.fd); + } + close(mPipe[0]); + close(mPipe[1]); } //todo: maybe have some: give me more time returned? /** - * start the block listening for filedescriptors. This is the mainloop. - */ + * start the block listening for filedescriptors. This is the mainloop. + */ void CAmSocketHandler::start_listenting() { - mDispatchDone = 0; + mDispatchDone = false; int16_t pollStatus; - //prepare the signalmask - sigset_t sigmask; - sigemptyset(&sigmask); - sigaddset(&sigmask, SIGINT); - sigaddset(&sigmask, SIGQUIT); - sigaddset(&sigmask, SIGTERM); - sigaddset(&sigmask, SIGHUP); - sigaddset(&sigmask, SIGQUIT); - +#ifndef WITH_TIMERFD clock_gettime(CLOCK_MONOTONIC, &mStartTime); - while (!mDispatchDone) +#endif + timespec buffertime; + + std::list<sh_poll_s> listPoll; + VectorListPoll_t cloneListPoll; + VectorListPoll_t::iterator listmPollIt; + VectorListPollfd_t::iterator itMfdPollingArray; + VectorListPollfd_t fdPollingArray; //!<the polling array for ppoll + + auto preparePollfd = [&](const sh_poll_s& row) { - //first we go through the registered filedescriptors and check if someone needs preparation: - std::for_each(mListPoll.begin(), mListPoll.end(), CAmShCallPrep()); + CAmSocketHandler::prepare((sh_poll_s&)row); + pollfd temp = row.pollfdValue; + temp.revents = 0; + fdPollingArray.push_back(temp); + }; + while (!mDispatchDone) + { if (mRecreatePollfds) { - mfdPollingArray.clear(); + fdPollingArray.clear(); + //freeze mListPoll by copying it - otherwise we get problems when we want to manipulate it during the next lines + cloneListPoll = mListPoll; //there was a change in the setup, so we need to recreate the fdarray from the list - std::for_each(mListPoll.begin(), mListPoll.end(), CAmShCopyPollfd(mfdPollingArray)); + std::for_each(cloneListPoll.begin(), cloneListPoll.end(), preparePollfd); mRecreatePollfds = false; } + else + { + //first we go through the registered filedescriptors and check if someone needs preparation: + std::for_each(cloneListPoll.begin(), cloneListPoll.end(), CAmSocketHandler::prepare); + } +#ifndef WITH_TIMERFD timerCorrection(); - +#endif //block until something is on a filedescriptor - timespec buffertime; - if ((pollStatus = ppoll(&mfdPollingArray[0], mfdPollingArray.size(), insertTime(buffertime), &sigmask)) < 0) + if ((pollStatus = ppoll(&fdPollingArray[0], fdPollingArray.size(), insertTime(buffertime), NULL)) < 0) { if (errno == EINTR) { @@ -121,112 +152,223 @@ void CAmSocketHandler::start_listenting() if (pollStatus != 0) //only check filedescriptors if there was a change { //todo: here could be a timer that makes sure naughty plugins return! - - //freeze mListPoll by copying it - otherwise we get problems when we want to manipulate it during the next lines - std::list<sh_poll_s> listPoll; - mListPoll_t::iterator listmPollIt; - - //remove all filedescriptors who did not fire - std::vector<pollfd>::iterator it = mfdPollingArray.begin(); - do + listPoll.clear(); + //stage 0+1, call firedCB + for (itMfdPollingArray = fdPollingArray.begin(); itMfdPollingArray != fdPollingArray.end(); itMfdPollingArray++) { - it = std::find_if(it, mfdPollingArray.end(), eventFired); - if (it != mfdPollingArray.end()) - { - listmPollIt = mListPoll.begin(); - std::advance(listmPollIt, std::distance(mfdPollingArray.begin(), it)); + if (CAmSocketHandler::eventFired(*itMfdPollingArray)) + { + listmPollIt = cloneListPoll.begin(); + std::advance(listmPollIt, std::distance(fdPollingArray.begin(), itMfdPollingArray)); + listPoll.push_back(*listmPollIt); - listPoll.back().pollfdValue = *it; - it++; + CAmSocketHandler::fire(*listmPollIt); } - } while (it != mfdPollingArray.end()); - - //stage 1, call firedCB - std::for_each(listPoll.begin(), listPoll.end(), CAmShCallFire()); - + } + //stage 2, lets ask around if some dispatching is necessary, the ones who need stay on the list - listPoll.remove_if(noDispatching); + listPoll.remove_if(CAmSocketHandler::noDispatching); //stage 3, the ones left need to dispatch, we do this as long as there is something to dispatch.. do { - listPoll.remove_if(dispatchingFinished); + listPoll.remove_if(CAmSocketHandler::dispatchingFinished); } while (!listPoll.empty()); } +#ifndef WITH_TIMERFD else //Timerevent { //this was a timer event, we need to take care about the timers + //find out the timedifference to starttime timerUp(); } +#endif } } /** - * exits the loop - */ + * exits the loop + */ void CAmSocketHandler::stop_listening() { - mDispatchDone = 1; - + mDispatchDone = true; +#ifndef WITH_TIMERFD //this is for all running timers only - we need to handle the additional offset here if (!mListActiveTimer.empty()) { timespec currentTime, correctionTime; clock_gettime(CLOCK_MONOTONIC, ¤tTime); correctionTime = timespecSub(currentTime, mStartTime); - std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime)); + std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), [&correctionTime](sh_timer_s& t) + { t.countdown = timespecSub(t.countdown, correctionTime);}); } +#endif +} + +void CAmSocketHandler::exit_mainloop() +{ + //end the while loop + stop_listening(); + + //fire the ending filedescriptor + int p(1); + ssize_t result = write(mPipe[1], &p, sizeof(p)); +} +bool CAmSocketHandler::fatalErrorOccurred() +{ + return ((mInternalCodes&internal_codes_e::PIPE_ERROR)>0)||((mInternalCodes&internal_codes_e::FD_ERROR)>0); +} + +am_Error_e CAmSocketHandler::getFDPollData(const sh_pollHandle_t handle, sh_poll_s & outPollData) +{ + VectorListPoll_t::iterator iterator = mListPoll.begin(); + for (; iterator != mListPoll.end(); ++iterator) + { + if (iterator->handle == handle) + { + outPollData = *iterator; + return (E_OK); + } + } + return (E_UNKNOWN); } /** - * Adds a filedescriptor to the polling loop - * @param fd the filedescriptor - * @param event the event flags - * @param prepare a callback that is called before the loop is entered - * @param fired a callback that is called when the filedescriptor needs to be read - * @param check a callback that is called to check if further actions are neccessary - * @param dispatch a callback that is called to dispatch the received data - * @param userData a pointer to userdata that is always passed around - * @param handle the handle of this poll - * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid - */ -am_Error_e CAmSocketHandler::addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void *userData, sh_pollHandle_t & handle) + * Adds a signal handler filedescriptor to the polling loop + * + */ +am_Error_e CAmSocketHandler::listenToSignals(const std::vector<uint8_t> & listSignals) +{ + int fdErr; + uint8_t addedSignals = 0; + sigset_t sigset; + + if(0==listSignals.size()) + { + logWarning("Empty signal list!"); + return (E_NOT_POSSIBLE); + } + + /* Create a sigset of all the signals that we're interested in */ + fdErr = sigemptyset(&sigset); + if (fdErr != 0) + { + logError("Could not create sigset!"); + return (E_NOT_POSSIBLE); + } + + for(uint8_t itSignal : listSignals) + { + fdErr = sigaddset(&sigset, itSignal); + if (fdErr != 0) + logWarning("Could not add", itSignal); + else + addedSignals++; + } + + if(0==addedSignals) + { + logWarning("None of the signals were added!"); + return (E_NOT_POSSIBLE); + } + + /* We must block the signals in order for signalfd to receive them */ + fdErr = sigprocmask(SIG_BLOCK, &sigset, NULL); + if (fdErr != 0) + { + logError("Could not block signals! They must be blocked in order to receive them!"); + return (E_NOT_POSSIBLE); + } + + int signalHandlerFd; + if(mSignalFdHandle) + { + sh_poll_s sgPollData; + if(E_OK!=getFDPollData(mSignalFdHandle, sgPollData)) + { + removeFDPoll(mSignalFdHandle); + mSignalFdHandle = 0; + } + else + { + int signalHandlerFd = signalfd(sgPollData.pollfdValue.fd, &sigset, 0); + if (signalHandlerFd == -1) + { + logError("Could not update signal fd!"); + return (E_NOT_POSSIBLE); + } + return E_OK; + } + } + + if(0==mSignalFdHandle) + { + /* Create the signalfd */ + signalHandlerFd = signalfd(-1, &sigset, 0); + if (signalHandlerFd == -1) + { + logError("Could not open signal fd!"); + return (E_NOT_POSSIBLE); + } + + auto actionPoll = [this](const pollfd pollfd, const sh_pollHandle_t, void*) + { + const VectorSignalHandlers_t & signalHandlers = mSignalHandlers; + /* We have a valid signal, read the info from the fd */ + struct signalfd_siginfo info; + ssize_t bytes = read(pollfd.fd, &info, sizeof(info)); + assert(bytes == sizeof(info)); + + /* Notify all listeners */ + for(auto it: signalHandlers) + it.callback(it.handle, info, it.userData); + }; + /* We're going to add the signal fd through addFDPoll. At this point we don't have any signal listeners. */ + am_Error_e shFdError = addFDPoll(signalHandlerFd, POLLIN | POLLERR | POLLHUP, NULL, actionPoll, [](const sh_pollHandle_t, void*) + { return (false);}, NULL, NULL, mSignalFdHandle); + return shFdError; + } +} + +/** + * Adds a filedescriptor to the polling loop + * @param fd the filedescriptor + * @param event the event flags + * @param prepare a std::function that is called before the loop is entered + * @param fired a std::function that is called when the filedescriptor needs to be read + * @param check a std::function that is called to check if further actions are neccessary + * @param dispatch a std::function that is called to dispatch the received data + * @param userData a pointer to userdata that is always passed around + * @param handle the handle of this poll + * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid + */ + +am_Error_e CAmSocketHandler::addFDPoll(const int fd, const short event, std::function<void(const sh_pollHandle_t handle, void* userData)> prepare, + std::function<void(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)> fired, std::function<bool(const sh_pollHandle_t handle, void* userData)> check, + std::function<bool(const sh_pollHandle_t handle, void* userData)> dispatch, void* userData, sh_pollHandle_t& handle) { if (!fdIsValid(fd)) return (E_NON_EXISTENT); - - //create a new handle for the poll - sh_pollHandle_t lastHandle(mLastInsertedPollHandle); - do + + //create a new handle for the poll + if (!nextHandle(mSetPollKeys)) { - ++mLastInsertedPollHandle; - if (mLastInsertedPollHandle == MAX_POLLHANDLE) - { - mLastInsertedPollHandle = 1; - } - if (mLastInsertedPollHandle==lastHandle) - { - logError(__func__,"Could not create new polls, too many open!"); - return (am_Error_e::E_NOT_POSSIBLE); - } - - } while (mSetPollKeys.find(mLastInsertedPollHandle) != mSetPollKeys.end()); - - mSetPollKeys.insert(mLastInsertedPollHandle); + logError("Could not create new polls, too many open!"); + return (E_NOT_POSSIBLE); + } sh_poll_s pollData; pollData.pollfdValue.fd = fd; - pollData.handle = mLastInsertedPollHandle; + pollData.handle = mSetPollKeys.lastUsedID; pollData.pollfdValue.events = event; pollData.pollfdValue.revents = 0; - pollData.userData = userData; pollData.prepareCB = prepare; pollData.firedCB = fired; pollData.checkCB = check; pollData.dispatchCB = dispatch; - + pollData.userData = userData; //add new data to the list mListPoll.push_back(pollData); @@ -234,23 +376,56 @@ am_Error_e CAmSocketHandler::addFDPoll(const int fd, const short event, IAmShPol handle = pollData.handle; return (E_OK); + } /** - * removes a filedescriptor from the poll loop - * @param handle - * @return - */ + * Adds a filedescriptor to the polling loop + * @param fd the filedescriptor + * @param event the event flags + * @param prepare a callback that is called before the loop is entered + * @param fired a callback that is called when the filedescriptor needs to be read + * @param check a callback that is called to check if further actions are neccessary + * @param dispatch a callback that is called to dispatch the received data + * @param userData a pointer to userdata that is always passed around + * @param handle the handle of this poll + * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid + */ +am::am_Error_e CAmSocketHandler::addFDPoll(const int fd, const short event, IAmShPollPrepare *prepare, IAmShPollFired *fired, IAmShPollCheck *check, IAmShPollDispatch *dispatch, void *userData, sh_pollHandle_t & handle) +{ + + std::function<void(const sh_pollHandle_t handle, void* userData)> prepareCB; //preperation callback + std::function<void(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)> firedCB; //fired callback + std::function<bool(const sh_pollHandle_t handle, void* userData)> checkCB; //check callback + std::function<bool(const sh_pollHandle_t handle, void* userData)> dispatchCB; //check callback + + if (prepare) + prepareCB = std::bind(&IAmShPollPrepare::Call, prepare, std::placeholders::_1, std::placeholders::_2); + if (fired) + firedCB = std::bind(&IAmShPollFired::Call, fired, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + if (check) + checkCB = std::bind(&IAmShPollCheck::Call, check, std::placeholders::_1, std::placeholders::_2); + if (dispatch) + dispatchCB = std::bind(&IAmShPollDispatch::Call, dispatch, std::placeholders::_1, std::placeholders::_2); + + return addFDPoll(fd, event, prepareCB, firedCB, checkCB, dispatchCB, userData, handle); +} + +/** + * removes a filedescriptor from the poll loop + * @param handle + * @return + */ am_Error_e CAmSocketHandler::removeFDPoll(const sh_pollHandle_t handle) { - mListPoll_t::iterator iterator = mListPoll.begin(); + VectorListPoll_t::iterator iterator = mListPoll.begin(); for (; iterator != mListPoll.end(); ++iterator) { if (iterator->handle == handle) { iterator = mListPoll.erase(iterator); - mSetPollKeys.erase(handle); + mSetPollKeys.pollHandles.erase(handle); mRecreatePollfds = true; return (E_OK); } @@ -259,93 +434,232 @@ am_Error_e CAmSocketHandler::removeFDPoll(const sh_pollHandle_t handle) } /** - * adds a timer to the list of timers. The callback will be fired when the timer is up. - * This is not a high precise timer, it is very coarse. It is meant to be used for timeouts when waiting - * for an answer via a filedescriptor. - * One time timer. If you need again a timer, you need to add a new timer in the callback of the old one. - * @param timeouts timeouts time until the callback is fired - * @param callback callback the callback - * @param handle handle the handle that is created for the timer is returned. Can be used to remove the timer - * @param userData pointer always passed with the call - * @return E_OK in case of success - */ -am_Error_e CAmSocketHandler::addTimer(const timespec timeouts, IAmShTimerCallBack* callback, sh_timerHandle_t& handle, void * userData) + * Adds a callback for any signals + * @param callback + * @param handle the handle of this poll + * @param userData a pointer to userdata that is always passed around + * @return E_OK if the descriptor was added, E_NON_EXISTENT if the fd is not valid + */ +am_Error_e CAmSocketHandler::addSignalHandler(std::function<void(const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData)> callback, sh_pollHandle_t& handle, void * userData) +{ + if (!nextHandle(mSetSignalhandlerKeys)) + { + logError("Could not create new polls, too many open!"); + return (E_NOT_POSSIBLE); + } + + mSignalHandlers.emplace_back(); + mSignalHandlers.back().callback = callback; + mSignalHandlers.back().handle = mSetSignalhandlerKeys.lastUsedID; + mSignalHandlers.back().userData = userData; + handle = mSetSignalhandlerKeys.lastUsedID; + + return E_OK; +} + +/** + * removes a signal handler from the list + * @param handle is signal handler id + * @return E_OK in case of success, E_UNKNOWN if the handler was not found. + */ +am_Error_e CAmSocketHandler::removeSignalHandler(const sh_pollHandle_t handle) +{ + VectorSignalHandlers_t::iterator it(mSignalHandlers.begin()); + for (; it != mSignalHandlers.end(); ++it) + { + if (it->handle == handle) + { + it = mSignalHandlers.erase(it); + mSetSignalhandlerKeys.pollHandles.erase(handle); + return (E_OK); + } + } + return (E_UNKNOWN); +} + +/** + * adds a timer to the list of timers. The callback will be fired when the timer is up. + * This is not a high precise timer, it is very coarse. It is meant to be used for timeouts when waiting + * for an answer via a filedescriptor. + * One time timer. If you need again a timer, you need to add a new timer in the callback of the old one. + * @param timeouts timeouts time until the callback is fired + * @param callback callback the callback + * @param handle handle the handle that is created for the timer is returned. Can be used to remove the timer + * @param userData pointer always passed with the call + * @return E_OK in case of success + */ + +am_Error_e CAmSocketHandler::addTimer(const timespec & timeouts, IAmShTimerCallBack* callback, sh_timerHandle_t& handle, void * userData, const bool repeats) { - assert(!((timeouts.tv_sec==0) && (timeouts.tv_nsec==0))); assert(callback!=NULL); - sh_timer_s timerItem; + std::function<void(const sh_timerHandle_t handle, void* userData)> callbackFunc; + callbackFunc = std::bind(&IAmShTimerCallBack::Call, callback, std::placeholders::_1, std::placeholders::_2); + return addTimer(timeouts, callbackFunc, handle, userData, repeats); +} + +am_Error_e CAmSocketHandler::addTimer(const timespec & timeouts, std::function<void(const sh_timerHandle_t handle, void* userData)> callback, sh_timerHandle_t& handle, void * userData, const bool repeats) +{ + assert(!((timeouts.tv_sec == 0) && (timeouts.tv_nsec == 0))); + + mListTimer.emplace_back(); + sh_timer_s & timerItem = mListTimer.back(); + +#ifndef WITH_TIMERFD //create a new handle for the timer - sh_timerHandle_t lastTimerHandle(mLastInsertedHandle); - do + if (!nextHandle(mSetTimerKeys)) { - ++mLastInsertedHandle; - if (mLastInsertedHandle == MAX_TIMERHANDLE) - { - mLastInsertedHandle = 1; - } - if (lastTimerHandle==mLastInsertedHandle) - { - logError(__func__,"Could not create new timers, too many open!"); - return (am_Error_e::E_NOT_POSSIBLE); - } - - } while (mSetTimerKeys.find(mLastInsertedHandle) != mSetTimerKeys.end()); - - mSetTimerKeys.insert(mLastInsertedHandle); - handle=mLastInsertedHandle; - timerItem.handle = handle; + logError("Could not create new timers, too many open!"); + mListTimer.pop_back(); + return (E_NOT_POSSIBLE); + } + //create a new handle for the timer + handle = mSetTimerKeys.lastUsedID; + timerItem.countdown = timeouts; timerItem.callback = callback; timerItem.userData = userData; - mListTimer.push_back(timerItem); + timerItem.handle = handle; //we add here the time difference between startTime and currenttime, because this time will be substracted later on in timecorrection timespec currentTime; clock_gettime(CLOCK_MONOTONIC, ¤tTime); - if (!mDispatchDone) //the mainloop is started - timerItem.countdown = timespecAdd(timeouts, timespecSub(currentTime, mStartTime)); - + if (!mDispatchDone)//the mainloop is started + timerItem.countdown = timespecAdd(timeouts, timespecSub(currentTime, mStartTime)); + mListTimer.push_back(timerItem); mListActiveTimer.push_back(timerItem); mListActiveTimer.sort(compareCountdown); return (E_OK); + +#else + timerItem.countdown.it_value = timeouts; + if (repeats) + timerItem.countdown.it_interval = timeouts; + else + { + timespec zero; + zero.tv_sec = 0; + zero.tv_nsec = 0; + timerItem.countdown.it_interval = zero; + } + + timerItem.fd = -1; + timerItem.userData = userData; + am_Error_e err = createTimeFD(timerItem.countdown, timerItem.fd); + if (err != E_OK) + { + mListTimer.pop_back(); + return err; + } + + static auto actionPoll = [](const pollfd pollfd, const sh_pollHandle_t handle, void* userData) + { + uint64_t mExpirations; + if (read(pollfd.fd, &mExpirations, sizeof(uint64_t)) == -1) + { + //error received...try again + read(pollfd.fd, &mExpirations, sizeof(uint64_t)); + } + }; + + err = addFDPoll(timerItem.fd, POLLIN, NULL, actionPoll, [callback](const sh_pollHandle_t handle, void* userData)->bool + { + callback(handle, userData); + return false; + }, + NULL, userData, handle); + if (E_OK == err) + { + timerItem.handle = handle; + } + else + { + mListTimer.pop_back(); + } + return err; +#endif + } /** - * removes a timer from the list of timers - * @param handle the handle to the timer - * @return E_OK in case of success, E_UNKNOWN if timer was not found. - */ + * removes a timer from the list of timers + * @param handle the handle to the timer + * @return E_OK in case of success, E_UNKNOWN if timer was not found. + */ am_Error_e CAmSocketHandler::removeTimer(const sh_timerHandle_t handle) { - assert(handle!=0); + assert(handle != 0); //stop the current timer - stopTimer(handle); +#ifdef WITH_TIMERFD + std::list<sh_timer_s>::iterator it = mListTimer.begin(); + for (; it != mListTimer.end(); ++it) + { + if (it->handle == handle) + break; + } + if (it == mListTimer.end()) + return (E_NON_EXISTENT); + close(it->fd); + mListTimer.erase(it); + return removeFDPoll(handle); +#else + stopTimer(handle); std::list<sh_timer_s>::iterator it(mListTimer.begin()); for (; it != mListTimer.end(); ++it) { if (it->handle == handle) { it = mListTimer.erase(it); - mSetTimerKeys.erase(handle); + mSetTimerKeys.pollHandles.erase(handle); return (E_OK); } } return (E_UNKNOWN); +#endif } /** - * restarts a timer and updates with a new interva - * @param handle handle to the timer - * @param timeouts new timout time - * @return E_OK on success, E_NON_EXISTENT if the handle was not found - */ -am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const timespec timeouts) + * restarts a timer and updates with a new interva + * @param handle handle to the timer + * @param timeouts new timout time + * @return E_OK on success, E_NON_EXISTENT if the handle was not found + */ +am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const timespec & timeouts) { +#ifdef WITH_TIMERFD + std::list<sh_timer_s>::iterator it = mListTimer.begin(); + for (; it != mListTimer.end(); ++it) + { + if (it->handle == handle) + break; + } + if (it == mListTimer.end()) + return (E_NON_EXISTENT); + + if (it->countdown.it_interval.tv_nsec != 0 || it->countdown.it_interval.tv_sec != 0) + it->countdown.it_interval = timeouts; + it->countdown.it_value = timeouts; + + if (!fdIsValid(it->fd)) + { + am_Error_e err = createTimeFD(it->countdown, it->fd); + if (err != E_OK) + return err; + } + else + { + if (timerfd_settime(it->fd, 0, &it->countdown, NULL)) + { + logError("Failed to set timer duration"); + return E_NOT_POSSIBLE; + } + } +#else + //update the mList .... sh_timer_s timerItem; std::list<sh_timer_s>::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin()); @@ -361,7 +675,7 @@ am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const ti } } if (!found) - return (E_NON_EXISTENT); + return (E_NON_EXISTENT); found = false; @@ -370,8 +684,8 @@ am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const ti currentTime.tv_nsec=timeoutsCorrected.tv_nsec=0; currentTime.tv_sec=timeoutsCorrected.tv_sec=0; clock_gettime(CLOCK_MONOTONIC, ¤tTime); - if (!mDispatchDone) //the mainloop is started - timeoutsCorrected = timespecAdd(timeouts, timespecSub(currentTime, mStartTime)); + if (!mDispatchDone)//the mainloop is started + timeoutsCorrected = timespecAdd(timeouts, timespecSub(currentTime, mStartTime)); for (; activeIt != mListActiveTimer.end(); ++activeIt) { @@ -384,20 +698,48 @@ am_Error_e CAmSocketHandler::updateTimer(const sh_timerHandle_t handle, const ti } if (!found) - timerItem.countdown = timeoutsCorrected; + timerItem.countdown = timeoutsCorrected; mListActiveTimer.push_back(timerItem); mListActiveTimer.sort(compareCountdown); + +#endif return (E_OK); } /** - * restarts a timer with the original value - * @param handle - * @return E_OK on success, E_NON_EXISTENT if the handle was not found - */ + * restarts a timer with the original value + * @param handle + * @return E_OK on success, E_NON_EXISTENT if the handle was not found + */ am_Error_e CAmSocketHandler::restartTimer(const sh_timerHandle_t handle) { +#ifdef WITH_TIMERFD + std::list<sh_timer_s>::iterator it = mListTimer.begin(); + for (; it != mListTimer.end(); ++it) + { + if (it->handle == handle) + break; + } + if (it == mListTimer.end()) + return (E_NON_EXISTENT); + + if (!fdIsValid(it->fd)) + { + am_Error_e err = createTimeFD(it->countdown, it->fd); + if (err != E_OK) + return err; + } + else + { + if (timerfd_settime(it->fd, 0, &it->countdown, NULL)) + { + logError("Failed to set timer duration"); + return E_NOT_POSSIBLE; + } + } +#else + sh_timer_s timerItem; //!<the original timer value //find the original value std::list<sh_timer_s>::iterator it(mListTimer.begin()), activeIt(mListActiveTimer.begin()); @@ -412,14 +754,14 @@ am_Error_e CAmSocketHandler::restartTimer(const sh_timerHandle_t handle) } } if (!found) - return (E_NON_EXISTENT); + return (E_NON_EXISTENT); found = false; //we add here the time difference between startTime and currenttime, because this time will be substracted later on in timecorrection timespec currentTime, timeoutsCorrected; clock_gettime(CLOCK_MONOTONIC, ¤tTime); - if (!mDispatchDone) //the mainloop is started + if (!mDispatchDone)//the mainloop is started { timeoutsCorrected = timespecAdd(timerItem.countdown, timespecSub(currentTime, mStartTime)); timerItem.countdown = timeoutsCorrected; @@ -436,20 +778,41 @@ am_Error_e CAmSocketHandler::restartTimer(const sh_timerHandle_t handle) } if (!found) - mListActiveTimer.push_back(timerItem); + mListActiveTimer.push_back(timerItem); mListActiveTimer.sort(compareCountdown); - +#endif return (E_OK); } /** - * stops a timer - * @param handle - * @return E_OK on success, E_NON_EXISTENT if the handle was not found - */ + * stops a timer + * @param handle + * @return E_OK on success, E_NON_EXISTENT if the handle was not found + */ am_Error_e CAmSocketHandler::stopTimer(const sh_timerHandle_t handle) { +#ifdef WITH_TIMERFD + std::list<sh_timer_s>::iterator it = mListTimer.begin(); + for (; it != mListTimer.end(); ++it) + { + if (it->handle == handle) + break; + } + if (it == mListTimer.end()) + return (E_NON_EXISTENT); + + itimerspec countdown = it->countdown; + countdown.it_value.tv_nsec = 0; + countdown.it_value.tv_sec = 0; + + if (timerfd_settime(it->fd, 0, &countdown, NULL)) + { + logError("Failed to set timer duration"); + return E_NOT_POSSIBLE; + } + return (E_OK); +#else //go through the list and remove the timer with the handle std::list<sh_timer_s>::iterator it(mListActiveTimer.begin()); for (; it != mListActiveTimer.end(); ++it) @@ -461,17 +824,18 @@ am_Error_e CAmSocketHandler::stopTimer(const sh_timerHandle_t handle) } } return (E_NON_EXISTENT); +#endif } /** - * updates the eventFlags of a poll - * @param handle - * @param events - * @return @return E_OK on succsess, E_NON_EXISTENT if fd was not found - */ + * updates the eventFlags of a poll + * @param handle + * @param events + * @return @return E_OK on succsess, E_NON_EXISTENT if fd was not found + */ am_Error_e CAmSocketHandler::updateEventFlags(const sh_pollHandle_t handle, const short events) { - mListPoll_t::iterator iterator = mListPoll.begin(); + VectorListPoll_t::iterator iterator = mListPoll.begin(); for (; iterator != mListPoll.end(); ++iterator) { @@ -486,27 +850,36 @@ am_Error_e CAmSocketHandler::updateEventFlags(const sh_pollHandle_t handle, cons } /** - * checks if a filedescriptor is validCAmShSubstractTime - * @param fd the filedescriptor - * @return true if the fd is valid - */ + * checks if a filedescriptor is validCAmShSubstractTime + * @param fd the filedescriptor + * @return true if the fd is valid + */ bool CAmSocketHandler::fdIsValid(const int fd) const { return (fcntl(fd, F_GETFL) != -1 || errno != EBADF); } +#ifndef WITH_TIMERFD /** - * timer is up. - */ + * timer is up. + */ void CAmSocketHandler::timerUp() { //find out the timedifference to starttime - timespec currentTime, diffTime; + static timespec currentTime, diffTime; clock_gettime(CLOCK_MONOTONIC, ¤tTime); diffTime = timespecSub(currentTime, mStartTime); + static auto countdownUp = [&](const sh_timer_s& row)->bool + { + timespec sub = timespecSub(row.countdown, diffTime); + if (sub.tv_nsec == 0 && sub.tv_sec == 0) + return (true); + return (false); + }; + //now we need to substract the diffTime from all timers and see if they are up - std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownUp(diffTime)); + std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), countdownUp); //copy all fired timers into a list std::vector<sh_timer_s> tempList(overflowIter, mListActiveTimer.rend()); @@ -516,28 +889,40 @@ void CAmSocketHandler::timerUp() mListActiveTimer.erase(mListActiveTimer.begin(), it); //call the callbacks for the timers - std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer()); + std::for_each(tempList.begin(), tempList.end(), CAmSocketHandler::callTimer); } /** - * correct timers and fire the ones who are up - */ + * correct timers and fire the ones who are up + */ void CAmSocketHandler::timerCorrection() { //get the current time and calculate the correction value - timespec currentTime, correctionTime; + static timespec currentTime, correctionTime; clock_gettime(CLOCK_MONOTONIC, ¤tTime); correctionTime = timespecSub(currentTime, mStartTime); mStartTime = currentTime; + static auto countdownZero = [](const sh_timer_s& row)->bool + { + if (row.countdown.tv_nsec == 0 && row.countdown.tv_sec == 0) + return (true); + return (false); + }; + + static auto substractTime = [&](sh_timer_s& t) + { + t.countdown = timespecSub(t.countdown, correctionTime); + }; + if (!mListActiveTimer.empty()) { //subtract the correction value from all items in the list - std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), CAmShSubstractTime(correctionTime)); + std::for_each(mListActiveTimer.begin(), mListActiveTimer.end(), substractTime); //find the last occurrence of zero -> timer overflowed - std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), CAmShCountdownZero()); + std::list<sh_timer_s>::reverse_iterator overflowIter = std::find_if(mListActiveTimer.rbegin(), mListActiveTimer.rend(), countdownZero); //only if a timer overflowed if (overflowIter != mListActiveTimer.rend()) @@ -550,100 +935,146 @@ void CAmSocketHandler::timerCorrection() mListActiveTimer.erase(mListActiveTimer.begin(), it); //call the callbacks for the timers - std::for_each(tempList.begin(), tempList.end(), CAmShCallTimer()); + std::for_each(tempList.begin(), tempList.end(), CAmSocketHandler::callTimer); } } } +#endif -void CAmSocketHandler::exit_mainloop() +/** + * prepare for poll + */ +void CAmSocketHandler::prepare(am::CAmSocketHandler::sh_poll_s& row) { - //end the while loop - stop_listening(); + if (row.prepareCB) + { + try + { + row.prepareCB(row.handle, row.userData); + } catch (std::exception& e) + { + logError("Sockethandler: Exception in Preparecallback,caught", e.what()); + } + } +} - //fire the ending filedescriptor - int p(1); - ssize_t result = write(mPipe[1], &p, sizeof(p)); +/** + * fire callback + */ +void CAmSocketHandler::fire(sh_poll_s& a) +{ + try + { + a.firedCB(a.pollfdValue, a.handle, a.userData); + } catch (std::exception& e) + { + logError("Sockethandler: Exception in Preparecallback,caught", e.what()); + } } /** - * is used to set the pointer for the ppoll command - * @param buffertime - * @return - */ + * should disptach + */ +bool CAmSocketHandler::noDispatching(const sh_poll_s& a) +{ + //remove from list of there is no checkCB + if (nullptr == a.checkCB) + return (true); + return (!a.checkCB(a.handle, a.userData)); +} + +/** + * disptach + */ +bool CAmSocketHandler::dispatchingFinished(const sh_poll_s& a) +{ + //remove from list of there is no dispatchCB + if (nullptr == a.dispatchCB) + return (true); + return (!a.dispatchCB(a.handle, a.userData)); +} + +/** + * event triggered + */ +bool CAmSocketHandler::eventFired(const pollfd& a) +{ + return (a.revents == 0 ? false : true); +} + +/** + * is used to set the pointer for the ppoll command + * @param buffertime + * @return + */ inline timespec* CAmSocketHandler::insertTime(timespec& buffertime) { +#ifndef WITH_TIMERFD if (!mListActiveTimer.empty()) { buffertime = mListActiveTimer.front().countdown; return (&buffertime); } else +#endif { return (NULL); } } -void CAmSocketHandler::CAmShCallFire::operator()(sh_poll_s& row) -{ - try - { - row.firedCB->Call(row.pollfdValue, row.handle, row.userData); - } - catch (std::exception& e) - { - logError("Sockethandler: Exception in FireCallback,caught",e.what()); - } -} - -void CAmSocketHandler::CAmShCallPrep::operator()(sh_poll_s& row) +#ifdef WITH_TIMERFD +am_Error_e CAmSocketHandler::createTimeFD(const itimerspec & timeouts, int & fd) { - if (row.prepareCB) - { - try - { - row.prepareCB->Call(row.handle, row.userData); - } - catch (std::exception& e) - { - logError("Sockethandler: Exception in Preparecallback,caught",e.what()); - } - } -} + fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); + if (fd <= 0) + { + logError("Failed to create timer"); + return E_NOT_POSSIBLE; + } -void CAmSocketHandler::CAmShCallTimer::operator()(sh_timer_s& row) -{ - try - { - row.callback->Call(row.handle, row.userData); - } - catch (std::exception& e) - { - logError("Sockethandler: Exception in Timercallback,caught",e.what()); - } + if (timerfd_settime(fd, 0, &timeouts, NULL)) + { + logError("Failed to set timer duration"); + return E_NOT_POSSIBLE; + } + return E_OK; } +#endif -void CAmSocketHandler::CAmShCopyPollfd::operator()(const sh_poll_s& row) +void CAmSocketHandler::callTimer(sh_timer_s& a) { - pollfd temp = row.pollfdValue; - temp.revents = 0; - mArray.push_back(temp); + try + { + a.callback(a.handle, a.userData); + } catch (std::exception& e) + { + logError("Sockethandler: Exception in Timercallback,caught", e.what()); + } } -bool CAmSocketHandler::CAmShCountdownUp::operator()(const sh_timer_s& row) +bool CAmSocketHandler::nextHandle(sh_identifier_s & handle) { - timespec sub = timespecSub(row.countdown, mDiffTime); - if (sub.tv_nsec == 0 && sub.tv_sec == 0) - return (true); - return (false); -} + //create a new handle for the poll + const sh_pollHandle_t lastHandle(handle.lastUsedID); + do + { + ++handle.lastUsedID; + if (handle.lastUsedID == handle.limit) + { + handle.lastUsedID = 1; + } + if (handle.lastUsedID == lastHandle) + { + logError("Could not create new polls, too many open!"); + return (false); + } -bool CAmSocketHandler::CAmShCountdownZero::operator()(const sh_timer_s& row) -{ - if (row.countdown.tv_nsec == 0 && row.countdown.tv_sec == 0) - return (true); - return (false); -} + } while (handle.pollHandles.find(handle.lastUsedID) != handle.pollHandles.end()); + handle.pollHandles.insert(handle.lastUsedID); + + return (true); +} } diff --git a/AudioManagerUtilities/test/AmSerializerTest/CAmSerializerTest.cpp b/AudioManagerUtilities/test/AmSerializerTest/CAmSerializerTest.cpp new file mode 100644 index 0000000..49c6738 --- /dev/null +++ b/AudioManagerUtilities/test/AmSerializerTest/CAmSerializerTest.cpp @@ -0,0 +1,207 @@ +/** + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2012, BMW AG + * + * This file is part of GENIVI Project AudioManager. + * + * Contributions are licensed to the GENIVI Alliance under one or more + * Contribution License Agreements. + * + * \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/. + * + * + * \author Christian Linke, christian.linke@bmw.de BMW 2011,2012 + * + * For further information see http://www.genivi.org/. + * + */ + +#include <cstdio> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <sys/ioctl.h> +#include <string.h> +#include <netdb.h> +#include <fcntl.h> +#include <sys/un.h> +#include <sys/poll.h> + +#include "CAmSocketHandler.h" +#include "CAmSerializer.h" +#include "CAmSerializerTest.h" + +using namespace testing; +using namespace am; + +CAmTimerSockethandlerController::CAmTimerSockethandlerController(CAmSocketHandler *myHandler, const timespec &timeout) : + MockIAmTimerCb(), mpSocketHandler(myHandler), mUpdateTimeout(timeout), pTimerCallback(this, &CAmTimerSockethandlerController::timerCallback) +{ +} + +am::CAmTimerSockethandlerController::~CAmTimerSockethandlerController() +{ +} + +void am::CAmTimerSockethandlerController::timerCallback(sh_timerHandle_t handle, void* userData) +{ + MockIAmTimerCb::timerCallback(handle, userData); + mpSocketHandler->stop_listening(); +} + +CAmSerializerTest::CAmSerializerTest() +{ +} + +CAmSerializerTest::~CAmSerializerTest() +{ +} + +void CAmSerializerTest::SetUp() +{ + +} + +void CAmSerializerTest::TearDown() +{ +} + +struct SerializerData +{ + + std::string testStr; + int result; + MockIAmSerializerCb *pSerCb; + CAmSocketHandler *pSocketHandler; + V2::CAmSerializer *pSerializer; +}; + +void* ptSerializerSync(void* data) +{ + SerializerData *pData = (SerializerData*) data; + std::string testStr(pData->testStr); + bool result = false; + int r = 0; + const uint32_t ten = 10; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + pData->pSerializer->syncCall(pData->pSerCb, &MockIAmSerializerCb::check); + pData->pSerializer->syncCall(pData->pSerCb, &MockIAmSerializerCb::checkInt, pData->result); + pData->pSerializer->syncCall(pData->pSerCb, &MockIAmSerializerCb::dispatchData, result, ten, pData->testStr); +#pragma GCC diagnostic pop + return (NULL); +} + +void* ptSerializerASync(void* data) +{ + SerializerData *pData = (SerializerData*) data; + std::string testStr; + bool result = false; + int r = 0; + const uint32_t ten = 10; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + for (uint32_t i = 0; i < 5; i++) + { + testStr = pData->testStr; + pData->pSerializer->asyncCall(pData->pSerCb, &MockIAmSerializerCb::dispatchData, i, testStr); + } + pData->testStr = testStr; + pData->pSerializer->asyncInvocation(std::bind([]()->bool + { return 1;})); + pData->pSerializer->asyncInvocation(std::bind([](const int i, int & result) + { result = i*10;}, 1, std::ref(r))); + + pData->pSerializer->asyncCall(pData->pSerCb, &MockIAmSerializerCb::check); + pData->pSerializer->asyncCall(pData->pSerCb, &MockIAmSerializerCb::check); + + pData->pSerializer->asyncCall(pData->pSerCb, &MockIAmSerializerCb::checkInt); + +#pragma GCC diagnostic pop + return (NULL); +} + +ACTION(ActionDispatchData){ +arg1="DispatchData"; +} + +TEST(CAmSerializerTest, syncTest) +{ + pthread_t serThread; + + MockIAmSerializerCb serCb; + CAmSocketHandler myHandler; + std::string testStr("testStr"); + V2::CAmSerializer serializer(&myHandler); + sh_timerHandle_t handle; + timespec timeout4; + timeout4.tv_nsec = 0; + timeout4.tv_sec = 3; + CAmTimerSockethandlerController testCallback4(&myHandler, timeout4); + myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); + EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); + + SerializerData serializerData; + serializerData.result = 0; + serializerData.testStr = testStr; + serializerData.pSerCb = &serCb; + serializerData.pSocketHandler = &myHandler; + serializerData.pSerializer = &serializer; + pthread_create(&serThread, NULL, ptSerializerSync, &serializerData); + + EXPECT_CALL(serCb,check()).Times(1); + EXPECT_CALL(serCb,checkInt()).Times(1).WillRepeatedly(Return(100)); + EXPECT_CALL(serCb,dispatchData(10,testStr)).Times(1).WillRepeatedly(DoAll(ActionDispatchData(), Return(true))); + + myHandler.start_listenting(); + + pthread_join(serThread, NULL); + ASSERT_TRUE(serializerData.testStr == "DispatchData"); + ASSERT_TRUE(serializerData.result == 100); +} + +TEST(CAmSerializerTest, asyncTest) +{ + pthread_t serThread; + + MockIAmSerializerCb serCb; + CAmSocketHandler myHandler; + std::string testStr("testStr"); + V2::CAmSerializer serializer(&myHandler); + sh_timerHandle_t handle; + timespec timeout4; + timeout4.tv_nsec = 0; + timeout4.tv_sec = 3; + CAmTimerSockethandlerController testCallback4(&myHandler, timeout4); + myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); + EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); + + SerializerData serializerData; + serializerData.result = 0; + serializerData.testStr = testStr; + serializerData.pSerCb = &serCb; + serializerData.pSocketHandler = &myHandler; + serializerData.pSerializer = &serializer; + pthread_create(&serThread, NULL, ptSerializerASync, &serializerData); + + EXPECT_CALL(serCb,check()).Times(2); + EXPECT_CALL(serCb,checkInt()).Times(1).WillRepeatedly(Return(100)); + for (int i = 0; i < 5; i++) + EXPECT_CALL(serCb,dispatchData(i,testStr)).WillOnce(DoAll(ActionDispatchData(), Return(true))); + + myHandler.start_listenting(); + + pthread_join(serThread, NULL); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/AudioManagerUtilities/test/AmSerializerTest/CAmSerializerTest.h b/AudioManagerUtilities/test/AmSerializerTest/CAmSerializerTest.h new file mode 100644 index 0000000..8ae3737 --- /dev/null +++ b/AudioManagerUtilities/test/AmSerializerTest/CAmSerializerTest.h @@ -0,0 +1,99 @@ +/** + * SPDX license identifier: MPL-2.0 + * + * Copyright (C) 2012, BMW AG + * + * This file is part of GENIVI Project AudioManager. + * + * Contributions are licensed to the GENIVI Alliance under one or more + * Contribution License Agreements. + * + * \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/. + * + * + * \author Christian Linke, christian.linke@bmw.de BMW 2011,2012 + * + * For further information see http://www.genivi.org/. + * + */ + +#ifndef SERIALIZERTEST_H_ +#define SERIALIZERTEST_H_ + +#define WITH_DLT + +#include <ctime> +#include <chrono> +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include <queue> +#include "CAmSocketHandler.h" + +namespace am +{ + + class IAmSerializerCb + { + public: + virtual ~IAmSerializerCb() + { + } + virtual bool dispatchData(const uint32_t handle, std::string & outString)=0; + virtual void check()=0; + virtual int checkInt()=0; + }; + + class IAmTimerCb + { + public: + virtual ~IAmTimerCb() + { + } + virtual void timerCallback(sh_timerHandle_t handle, void * userData)=0; + }; + + class MockIAmTimerCb: public IAmTimerCb + { + public: + MOCK_CONST_METHOD2(timerCallback, + void(sh_timerHandle_t handle, void *userData)); + }; + + class CAmTimerSockethandlerController: public MockIAmTimerCb + { + CAmSocketHandler *mpSocketHandler; + timespec mUpdateTimeout; + public: + explicit CAmTimerSockethandlerController(CAmSocketHandler *SocketHandler, const timespec &timeout); + virtual ~CAmTimerSockethandlerController(); + + void timerCallback(sh_timerHandle_t handle, void * userData); + + TAmShTimerCallBack<CAmTimerSockethandlerController> pTimerCallback; + }; + + class MockIAmSerializerCb: public IAmSerializerCb + { + public: + MOCK_METHOD2(dispatchData, + bool(const uint32_t handle, std::string & outString)); + MOCK_METHOD0(check, + void()); + MOCK_METHOD0(checkInt, + int()); + }; + + class CAmSerializerTest: public ::testing::Test + { + public: + CAmSerializerTest(); + ~CAmSerializerTest(); + void SetUp(); + void TearDown(); + }; + +} /* namespace am */ +#endif /* SOCKETHANDLERTEST_H_ */ diff --git a/AudioManagerUtilities/test/AmSerializerTest/CMakeLists.txt b/AudioManagerUtilities/test/AmSerializerTest/CMakeLists.txt new file mode 100644 index 0000000..e0d2287 --- /dev/null +++ b/AudioManagerUtilities/test/AmSerializerTest/CMakeLists.txt @@ -0,0 +1,48 @@ +# Copyright (C) 2012, BMW AG +# +# This file is part of GENIVI Project AudioManager. +# +# Contributions are licensed to the GENIVI Alliance under one or more +# Contribution License Agreements. +# +# 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/. +# +# author Christian Linke, christian.linke@bmw.de BMW 2011,2012 +# +# For further information see http://www.genivi.org/. +# + +cmake_minimum_required(VERSION 3.0) + +project(AmSerializerTest LANGUAGES CXX VERSION ${DAEMONVERSION}) + +INCLUDE_DIRECTORIES( + ${AUDIOMANAGER_UTILITIES_INCLUDE} + ${GMOCK_INCLUDE_DIRS} + ${GTEST_INCLUDE_DIRS}) + +file(GLOB Socket_SRCS_CXX + "*.cpp" +) + +ADD_EXECUTABLE(AmSerializerTest ${Socket_SRCS_CXX}) + +TARGET_LINK_LIBRARIES(AmSerializerTest + ${GTEST_LIBRARIES} + ${GMOCK_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + AudioManagerUtilities +) + +ADD_DEPENDENCIES(AmSerializerTest AudioManagerUtilities) + +INSTALL(TARGETS AmSerializerTest + DESTINATION ${TEST_EXECUTABLE_INSTALL_PATH} + PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ + COMPONENT tests +) + + diff --git a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp index 50e2aa9..ecd38fe 100644 --- a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp +++ b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.cpp @@ -30,6 +30,7 @@ #include <fcntl.h> #include <sys/un.h> #include <sys/poll.h> + #include "CAmSocketHandler.h" //todo: expand test, implement more usecases @@ -37,9 +38,32 @@ #define SOCK_PATH "/tmp/mysock" +#define SOCKET_TEST_LOOPS_COUNT 1000 + using namespace testing; using namespace am; +static const char * TEST_SOCKET_DATA = "Got It?"; +static const char * TEST_SOCKET_DATA_FINAL = "finish!"; + +static const std::chrono::time_point<std::chrono::high_resolution_clock> TP_ZERO; + + +MockIAmSignalHandler *pMockSignalHandler = NULL; +static void signalHandler(int sig, siginfo_t *siginfo, void *context) +{ + (void) sig; + (void) siginfo; + (void) context; + + if(pMockSignalHandler!=NULL) + pMockSignalHandler->signalHandler(sig, siginfo, context); + +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT + std::cout<<"signal handler was called with signal " << sig << std::endl; +#endif +} + CAmSocketHandlerTest::CAmSocketHandlerTest() { } @@ -48,106 +72,425 @@ CAmSocketHandlerTest::~CAmSocketHandlerTest() { } -CAmTimerCb::CAmTimerCb(CAmSocketHandler *myHandler) : - pTimer1Callback(this, &CAmTimerCb::timer1Callback), // - pTimer2Callback(this, &CAmTimerCb::timer2Callback), // - pTimer3Callback(this, &CAmTimerCb::timer3Callback), // - pTimer4Callback(this, &CAmTimerCb::timer4Callback), // - mSocketHandler(myHandler) +void CAmSocketHandlerTest::SetUp() +{ + +} +void CAmSocketHandlerTest::TearDown() { } -am::CAmTimerCb::~CAmTimerCb() +CAmTimerSockethandlerController::CAmTimerSockethandlerController(CAmSocketHandler *myHandler, const timespec &timeout) : + MockIAmTimerCb(), mpSocketHandler(myHandler), mUpdateTimeout(timeout), pTimerCallback(this, &CAmTimerSockethandlerController::timerCallback) { } -void am::CAmTimerCb::timer1Callback(sh_timerHandle_t handle, void* userData) +am::CAmTimerSockethandlerController::~CAmTimerSockethandlerController() { - (void) handle; - (void) userData; - std::cout << "callback1 called" << std::endl; - timespec timeout; - timeout.tv_nsec = 0; - timeout.tv_sec = 1; - mSocketHandler->updateTimer(handle,timeout); } -void am::CAmTimerCb::timer2Callback(sh_timerHandle_t handle, void* userData) +void am::CAmTimerSockethandlerController::timerCallback(sh_timerHandle_t handle, void* userData) { - (void) handle; - (void) userData; - std::cout << "callback2 called" << std::endl; - timespec timeout; - timeout.tv_nsec = 011110000; - timeout.tv_sec = 1; - mSocketHandler->updateTimer(handle,timeout); + MockIAmTimerCb::timerCallback(handle, userData); + mpSocketHandler->stop_listening(); } -void am::CAmTimerCb::timer3Callback(sh_timerHandle_t, void* userData) +CAmTimerSignalHandler::CAmTimerSignalHandler(CAmSocketHandler *myHandler, const timespec &timeout, const std::set<unsigned> & signals) : + MockIAmTimerCb(), mIndex(0), mSignals(signals), mpSocketHandler(myHandler), mUpdateTimeout(timeout), pTimerCallback(this, &CAmTimerSignalHandler::timerCallback) { - (void) userData; - std::cout << "callback3 called" << std::endl; + } -void am::CAmTimerCb::timer4Callback(sh_timerHandle_t, void* userData) +am::CAmTimerSignalHandler::~CAmTimerSignalHandler() { - (void) userData; - std::cout << "callback4 called" << std::endl; - mSocketHandler->stop_listening(); +} + +void am::CAmTimerSignalHandler::timerCallback(sh_timerHandle_t handle, void* userData) +{ + MockIAmTimerCb::timerCallback(handle, userData); + if(mIndex<mSignals.size()) + { + std::set<unsigned>::iterator it = mSignals.begin(); + std::advance(it, mIndex); + kill(getpid(), *it); + mIndex++; + +#ifndef WITH_TIMERFD + mpSocketHandler->updateTimer( handle, mUpdateTimeout); +#endif + } + else + mpSocketHandler->stop_listening(); + +} + +CAmTimer::CAmTimer(CAmSocketHandler *myHandler, const timespec &timeout, const int32_t repeats) : + MockIAmTimerCb(), mpSocketHandler(myHandler), mUpdateTimeout(timeout), pTimerCallback(this, &CAmTimer::timerCallback), mRepeats(repeats) +{ +} + +am::CAmTimer::~CAmTimer() +{ +} + +void am::CAmTimer::timerCallback(sh_timerHandle_t handle, void* userData) +{ + MockIAmTimerCb::timerCallback(handle, userData); + if (--mRepeats > 0) + { +#ifndef WITH_TIMERFD + mpSocketHandler->updateTimer( handle, mUpdateTimeout); +#endif + } + else + { + mpSocketHandler->stopTimer(handle); + } +} + +CAmTimerMeasurment::CAmTimerMeasurment(CAmSocketHandler *myHandler, const timespec &timeout, const std::string & label, const int32_t repeats, void * userData) : + MockIAmTimerCb(), pTimerCallback(this, &CAmTimerMeasurment::timerCallback), // + mSocketHandler(myHandler), mUpdateTimeout(timeout), mUpdateTimePoint(std::chrono::seconds + { mUpdateTimeout.tv_sec } + std::chrono::nanoseconds + { mUpdateTimeout.tv_nsec }), mLastInvocationTime(), mExpected(mUpdateTimePoint - TP_ZERO), mRepeats(repeats), mpUserData(userData), mDebugText(label) +{ +} + +am::CAmTimerMeasurment::~CAmTimerMeasurment() +{ +} + +void am::CAmTimerMeasurment::timerCallback(sh_timerHandle_t handle, void* userData) +{ + MockIAmTimerCb::timerCallback(handle, userData); + + std::chrono::time_point<std::chrono::high_resolution_clock> t_end = std::chrono::high_resolution_clock::now(); + if (TP_ZERO != mLastInvocationTime) + { + auto durationLast = t_end - mLastInvocationTime; + double diff = (std::chrono::duration<double, std::milli>(mExpected - durationLast).count()); + +#ifdef ENABLED_TIMERS_TEST_OUTPUT + std::cout << mDebugText << + " [ expected:" <<std::chrono::duration<double, std::milli>(mExpected).count() << "ms" + " , current:" << std::chrono::duration<double, std::milli>(durationLast).count() << "ms" + ", diff:" << diff << "ms ] " << + std::endl; +#endif + if (diff > TIMERS_CB_TOLERANCE) + std::cout << mDebugText << " Warning [ expected:" << std::chrono::duration<double, std::milli>(mExpected).count() << "ms, current:" << std::chrono::duration<double, std::milli>(durationLast).count() << "ms ]" << std::endl; + if (diff < -TIMERS_CB_TOLERANCE) + std::cout << mDebugText << " Warning [ expected:" << std::chrono::duration<double, std::milli>(mExpected).count() << "ms, current:" << std::chrono::duration<double, std::milli>(durationLast).count() << "ms ]" << std::endl; + + mLastInvocationTime = t_end; + if (--mRepeats > 0) + { +#ifndef WITH_TIMERFD + mSocketHandler->updateTimer( handle, mUpdateTimeout); +#endif + } + else + { + mSocketHandler->stopTimer(handle); + } + } + else + { +#ifdef ENABLED_TIMERS_TEST_OUTPUT + std::cout << mDebugText << " Init measurment " << std::endl; +#endif + mLastInvocationTime = t_end; + mSocketHandler->updateTimer(handle, mUpdateTimeout); + } + } void* playWithSocketServer(void* data) { - (void) data; - CAmSocketHandler myHandler; - CAmSamplePlugin::sockType_e type = CAmSamplePlugin::INET; - CAmSamplePlugin myplugin(&myHandler, type); - myHandler.start_listenting(); + CAmSocketHandler *pSockethandler = (CAmSocketHandler*) data; + pSockethandler->start_listenting(); return (NULL); } void* playWithUnixSocketServer(void* data) { - (void) data; + CAmSocketHandler *pSockethandler = (CAmSocketHandler*) data; + pSockethandler->start_listenting(); + return (NULL); +} + +TEST(CAmSocketHandlerTest, timersOneshot) +{ CAmSocketHandler myHandler; - CAmSamplePlugin::sockType_e type = CAmSamplePlugin::UNIX; - CAmSamplePlugin myplugin(&myHandler, type); + ASSERT_FALSE(myHandler.fatalErrorOccurred()); + timespec timeoutTime; + timeoutTime.tv_sec = 1; + timeoutTime.tv_nsec = 0; + CAmTimer testCallback1(&myHandler, timeoutTime); + + struct TestUserData + { + int i; + float f; + }; + TestUserData userData; + userData.i = 1; + userData.f = 1.f; + + sh_timerHandle_t handle; + myHandler.addTimer(timeoutTime, &testCallback1.pTimerCallback, handle, &userData); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 2); +#endif + EXPECT_CALL(testCallback1,timerCallback(handle,&userData)).Times(1); + + timespec timeout4; + timeout4.tv_nsec = 0; + timeout4.tv_sec = 3; + CAmTimerSockethandlerController testCallback4(&myHandler, timeout4); + + myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 2); +#else + ASSERT_EQ(handle, 3); +#endif + EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); + myHandler.start_listenting(); +} + +TEST(CAmSocketHandlerTest, timersStop) +{ + CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); + timespec timeoutTime; + timeoutTime.tv_sec = 1; + timeoutTime.tv_nsec = 0; + CAmTimer testCallback1(&myHandler, timeoutTime, 4); + + struct TestUserData + { + int i; + float f; + }; + TestUserData userData; + userData.i = 1; + userData.f = 1.f; + + sh_timerHandle_t handle; + myHandler.addTimer(timeoutTime, &testCallback1.pTimerCallback, handle, &userData, true); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 2); +#endif + EXPECT_CALL(testCallback1,timerCallback(handle,&userData)).Times(4); + + timespec timeout4; + timeout4.tv_nsec = 0; + timeout4.tv_sec = 6; + CAmTimerSockethandlerController testCallback4(&myHandler, timeout4); + + myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 2); +#else + ASSERT_EQ(handle, 3); +#endif + EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); + myHandler.start_listenting(); +} + +TEST(CAmSocketHandlerTest, timersGeneral) +{ + CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); + + timespec timeoutTime; + timeoutTime.tv_sec = 1; + timeoutTime.tv_nsec = 0; + CAmTimer testCallback1(&myHandler, timeoutTime, 4); + + struct TestUserData + { + int i; + float f; + }; + TestUserData userData; + userData.i = 1; + userData.f = 1.f; + + sh_timerHandle_t handle; + myHandler.addTimer(timeoutTime, &testCallback1.pTimerCallback, handle, &userData, true); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 2); +#endif + EXPECT_CALL(testCallback1,timerCallback(handle,&userData)).Times(4); //+1 because of measurment + + timespec timeout4; + timeout4.tv_nsec = 0; + timeout4.tv_sec = 5; + CAmTimerSockethandlerController testCallback4(&myHandler, timeout4); + + myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 2); +#else + ASSERT_EQ(handle, 3); +#endif + EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); myHandler.start_listenting(); - return (NULL); } TEST(CAmSocketHandlerTest,playWithTimers) { CAmSocketHandler myHandler; - CAmTimerCb testCallback(&myHandler); + ASSERT_FALSE(myHandler.fatalErrorOccurred()); timespec timeoutTime, timeout2, timeout3, timeout4; timeoutTime.tv_sec = 1; - timeoutTime.tv_nsec = 02223234; - timeout2.tv_nsec = 333000; + timeoutTime.tv_nsec = 34000000; + CAmTimerMeasurment testCallback1(&myHandler, timeoutTime, "repeatedCallback 1", std::numeric_limits<int32_t>::max()); + + timeout2.tv_nsec = 2000000; timeout2.tv_sec = 0; - timeout3.tv_nsec = 333; + CAmTimerMeasurment testCallback2(&myHandler, timeout2, "repeatedCallback 2", std::numeric_limits<int32_t>::max()); + + timeout3.tv_nsec = 333000000; timeout3.tv_sec = 3; + CAmTimerMeasurment testCallback3(&myHandler, timeout3, "oneshotCallback 3"); timeout4.tv_nsec = 0; - timeout4.tv_sec = 20; + timeout4.tv_sec = 8; + CAmTimerSockethandlerController testCallback4(&myHandler, timeout4); + sh_timerHandle_t handle; - myHandler.addTimer(timeoutTime, &testCallback.pTimer1Callback, handle, NULL); - myHandler.addTimer(timeout2, &testCallback.pTimer2Callback, handle, NULL); - myHandler.addTimer(timeout3, &testCallback.pTimer3Callback, handle, NULL); - myHandler.addTimer(timeout4, &testCallback.pTimer4Callback, handle, NULL); - myHandler.start_listenting(); + myHandler.addTimer(timeoutTime, &testCallback1.pTimerCallback, handle, NULL, true); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 2); +#endif + EXPECT_CALL(testCallback1,timerCallback(handle,NULL)).Times(AnyNumber()); + + myHandler.addTimer(timeout2, &testCallback2.pTimerCallback, handle, NULL, true); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 2); +#else + ASSERT_EQ(handle, 3); +#endif + EXPECT_CALL(testCallback2,timerCallback(handle,NULL)).Times(AnyNumber()); + + myHandler.addTimer(timeout3, &testCallback3.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 3); +#else + ASSERT_EQ(handle, 4); +#endif + EXPECT_CALL(testCallback3,timerCallback(handle,NULL)).Times(2); //+1 because of measurment + + myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 4); +#else + ASSERT_EQ(handle, 5); +#endif + EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(1); + myHandler.start_listenting(); } + +TEST(CAmSocketHandlerTest, signalHandlerPrimaryPlusSecondary) +{ + pMockSignalHandler = new MockIAmSignalHandler; + CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); + ASSERT_TRUE(myHandler.listenToSignals({SIGHUP})==E_OK); + ASSERT_TRUE(myHandler.listenToSignals({SIGHUP, SIGTERM, SIGCHLD})==E_OK); + sh_pollHandle_t signalHandler1, signalHandler2; + + std::string userData = "User data"; + +// critical signals are registered here: + struct sigaction signalAction; + memset(&signalAction, '\0', sizeof(signalAction)); + signalAction.sa_sigaction = &signalHandler; + signalAction.sa_flags = SA_RESETHAND | SA_NODEFER| SA_SIGINFO; + sigaction(SIGINT, &signalAction, NULL); + sigaction(SIGQUIT, &signalAction, NULL); + + myHandler.addSignalHandler([&](const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData) + { + unsigned sig = info.ssi_signo; + pMockSignalHandler->signalHandlerAction(handle, sig, userData); +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT + unsigned user = info.ssi_uid; + std::cout<<"signal handler was called from user "<< user << " with signal " << sig << std::endl; +#endif + }, signalHandler1, &userData); + ASSERT_EQ(signalHandler1, 1); + myHandler.addSignalHandler([&](const sh_pollHandle_t handle, const signalfd_siginfo & info, void* userData) + { + unsigned sig = info.ssi_signo; + pMockSignalHandler->signalHandlerAction(handle, sig, userData); +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT + unsigned user = info.ssi_uid; + std::cout<<"signal handler was called from user "<< user << " with signal " << sig << std::endl; +#endif + }, signalHandler2, &userData); + ASSERT_EQ(signalHandler2, 2); + timespec timeout4; + timeout4.tv_nsec = 200000000; + timeout4.tv_sec = 0; + std::set<unsigned> secondarySignals; + secondarySignals.insert({SIGHUP,SIGTERM, SIGCHLD}); + std::set<unsigned> primarySignals({SIGQUIT,SIGINT}); + std::set<unsigned> signals(primarySignals); + signals.insert(secondarySignals.begin(), secondarySignals.end()); + + CAmTimerSignalHandler testCallback4(&myHandler, timeout4, signals); + sh_timerHandle_t handle; + + myHandler.addTimer(timeout4, &testCallback4.pTimerCallback, handle, NULL, true); +#ifndef WITH_TIMERFD + ASSERT_EQ(handle, 1); +#else + ASSERT_EQ(handle, 3); +#endif + EXPECT_CALL(testCallback4,timerCallback(handle,NULL)).Times(signals.size()+1); + for(auto it: secondarySignals) + EXPECT_CALL(*pMockSignalHandler,signalHandlerAction(signalHandler1,it,&userData)).Times(1); + for(auto it: secondarySignals) + EXPECT_CALL(*pMockSignalHandler,signalHandlerAction(signalHandler2,it,&userData)).Times(1); + for(auto it: primarySignals) + EXPECT_CALL(*pMockSignalHandler,signalHandler(it,_,_)).Times(1); + + myHandler.start_listenting(); + delete pMockSignalHandler; +} + TEST(CAmSocketHandlerTest,playWithUNIXSockets) { pthread_t serverThread; struct sockaddr_un servAddr; int socket_; + CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); + CAmSamplePlugin::sockType_e type = CAmSamplePlugin::UNIX; + CAmSamplePlugin myplugin(&myHandler, type); + + EXPECT_CALL(myplugin,receiveData(_,_,_)).Times(SOCKET_TEST_LOOPS_COUNT + 1); + EXPECT_CALL(myplugin,dispatchData(_,_)).Times(SOCKET_TEST_LOOPS_COUNT + 1); + EXPECT_CALL(myplugin,check(_,_)).Times(SOCKET_TEST_LOOPS_COUNT + 1); + //creates a thread that handles the serverpart - pthread_create(&serverThread, NULL, playWithUnixSocketServer, NULL); + pthread_create(&serverThread, NULL, playWithUnixSocketServer, &myHandler); sleep(1); //we need that here because the port needs to be opened if ((socket_ = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) @@ -164,15 +507,16 @@ TEST(CAmSocketHandlerTest,playWithUNIXSockets) std::cout << "ERROR: connect() failed\n" << std::endl; } - for (int i = 0; i <= 1000; i++) + for (int i = 1; i <= SOCKET_TEST_LOOPS_COUNT; i++) { - std::string string("Got It?"); - send(socket_, string.c_str(), string.size(), 0); + std::string stringToSend(TEST_SOCKET_DATA); + send(socket_, stringToSend.c_str(), stringToSend.size(), 0); } - std::string string("finish!"); - send(socket_, string.c_str(), string.size(), 0); + std::string stringToSend(TEST_SOCKET_DATA_FINAL); + send(socket_, stringToSend.c_str(), stringToSend.size(), 0); pthread_join(serverThread, NULL); + } TEST(CAmSocketHandlerTest,playWithSockets) @@ -183,8 +527,17 @@ TEST(CAmSocketHandlerTest,playWithSockets) struct hostent *host; int socket_; + CAmSocketHandler myHandler; + ASSERT_FALSE(myHandler.fatalErrorOccurred()); + CAmSamplePlugin::sockType_e type = CAmSamplePlugin::INET; + CAmSamplePlugin myplugin(&myHandler, type); + + EXPECT_CALL(myplugin,receiveData(_,_,_)).Times(SOCKET_TEST_LOOPS_COUNT + 1); + EXPECT_CALL(myplugin,dispatchData(_,_)).Times(SOCKET_TEST_LOOPS_COUNT + 1); + EXPECT_CALL(myplugin,check(_,_)).Times(SOCKET_TEST_LOOPS_COUNT + 1); + //creates a thread that handles the serverpart - pthread_create(&serverThread, NULL, playWithSocketServer, NULL); + pthread_create(&serverThread, NULL, playWithSocketServer, &myHandler); sleep(1); //we need that here because the port needs to be opened if ((socket_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) @@ -209,24 +562,16 @@ TEST(CAmSocketHandlerTest,playWithSockets) std::cout << "ERROR: connect() failed\n" << std::endl; } - for (int i = 0; i <= 1000; i++) + for (int i = 1; i <= SOCKET_TEST_LOOPS_COUNT; i++) { - std::string string("Got It?"); + std::string string(TEST_SOCKET_DATA); send(socket_, string.c_str(), string.size(), 0); } - std::string string("finish!"); + std::string string(TEST_SOCKET_DATA_FINAL); send(socket_, string.c_str(), string.size(), 0); pthread_join(serverThread, NULL); -} - - -void CAmSocketHandlerTest::SetUp() -{ -} -void CAmSocketHandlerTest::TearDown() -{ } int main(int argc, char **argv) @@ -236,14 +581,14 @@ int main(int argc, char **argv) } am::CAmSamplePlugin::CAmSamplePlugin(CAmSocketHandler *mySocketHandler, sockType_e socketType) : - connectFiredCB(this, &CAmSamplePlugin::connectSocket), // + MockSocketHandlerCb(), connectFiredCB(this, &CAmSamplePlugin::connectSocket), // receiveFiredCB(this, &CAmSamplePlugin::receiveData), // sampleDispatchCB(this, &CAmSamplePlugin::dispatchData), // sampleCheckCB(this, &CAmSamplePlugin::check), // mSocketHandler(mySocketHandler), // mConnecthandle(), // - mReceiveHandle(), // - msgList() + mReceiveHandle(), // + msgList() { int yes = 1; @@ -254,29 +599,31 @@ am::CAmSamplePlugin::CAmSamplePlugin(CAmSocketHandler *mySocketHandler, sockType switch (socketType) { - case UNIX: - socketHandle = socket(AF_UNIX, SOCK_STREAM, 0); - unixAddr.sun_family = AF_UNIX; - strcpy(unixAddr.sun_path, SOCK_PATH); - unlink(unixAddr.sun_path); - bind(socketHandle, (struct sockaddr *) &unixAddr, strlen(unixAddr.sun_path) + sizeof(unixAddr.sun_family)); - break; - case INET: - socketHandle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - setsockopt(socketHandle, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); - memset(&servAddr, 0, sizeof(servAddr)); - servAddr.sin_family = AF_INET; - servAddr.sin_addr.s_addr = INADDR_ANY; - servAddr.sin_port = htons(servPort); - bind(socketHandle, (struct sockaddr *) &servAddr, sizeof(servAddr)); - break; - default: - break; + case UNIX: + socketHandle = socket(AF_UNIX, SOCK_STREAM, 0); + unixAddr.sun_family = AF_UNIX; + strcpy(unixAddr.sun_path, SOCK_PATH); + unlink(unixAddr.sun_path); + bind(socketHandle, (struct sockaddr *) &unixAddr, strlen(unixAddr.sun_path) + sizeof(unixAddr.sun_family)); + break; + case INET: + socketHandle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + setsockopt(socketHandle, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = INADDR_ANY; + servAddr.sin_port = htons(servPort); + bind(socketHandle, (struct sockaddr *) &servAddr, sizeof(servAddr)); + break; + default: + break; } if (listen(socketHandle, 3) < 0) { +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT std::cout << "listen ok" << std::endl; +#endif } /* if */ int a = 1; @@ -286,7 +633,9 @@ am::CAmSamplePlugin::CAmSamplePlugin(CAmSocketHandler *mySocketHandler, sockType short events = 0; events |= POLLIN; mySocketHandler->addFDPoll(socketHandle, events, NULL, &connectFiredCB, NULL, NULL, NULL, mConnecthandle); +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT std::cout << "setup server - listening" << std::endl; +#endif } void am::CAmSamplePlugin::connectSocket(const pollfd pollfd1, const sh_pollHandle_t handle, void *userData) @@ -294,7 +643,9 @@ void am::CAmSamplePlugin::connectSocket(const pollfd pollfd1, const sh_pollHandl (void) handle; (void) userData; //first, accept the connection, create a new filedescriptor +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT std::cout << "Got a connection request !" << std::endl; +#endif struct sockaddr answer; socklen_t len = sizeof(answer); int receiveFD = accept(pollfd1.fd, (struct sockaddr*) &answer, &len); @@ -312,6 +663,7 @@ void am::CAmSamplePlugin::receiveData(const pollfd pollfd, const sh_pollHandle_t { (void) handle; (void) userData; + MockSocketHandlerCb::receiveData(pollfd, handle, userData); //initialize buffer char buffer[10]; //read until buffer is full or no more data is there @@ -321,7 +673,9 @@ void am::CAmSamplePlugin::receiveData(const pollfd pollfd, const sh_pollHandle_t //read the message and store it in a queue std::string msg = std::string(buffer, read); msgList.push(msg); +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT std::cout << "Got a message !" << std::endl; +#endif } } @@ -330,13 +684,20 @@ bool am::CAmSamplePlugin::dispatchData(const sh_pollHandle_t handle, void *userD (void) handle; (void) userData; //read data from the queue + MockSocketHandlerCb::dispatchData(handle, userData); +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT std::cout << "Data:" << msgList.front() << std::endl; - +#endif //if the message was our finish message, we quit the poll loop - if (msgList.front().compare("finish!") == 0) + if (!(msgList.front().compare(TEST_SOCKET_DATA_FINAL) == 0 || msgList.front().compare(TEST_SOCKET_DATA) == 0)) //error { mSocketHandler->stop_listening(); } + if (msgList.front().compare(TEST_SOCKET_DATA_FINAL) == 0) //ok + { + mSocketHandler->stop_listening(); + } + //remove the message from the queue and return false if there is no more message to read. msgList.pop(); if (msgList.size() != 0) @@ -348,8 +709,11 @@ bool am::CAmSamplePlugin::check(const sh_pollHandle_t handle, void *userData) { (void) handle; (void) userData; + MockSocketHandlerCb::check(handle, userData); //checks if there is data to dispatch +#ifdef ENABLED_SOCKETHANDLER_TEST_OUTPUT std::cout << "check!:" << std::endl; +#endif if (msgList.size() != 0) return true; return false; diff --git a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.h b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.h index 95e5446..ba2bf51 100644 --- a/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.h +++ b/AudioManagerUtilities/test/AmSocketHandlerTest/CAmSocketHandlerTest.h @@ -25,63 +25,169 @@ #define WITH_DLT +#include <ctime> +#include <chrono> #include "gtest/gtest.h" +#include "gmock/gmock.h" #include <queue> #include "CAmSocketHandler.h" +#undef ENABLED_SOCKETHANDLER_TEST_OUTPUT +#undef ENABLED_TIMERS_TEST_OUTPUT +#define TIMERS_CB_TOLERANCE 8.f + namespace am { + class IAmTimerCb + { + public: + virtual ~IAmTimerCb() + { + } + virtual void timerCallback(sh_timerHandle_t handle, void * userData)=0; + }; -class CAmSamplePlugin -{ -public: - enum sockType_e + class IAmSignalHandler { - UNIX, INET + public: + virtual ~IAmSignalHandler() + { + } + virtual void signalHandlerAction(const sh_pollHandle_t handle, const unsigned sig, void* userData)=0; + virtual void signalHandler(int sig, siginfo_t *siginfo, void *context)=0; }; - CAmSamplePlugin(CAmSocketHandler *mySocketHandler, sockType_e socketType); - ~CAmSamplePlugin() + + class IAmSocketHandlerCb { - } - ; - void connectSocket(const pollfd pollfd, const sh_pollHandle_t handle, void* userData); - void receiveData(const pollfd pollfd, const sh_pollHandle_t handle, void* userData); - bool dispatchData(const sh_pollHandle_t handle, void* userData); - bool check(const sh_pollHandle_t handle, void* userData); - TAmShPollFired<CAmSamplePlugin> connectFiredCB; - TAmShPollFired<CAmSamplePlugin> receiveFiredCB; - TAmShPollDispatch<CAmSamplePlugin> sampleDispatchCB; - TAmShPollCheck<CAmSamplePlugin> sampleCheckCB; -private: - CAmSocketHandler *mSocketHandler; - sh_pollHandle_t mConnecthandle, mReceiveHandle; - std::queue<std::string> msgList; -}; - -class CAmTimerCb -{ -public: - CAmTimerCb(CAmSocketHandler *SocketHandler); - virtual ~CAmTimerCb(); - void timer1Callback(sh_timerHandle_t handle, void * userData); - void timer2Callback(sh_timerHandle_t handle, void * userData); - void timer3Callback(sh_timerHandle_t handle, void * userData); - void timer4Callback(sh_timerHandle_t handle, void * userData); - TAmShTimerCallBack<CAmTimerCb> pTimer1Callback; - TAmShTimerCallBack<CAmTimerCb> pTimer2Callback; - TAmShTimerCallBack<CAmTimerCb> pTimer3Callback; - TAmShTimerCallBack<CAmTimerCb> pTimer4Callback; - CAmSocketHandler *mSocketHandler; -}; - -class CAmSocketHandlerTest: public ::testing::Test -{ -public: - CAmSocketHandlerTest(); - ~CAmSocketHandlerTest(); - void SetUp(); - void TearDown(); -}; + public: + virtual ~IAmSocketHandlerCb() + { + } + virtual void receiveData(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)=0; + virtual bool dispatchData(const sh_pollHandle_t handle, void* userData)=0; + virtual bool check(const sh_pollHandle_t handle, void* userData)=0; + }; + + class MockIAmTimerCb: public IAmTimerCb + { + public: + MOCK_CONST_METHOD2(timerCallback, + void(sh_timerHandle_t handle, void *userData)); + }; + + class MockIAmSignalHandler: public IAmSignalHandler + { + public: + MOCK_METHOD3(signalHandlerAction, void (const sh_pollHandle_t handle, const unsigned sig, void* userData)); + MOCK_METHOD3(signalHandler, void(int sig, siginfo_t *siginfo, void *context)); + }; + + class MockSocketHandlerCb: public IAmSocketHandlerCb + { + public: + MOCK_CONST_METHOD3(receiveData, + void(const pollfd pollfd, const sh_pollHandle_t handle, void* userData)); + MOCK_CONST_METHOD2(dispatchData, + void(const sh_pollHandle_t handle, void* userData)); + MOCK_CONST_METHOD2(check, + void(const sh_pollHandle_t handle, void* userData)); + }; + + class CAmSamplePlugin: public MockSocketHandlerCb + { + public: + enum sockType_e + { + UNIX, INET + }; + CAmSamplePlugin(CAmSocketHandler *mySocketHandler, sockType_e socketType); + ~CAmSamplePlugin() + { + } + ; + void connectSocket(const pollfd pollfd, const sh_pollHandle_t handle, void* userData); + void receiveData(const pollfd pollfd, const sh_pollHandle_t handle, void* userData); + bool dispatchData(const sh_pollHandle_t handle, void* userData); + bool check(const sh_pollHandle_t handle, void* userData); + TAmShPollFired<CAmSamplePlugin> connectFiredCB; + TAmShPollFired<CAmSamplePlugin> receiveFiredCB; + TAmShPollDispatch<CAmSamplePlugin> sampleDispatchCB; + TAmShPollCheck<CAmSamplePlugin> sampleCheckCB; + + private: + CAmSocketHandler *mSocketHandler; + sh_pollHandle_t mConnecthandle, mReceiveHandle; + std::queue<std::string> msgList; + }; + + class CAmTimerSockethandlerController: public MockIAmTimerCb + { + CAmSocketHandler *mpSocketHandler; + timespec mUpdateTimeout; + public: + explicit CAmTimerSockethandlerController(CAmSocketHandler *SocketHandler, const timespec &timeout); + virtual ~CAmTimerSockethandlerController(); + + void timerCallback(sh_timerHandle_t handle, void * userData); + + TAmShTimerCallBack<CAmTimerSockethandlerController> pTimerCallback; + }; + + class CAmTimerSignalHandler: public MockIAmTimerCb + { + unsigned mIndex; + std::set<unsigned> mSignals; + CAmSocketHandler *mpSocketHandler; + timespec mUpdateTimeout; + public: + explicit CAmTimerSignalHandler(CAmSocketHandler *SocketHandler, const timespec &timeout, const std::set<unsigned> & signals); + virtual ~CAmTimerSignalHandler(); + + void timerCallback(sh_timerHandle_t handle, void * userData); + + TAmShTimerCallBack<CAmTimerSignalHandler> pTimerCallback; + }; + + class CAmTimer: public MockIAmTimerCb + { + CAmSocketHandler *mpSocketHandler; + timespec mUpdateTimeout; + int32_t mRepeats; + public: + explicit CAmTimer(CAmSocketHandler *SocketHandler, const timespec &timeout, const int32_t repeats = 0u); + virtual ~CAmTimer(); + + void timerCallback(sh_timerHandle_t handle, void * userData); + + TAmShTimerCallBack<CAmTimer> pTimerCallback; + }; + + class CAmTimerMeasurment: public MockIAmTimerCb + { + CAmSocketHandler *mSocketHandler; + timespec mUpdateTimeout; + std::chrono::time_point<std::chrono::high_resolution_clock> mUpdateTimePoint; + std::chrono::time_point<std::chrono::high_resolution_clock> mLastInvocationTime; + std::chrono::duration<long, std::ratio<1l, 1000000000l>> mExpected; + int32_t mRepeats; + void * mpUserData; + std::string mDebugText; + public: + explicit CAmTimerMeasurment(CAmSocketHandler *SocketHandler, const timespec &timeout, const std::string & label, const int32_t repeats = 0u, void * userData = NULL); + virtual ~CAmTimerMeasurment(); + + void timerCallback(sh_timerHandle_t handle, void * userData); + TAmShTimerCallBack<CAmTimerMeasurment> pTimerCallback; + }; + + class CAmSocketHandlerTest: public ::testing::Test + { + public: + CAmSocketHandlerTest(); + ~CAmSocketHandlerTest(); + void SetUp(); + void TearDown(); + }; } /* namespace am */ #endif /* SOCKETHANDLERTEST_H_ */ diff --git a/AudioManagerUtilities/test/AmSocketHandlerTest/CMakeLists.txt b/AudioManagerUtilities/test/AmSocketHandlerTest/CMakeLists.txt index 8f0c9e6..5e5b9e1 100644 --- a/AudioManagerUtilities/test/AmSocketHandlerTest/CMakeLists.txt +++ b/AudioManagerUtilities/test/AmSocketHandlerTest/CMakeLists.txt @@ -33,6 +33,7 @@ ADD_EXECUTABLE(AmSocketHandlerTest ${Socket_SRCS_CXX}) TARGET_LINK_LIBRARIES(AmSocketHandlerTest ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} AudioManagerUtilities ) diff --git a/AudioManagerUtilities/test/CMakeLists.txt b/AudioManagerUtilities/test/CMakeLists.txt index fb55831..414e199 100644 --- a/AudioManagerUtilities/test/CMakeLists.txt +++ b/AudioManagerUtilities/test/CMakeLists.txt @@ -1,4 +1,2 @@ add_subdirectory (AmSocketHandlerTest) - - - +add_subdirectory (AmSerializerTest) diff --git a/CMakeLists.txt b/CMakeLists.txt index 33433ee..5c70c61 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") @@ -138,6 +141,7 @@ if(WITH_TESTS) #check if we can find the google stuff pkg_check_modules (GTEST "gtest >= 1.6.0") pkg_check_modules (GMOCK "gmock >= 1.6.0") + find_package (Threads) if (NOT("${GTEST_FOUND}" AND "${GMOCK_FOUND}")) message (STATUS "Building and installing with shipped sources") add_subdirectory(googleMock) @@ -219,6 +223,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@" diff --git a/docs/main_8cpp_source.html b/docs/main_8cpp_source.html index 9b9df41..0c55aa5 100644 --- a/docs/main_8cpp_source.html +++ b/docs/main_8cpp_source.html @@ -279,7 +279,7 @@ $(document).ready(function(){initNavTree('main_8cpp_source.html','');}); <div class="line"><a name="l00204"></a><span class="lineno"> 204</span>  <span class="keywordflow">switch</span> (sig)</div> <div class="line"><a name="l00205"></a><span class="lineno"> 205</span>  {</div> <div class="line"><a name="l00206"></a><span class="lineno"> 206</span>  <span class="comment">/*ctl +c lets call direct controllerRundown, because we might be blocked at the moment.</span></div> -<div class="line"><a name="l00207"></a><span class="lineno"> 207</span> <span class="comment"> But there is the risk of interrupting something important */</span>https:<span class="comment">//asc.bmwgroup.net/wiki/display/MGUROTO/Lastest+and+greatest</span></div> +<div class="line"><a name="l00207"></a><span class="lineno"> 207</span> <span class="comment"> But there is the risk of interrupting something important */</span></div> <div class="line"><a name="l00208"></a><span class="lineno"> 208</span>  <span class="keywordflow">case</span> SIGINT:</div> <div class="line"><a name="l00209"></a><span class="lineno"> 209</span>  <a class="code" href="classam_1_1CAmControlSender.html#a347a2af727aeb11657f145329dd23dd8">CAmControlSender::CallsetControllerRundown</a>(sig);</div> <div class="line"><a name="l00210"></a><span class="lineno"> 210</span>  <span class="keywordflow">break</span>;</div> |