mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-29 10:26:36 +01:00
198 lines
5.2 KiB
C++
198 lines
5.2 KiB
C++
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
|
|
|
/*
|
|
* Copyright 2005 by Eric House (xwords@eehouse.org). All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <signal.h>
|
|
#include <sys/time.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
#include "timermgr.h"
|
|
#include "xwrelay_priv.h"
|
|
#include "configs.h"
|
|
#include "mlock.h"
|
|
|
|
TimerMgr::TimerMgr()
|
|
: m_nextFireTime(0)
|
|
,m_nextID(0)
|
|
{
|
|
pthread_mutex_init( &m_timersMutex, NULL );
|
|
}
|
|
|
|
/* static */TimerMgr*
|
|
TimerMgr::GetTimerMgr()
|
|
{
|
|
static TimerMgr* mgr = NULL;
|
|
if ( mgr == NULL ) {
|
|
mgr = new TimerMgr();
|
|
}
|
|
return mgr;
|
|
}
|
|
|
|
void
|
|
TimerMgr::SetTimer( time_t inSeconds, TimerProc proc, void* closure,
|
|
int interval )
|
|
{
|
|
logf( XW_LOGINFO, "%s: uptime = %ld", __func__, uptime() );
|
|
TimerInfo ti;
|
|
ti.proc = proc;
|
|
ti.closure = closure;
|
|
ti.when = uptime() + inSeconds;
|
|
ti.interval = interval;
|
|
|
|
MutexLock ml( &m_timersMutex );
|
|
ti.id = ++m_nextID;
|
|
|
|
if ( getTimer( proc, closure ) ) {
|
|
logf( XW_LOGINFO, "%s: clearing old timer", __func__ );
|
|
clearTimerImpl( proc, closure );
|
|
}
|
|
|
|
m_timers.push_back( ti );
|
|
|
|
figureNextFire();
|
|
logf( XW_LOGINFO, "setTimer done" );
|
|
}
|
|
|
|
time_t
|
|
TimerMgr::GetPollTimeoutMillis()
|
|
{
|
|
MutexLock ml( &m_timersMutex );
|
|
|
|
time_t tout = m_nextFireTime;
|
|
if ( tout == 0 ) {
|
|
tout = -1;
|
|
} else {
|
|
tout -= uptime();
|
|
if ( tout < 0 ) {
|
|
tout = 0;
|
|
}
|
|
tout *= 1000; /* convert to milliseconds */
|
|
}
|
|
return tout;
|
|
} /* GetPollTimeoutMillis */
|
|
|
|
bool
|
|
TimerMgr::getTimer( TimerProc proc, void* closure )
|
|
{
|
|
/* Don't call this unless have the lock!!! */
|
|
list<TimerInfo>::iterator iter;
|
|
for ( iter = m_timers.begin(); iter != m_timers.end(); ++iter ) {
|
|
if ( (*iter).proc == proc
|
|
&& (*iter).closure == closure ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
} /* getTimer */
|
|
|
|
void
|
|
TimerMgr::figureNextFire()
|
|
{
|
|
/* Don't call this unless have the lock!!! */
|
|
time_t t = 0x7FFFFFFF;
|
|
time_t cur = uptime();
|
|
|
|
list<TimerInfo>::iterator iter = m_timers.begin();
|
|
|
|
while ( iter != m_timers.end() ) {
|
|
time_t when = iter->when;
|
|
|
|
if ( when == 0 ) {
|
|
if ( iter->interval ) {
|
|
when = iter->when = cur + iter->interval;
|
|
} else {
|
|
m_timers.erase(iter);
|
|
iter = m_timers.begin();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ( when < t ) {
|
|
t = when;
|
|
}
|
|
++iter;
|
|
}
|
|
|
|
m_nextFireTime = t == 0x7FFFFFFF? 0 : t;
|
|
} /* figureNextFire */
|
|
|
|
void
|
|
TimerMgr::ClearTimer( TimerProc proc, void* closure )
|
|
{
|
|
MutexLock ml( &m_timersMutex );
|
|
clearTimerImpl( proc, closure );
|
|
}
|
|
|
|
void
|
|
TimerMgr::FireElapsedTimers()
|
|
{
|
|
time_t curTime = uptime();
|
|
|
|
vector<TimerProc> procs;
|
|
vector<void*> closures;
|
|
vector<uint32_t> ids;
|
|
{
|
|
MutexLock ml( &m_timersMutex );
|
|
/* loop until we get through without firing a single one. Only fire one
|
|
per run, though, since calling erase invalidates the iterator.
|
|
PENDING: all this needs a mutex!!!! */
|
|
list<TimerInfo>::iterator iter;
|
|
for ( iter = m_timers.begin(); iter != m_timers.end(); ++iter ) {
|
|
TimerInfo* tip = &(*iter);
|
|
if ( tip->when <= curTime ) {
|
|
|
|
procs.push_back(tip->proc);
|
|
closures.push_back(tip->closure);
|
|
ids.push_back(tip->id);
|
|
|
|
if ( tip->interval ) {
|
|
tip->when += tip->interval;
|
|
} else {
|
|
tip->when = 0; /* flag for removal */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
vector<TimerProc>::const_iterator procs_iter = procs.begin();
|
|
vector<void*>::const_iterator closures_iter = closures.begin();
|
|
vector<uint32_t>::const_iterator ids_iter = ids.begin();
|
|
while ( procs_iter != procs.end() ) {
|
|
logf( XW_LOGINFO, "%s: firing timer id=%d", __func__, *ids_iter++ );
|
|
(*procs_iter++)(*closures_iter++);
|
|
}
|
|
|
|
MutexLock ml( &m_timersMutex );
|
|
figureNextFire();
|
|
} /* fireElapsedTimers */
|
|
|
|
void
|
|
TimerMgr::clearTimerImpl( TimerProc proc, void* closure )
|
|
{
|
|
list<TimerInfo>::iterator iter;
|
|
for ( iter = m_timers.begin(); iter != m_timers.end(); ++iter ) {
|
|
TimerInfo* tip = &(*iter);
|
|
if ( tip->proc == proc && tip->closure == closure ) {
|
|
logf( XW_LOGINFO, "clearing timer id=%d", tip->id );
|
|
m_timers.erase(iter);
|
|
break;
|
|
}
|
|
}
|
|
}
|