Files
epics-base/modules/libcom/src/timer/timerQueue.cpp
Torsten Bögershausen 420fb45fbc Fix several compilation errors for -DDEBUG
After Adding "-DDEBUG" to the compiler options some files don't
compile any more.
Fix the compilation errors.
2021-09-01 11:13:40 +02:00

227 lines
7.1 KiB
C++

/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* SPDX-License-Identifier: EPICS
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#include <stdio.h>
#include <float.h>
#include "epicsGuard.h"
#include "timerPrivate.h"
#include "errlog.h"
const double timerQueue :: exceptMsgMinPeriod = 60.0 * 5.0; // seconds
epicsTimerQueue::~epicsTimerQueue () {}
timerQueue::timerQueue ( epicsTimerQueueNotify & notifyIn ) :
mutex(__FILE__, __LINE__),
notify ( notifyIn ),
pExpireTmr ( 0 ),
processThread ( 0 ),
exceptMsgTimeStamp (
epicsTime :: getCurrent () - exceptMsgMinPeriod ),
cancelPending ( false )
{
}
timerQueue::~timerQueue ()
{
timer *pTmr;
while ( ( pTmr = this->timerList.get () ) ) {
pTmr->curState = timer::stateLimbo;
}
}
void timerQueue ::
printExceptMsg ( const char * pName, const type_info & type )
{
char date[64];
double delay;
try {
epicsTime cur = epicsTime :: getCurrent ();
delay = cur - this->exceptMsgTimeStamp;
cur.strftime ( date, sizeof ( date ),
"%a %b %d %Y %H:%M:%S.%f" );
if ( delay >= exceptMsgMinPeriod ) {
this->exceptMsgTimeStamp = cur;
}
}
catch ( ... ) {
delay = DBL_MAX;
strcpy ( date, "UKN DATE" );
}
if ( delay >= exceptMsgMinPeriod ) {
// we don't touch the typeid for the timer expiration
// notify interface here because they might have
// destroyed the timer during its callback
errlogPrintf (
"timerQueue: Unexpected C++ exception \"%s\" "
"with type \"%s\" during timer expiration "
"callback at %s\n",
pName,
type.name (),
date );
errlogFlush ();
}
}
double timerQueue::process ( const epicsTime & currentTime )
{
epicsGuard < epicsMutex > guard ( this->mutex );
if ( this->pExpireTmr ) {
// if some other thread is processing the queue
// (or if this is a recursive call)
timer * pTmr = this->timerList.first ();
if ( pTmr ) {
double delay = pTmr->exp - currentTime;
if ( delay < 0.0 ) {
delay = 0.0;
}
return delay;
}
else {
return DBL_MAX;
}
}
//
// Tag current expired tmr so that we can detect if call back
// is in progress when canceling the timer.
//
if ( this->timerList.first () ) {
if ( currentTime >= this->timerList.first ()->exp ) {
this->pExpireTmr = this->timerList.first ();
this->timerList.remove ( *this->pExpireTmr );
this->pExpireTmr->curState = timer::stateActive;
this->processThread = epicsThreadGetIdSelf ();
# ifdef DEBUG
this->pExpireTmr->show ( 0u );
# endif
}
else {
double delay = this->timerList.first ()->exp - currentTime;
debugPrintf ( ( "no activity process %f to next\n", delay ) );
return delay;
}
}
else {
return DBL_MAX;
}
# ifdef DEBUG
unsigned N = 0u;
# endif
double delay = DBL_MAX;
while ( true ) {
epicsTimerNotify *pTmpNotify = this->pExpireTmr->pNotify;
this->pExpireTmr->pNotify = 0;
epicsTimerNotify::expireStatus expStat ( epicsTimerNotify::noRestart );
{
epicsGuardRelease < epicsMutex > unguard ( guard );
debugPrintf ( ( "%5u expired \"%s\" with error %f sec\n",
N++, typeid ( this->pExpireTmr->pNotify ).name (),
currentTime - this->pExpireTmr->exp ) );
try {
expStat = pTmpNotify->expire ( currentTime );
}
catch ( std::exception & except ) {
printExceptMsg ( except.what (), typeid ( except ) );
}
catch ( ... ) {
printExceptMsg ( "non-standard exception", typeid ( void ) );
}
}
//
// only restart if they didnt cancel() the timer
// while the call back was running
//
if ( this->cancelPending ) {
// 1) if another thread is canceling then cancel() waits for
// the event below
// 2) if this thread is canceling in the timer callback then
// don't touch timer or notify here because the cancel might
// have occurred because they destroyed the timer in the
// callback
this->cancelPending = false;
this->cancelBlockingEvent.signal ();
}
else {
this->pExpireTmr->curState = timer::stateLimbo;
if ( this->pExpireTmr->pNotify ) {
// pNotify was cleared above so if it is valid now we know that
// someone has started the timer from another thread and that
// predominates over the restart parameters from expire.
this->pExpireTmr->privateStart (
*this->pExpireTmr->pNotify, this->pExpireTmr->exp );
}
else if ( expStat.restart() ) {
// restart as nec
this->pExpireTmr->privateStart (
*pTmpNotify, currentTime + expStat.expirationDelay() );
}
}
this->pExpireTmr = 0;
if ( this->timerList.first () ) {
if ( currentTime >= this->timerList.first ()->exp ) {
this->pExpireTmr = this->timerList.first ();
this->timerList.remove ( *this->pExpireTmr );
this->pExpireTmr->curState = timer::stateActive;
# ifdef DEBUG
this->pExpireTmr->show ( 0u );
# endif
}
else {
delay = this->timerList.first ()->exp - currentTime;
this->processThread = 0;
break;
}
}
else {
this->processThread = 0;
delay = DBL_MAX;
break;
}
}
return delay;
}
epicsTimer & timerQueue::createTimer ()
{
return * new ( this->timerFreeList ) timer ( * this );
}
epicsTimerForC & timerQueue::createTimerForC ( epicsTimerCallback pCallback, void *pArg )
{
return * new ( this->timerForCFreeList ) epicsTimerForC ( *this, pCallback, pArg );
}
void timerQueue::show ( unsigned level ) const
{
epicsGuard < epicsMutex > locker ( this->mutex );
printf ( "epicsTimerQueue with %u items pending\n", this->timerList.count () );
if ( level >= 1u ) {
tsDLIterConst < timer > iter = this->timerList.firstIter ();
while ( iter.valid () ) {
iter->show ( level - 1u );
++iter;
}
}
}