/** * SPDX license identifier: MPL-2.0 * * 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, 2017 * * \copyright * This Source Code Form is subject to the terms of the * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with * this file, You can obtain one at http://mozilla.org/MPL/2.0/. * * \file CAmSerializer.h * For further information see http://www.genivi.org/. */ #ifndef CAMSERIALIZER_H_ #define CAMSERIALIZER_H_ #include #include #include #include #include #include "CAmDltWrapper.h" #include "CAmSocketHandler.h" /*! * \brief Helper structures used within std::bind for automatically identification of all placeholders. */ template struct indices { }; template struct build_indices: build_indices { }; template struct build_indices<0, Is...> : indices { }; template struct placeholder { }; namespace std { template struct is_placeholder<::placeholder> : std::integral_constant { }; } #if defined(__GNUC__) # define DEPRECATED(MSG) __attribute__ ((__deprecated__((#MSG)))) #else # define DEPRECATED(MSG) #endif namespace am { /** * 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. * */ /** * \defgroup Deprecated Obsolete class! * @{ */ namespace V1 { 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 CAmDelegateAsyncImpl: public CAmDelegate { Class mInstance; Method mMethod; Tuple mArguments; public: friend class CAmSerializer; static void call(Class instance, Method method, Tuple && arguments) { CAmDelegateAsyncImpl::call(instance, method, std::forward(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(mArguments)); return (AsyncCallType); } ; }; /** * Prototype for a delegate with variadic template arguments. */ template class CAmDelegateAsyncImpl : 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(std::forward(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(mArguments)); return (AsyncCallType); } ; }; /** * Prototype for a delegate with variadic template arguments in conjunction with the following class. */ template 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::call(instance, method, result, std::forward(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(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 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 && t) { result = (*instance.*method)(std::get(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(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 void doAsyncCall(Class intsance, Method method, Tuple & arguments) { typedef typename std::decay::type ttype; typedef CAmDelegateAsyncImpl::value, std::tuple_size::value> AsyncDelegate; AsyncDelegate *pImp = new AsyncDelegate(intsance, method, std::forward(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 void doSyncCall(Class intsance, Method method, Return & result, Tuple & arguments) { typedef typename std::decay::type ttype; typedef CAmDelegateSyncImpl::value, std::tuple_size::value> SyncDelegate; SyncDelegate *pImp = new SyncDelegate(intsance, method, std::forward(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 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(&anInstance,&MyGreatClass::AGreatMethod, result, 100); * @endcode */ template 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(&anInstance,&MyGreatClass::AGreatMethod, 100); * @endcode */ template 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(&instanceMyClass,&myClass::myfunction); * @endcode */ template 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(&instanceMyClass,&myClass::myfunction,k); * @endcode * */ template 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(&instanceMyClass,&myClass::myfunction,k); * @endcode * */ template 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 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 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 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 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 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 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 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 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 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 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 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 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 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(&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 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(&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 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 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 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 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 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 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 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 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 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 receiverCallbackT; TAmShPollDispatch dispatcherCallbackT; TAmShPollCheck 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 { class CAmSerializer { /** * 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 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 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 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 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 void asyncInvocation(TFunc invocation) { static_assert(std::is_bind_expression::value,"The type is not produced by std::bind"); typedef CAmDelegateAsyncImpl AsyncDelegate; AsyncDelegate *pImp = new AsyncDelegate(std::forward(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 void asyncCall(TClass* instance, TMeth method, TArgs && ... arguments) { auto invocation = std::bind(method, instance, std::forward(arguments)...); asyncInvocation(invocation); } template void asyncCall(TClass* instance, TMeth method, TArgs && ... arguments) { auto invocation = std::bind(method, instance, std::forward(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 void syncInvocation(TFunc invocation, TRet && result) { static_assert(std::is_bind_expression::value,"The type is not produced by std::bind"); typedef CAmDelegateSyncImpl SyncDelegate; SyncDelegate *pImp = new SyncDelegate(std::forward(invocation), std::forward(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 void syncInvocation(TFunc invocation) { static_assert(std::is_bind_expression::value,"The type is not produced by std::bind"); typedef CAmDelegateSyncVoidImpl SyncDelegate; SyncDelegate *pImp = new SyncDelegate(std::forward(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 void syncCall(TClass* instance, TMeth method, TRet & result, TArgs && ... arguments) { auto invocation = std::bind(method, instance, std::ref(arguments)...); syncInvocation(invocation, result); } template 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 receiverCallbackT; TAmShPollDispatch dispatcherCallbackT; TAmShPollCheck 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!"); } /* namespace am */ #endif /* CAMSERIALIZER_H_ */