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.
165 lines
4.1 KiB
165 lines
4.1 KiB
#include "TimerThread.hpp"
|
|
|
|
#include "Common.hpp"
|
|
#include "ScopedLock.hpp"
|
|
|
|
#include <errno.h> // ETIMEDOUT
|
|
#include <pthread.h> // pthread_attr_t, sched_param
|
|
|
|
|
|
|
|
TimerThread::TimerThread()
|
|
: Thread(true)
|
|
, m_mutex()
|
|
, m_condVar(m_mutex)
|
|
, m_users()
|
|
{
|
|
TRACE;
|
|
}
|
|
|
|
|
|
TimerThread::~TimerThread()
|
|
{
|
|
TRACE;
|
|
}
|
|
|
|
|
|
void TimerThread::addTimerUser(TimerUser* user,
|
|
const time_t expiration,
|
|
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<timespec, UserEntry>( expirationTS, userEntry ) );
|
|
|
|
std::string s;
|
|
s = std::string("adding user: ") + stringify(user);
|
|
LOG(Logger::FINEST, s.c_str());
|
|
|
|
m_condVar.signal();
|
|
}
|
|
|
|
|
|
void TimerThread::addTimerUser( TimerUser* user,
|
|
const timespec expiration,
|
|
const timespec periodTime )
|
|
{
|
|
TRACE;
|
|
ScopedLock sl( m_mutex );
|
|
if ( not m_isRunning ) return;
|
|
UserEntry userEntry = { periodTime, user };
|
|
m_users.insert( std::pair<timespec, UserEntry>( expiration, userEntry ) );
|
|
|
|
std::string s;
|
|
s = std::string("adding user: ") + stringify(user);
|
|
LOG(Logger::FINEST, s.c_str());
|
|
|
|
m_condVar.signal();
|
|
}
|
|
|
|
|
|
bool TimerThread::removeTimerUser ( void* timerUser )
|
|
{
|
|
TRACE;
|
|
ScopedLock sl( m_mutex );
|
|
if ( not m_isRunning ) return false;
|
|
std::multimap<timespec, UserEntry>::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
|
|
} else {
|
|
it++;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
// override to signal as well
|
|
void TimerThread::stop()
|
|
{
|
|
TRACE;
|
|
ScopedLock sl( m_mutex );
|
|
m_isRunning = false;
|
|
m_condVar.broadcast();
|
|
}
|
|
|
|
|
|
void* TimerThread::run( void )
|
|
{
|
|
TRACE;
|
|
timespec nextExpiration;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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();
|
|
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<timespec, UserEntry>(
|
|
it->second.periodTime, it->second ) );
|
|
}
|
|
}
|
|
m_users.erase( nextExpiration );
|
|
m_users.insert( tmp.begin(), tmp.end() );
|
|
m_mutex.unlock();
|
|
|
|
}
|
|
|
|
if ( not m_users.empty() ) {
|
|
for ( it = m_users.begin(); it != m_users.end(); it++ ) {
|
|
LOG(Logger::FINEST, "Calling timerDestroyed on one user.");
|
|
it->second.user->timerDestroyed();
|
|
}
|
|
}
|
|
return 0;
|
|
}
|