installed
This commit is contained in:
124
src/libCom/timer/epicsTimer.cpp
Normal file
124
src/libCom/timer/epicsTimer.cpp
Normal 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
|
||||
161
src/libCom/timer/epicsTimerPrivate.h
Normal file
161
src/libCom/timer/epicsTimerPrivate.h
Normal 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 ¬ify; // 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 ¬ify );
|
||||
~timerQueue ();
|
||||
void process ();
|
||||
double delayToFirstExpire () const;
|
||||
void show ( unsigned int level ) const;
|
||||
private:
|
||||
mutable epicsMutex mutex;
|
||||
epicsEvent cancelBlockingEvent;
|
||||
tsDLList < timer > timerList;
|
||||
timerQueueNotify ¬ify;
|
||||
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
174
src/libCom/timer/timer.cpp
Normal 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 ¬ifyIn, 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 );
|
||||
}
|
||||
}
|
||||
159
src/libCom/timer/timerQueue.cpp
Normal file
159
src/libCom/timer/timerQueue.cpp
Normal 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 ¬ifyIn ) :
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
src/libCom/timer/timerQueueThreaded.cpp
Normal file
118
src/libCom/timer/timerQueueThreaded.cpp
Normal 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' );
|
||||
}
|
||||
}
|
||||
85
src/libCom/timer/timerQueueThreadedMgr.cpp
Normal file
85
src/libCom/timer/timerQueueThreadedMgr.cpp
Normal 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 ()
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user