diff --git a/include/TimerThread.hpp b/include/TimerThread.hpp index ab3290c..6f9241c 100644 --- a/include/TimerThread.hpp +++ b/include/TimerThread.hpp @@ -48,7 +48,7 @@ public: const timespec expiration, const timespec periodTime = timespec_ctor() ); - bool removeTimerUser ( void* timerUser ); + bool removeTimerUser( TimerUser* timerUser ); // override to signal as well void stop(); @@ -56,9 +56,11 @@ public: private: + void notifyAndRemove( const timespec t ); + void* run( void ); - // facory function + // ctor function inline static timespec timespec_ctor() { timespec tmp = { 0, 0 }; return tmp; diff --git a/src/TimerThread.cpp b/src/TimerThread.cpp index 87a9cbf..d340bb0 100644 --- a/src/TimerThread.cpp +++ b/src/TimerThread.cpp @@ -4,12 +4,11 @@ #include "ScopedLock.hpp" #include // ETIMEDOUT -#include // pthread_attr_t, sched_param TimerThread::TimerThread() - : Thread(true) + : Thread() , m_mutex() , m_condVar(m_mutex) , m_users() @@ -29,19 +28,11 @@ void TimerThread::addTimerUser(TimerUser* user, const time_t periodTime) { TRACE; - ScopedLock sl( m_mutex ); - if ( not m_isRunning ) return; - timespec expirationTS = { expiration, 0 }; - timespec periodTimeTS = { periodTime, 0 }; - - UserEntry userEntry = { periodTimeTS, user }; - m_users.insert( std::pair( expirationTS, userEntry ) ); - std::string s; - s = std::string("adding user: ") + stringify(user); - LOG(Logger::FINEST, s.c_str()); + timespec periodTimeTS = { periodTime, 0 }; + timespec expirationTS = { expiration, 0 }; - m_condVar.signal(); + addTimerUser( user, expirationTS, periodTimeTS ); } @@ -52,35 +43,30 @@ void TimerThread::addTimerUser( TimerUser* user, TRACE; ScopedLock sl( m_mutex ); if ( not m_isRunning ) return; - UserEntry userEntry = { periodTime, user }; - m_users.insert( std::pair( expiration, userEntry ) ); - std::string s; - s = std::string("adding user: ") + stringify(user); - LOG(Logger::FINEST, s.c_str()); + timespec ts; + clock_gettime( CLOCK_REALTIME, &ts ); + ts = timespecAdd ( ts, expiration ); + + UserEntry userEntry = { periodTime, user }; + m_users.insert( std::pair( ts, userEntry ) ); m_condVar.signal(); } -bool TimerThread::removeTimerUser ( void* timerUser ) +bool TimerThread::removeTimerUser( TimerUser* timerUser ) { TRACE; ScopedLock sl( m_mutex ); if ( not m_isRunning ) return false; + std::multimap::iterator it, tmp; bool found(false); for ( it = m_users.begin(); it != m_users.end(); ) { - std::string s; - s = stringify(it->second.user) + " = ? = " + stringify(timerUser); - LOG(Logger::FINEST, "Checking user to delete...does it match? "); - LOG(Logger::FINEST, s.c_str()); - - /// @todo solve the abstract pointer problem if ( (it->second.user) == timerUser ) { tmp = it++; - LOG(Logger::FINEST, "Removing a user."); m_users.erase(tmp); m_condVar.signal(); found = true; // one user can be registered multiple times @@ -91,7 +77,7 @@ bool TimerThread::removeTimerUser ( void* timerUser ) return found; } -// override to signal as well + void TimerThread::stop() { TRACE; @@ -101,62 +87,78 @@ void TimerThread::stop() } -void* TimerThread::run( void ) +void TimerThread::notifyAndRemove( const timespec t ) { TRACE; - timespec nextExpiration; + ScopedLock sl( m_mutex ); + if ( not m_isRunning ) return; + timespec ts; std::multimap tmp; std::multimap::iterator it; std::pair::iterator, std::multimap::iterator> ret; + ret = m_users.equal_range( t ); + + /// @todo modify key values in multimap, must be a better way + tmp.clear(); + for ( it = ret.first; it != ret.second; it++ ) { + it->second.user->timerExpired(); + if ( it->second.periodTime.tv_sec != 0 or it->second.periodTime.tv_nsec != 0) { + + clock_gettime( CLOCK_REALTIME, &ts ); + ts = timespecAdd( ts, it->second.periodTime ); + + tmp.insert(std::pair( ts, it->second ) ); + m_condVar.signal(); + } + } + m_users.erase( t ); + m_users.insert( tmp.begin(), tmp.end() ); +} + + +void* TimerThread::run( void ) +{ + TRACE; + timespec nextExpiration; + timespec ts, wait; + while( m_isRunning ) { m_mutex.lock(); while ( m_users.empty() and m_isRunning ) { - LOG(Logger::FINEST, "Waiting for a user, since the map is empty."); m_condVar.wait(); } m_mutex.unlock(); if ( not m_isRunning) return 0; + nextExpiration = m_users.begin()->first; + clock_gettime( CLOCK_REALTIME, &ts ); - m_mutex.lock(); - // timer deleted / added, get nextExpiration again - if ( m_condVar.wait( nextExpiration.tv_sec, - nextExpiration.tv_nsec ) != ETIMEDOUT ) { - LOG(Logger::FINEST, "Abort sleep: user has been added/removed."); - m_mutex.unlock(); + wait = timespecSubstract ( nextExpiration, ts ); + if ( wait.tv_sec == 0 and wait.tv_nsec == 0 ) { + notifyAndRemove ( nextExpiration ); continue; } - m_mutex.unlock(); - - // notify & remove m_mutex.lock(); - ret = m_users.equal_range( nextExpiration ); - - /// @todo modify key values in multimap, must be a better way - tmp.clear(); - for ( it = ret.first; it != ret.second; it++ ) { - LOG(Logger::FINEST, "Notifying one user."); - it->second.user->timerExpired(); - if ( it->second.periodTime.tv_sec != 0 or it->second.periodTime.tv_nsec != 0) { - LOG(Logger::FINEST, "Periodic, re-adding."); - tmp.insert(std::pair( - it->second.periodTime, it->second ) ); - } + + if ( m_condVar.wait( wait.tv_sec, + wait.tv_nsec ) != ETIMEDOUT ) { + m_mutex.unlock(); + continue; } - m_users.erase( nextExpiration ); - m_users.insert( tmp.begin(), tmp.end() ); m_mutex.unlock(); + notifyAndRemove( nextExpiration ); } + // end ... if ( not m_users.empty() ) { + std::multimap::iterator it; for ( it = m_users.begin(); it != m_users.end(); it++ ) { - LOG(Logger::FINEST, "Calling timerDestroyed on one user."); it->second.user->timerDestroyed(); } }