You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
3.6 KiB
167 lines
3.6 KiB
14 years ago
|
#include "TimerThreadMultimap.hpp"
|
||
14 years ago
|
|
||
|
#include "Common.hpp"
|
||
|
#include "ScopedLock.hpp"
|
||
|
|
||
|
#include <errno.h> // ETIMEDOUT
|
||
|
|
||
|
|
||
|
|
||
14 years ago
|
TimerThreadMultimap::TimerThreadMultimap()
|
||
14 years ago
|
: Thread()
|
||
14 years ago
|
, m_mutex()
|
||
14 years ago
|
, m_condVar( m_mutex )
|
||
14 years ago
|
, m_users()
|
||
|
{
|
||
|
TRACE;
|
||
|
}
|
||
|
|
||
|
|
||
14 years ago
|
TimerThreadMultimap::~TimerThreadMultimap()
|
||
14 years ago
|
{
|
||
|
TRACE;
|
||
|
}
|
||
|
|
||
|
|
||
14 years ago
|
void TimerThreadMultimap::addTimerUser( TimerUser* user,
|
||
14 years ago
|
const time_t expiration,
|
||
|
const time_t periodTime )
|
||
14 years ago
|
{
|
||
|
TRACE;
|
||
14 years ago
|
|
||
14 years ago
|
timespec periodTimeTS = { periodTime, 0 };
|
||
|
timespec expirationTS = { expiration, 0 };
|
||
14 years ago
|
|
||
14 years ago
|
addTimerUser( user, expirationTS, periodTimeTS );
|
||
14 years ago
|
}
|
||
|
|
||
|
|
||
14 years ago
|
void TimerThreadMultimap::addTimerUser( TimerUser* user,
|
||
14 years ago
|
const timespec expiration,
|
||
|
const timespec periodTime )
|
||
14 years ago
|
{
|
||
|
TRACE;
|
||
|
ScopedLock sl( m_mutex );
|
||
|
if ( not m_isRunning ) return;
|
||
14 years ago
|
|
||
14 years ago
|
timespec ts;
|
||
|
clock_gettime( CLOCK_REALTIME, &ts );
|
||
14 years ago
|
ts = timespecAdd( ts, expiration );
|
||
14 years ago
|
|
||
|
UserEntry userEntry = { periodTime, user };
|
||
|
m_users.insert( std::pair<timespec, UserEntry>( ts, userEntry ) );
|
||
14 years ago
|
|
||
14 years ago
|
m_condVar.signal();
|
||
|
}
|
||
|
|
||
14 years ago
|
|
||
14 years ago
|
bool TimerThreadMultimap::removeTimerUser( TimerUser* timerUser )
|
||
14 years ago
|
{
|
||
|
TRACE;
|
||
|
ScopedLock sl( m_mutex );
|
||
14 years ago
|
if ( not m_isRunning ) return false;
|
||
14 years ago
|
|
||
14 years ago
|
std::multimap<timespec, UserEntry>::iterator it, tmp;
|
||
14 years ago
|
bool found( false );
|
||
14 years ago
|
for ( it = m_users.begin(); it != m_users.end(); ) {
|
||
14 years ago
|
|
||
14 years ago
|
if ( it->second.user == timerUser ) {
|
||
14 years ago
|
tmp = it++;
|
||
14 years ago
|
m_users.erase( tmp );
|
||
14 years ago
|
m_condVar.signal();
|
||
14 years ago
|
found = true; // one user can be registered multiple times
|
||
14 years ago
|
} else {
|
||
|
it++;
|
||
14 years ago
|
}
|
||
|
}
|
||
|
return found;
|
||
|
}
|
||
|
|
||
14 years ago
|
|
||
14 years ago
|
void TimerThreadMultimap::stop()
|
||
14 years ago
|
{
|
||
|
TRACE;
|
||
|
ScopedLock sl( m_mutex );
|
||
|
m_isRunning = false;
|
||
14 years ago
|
m_condVar.broadcast();
|
||
14 years ago
|
}
|
||
|
|
||
|
|
||
14 years ago
|
void TimerThreadMultimap::notifyAndRemove( const timespec t )
|
||
14 years ago
|
{
|
||
|
TRACE;
|
||
14 years ago
|
ScopedLock sl( m_mutex );
|
||
|
if ( not m_isRunning ) return;
|
||
14 years ago
|
|
||
14 years ago
|
timespec ts;
|
||
14 years ago
|
std::multimap<timespec, UserEntry, timespec_cmp> tmp;
|
||
|
std::multimap<timespec, UserEntry>::iterator it;
|
||
|
std::pair<std::multimap<timespec, UserEntry>::iterator,
|
||
|
std::multimap<timespec, UserEntry>::iterator> ret;
|
||
14 years ago
|
|
||
14 years ago
|
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<timespec, UserEntry>( ts, it->second ) );
|
||
|
m_condVar.signal();
|
||
|
}
|
||
|
}
|
||
|
m_users.erase( t );
|
||
|
m_users.insert( tmp.begin(), tmp.end() );
|
||
|
}
|
||
|
|
||
|
|
||
14 years ago
|
void* TimerThreadMultimap::run( void )
|
||
14 years ago
|
{
|
||
|
TRACE;
|
||
|
timespec nextExpiration;
|
||
|
timespec ts, wait;
|
||
|
|
||
14 years ago
|
while( m_isRunning ) {
|
||
|
|
||
14 years ago
|
m_mutex.lock();
|
||
14 years ago
|
while ( m_users.empty() and m_isRunning ) {
|
||
|
m_condVar.wait();
|
||
|
}
|
||
14 years ago
|
m_mutex.unlock();
|
||
14 years ago
|
|
||
14 years ago
|
if ( not m_isRunning ) return 0;
|
||
14 years ago
|
|
||
14 years ago
|
nextExpiration = m_users.begin()->first;
|
||
14 years ago
|
clock_gettime( CLOCK_REALTIME, &ts );
|
||
14 years ago
|
|
||
14 years ago
|
wait = timespecSubstract ( nextExpiration, ts );
|
||
|
if ( wait.tv_sec == 0 and wait.tv_nsec == 0 ) {
|
||
|
notifyAndRemove ( nextExpiration );
|
||
14 years ago
|
continue;
|
||
|
}
|
||
14 years ago
|
m_mutex.lock();
|
||
14 years ago
|
|
||
|
if ( m_condVar.wait( wait.tv_sec,
|
||
|
wait.tv_nsec ) != ETIMEDOUT ) {
|
||
|
m_mutex.unlock();
|
||
|
continue;
|
||
14 years ago
|
}
|
||
14 years ago
|
m_mutex.unlock();
|
||
14 years ago
|
|
||
14 years ago
|
notifyAndRemove( nextExpiration );
|
||
14 years ago
|
}
|
||
|
|
||
14 years ago
|
// end ...
|
||
14 years ago
|
if ( not m_users.empty() ) {
|
||
14 years ago
|
std::multimap<timespec, UserEntry>::iterator it;
|
||
14 years ago
|
for ( it = m_users.begin(); it != m_users.end(); it++ ) {
|
||
|
it->second.user->timerDestroyed();
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|