installed

This commit is contained in:
Jeff Hill
2001-02-15 17:14:50 +00:00
parent e414071448
commit a9ff0223af
6 changed files with 821 additions and 0 deletions

View File

@@ -0,0 +1,124 @@
/*
* $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
*
*/
#include <typeinfo>
#define epicsExportSharedSymbols
#include "epicsTimer.h"
#if 0
#include "tsFreeList.h"
#include "tsDLList.h"
#include "epicsMutex.h"
#include "locationException.h"
#include "errlog.h"
#endif
epicsTimerQueueNonThreaded::~epicsTimerQueueNonThreaded () {}
void epicsTimerNotify::show ( unsigned /* level */ ) const {}
#if 0
class epicsTimerForC : public epicsTimer {
epicsShareFunc virtual void expire ();
epicsShareFunc virtual void destroy ();
epicsShareFunc virtual bool again () const;
epicsShareFunc virtual double delay () const;
epicsShareFunc virtual void show ( unsigned level ) const;
const epicsTimerJumpTable &jt;
void * pPrivate;
public:
epicsTimerForC ( const epicsTimerJumpTable &jtIn, epicsTimerQueue &queue, void *pPrivateIn );
};
epicsTimerForC::epicsTimerForC ( const epicsTimerJumpTable &jtIn, epicsTimerQueue &queue, void *pPrivateIn ) :
epicsTimer ( queue ), jt ( jtIn ), pPrivate ( pPrivateIn ) {}
void epicsTimerForC::expire ()
{
( *this->jt.expire ) ( this->pPrivate );
}
void epicsTimerForC::destroy ()
{
( *this->jt.destroy ) ( this->pPrivate );
}
bool epicsTimerForC::again () const
{
return ( *this->jt.again ) ( this->pPrivate ) ? true : false ;
}
double epicsTimerForC::delay () const
{
return ( *this->jt.delay ) ( this->pPrivate );
}
void epicsTimerForC::show ( unsigned level ) const
{
( *this->jt.show ) ( this->pPrivate, level );
}
extern "C" epicsShareFunc epicsTimerId epicsShareAPI epicsTimerCreate (
const epicsTimerJumpTable *pjtIn, epicsTimerQueueId queueIdIn, void *pPrivateIn )
{
assert ( pjtIn );
assert ( queueIdIn );
return ( epicsTimerId ) new epicsTimerForC
( *pjtIn, *static_cast < epicsTimerQueue * > ( queueIdIn ), pPrivateIn );
}
extern "C" epicsShareFunc void epicsShareAPI epicsTimerArm ( epicsTimerId tmrIdIn, double delay )
{
epicsTimerForC *pTmr = static_cast < epicsTimerForC * > ( tmrIdIn );
assert ( pTmr );
pTmr->reschedule ( delay );
}
extern "C" epicsShareFunc void epicsShareAPI epicsTimerCancel ( epicsTimerId tmrIdIn )
{
epicsTimerForC *pTmr = static_cast < epicsTimerForC * > ( tmrIdIn );
assert ( pTmr );
pTmr->cancel ();
}
extern "C" epicsShareFunc double epicsShareAPI epicsTimerTimeRemaining ( epicsTimerId idIn )
{
epicsTimerForC *pTmr = static_cast < epicsTimerForC * > ( idIn );
assert ( pTmr );
return pTmr->timeRemaining ();
}
extern "C" epicsShareFunc epicsTimeStamp epicsShareAPI epicsTimerExpirationDate ( epicsTimerId idIn )
{
epicsTimerForC *pTmr = static_cast < epicsTimerForC * > ( idIn );
assert ( pTmr );
return pTmr->expirationDate ();
}
#endif

View File

@@ -0,0 +1,161 @@
/*
* $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
*
*/
#ifndef epicsTimerPrivate_h
#define epicsTimerPrivate_h
#include "tsFreeList.h"
#include "tsDLList.h"
#include "epicsTimer.h"
#ifdef DEBUG
# define debugPrintf(ARGSINPAREN) printf ARGSINPAREN
#else
# define debugPrintf(ARGSINPAREN)
#endif
class timer : public epicsTimer, public tsDLNode < timer > {
public:
timer ( epicsTimerNotify &, class timerQueue & );
void start ( const epicsTime & );
void start ( double delaySeconds );
void cancel ();
double getExpireDelay () const;
void show ( unsigned int level ) const;
void * operator new ( size_t size );
void operator delete ( void *pCadaver, size_t size );
class noMemory {}; // exception
protected:
~timer ();
private:
enum state { statePending = 45, stateLimbo = 78 };
epicsTime exp; // experation time
state curState; // current state
epicsTimerNotify &notify; // callback
timerQueue &queue;
void privateStart ( const epicsTime & );
void privateCancel ();
double privateDelayToFirstExpire () const;
static tsFreeList < class timer, 0x20 > freeList;
friend class timerQueue;
};
class timerQueueNotify {
public:
virtual void reschedule () = 0;
};
class timerQueue {
public:
timerQueue ( timerQueueNotify &notify );
~timerQueue ();
void process ();
double delayToFirstExpire () const;
void show ( unsigned int level ) const;
private:
mutable epicsMutex mutex;
epicsEvent cancelBlockingEvent;
tsDLList < timer > timerList;
timerQueueNotify &notify;
timer *pExpireTmr;
epicsThreadId processThread;
bool cancelPending;
friend class timer;
};
class timerQueueThreadedMgrPrivate {
public:
timerQueueThreadedMgrPrivate ();
protected:
virtual ~timerQueueThreadedMgrPrivate () = 0;
private:
unsigned referenceCount;
friend class timerQueueThreadedMgr;
};
class timerQueueThreaded : public epicsTimerQueueThreaded,
public epicsThreadRunable, public timerQueueNotify,
public timerQueueThreadedMgrPrivate,
public tsDLNode < timerQueueThreaded > {
public:
timerQueueThreaded ( unsigned priority );
epicsTimer & createTimer ( epicsTimerNotify & );
void show ( unsigned int level ) const;
void * operator new ( size_t size );
void operator delete ( void *pCadaver, size_t size );
void release ();
int threadPriority () const;
protected:
~timerQueueThreaded ();
private:
timerQueue queue;
epicsEvent rescheduleEvent;
epicsEvent exitEvent;
epicsThread thread;
bool exitFlag;
bool terminateFlag;
void run ();
void reschedule ();
static tsFreeList < class timerQueueThreaded, 0x8 > freeList;
};
class timerQueueThreadedMgr {
public:
~timerQueueThreadedMgr ();
timerQueueThreaded & create ( bool okToShare,
int threadPriority = epicsThreadPriorityMin + 10 );
void release ( timerQueueThreaded & );
private:
epicsMutex mutex;
tsDLList < timerQueueThreaded > queueList;
};
inline void * timer::operator new ( size_t size )
{
return timer::freeList.allocate ( size );
}
inline void timer::operator delete ( void *pCadaver, size_t size )
{
timer::freeList.release ( pCadaver, size );
}
inline void * timerQueueThreaded::operator new ( size_t size )
{
return timerQueueThreaded::freeList.allocate ( size );
}
inline void timerQueueThreaded::operator delete ( void *pCadaver, size_t size )
{
timerQueueThreaded::freeList.release ( pCadaver, size );
}
#endif // epicsTimerPrivate_h

174
src/libCom/timer/timer.cpp Normal file
View File

@@ -0,0 +1,174 @@
/*
* $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 "epicsTimerPrivate.h"
tsFreeList < class timer, 0x20 > timer::freeList;
epicsTimer::~epicsTimer () {}
timer::timer ( epicsTimerNotify &notifyIn, timerQueue &queueIn ) :
curState ( stateLimbo ), notify ( notifyIn ), queue ( queueIn )
{
}
timer::~timer()
{
this->cancel ();
}
inline double timer::privateDelayToFirstExpire () const
{
if ( this->curState == statePending ) {
double delay = this->exp - epicsTime::getCurrent ();
if ( delay < 0.0 ) {
delay = 0.0;
}
return delay;
}
else {
return -DBL_MAX;
}
}
void timer::start ( double delaySeconds )
{
this->start ( epicsTime::getCurrent () + delaySeconds );
}
void timer::start ( const epicsTime & expire )
{
epicsAutoMutex locker ( this->queue.mutex );
this->privateStart ( expire );
}
void timer::privateStart ( const epicsTime & expire )
{
this->privateCancel ();
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;
# ifdef DEBUG
this->show ( 10u );
this->queue.show ( 10u );
# endif
debugPrintf ( ("Arm 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 ();
// 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()
if ( this->queue.cancelPending ) {
while ( this->queue.cancelPending ) {
this->queue.cancelBlockingEvent.wait ();
}
// in case other threads are waiting
this->queue.cancelBlockingEvent.signal ();
}
}
void timer::privateCancel ()
{
if ( this->curState == statePending ) {
this->queue.timerList.remove ( *this );
this->curState = stateLimbo;
}
}
double timer::getExpireDelay () const
{
epicsAutoMutex locker ( this->queue.mutex );
return this->privateDelayToFirstExpire ();
}
void timer::show ( unsigned int level ) const
{
double delay = this->getExpireDelay ();
printf ( "%s, state = %s, delay to expire = %g\n",
typeid ( this->notify ).name (),
this->curState == statePending ? "pending" : "limbo",
delay );
if ( level >= 1u ) {
this->notify.show ( level - 1u );
}
}

View File

@@ -0,0 +1,159 @@
/*
* $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 "epicsTimerPrivate.h"
timerQueue::timerQueue ( timerQueueNotify &notifyIn ) :
notify ( notifyIn ), pExpireTmr ( 0 ),
processThread ( 0 ), cancelPending ( false )
{
}
timerQueue::~timerQueue ()
{
timer *pTmr;
this->mutex.lock ();
while ( ( pTmr = this->timerList.get () ) ) {
pTmr->curState = timer::stateLimbo;
}
}
double timerQueue::delayToFirstExpire () const
{
epicsAutoMutex locker ( this->mutex );
timer *pTmr = this->timerList.first ();
if ( pTmr ) {
return pTmr->privateDelayToFirstExpire ();
}
else {
return DBL_MAX;
}
}
void timerQueue::process ()
{
epicsTime cur ( epicsTime::getCurrent () );
{
epicsAutoMutex locker ( this->mutex );
if ( this->pExpireTmr ) {
// if some other thread is processing the queue
// (or if this is a recursive call)
return;
}
this->pExpireTmr = this->timerList.get ();
if ( ! this->pExpireTmr ) {
return;
}
if ( cur > this->pExpireTmr->exp ) {
//
// Tag current epired tmr so that we can detect if call back
// is in progress when canceling the timer.
//
# ifdef DEBUG
this->pExpireTmr->show ( 0u );
# endif
this->pExpireTmr->curState = timer::stateLimbo;
this->processThread = epicsThreadGetIdSelf ();
}
else {
// no activity
debugPrintf ( ( "no activity process\n" ) );
this->timerList.push ( *this->pExpireTmr );
this->pExpireTmr = 0;
return;
}
}
# ifdef DEBUG
unsigned N = 0u;
# endif
while ( true ) {
debugPrintf ( ( "%5u expired \"%s\" with error %f sec\n",
N++, typeid ( this->pExpireTmr->notify ).name (),
cur - this->pExpireTmr->exp ) );
epicsTimerNotify::expireStatus expStat = this->pExpireTmr->notify.expire ();
epicsAutoMutex locker ( this->mutex );
//
// only restart if they didnt cancel() the timer
// while the call back was running
//
if ( this->cancelPending ) {
// cancel () waits for this
this->cancelPending = false;
this->cancelBlockingEvent.signal ();
}
// restart as nec
else if ( expStat.restart () ) {
this->pExpireTmr->privateStart ( cur + expStat.expirationDelay () );
}
this->pExpireTmr = this->timerList.get ();
if ( ! this->pExpireTmr ) {
this->processThread = 0;
return;
}
if ( cur > this->pExpireTmr->exp ) {
# ifdef DEBUG
this->pExpireTmr->show ( 0u );
# endif
this->pExpireTmr->curState = timer::stateLimbo;
}
else {
// no activity
this->timerList.push ( *this->pExpireTmr );
this->pExpireTmr = 0;
this->processThread = 0;
return;
}
}
}
void timerQueue::show ( unsigned level ) const
{
epicsAutoMutex locker ( this->mutex );
printf ( "epicsTimerQueue with %u items pending\n", this->timerList.count () );
if ( level >= 1u ) {
tsDLIterConstBD < timer > iter = this->timerList.firstIter ();
while ( iter.valid () ) {
iter->show ( level - 1u );
++iter;
}
}
}

View File

@@ -0,0 +1,118 @@
/*
* $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 "epicsTimerPrivate.h"
static timerQueueThreadedMgr queueMgr;
epicsTimerQueueThreaded::~epicsTimerQueueThreaded () {}
epicsTimerQueueThreaded &epicsTimerQueueThreaded::create ( bool okToShare, int threadPriority )
{
return queueMgr.create ( okToShare, threadPriority );
}
tsFreeList < class timerQueueThreaded, 0x8 > timerQueueThreaded::freeList;
timerQueueThreaded::timerQueueThreaded ( unsigned priority ) :
thread ( *this, "epicsTimerQueue",
epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ),
queue ( *this ), exitFlag ( false ), terminateFlag ( false )
{
this->thread.start ();
}
timerQueueThreaded::~timerQueueThreaded ()
{
this->terminateFlag = true;
this->rescheduleEvent.signal ();
while ( ! this->exitFlag && ! this->thread.isSuspended () ) {
this->exitEvent.wait ( 1.0 );
}
// in case other threads are waiting here also
this->exitEvent.signal ();
}
int timerQueueThreaded::threadPriority () const
{
return thread.getPriority ();
}
void timerQueueThreaded::release ()
{
queueMgr.release ( *this );
}
void timerQueueThreaded::run ()
{
this->exitFlag = false;
while ( ! this->terminateFlag ) {
double delay = this->queue.delayToFirstExpire ();
if ( delay <= 0.0 ) {
this->queue.process ();
}
else {
debugPrintf ( ( "timer thread sleeping for %g sec (max)\n", delay ) );
this->rescheduleEvent.wait ( delay );
}
}
this->exitFlag = true;
this->exitEvent.signal (); // no access to queue after exitEvent signal
}
epicsTimer & timerQueueThreaded::createTimer ( epicsTimerNotify & notify )
{
timer *pTmr = new timer ( notify, this->queue );
if ( ! pTmr ) {
throwWithLocation ( timer::noMemory () );
}
return *pTmr;
}
void timerQueueThreaded::reschedule ()
{
this->rescheduleEvent.signal ();
}
void timerQueueThreaded::show ( unsigned int level ) const
{
printf ( "EPICS threaded timer queue at %p\n", this );
if ( level >=1u ) {
this->queue.show ( level - 1u );
printf ( "reschedule event\n" );
this->rescheduleEvent.show ( level - 1u );
printf ( "exit event\n" );
this->exitEvent.show ( level - 1u );
printf ( "exitFlag = %c, terminateFlag = %c\n",
this->exitFlag ? 'T' : 'F',
this->terminateFlag ? 'T' : 'F' );
}
}

View File

@@ -0,0 +1,85 @@
/*
* $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
*
*/
#include <limits.h>
#define epicsExportSharedSymbols
#include "epicsTimerPrivate.h"
timerQueueThreadedMgr::~timerQueueThreadedMgr ()
{
epicsAutoMutex locker ( this->mutex );
while ( timerQueueThreaded * pQ = this->queueList.get () ) {
timerQueueThreadedMgrPrivate *pPriv = pQ;
delete pPriv;
}
}
timerQueueThreaded & timerQueueThreadedMgr::create (
bool okToShare, int threadPriority )
{
epicsAutoMutex locker ( this->mutex );
tsDLIterBD < timerQueueThreaded > iter = this->queueList.firstIter ();
while ( iter.valid () ) {
if ( iter->threadPriority () == threadPriority ) {
assert ( iter->timerQueueThreadedMgrPrivate::referenceCount < UINT_MAX );
iter->timerQueueThreadedMgrPrivate::referenceCount++;
return *iter;
}
}
timerQueueThreaded *pQueue = new timerQueueThreaded ( threadPriority );
if ( ! pQueue ) {
throwWithLocation ( timer::noMemory () );
}
pQueue->timerQueueThreadedMgrPrivate::referenceCount = 1u;
this->queueList.add ( *pQueue );
return *pQueue;
}
void timerQueueThreadedMgr::release ( timerQueueThreaded &queue )
{
epicsAutoMutex locker ( this->mutex );
assert ( queue.timerQueueThreadedMgrPrivate::referenceCount > 0u );
queue.timerQueueThreadedMgrPrivate::referenceCount--;
if ( queue.timerQueueThreadedMgrPrivate::referenceCount == 0u ) {
this->queueList.remove ( queue );
timerQueueThreadedMgrPrivate *pPriv = &queue;
delete pPriv;
}
}
timerQueueThreadedMgrPrivate::timerQueueThreadedMgrPrivate () :
referenceCount ( 0u )
{
}
timerQueueThreadedMgrPrivate::~timerQueueThreadedMgrPrivate ()
{
}