From 01c2655c0dc1f066a2305bfab81f77fa609601f3 Mon Sep 17 00:00:00 2001 From: Aleksandar Donchev Date: Thu, 12 Oct 2017 17:38:49 +0200 Subject: Fix for CAPI timeouts and support for more than one CAPI watch Signed-off-by: Christian Linke Change-Id: I9a9d2c424bc8fac62c76a66545a531c518edb2e3 --- .../include/CAmCommonAPIWrapper.h | 46 ++-- AudioManagerUtilities/src/CAmCommonAPIWrapper.cpp | 268 +++++++++++++-------- 2 files changed, 198 insertions(+), 116 deletions(-) diff --git a/AudioManagerUtilities/include/CAmCommonAPIWrapper.h b/AudioManagerUtilities/include/CAmCommonAPIWrapper.h index a83b5b3..0f770c4 100644 --- a/AudioManagerUtilities/include/CAmCommonAPIWrapper.h +++ b/AudioManagerUtilities/include/CAmCommonAPIWrapper.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -48,29 +49,37 @@ class CAmSocketHandler; class CAmCommonAPIWrapper { - void commonPrepareCallback(const sh_pollHandle_t handle, void* userData); + void commonPrepareCallback ( const sh_pollHandle_t, void* ); TAmShPollPrepare pCommonPrepareCallback; - bool commonDispatchCallback(const sh_pollHandle_t handle, void* userData); - TAmShPollDispatch pCommonDispatchCallback; - void commonFireCallback(const pollfd pollfd, const sh_pollHandle_t, void*); TAmShPollFired pCommonFireCallback; bool commonCheckCallback(const sh_pollHandle_t handle, void*); TAmShPollCheck pCommonCheckCallback; + + bool commonDispatchCallback(const sh_pollHandle_t handle, void* userData); + TAmShPollDispatch pCommonDispatchCallback; void commonTimerCallback(sh_timerHandle_t handle, void* userData); TAmShTimerCallBack pCommonTimerCallback; - struct timerHandles - { - sh_timerHandle_t handle; - CommonAPI::Timeout* timeout; - }; - CAmSocketHandler *mpSocketHandler; //!< pointer to the sockethandler + typedef std::vector ArrayDispatchSources; + typedef ArrayDispatchSources::iterator IteratorArrayDispatchSources; + typedef std::unordered_map MapWatches; + typedef MapWatches::iterator IteratorMapWatches; + typedef std::unordered_map> MapDispatchSources; + typedef MapDispatchSources::iterator IteratorDispatchSources; + typedef std::unordered_map MapTimeouts; + typedef MapTimeouts::iterator IteratorMapTimeouts; + + ArrayDispatchSources mRegisteredDispatchSources; + MapWatches mMapWatches; + MapDispatchSources mSourcesToDispatch; + MapTimeouts mListTimerhandles; + std::shared_ptr mRuntime; std::shared_ptr mContext; @@ -78,22 +87,23 @@ class CAmCommonAPIWrapper CommonAPI::WatchListenerSubscription mWatchListenerSubscription; CommonAPI::TimeoutSourceListenerSubscription mTimeoutSourceListenerSubscription; CommonAPI::WakeupListenerSubscription mWakeupListenerSubscription; - std::multimap mRegisteredDispatchSources; - std::map mMapWatches; - CommonAPI::Watch* mWatchToCheck; - std::list mSourcesToDispatch; - std::vector mpListTimerhandles; + void registerDispatchSource(CommonAPI::DispatchSource* dispatchSource, const CommonAPI::DispatchPriority dispatchPriority); void deregisterDispatchSource(CommonAPI::DispatchSource* dispatchSource); + void deregisterAllDispatchSource(); void registerWatch(CommonAPI::Watch* watch, const CommonAPI::DispatchPriority dispatchPriority); void deregisterWatch(CommonAPI::Watch* watch); + void deregisterAllWatches(); void registerTimeout(CommonAPI::Timeout* timeout, const CommonAPI::DispatchPriority dispatchPriority); void deregisterTimeout(CommonAPI::Timeout* timeout); - void wakeup(); - + void deregisterAllTimeouts(); + + CommonAPI::Watch* watchWithHandle(const sh_pollHandle_t handle); + CommonAPI::Timeout* timeoutWithHandle(const sh_pollHandle_t handle); + protected: - CAmCommonAPIWrapper(CAmSocketHandler* socketHandler, const std::string & applicationName = "") ; + CAmCommonAPIWrapper ( CAmSocketHandler* socketHandler, const std::string& applicationName = "" ) ; public: diff --git a/AudioManagerUtilities/src/CAmCommonAPIWrapper.cpp b/AudioManagerUtilities/src/CAmCommonAPIWrapper.cpp index caa7aa8..702d384 100644 --- a/AudioManagerUtilities/src/CAmCommonAPIWrapper.cpp +++ b/AudioManagerUtilities/src/CAmCommonAPIWrapper.cpp @@ -36,21 +36,47 @@ namespace am static CAmCommonAPIWrapper* pSingleCommonAPIInstance = NULL; +bool timeoutToTimespec(const int64_t & localTimeout, timespec & pollTimeout) +{ + if(CommonAPI::TIMEOUT_INFINITE == localTimeout)//dispatch never + { + return false; + } + else + { + if(CommonAPI::TIMEOUT_NONE==localTimeout)//dispatch immediately + { + pollTimeout.tv_sec = 0; + pollTimeout.tv_nsec = 5000000;//5 ms + } + else + { + pollTimeout.tv_sec = localTimeout / 1000; + pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000; + } + return true; + } +} + + CAmCommonAPIWrapper::CAmCommonAPIWrapper(CAmSocketHandler* socketHandler, const std::string & applicationName): pCommonPrepareCallback(this,&CAmCommonAPIWrapper::commonPrepareCallback), // - pCommonDispatchCallback(this, &CAmCommonAPIWrapper::commonDispatchCallback), // pCommonFireCallback(this, &CAmCommonAPIWrapper::commonFireCallback), // pCommonCheckCallback(this, &CAmCommonAPIWrapper::commonCheckCallback), // + pCommonDispatchCallback(this, &CAmCommonAPIWrapper::commonDispatchCallback), // pCommonTimerCallback(this, &CAmCommonAPIWrapper::commonTimerCallback), // - mpSocketHandler(socketHandler), // - mWatchToCheck(NULL) + mpSocketHandler(socketHandler), + mRegisteredDispatchSources(), + mMapWatches(), + mSourcesToDispatch(), + mListTimerhandles() { assert(NULL!=socketHandler); //Get the runtime mRuntime = CommonAPI::Runtime::get(); assert(NULL!=mRuntime); - //Create the context +//Create the context if(applicationName.size()) mContext = std::make_shared(applicationName); else @@ -75,9 +101,11 @@ CAmCommonAPIWrapper::~CAmCommonAPIWrapper() mContext->unsubscribeForDispatchSources(mDispatchSourceListenerSubscription); mContext->unsubscribeForWatches(mWatchListenerSubscription); mContext->unsubscribeForTimeouts(mTimeoutSourceListenerSubscription); + deregisterAllDispatchSource(); + deregisterAllTimeouts(); + deregisterAllWatches(); mContext.reset(); mpSocketHandler = NULL; - mWatchToCheck = NULL; } CAmCommonAPIWrapper* CAmCommonAPIWrapper::instantiateOnce(CAmSocketHandler* socketHandler, const std::string & applicationName) @@ -115,170 +143,214 @@ CAmCommonAPIWrapper* CAmCommonAPIWrapper::getInstance() return pSingleCommonAPIInstance; } -bool CAmCommonAPIWrapper::commonDispatchCallback(const sh_pollHandle_t handle, void *userData) +void CAmCommonAPIWrapper::commonPrepareCallback(const sh_pollHandle_t, void*) { - (void) handle; - (void) userData; - - std::list::iterator iterator(mSourcesToDispatch.begin()); - for(;iterator!=mSourcesToDispatch.end();) + for (auto dispatchSourceIterator = mRegisteredDispatchSources.begin(); + dispatchSourceIterator != mRegisteredDispatchSources.end(); + dispatchSourceIterator++) { - CommonAPI::DispatchSource* source = *iterator; - if (!source->dispatch()) { - iterator=mSourcesToDispatch.erase(iterator); + int64_t dispatchTimeout(CommonAPI::TIMEOUT_INFINITE); + if((*dispatchSourceIterator)->prepare(dispatchTimeout)) + { + while ((*dispatchSourceIterator)->dispatch()); } - else - iterator++; } - if (!mSourcesToDispatch.empty()) - return (true); +} - return false; +void CAmCommonAPIWrapper::commonFireCallback(const pollfd pollfd, const sh_pollHandle_t handle, void *) +{ + CommonAPI::Watch* pWatchToCheck = watchWithHandle(handle); + if( pWatchToCheck ) + pWatchToCheck->dispatch(pollfd.revents); } -bool CAmCommonAPIWrapper::commonCheckCallback(const sh_pollHandle_t, void *) +bool CAmCommonAPIWrapper::commonCheckCallback(const sh_pollHandle_t handle, void *) { - std::vector vecDispatch=mWatchToCheck->getDependentDispatchSources(); - mSourcesToDispatch.insert(mSourcesToDispatch.end(), vecDispatch.begin(), vecDispatch.end()); + CommonAPI::Watch* pWatchToCheck = watchWithHandle(handle); + if( pWatchToCheck ) + { + const ArrayDispatchSources & vecDispatch = pWatchToCheck->getDependentDispatchSources(); + if(vecDispatch.size()>0) + { + mSourcesToDispatch[handle].insert(mSourcesToDispatch[handle].end(), vecDispatch.begin(), vecDispatch.end()); + return true; + } + } + return false; +} - return (mWatchToCheck || !mSourcesToDispatch.empty()); +bool CAmCommonAPIWrapper::commonDispatchCallback(const sh_pollHandle_t handle, void *) +{ + CommonAPI::Watch* pWatchToCheck = watchWithHandle(handle); + if( pWatchToCheck ) + { + std::list & srcList = mSourcesToDispatch[handle]; + for(auto it = srcList.begin();it!=srcList.end();) + { + if (false==(*it)->dispatch()) + it=srcList.erase(it); + else + it++; + } + if (!srcList.empty()) + return (true); + } + mSourcesToDispatch.erase(handle); + return false; } -void CAmCommonAPIWrapper::commonFireCallback(const pollfd pollfd, const sh_pollHandle_t, void *) +void CAmCommonAPIWrapper::commonTimerCallback(sh_timerHandle_t handle, void *) { - mWatchToCheck=NULL; - try + CommonAPI::Timeout* pTimeout = timeoutWithHandle(handle); + + if( NULL==pTimeout ) { - mWatchToCheck=mMapWatches.at(pollfd.fd); + //erroneous call because deregisterTimeout has been called, so try to remove the timer from the sockethandler + mpSocketHandler->removeTimer(handle); } - catch (const std::out_of_range& error) { - logInfo(__PRETTY_FUNCTION__,error.what()); - return; + else + { + if ( false==pTimeout->dispatch() ) //it should be removed + { + mpSocketHandler->removeTimer(handle); + mListTimerhandles.erase(handle); + } + #ifndef WITH_TIMERFD + else //the timeout should be rescheduled + mpSocketHandler->restartTimer(handle); + #endif } +} - mWatchToCheck->dispatch(pollfd.revents); +void CAmCommonAPIWrapper::registerDispatchSource(CommonAPI::DispatchSource* dispatchSource, const CommonAPI::DispatchPriority) +{ + mRegisteredDispatchSources.push_back(dispatchSource); } -void CAmCommonAPIWrapper::commonPrepareCallback(const sh_pollHandle_t, void*) +void CAmCommonAPIWrapper::deregisterDispatchSource(CommonAPI::DispatchSource* dispatchSource) { - for (auto dispatchSourceIterator = mRegisteredDispatchSources.begin(); - dispatchSourceIterator != mRegisteredDispatchSources.end(); - dispatchSourceIterator++) + for(IteratorArrayDispatchSources dispatchSourceIterator = mRegisteredDispatchSources.begin(); dispatchSourceIterator != mRegisteredDispatchSources.end(); dispatchSourceIterator++) { - int64_t dispatchTimeout(CommonAPI::TIMEOUT_INFINITE); - if(dispatchSourceIterator->second->prepare(dispatchTimeout)) + if( *dispatchSourceIterator == dispatchSource ) { - while (dispatchSourceIterator->second->dispatch()); + mRegisteredDispatchSources.erase(dispatchSourceIterator); + break; } } } -void CAmCommonAPIWrapper::registerDispatchSource(CommonAPI::DispatchSource* dispatchSource, const CommonAPI::DispatchPriority dispatchPriority) +void CAmCommonAPIWrapper::deregisterAllDispatchSource() { - mRegisteredDispatchSources.insert({dispatchPriority, dispatchSource}); + mRegisteredDispatchSources.clear(); } -void CAmCommonAPIWrapper::deregisterDispatchSource(CommonAPI::DispatchSource* dispatchSource) +void CAmCommonAPIWrapper::registerWatch(CommonAPI::Watch* watch, const CommonAPI::DispatchPriority) { - for(auto dispatchSourceIterator = mRegisteredDispatchSources.begin(); - dispatchSourceIterator != mRegisteredDispatchSources.end(); - dispatchSourceIterator++) { + logInfo(__PRETTY_FUNCTION__); + pollfd pollfd_ (watch->getAssociatedFileDescriptor()); + sh_pollHandle_t handle (0); - if(dispatchSourceIterator->second == dispatchSource) { - mRegisteredDispatchSources.erase(dispatchSourceIterator); - break; - } + am_Error_e error = mpSocketHandler->addFDPoll(pollfd_.fd, pollfd_.events, &pCommonPrepareCallback, &pCommonFireCallback, &pCommonCheckCallback, &pCommonDispatchCallback, watch, handle); + + //if everything is alright, add the watch and the handle to our map so we know this relationship + if (error != am_Error_e::E_OK || handle == 0) + { + logError(__func__,"entering watch failed"); } + else + mMapWatches.insert(std::make_pair(handle,watch)); } void CAmCommonAPIWrapper::deregisterWatch(CommonAPI::Watch* watch) { - for(std::map::iterator iter(mMapWatches.begin());iter!=mMapWatches.end();iter++) + for(IteratorMapWatches iter=mMapWatches.begin();iter!=mMapWatches.end();iter++) { if (iter->second == watch) { + mpSocketHandler->removeFDPoll(iter->first); mMapWatches.erase(iter); break; } } } +void CAmCommonAPIWrapper::deregisterAllWatches() +{ + for(IteratorMapWatches iter=mMapWatches.begin();iter!=mMapWatches.end();iter++) + mpSocketHandler->removeFDPoll(iter->first); + mMapWatches.clear(); +} + void CAmCommonAPIWrapper::registerTimeout(CommonAPI::Timeout* timeout, const CommonAPI::DispatchPriority) { timespec pollTimeout; - int64_t localTimeout = timeout->getTimeoutInterval(); - - if(CommonAPI::TIMEOUT_INFINITE==localTimeout)//dispatch never - { - pollTimeout.tv_sec = localTimeout; - pollTimeout.tv_nsec = 0; - } - else if(CommonAPI::TIMEOUT_NONE==localTimeout)//dispatch immediately + if(timeoutToTimespec(timeout->getTimeoutInterval(), pollTimeout)) { - pollTimeout.tv_sec = 0; - pollTimeout.tv_nsec = 1000000; - } - else - { - pollTimeout.tv_sec = localTimeout / 1000; - pollTimeout.tv_nsec = (localTimeout % 1000) * 1000000; - } + //prepare handle and callback. new is eval, but there is no other choice because we need the pointer! + sh_timerHandle_t handle; - //prepare handle and callback. new is eval, but there is no other choice because we need the pointer! - sh_timerHandle_t handle; - - //add the timer to the pollLoop - am_Error_e error = mpSocketHandler->addTimer(pollTimeout, &pCommonTimerCallback, handle, timeout); - if (error != am_Error_e::E_OK || handle == 0) - { - logError(__func__,"adding timer failed"); - } - else - { - timerHandles myHandle({handle,timeout}); - mpListTimerhandles.push_back(myHandle); + //add the timer to the pollLoop + am_Error_e error = mpSocketHandler->addTimer(pollTimeout, &pCommonTimerCallback, handle, timeout, true); + if (error != am_Error_e::E_OK || handle == 0) + { + logError(__func__,"adding timer failed"); + } + else + { + mListTimerhandles.insert(std::make_pair(handle,timeout)); + } } } void CAmCommonAPIWrapper::deregisterTimeout(CommonAPI::Timeout* timeout) { - for( std::vector::iterator iter(mpListTimerhandles.begin());iter!=mpListTimerhandles.end();iter++) + for( IteratorMapTimeouts iter=mListTimerhandles.begin();iter!= mListTimerhandles.end();iter++) { - if(iter->timeout==timeout) + if(iter->second==timeout) { - mpSocketHandler->removeTimer(iter->handle); + mpSocketHandler->removeTimer(iter->first); + mListTimerhandles.erase(iter->first); + break; } } } -void CAmCommonAPIWrapper::registerWatch(CommonAPI::Watch* watch, const CommonAPI::DispatchPriority) +void CAmCommonAPIWrapper::deregisterAllTimeouts() { - logInfo(__PRETTY_FUNCTION__); - pollfd pollfd_ (watch->getAssociatedFileDescriptor()); - sh_pollHandle_t handle (0); - - am_Error_e error = mpSocketHandler->addFDPoll(pollfd_.fd, pollfd_.events, &pCommonPrepareCallback, &pCommonFireCallback, &pCommonCheckCallback, &pCommonDispatchCallback, watch, handle); + for( IteratorMapTimeouts iter=mListTimerhandles.begin();iter!= mListTimerhandles.end();iter++) + mpSocketHandler->removeTimer(iter->first); + mListTimerhandles.clear(); +} - //if everything is alright, add the watch and the handle to our map so we know this relationship - if (error != am_Error_e::E_OK || handle == 0) +CommonAPI::Watch* CAmCommonAPIWrapper::watchWithHandle(const sh_pollHandle_t handle) +{ + CommonAPI::Watch* pWatchToCheck = NULL; + try { - logError(__func__,"entering watch failed"); + pWatchToCheck = mMapWatches.at(handle); } - else - mMapWatches.insert(std::make_pair(pollfd_.fd,watch)); + catch (const std::out_of_range& error) + { + logInfo(__PRETTY_FUNCTION__,error.what()); + } + return pWatchToCheck; } -void CAmCommonAPIWrapper::commonTimerCallback(sh_timerHandle_t handle, void *) +CommonAPI::Timeout* CAmCommonAPIWrapper::timeoutWithHandle(const sh_pollHandle_t handle) { - for( std::vector::iterator iter(mpListTimerhandles.begin());iter!=mpListTimerhandles.end();iter++) + CommonAPI::Timeout* pTimeout = NULL; + try { - if(iter->handle==handle) - { - iter->timeout->dispatch(); - } + pTimeout = mListTimerhandles.at(handle); } + catch (const std::out_of_range& error) + { + logInfo(__PRETTY_FUNCTION__,error.what()); + } + return pTimeout; } + CAmCommonAPIWrapper* (*getCAPI)() = CAmCommonAPIWrapper::getInstance; } -- cgit v1.2.1