Files
pcas/src/libCom/timer/timer.cpp
2001-05-22 01:46:13 +00:00

181 lines
4.9 KiB
C++

/*
* $Id$
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*/
#define epicsExportSharedSymbols
#include "timerPrivate.h"
tsFreeList < class timer, 0x20 > timer::freeList;
epicsMutex timer::freeListMutex;
epicsTimer::~epicsTimer () {}
timer::timer ( timerQueue &queueIn ) :
curState ( stateLimbo ), pNotify ( 0 ), queue ( queueIn )
{
}
timer::~timer()
{
this->cancel ();
}
void timer::start ( epicsTimerNotify & notify, double delaySeconds )
{
this->start ( notify, epicsTime::getCurrent () + delaySeconds );
}
void timer::start ( epicsTimerNotify & notify, const epicsTime & expire )
{
epicsAutoMutex locker ( this->queue.mutex );
this->privateCancel ();
this->privateStart ( notify, expire );
}
void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire )
{
this->pNotify = & notify;
this->exp = expire;
# ifdef DEBUG
unsigned preemptCount=0u;
# endif
//
// insert into the pending queue
//
// Finds proper time sorted location using a linear search.
//
// **** this should use a binary tree ????
//
tsDLIterBD < timer > pTmr = this->queue.timerList.lastIter ();
while ( true ) {
if ( ! pTmr.valid () ) {
//
// add to the beginning of the list
//
this->queue.timerList.push ( *this );
this->queue.notify.reschedule ();
break;
}
if ( pTmr->exp <= this->exp ) {
//
// add after the item found that expires earlier
//
this->queue.timerList.insertAfter ( *this, *pTmr );
break;
}
# ifdef DEBUG
preemptCount++;
# endif
--pTmr;
}
this->curState = timer::statePending;
# if defined(DEBUG) && 0
this->show ( 10u );
this->queue.show ( 10u );
# endif
debugPrintf ( ("Start of \"%s\" with delay %f at %p preempting %u\n",
typeid ( this->notify ).name (),
expire - epicsTime::getCurrent (),
this, preemptCount ) );
}
void timer::cancel ()
{
epicsAutoMutex locker ( this->queue.mutex );
this->privateCancel ();
}
void timer::privateCancel ()
{
while ( true ) {
if ( this->curState == statePending ) {
this->queue.timerList.remove ( *this );
this->curState = stateLimbo;
this->pNotify = 0;
}
// dont wait if this was called indirectly by expire ()
if ( this->queue.pExpireTmr == this &&
this->queue.processThread != epicsThreadGetIdSelf() ) {
this->queue.cancelPending = true;
// make certain timer expire() does not run after cancel () returns,
// but dont require that lock is applied while calling expire()
{
epicsAutoMutexRelease autoRelease ( this->queue.mutex );
while ( this->queue.cancelPending ) {
this->queue.cancelBlockingEvent.wait ();
}
// in case other threads are waiting
this->queue.cancelBlockingEvent.signal ();
}
}
else {
return;
}
}
}
epicsTimer::expireInfo timer::getExpireInfo () const
{
epicsAutoMutex locker ( this->queue.mutex );
if ( this->curState == statePending || this->queue.pExpireTmr == this ) {
return expireInfo ( true, this->exp );
}
else {
return expireInfo ( false, epicsTime() );
}
}
void timer::show ( unsigned int level ) const
{
epicsAutoMutex locker ( this->queue.mutex );
const char * pName = "<no notify attached>";
if ( this->pNotify ) {
pName = typeid ( *this->pNotify ).name ();
}
double delay;
if ( this->curState == statePending ) {
delay = this->exp - epicsTime::getCurrent();
}
else {
delay = -DBL_MAX;
}
printf ( "%s, state = %s, delay = %f\n",
pName, this->curState == statePending ? "pending" : "limbo",
delay );
if ( level >= 1u && this->pNotify ) {
this->pNotify->show ( level - 1u );
}
}