diff --git a/src/libCom/test/epicsTimerTest.cpp b/src/libCom/test/epicsTimerTest.cpp index bcac7e38f..ae790946e 100644 --- a/src/libCom/test/epicsTimerTest.cpp +++ b/src/libCom/test/epicsTimerTest.cpp @@ -40,7 +40,6 @@ static const double delayVerifyOffset = 1.0; // sec class delayVerify : public epicsTimerNotify { public: delayVerify ( double expectedDelay, epicsTimerQueue & ); - expireStatus expire (); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); void start ( const epicsTime &expireTime ); @@ -54,6 +53,7 @@ private: epicsTime beginStamp; epicsTime expireStamp; double expectedDelay; + expireStatus expire ( const epicsTime & ); static tsFreeList < class delayVerify, 0x20 > freeList; static epicsMutex freeListMutex; }; @@ -62,7 +62,7 @@ static unsigned expireCount; static epicsEvent expireEvent; delayVerify::delayVerify ( double expectedDelayIn, epicsTimerQueue &queue ) : - timer ( queue.createTimer ( *this ) ), expectedDelay ( expectedDelayIn ) + timer ( queue.createTimer() ), expectedDelay ( expectedDelayIn ) { } @@ -95,7 +95,7 @@ void delayVerify::checkError () const inline void delayVerify::start ( const epicsTime &expireTime ) { - this->timer.start ( expireTime ); + this->timer.start ( *this, expireTime ); } tsFreeList < class delayVerify, 0x20 > delayVerify::freeList; @@ -113,9 +113,9 @@ inline void delayVerify::operator delete ( void *pCadaver, size_t size ) delayVerify::freeList.release ( pCadaver, size ); } -epicsTimerNotify::expireStatus delayVerify::expire () +epicsTimerNotify::expireStatus delayVerify::expire ( const epicsTime ¤tTime ) { - this->expireStamp = epicsTime::getCurrent (); + this->expireStamp = currentTime; if ( --expireCount == 0u ) { expireEvent.signal (); } @@ -156,7 +156,6 @@ void testAccuracy () class cancelVerify : public epicsTimerNotify { public: cancelVerify ( epicsTimerQueue & ); - expireStatus expire (); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); void start ( const epicsTime &expireTime ); @@ -166,12 +165,13 @@ protected: private: epicsTimer &timer; bool failOutIfExpireIsCalled; + expireStatus expire ( const epicsTime & ); static tsFreeList < class cancelVerify, 0x20 > freeList; static epicsMutex freeListMutex; }; cancelVerify::cancelVerify ( epicsTimerQueue &queue ) : - timer ( queue.createTimer ( *this ) ), failOutIfExpireIsCalled ( false ) + timer ( queue.createTimer () ), failOutIfExpireIsCalled ( false ) { } @@ -182,7 +182,7 @@ cancelVerify::~cancelVerify () inline void cancelVerify::start ( const epicsTime &expireTime ) { - this->timer.start ( expireTime ); + this->timer.start ( *this, expireTime ); } tsFreeList < class cancelVerify, 0x20 > cancelVerify::freeList; @@ -206,7 +206,7 @@ inline void cancelVerify::cancel () this->failOutIfExpireIsCalled = true; } -epicsTimerNotify::expireStatus cancelVerify::expire () +epicsTimerNotify::expireStatus cancelVerify::expire ( const epicsTime & ) { double root = 3.14159; for ( unsigned i = 0u; i < 10000; i++ ) { @@ -247,7 +247,6 @@ void testCancel () class periodicVerify : public epicsTimerNotify { public: periodicVerify ( epicsTimerQueue & ); - expireStatus expire (); void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); void start ( const epicsTime &expireTime ); @@ -259,12 +258,13 @@ private: unsigned nExpire; epicsTimer &timer; bool failOutIfExpireIsCalled; + expireStatus expire ( const epicsTime & ); static tsFreeList < class periodicVerify, 0x20 > freeList; static epicsMutex freeListMutex; }; periodicVerify::periodicVerify ( epicsTimerQueue &queue ) : - nExpire ( 0u ), timer ( queue.createTimer ( *this ) ), failOutIfExpireIsCalled ( false ) + nExpire ( 0u ), timer ( queue.createTimer () ), failOutIfExpireIsCalled ( false ) { } @@ -275,7 +275,7 @@ periodicVerify::~periodicVerify () inline void periodicVerify::start ( const epicsTime &expireTime ) { - this->timer.start ( expireTime ); + this->timer.start ( *this, expireTime ); } tsFreeList < class periodicVerify, 0x20 > periodicVerify::freeList; @@ -304,7 +304,7 @@ inline void periodicVerify::verifyCount () assert ( this->nExpire > 1u ); } -epicsTimerNotify::expireStatus periodicVerify::expire () +epicsTimerNotify::expireStatus periodicVerify::expire ( const epicsTime & ) { this->nExpire++; double root = 3.14159; diff --git a/src/libCom/timer/epicsTimer.cpp b/src/libCom/timer/epicsTimer.cpp index 0a20882b0..ea00674c2 100644 --- a/src/libCom/timer/epicsTimer.cpp +++ b/src/libCom/timer/epicsTimer.cpp @@ -43,7 +43,7 @@ protected: private: epicsTimerCallback pCallBack; void * pPrivate; - expireStatus expire (); + expireStatus expire ( const epicsTime & currentTime ); static tsFreeList < epicsTimerForC > freeList; static epicsMutex freeListMutex; }; @@ -70,7 +70,7 @@ tsFreeList < epicsTimerForC > epicsTimerForC::freeList; epicsMutex epicsTimerForC::freeListMutex; epicsTimerForC::epicsTimerForC ( timerQueue &queue, epicsTimerCallback pCBIn, void *pPrivateIn ) : - timer ( *this, queue ), pCallBack ( pCBIn ), pPrivate ( pPrivateIn ) + timer ( queue ), pCallBack ( pCBIn ), pPrivate ( pPrivateIn ) { } @@ -95,7 +95,7 @@ inline void epicsTimerForC::operator delete ( void *pCadaver, size_t size ) epicsTimerForC::freeList.release ( pCadaver, size ); } -epicsTimerNotify::expireStatus epicsTimerForC::expire () +epicsTimerNotify::expireStatus epicsTimerForC::expire ( const epicsTime & ) { ( *this->pCallBack ) ( this->pPrivate ); return noRestart; @@ -171,17 +171,10 @@ extern "C" void epicsShareAPI pQueue->destroy (); } -extern "C" void epicsShareAPI +extern "C" double epicsShareAPI epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId pQueue ) { - pQueue->process (); -} - -extern "C" double epicsShareAPI - epicsTimerQueuePassiveGetDelayToNextExpire ( - epicsTimerQueuePassiveId pQueue ) -{ - return pQueue->getNextExpireDelay (); + return pQueue->process ( epicsTime::getCurrent() ); } extern "C" epicsTimerId epicsShareAPI epicsTimerQueuePassiveCreateTimer ( @@ -243,13 +236,13 @@ extern "C" void epicsShareAPI epicsTimerDestroy ( epicsTimerId pTmr ) extern "C" void epicsShareAPI epicsTimerStartTime ( epicsTimerId pTmr, const epicsTimeStamp *pTime ) { - pTmr->start ( *pTime ); + pTmr->start ( *pTmr, *pTime ); } extern "C" void epicsShareAPI epicsTimerStartDelay ( epicsTimerId pTmr, double delaySeconds ) { - pTmr->start ( delaySeconds ); + pTmr->start ( *pTmr, delaySeconds ); } extern "C" void epicsShareAPI epicsTimerCancel ( epicsTimerId pTmr ) diff --git a/src/libCom/timer/epicsTimer.h b/src/libCom/timer/epicsTimer.h index 573ec1024..109fa5c2e 100644 --- a/src/libCom/timer/epicsTimer.h +++ b/src/libCom/timer/epicsTimer.h @@ -20,6 +20,11 @@ of this distribution. #ifdef __cplusplus +// +// Notes: +// 1) epicsTimer does not hold its lock when calling callbacks. +// + // code using a timer must implement epicsTimerNotify class epicsTimerNotify { public: @@ -35,23 +40,29 @@ public: double delay; }; // return noRestart OR return expireStatus ( restart, 30.0 /* sec */ ); - virtual expireStatus expire () = 0; + virtual expireStatus expire ( const epicsTime & currentTime ) = 0; virtual epicsShareFunc void show ( unsigned int level ) const; }; class epicsTimer { public: virtual ~epicsTimer () = 0; - virtual void start ( const epicsTime & ) = 0; - virtual void start ( double delaySeconds ) = 0; + virtual void start ( epicsTimerNotify &, const epicsTime & ) = 0; + virtual void start ( epicsTimerNotify &, double delaySeconds ) = 0; virtual void cancel () = 0; - virtual double getExpireDelay () const = 0; + struct expireInfo { + expireInfo ( bool active, const epicsTime &expireTime ); + bool active; + epicsTime expireTime; + }; + virtual expireInfo getExpireInfo () const = 0; + double getExpireDelay (); virtual void show ( unsigned int level ) const = 0; }; class epicsTimerQueue { public: - virtual epicsTimer & createTimer ( epicsTimerNotify & ) = 0; + virtual epicsTimer & createTimer () = 0; virtual void show ( unsigned int level ) const = 0; protected: virtual ~epicsTimerQueue () = 0; @@ -77,8 +88,7 @@ class epicsTimerQueuePassive : public epicsTimerQueue { public: static epicsShareFunc epicsTimerQueuePassive & create ( epicsTimerQueueNotify & ); virtual ~epicsTimerQueuePassive () = 0; - virtual void process () = 0; - virtual double getNextExpireDelay () const = 0; + virtual double process ( const epicsTime & currentTime ) = 0; // returns delay to next expire }; inline epicsTimerNotify::expireStatus::expireStatus ( restart_t restart ) : @@ -105,6 +115,27 @@ inline double epicsTimerNotify::expireStatus::expirationDelay () const return this->delay; } +inline epicsTimer::expireInfo::expireInfo ( bool activeIn, + const epicsTime & expireTimeIn ) : + active ( activeIn ), expireTime ( expireTimeIn ) +{ +} + +inline double epicsTimer::getExpireDelay () +{ + epicsTimer::expireInfo info = this->getExpireInfo (); + if ( info.active ) { + double delay = info.expireTime - epicsTime::getCurrent (); + if ( delay < 0.0 ) { + delay = 0.0; + } + return delay; + } + else { + return - DBL_MAX; + } +} + extern "C" { #endif /* __cplusplus */ @@ -133,11 +164,8 @@ epicsShareFunc void epicsShareAPI epicsShareFunc epicsTimerId epicsShareAPI epicsTimerQueuePassiveCreateTimer ( epicsTimerQueuePassiveId queueid, epicsTimerCallback pCallback, void *pArg ); -epicsShareFunc void epicsShareAPI - epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId ); epicsShareFunc double epicsShareAPI - epicsTimerQueuePassiveGetDelayToNextExpire ( - epicsTimerQueuePassiveId ); + epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId ); epicsShareFunc void epicsShareAPI epicsTimerQueuePassiveShow ( epicsTimerQueuePassiveId id, unsigned int level ); diff --git a/src/libCom/timer/osiTimer.cpp b/src/libCom/timer/osiTimer.cpp deleted file mode 100644 index b29e3e1d6..000000000 --- a/src/libCom/timer/osiTimer.cpp +++ /dev/null @@ -1,714 +0,0 @@ -/* - * $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 assert // allow use of epicsAssert.h -#include -#endif -#include -#include - -#define epicsExportSharedSymbols -#include "osiTimer.h" -#include "locationException.h" -#include "errlog.h" - -class osiTimerThread : public epicsThreadRunable { -public: - osiTimerThread (osiTimerQueue &, unsigned priority); - virtual ~osiTimerThread(); -private: - friend class osiTimer; - friend class osiTimerQueue; - epicsThread thread; - osiTimerQueue &queue; - - virtual void run(); -}; - -// -// default global timer queue -// -osiTimerQueue osiDefaultTimerQueue ( osiTimerQueue::mtsNoManagerThread ); - -// -// osiTimer::osiTimer () -// -// create an active timer that will expire in delay seconds -// -osiTimer::osiTimer (double delay, osiTimerQueue & queueIn) : - queue (queueIn) -{ - this->arm (delay); -} - -// -// osiTimer::osiTimer () -// -// create an active timer that will expire in delay seconds -// -osiTimer::osiTimer (double delay) : - queue (osiDefaultTimerQueue) -{ - this->arm (delay); -} - -// -// osiTimer::osiTimer () -// -// create an inactive timer -// -osiTimer::osiTimer (osiTimerQueue & queueIn) : -curState (osiTimer::stateIdle), queue (queueIn) -{ - epicsAutoMutex ( this->queue.mutex ); - this->queue.timerLists[stateIdle].add (*this); -} - -// -// osiTimer::osiTimer () -// -// create an inactive timer -// -osiTimer::osiTimer () : -curState (osiTimer::stateIdle), queue (osiDefaultTimerQueue) -{ - epicsAutoMutex ( this->queue.mutex ); - this->queue.timerLists[stateIdle].add (*this); -} - -// -// osiTimer::~osiTimer() -// -osiTimer::~osiTimer() -{ - if ( this->curState == stateLimbo ) { - return; // queue was destroyed - } - - epicsAutoMutex ( this->queue.mutex ); - // - // signal the timer queue if this - // occurring during the expire call - // back - // - if (this == this->queue.pExpireTmr) { - this->queue.pExpireTmr = 0; - } - this->queue.timerLists[this->curState].remove(*this); - this->curState = stateLimbo; -} - -// -// osiTimer::cancel () -// -void osiTimer::cancel () -{ - if ( this->curState == stateLimbo ) { - return; // queue was destroyed - } - - { - epicsAutoMutex ( this->queue.mutex ); - - // - // signal the timer queue if this - // occurring during the expire call - // back - // - if (this == this->queue.pExpireTmr) { - this->queue.pExpireTmr = 0; - } - - this->queue.timerLists[this->curState].remove (*this); - this->curState = stateIdle; - this->queue.timerLists[stateIdle].add (*this); - } - - this->destroy (); -} - -// -// osiTimer::reschedule() -// -// pull this timer out of the queue and reinstall -// it with a new experation time -// -void osiTimer::reschedule () -{ - this->reschedule ( this->delay () ); -} - -// -// osiTimer::reschedule() -// -// pull this timer out of the queue ans reinstall -// it with a new experation time -// -void osiTimer::reschedule (double newDelay) -{ - if ( this->curState == stateLimbo ) { - return; // queue was destroyed - } - - epicsAutoMutex ( this->queue.mutex ); - - // - // signal the timer queue if this - // occurring during the expire call - // back - // - if ( this == this->queue.pExpireTmr ) { - this->queue.pExpireTmr = 0; - } - this->queue.timerLists[this->curState].remove (*this); - this->curState = stateLimbo; - this->arm (newDelay); -} - -// -// Start the timer with delay this->delay() if inactive -// -epicsShareFunc void osiTimer::activate () -{ - this->activate ( this->delay () ); -} - -// -// Start the timer with delay newDelay if inactive -// -epicsShareFunc void osiTimer::activate ( double newDelay ) -{ - if ( this->curState == stateLimbo ) { - return; // queue was destroyed - } - - epicsAutoMutex ( this->queue.mutex ); - - if ( this->curState == stateIdle ) { - // - // signal the timer queue if this - // occurring during the expire call - // back - // - if ( this == this->queue.pExpireTmr ) { - this->queue.pExpireTmr = 0; - } - this->queue.timerLists[this->curState].remove (*this); - this->curState = stateLimbo; - this->arm (newDelay); - } -} - -// -// osiTimer::arm () -// -void osiTimer::arm (double initialDelay) -{ - bool first; - -# ifdef DEBUG - unsigned preemptCount = 0u; -# endif - - { - epicsAutoMutex ( this->queue.mutex ); - - // - // create manager thread on demand so we dont have threads hanging - // around that are not used - // - if ( ! this->queue.terminateFlag && this->queue.pMgrThread == NULL ) { - this->queue.pMgrThread = new osiTimerThread (this->queue, this->queue.mgrThreadPriority); - if ( this->queue.pMgrThread == NULL ) { - throwWithLocation ( noMemory () ); - } - } - - // - // calculate absolute expiration time - // - this->exp = epicsTime::getCurrent () + initialDelay; - - // - // insert into the pending queue - // - // Finds proper time sorted location using - // a linear search. - // - // **** this should use a binary tree ???? - // - tsDLIterBD iter = this->queue.timerLists[statePending].lastIter (); - while (1) { - if ( ! iter.valid () ) { - // - // add to the beginning of the list - // - this->queue.timerLists[statePending].push (*this); - first = true; - break; - } - if ( iter->exp <= this->exp ) { - // - // add after the item found that expires earlier - // - this->queue.timerLists[statePending].insertAfter (*this, *iter); - first = false; - break; - } -# ifdef DEBUG - preemptCount++; -# endif - --iter; - } - - this->curState = osiTimer::statePending; - -# ifdef DEBUG - this->show (10u); -# endif - -# ifdef DEBUG - // - // name virtual function isnt always useful here because this is - // often called inside the constructor (unless we are - // rearming the same timer) - // - printf ("Arm of \"%s\" with delay %f at %lx preempting %u\n", - this->name(), initialDelay, (unsigned long)this, preemptCount); - # endif - } - - if (first) { - this->queue.rescheduleEvent.signal (); - } -} - -// -// osiTimer::again() -// -bool osiTimer::again () const -{ - // - // default is to run the timer only once - // - return false; -} - -// -// osiTimer::destroy() -// -void osiTimer::destroy () -{ - delete this; -} - -// -// osiTimer::delay() -// -double osiTimer::delay () const -{ - throwWithLocation ( noDelaySpecified () ); - return DBL_MAX; // never here -} - -// -// osiTimer::show() -// -void osiTimer::show (unsigned level) const -{ - epicsTime cur = epicsTime::getCurrent (); - printf ("osiTimer at %p for \"%s\" with again = %d\n", - static_cast (this), this->name(), this->again()); - if (level>=1u) { - double delay = this->exp - cur; - printf ("\tdelay to expire = %f, state = %d\n", - delay, this->curState); - } -} - -// -// osiTimer::name() -// virtual base default -// -const char *osiTimer::name() const -{ - return "osiTimer"; -} - -// -// osiTimer::timeRemaining() -// -// return the number of seconds remaining before -// this timer will expire -// -double osiTimer::timeRemaining () const -{ - double delay; - - epicsAutoMutex ( this->queue.mutex ); - - switch (this->curState) { - case statePending: - delay = this->exp - epicsTime::getCurrent(); - if ( delay < 0.0 ) { - delay = 0.0; - } - break; - - case stateIdle: - delay = DBL_MAX; - break; - - case stateExpired: - delay = 0.0; - break; - - case stateLimbo: - errlogPrintf ("time remaning fetched on a osiTimer with no queue?\n"); - delay = DBL_MAX; // queue was destroyed - break; - - default: - errlogPrintf ("saw osiTimer in undefined state\n"); - delay = DBL_MAX; - break; - } - - return delay; -} - -// -// osiTimerQueue::osiTimerQueue () -// -epicsShareFunc osiTimerQueue::osiTimerQueue ( managerThreadSelect mts, - unsigned managerThreadPriority ) : - pExpireTmr (0), pMgrThread (0), mgrThreadPriority (managerThreadPriority), - inProcess (false), exitFlag (false) -{ - this->terminateFlag = ( mts != mtsCreateManagerThread ); -} - -// -// osiTimerQueue::~osiTimerQueue() -// -osiTimerQueue::~osiTimerQueue() -{ - osiTimer *pTmr; - - this->terminateManagerThread (); - - this->mutex.lock (); - - // - // destroy any unexpired timers - // - while ( ( pTmr = this->timerLists[osiTimer::statePending].get () ) ) { - pTmr->curState = osiTimer::stateLimbo; - pTmr->destroy (); - } - - // - // destroy any expired timers - // - while ( (pTmr = this->timerLists[osiTimer::stateExpired].get()) ) { - pTmr->curState = osiTimer::stateLimbo; - pTmr->destroy (); - } -} - -// -// osiTimerQueue::terminateManagerThread () -// -void osiTimerQueue::terminateManagerThread () -{ - // stop current thread if started and - // prevent launching of thread in the future - this->terminateFlag = true; - if ( this->pMgrThread ) { - - this->rescheduleEvent.signal (); - - while ( ! this->exitFlag && ! this->pMgrThread->thread.isSuspended () ) { - this->exitEvent.wait ( 1.0 ); - } - - { - epicsAutoMutex ( this->mutex ); - if ( this->pMgrThread ) { - delete this->pMgrThread; - this->pMgrThread = 0; - } - } - - // in case other threads are waiting here also - this->exitEvent.signal (); - } -} - -// -// osiTimerThread::osiTimerThread () -// -osiTimerThread::osiTimerThread (osiTimerQueue &queueIn, unsigned priority) : - thread( *this, "osiTimerQueue", - epicsThreadGetStackSize (epicsThreadStackMedium), priority) , - queue (queueIn) -{ - this->thread.start (); -} - -osiTimerThread::~osiTimerThread() {}; - -// -// osiTimerThread::run () -// -void osiTimerThread::run () -{ - queue.exitFlag = false; - while ( ! queue.terminateFlag ) { - queue.privateProcess (); - double delay = queue.delayToFirstExpire (); - queue.rescheduleEvent.wait ( delay ); - } - queue.exitFlag = true; - queue.exitEvent.signal (); // no access to queue after exitEvent signal -} - -// -// osiTimerQueue::delayToFirstExpire () -// -double osiTimerQueue::delayToFirstExpire () const -{ - osiTimer *pTmr; - double delay; - - epicsAutoMutex locker ( this->mutex ); - - pTmr = this->timerLists[osiTimer::statePending].first (); - if (pTmr) { - delay = pTmr->timeRemaining (); -# ifdef DEBUG - printf ("delay for %f sec for %s\n", delay, pTmr->name () ); -# endif - } - else { - // - // no timer in the queue - return a long delay - 30 min - // - delay = 30u * epicsTime::secPerMin; - } - - return delay; // seconds -} - -// -// osiTimerQueue::process() -// -void osiTimerQueue::process () -{ - if ( this->terminateFlag ) { - this->privateProcess (); - } -} - -void osiTimerQueue::privateProcess () -{ - epicsTime cur ( epicsTime::getCurrent () ); - osiTimer *pTmr; - - this->mutex.lock (); - - // no recursion - if (this->inProcess) { - this->mutex.unlock (); - return; - } - this->inProcess = true; - - - tsDLIterBD iter = this->timerLists[osiTimer::statePending].firstIter (); - while ( iter.valid () ) { - if ( iter->exp > cur ) { - break; - } - tsDLIterBD tmp = iter; - ++tmp; - this->timerLists[osiTimer::statePending].remove(*iter); - iter->curState = osiTimer::stateExpired; - this->timerLists[osiTimer::stateExpired].add(*iter); - iter = tmp; - } - - // - // I am careful to prevent problems if they access the - // above list while in an "expire()" call back - // - while ( ( pTmr = this->timerLists[osiTimer::stateExpired].get () ) ) { - - pTmr->curState = osiTimer::stateIdle; - this->timerLists[osiTimer::stateIdle].add (*pTmr); - - // - // Tag current tmr so that we - // can detect if it was deleted - // during the expire call back - // - this->pExpireTmr = pTmr; - - // - // remove lock while calling their callback - // - this->mutex.unlock (); - -#ifdef DEBUG - double diff = cur-pTmr->exp; - printf ("expired %lx for \"%s\" with error %f\n", - (unsigned long)pTmr, pTmr->name(), diff); -#endif - - pTmr->expire(); - - this-> mutex.lock(); - - if ( this->pExpireTmr == pTmr ) { - if ( pTmr->again () ) { - this->timerLists[osiTimer::stateIdle].remove (*pTmr); - pTmr->arm (pTmr->delay()); - } - else { - pTmr->destroy (); - } - } - else { - // - // no recursive calls to process allowed - // - assert (this->pExpireTmr == 0); - } - } - this->inProcess = false; - - this->mutex.unlock(); -} - -// -// osiTimerQueue::show() const -// -void osiTimerQueue::show(unsigned level) const -{ - epicsAutoMutex locker ( this->mutex ); - printf("osiTimerQueue with %u items pending and %u items expired\n", - this->timerLists[osiTimer::statePending].count(), - this->timerLists[osiTimer::stateExpired].count()); - tsDLIterConstBD iter = this->timerLists[osiTimer::statePending].firstIter (); - while ( iter.valid () ) { - iter->show(level); - ++iter; - } -} - -extern "C" epicsShareFunc osiTimerQueueId epicsShareAPI osiTimerQueueCreate ( unsigned managerThreadPriority ) -{ - return (osiTimerQueueId) new osiTimerQueue ( osiTimerQueue::mtsCreateManagerThread, managerThreadPriority ); -} - -class osiTimerForC : public osiTimer { - 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 osiTimerJumpTable &jt; - void * pPrivate; -public: - osiTimerForC (const osiTimerJumpTable &jtIn, osiTimerQueue &queue, void *pPrivateIn); -}; - -osiTimerForC::osiTimerForC (const osiTimerJumpTable &jtIn, osiTimerQueue &queue, void *pPrivateIn) : - osiTimer (queue), jt (jtIn), pPrivate (pPrivateIn) {} - -void osiTimerForC::expire () -{ - (*this->jt.expire) (this->pPrivate); -} - -void osiTimerForC::destroy () -{ - (*this->jt.destroy) (this->pPrivate); -} - -bool osiTimerForC::again () const -{ - return (*this->jt.again) (this->pPrivate) ? true : false ; -} - -double osiTimerForC::delay () const -{ - return (*this->jt.delay) (this->pPrivate); -} - -void osiTimerForC::show (unsigned level) const -{ - (*this->jt.show) (this->pPrivate, level); -} - -extern "C" epicsShareFunc osiTimerId epicsShareAPI osiTimerCreate (const osiTimerJumpTable *pjtIn, osiTimerQueueId queueIdIn, void *pPrivateIn) -{ - assert (pjtIn); - assert (queueIdIn); - return (osiTimerId) new osiTimerForC (*pjtIn, *static_cast(queueIdIn), pPrivateIn); -} - -extern "C" epicsShareFunc void epicsShareAPI osiTimerArm (osiTimerId tmrIdIn, double delay) -{ - osiTimerForC *pTmr = static_cast(tmrIdIn); - assert (pTmr); - pTmr->reschedule (delay); -} - -extern "C" epicsShareFunc void epicsShareAPI osiTimerCancel (osiTimerId tmrIdIn) -{ - osiTimerForC *pTmr = static_cast(tmrIdIn); - assert (pTmr); - pTmr->cancel (); -} - -extern "C" epicsShareFunc double epicsShareAPI osiTimerTimeRemaining (osiTimerId idIn) -{ - osiTimerForC *pTmr = static_cast (idIn); - assert (pTmr); - return pTmr->timeRemaining (); -} - -extern "C" epicsShareFunc epicsTimeStamp epicsShareAPI osiTimerExpirationDate (osiTimerId idIn) -{ - osiTimerForC *pTmr = static_cast (idIn); - assert (pTmr); - return pTmr->expirationDate (); -} diff --git a/src/libCom/timer/osiTimer.h b/src/libCom/timer/osiTimer.h deleted file mode 100644 index 375bb8b09..000000000 --- a/src/libCom/timer/osiTimer.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * $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 osiTimerHInclude -#define osiTimerHInclude - -#include "shareLib.h" /* reset share lib defines */ -#include "epicsThread.h" -#include "epicsTime.h" - -#ifdef __cplusplus - -#include "epicsTime.h" -#include "tsDLList.h" -#include "epicsMutex.h" -#include "epicsEvent.h" - -class osiTimerQueue; - -/* - * osiTimer - */ -class osiTimer : public tsDLNode { -public: - class noDelaySpecified {}; /* exception */ - class noMemory {}; /* exception */ - - /* - * Create an active timer that will expire delay seconds after it is created - * or create an inactive timer respectively. - * - * ** Warning ** default timer queue has no manager thread and is typically - * processed by the file descriptor manager - */ - epicsShareFunc osiTimer ( double delay, osiTimerQueue & queueIn ); - epicsShareFunc osiTimer ( double delay ); - - /* - * Create an inactive timer - * - * ** Warning ** default timer queue has no manager thread and is typically - * processed by the file descriptor manager - */ - epicsShareFunc osiTimer ( osiTimerQueue & queueIn ); - epicsShareFunc osiTimer (); - - /* - * change the timers expiration to newDelay - * seconds after when reschedule() is called - */ - epicsShareFunc void reschedule (double newDelay); - - /* - * change the timers expiration to this->delay() - * seconds after when reschedule() is called - */ - epicsShareFunc void reschedule (); - - /* - * Start the timer with delay newDelay if inactive. - */ - epicsShareFunc void activate ( double newDelay ); - - /* - * Start the timer with delay this->delay() if inactive. - */ - epicsShareFunc void activate (); - - /* - * inactivate the timer and call the virtual destroy() - * member function - */ - epicsShareFunc void cancel (); - - /* - * return the number of seconds remaining before - * this osiTimer will expire or the expiration date - * respectively - */ - epicsShareFunc double timeRemaining () const; /* returns seconds, but inefficent */ - epicsShareFunc epicsTime expirationDate () const; /* efficent */ - - /* - * called when the osiTimer expires - */ - epicsShareFunc virtual void expire () = 0; - - /* - * called if - * 1) osiTimer exists and the osiTimerQueue is deleted - * 2) when the osiTimer expires and again() returns false - * - * osiTimer::destroy() does a "delete this" - * - * if the derived class replaces this function then it - * is taking responsibility for freeing (deleting) - * timer resources when they are nolonger needed. - */ - epicsShareFunc virtual void destroy (); - - /* - * returning true indicates that the - * osiTimer should be rearmed with delay - * "delay()" when it expires - * - * the defaut osiTimer::again() returns false - * (run the osiTimer once only) - */ - epicsShareFunc virtual bool again () const; - - /* - * returns the delay prior to expire - * for subsequent iterations (if "again()" - * returns true) - * - * the default osiTimer::delay() throws the - * exception type noDelaySpecified, but it will - * not be called unless the again() virtual - * function returns true. - */ - epicsShareFunc virtual double delay () const; - - epicsShareFunc virtual void show (unsigned level) const; - - /* - * for diagnostics - */ - epicsShareFunc virtual const char *name () const; - - epicsShareFunc virtual ~osiTimer (); - -private: - friend class osiTimerQueue; - enum state {statePending, stateExpired, stateIdle, - numberOfTimerLists, stateLimbo}; - - epicsTime exp; /* experation time */ - state curState; /* current state */ - osiTimerQueue &queue; /* pointer to current timer queue */ - - /* - * place osiTimer in the pending queue - */ - void arm (double initialDelay); -}; - -/* - * osiTimerQueue - */ -class osiTimerQueue { -friend class osiTimer; -friend class osiTimerThread; -public: - enum managerThreadSelect { - mtsNoManagerThread, // you must call the process method (or the fdManager) to expire timers - mtsCreateManagerThread // manager thread expires timers asnychronously - }; - epicsShareFunc osiTimerQueue ( managerThreadSelect mts, - unsigned managerThreadPriority = epicsThreadPriorityMin ); - epicsShareFunc virtual ~osiTimerQueue(); - epicsShareFunc double delayToFirstExpire () const; /* returns seconds */ - epicsShareFunc void process (); - epicsShareFunc void show (unsigned level) const; -private: - mutable epicsMutex mutex; - epicsEvent rescheduleEvent; - epicsEvent exitEvent; - tsDLList timerLists [osiTimer::numberOfTimerLists]; - osiTimer *pExpireTmr; - class osiTimerThread *pMgrThread; - unsigned mgrThreadPriority; - bool inProcess; - bool terminateFlag; - bool exitFlag; - - void install (osiTimer &tmr, double delay); - void privateProcess (); - void terminateManagerThread (); -}; - -/* - * ** Warning ** - * the default timer queue has no manager thread and is typically - * processed by the file descriptor manager - */ -epicsShareExtern osiTimerQueue osiDefaultTimerQueue; - -inline epicsTime osiTimer::expirationDate () const -{ - return this->exp; -} - -#endif /* ifdef __cplusplus */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * osiTimerJumpTable - */ -typedef struct osiTimerJumpTable { - void (*expire) (void *pPrivate); /* called when timer expires */ - void (*destroy) (void *pPrivate); /* called after expire() when again() is false */ - int (*again) (void *pPrivate); /* rearm after expire when again() is true */ - double (*delay) (void *pPrivate); /* rearm delay */ - void (*show) (void *pPrivate, unsigned level); /* diagnostic */ -}osiTimerJumpTable; - -typedef void * osiTimerQueueId; -/* see epicsThread.h for the range of priorities allowed here */ -epicsShareFunc osiTimerQueueId epicsShareAPI osiTimerQueueCreate (unsigned managerThreadPriority); - -typedef void * osiTimerId; -epicsShareFunc osiTimerId epicsShareAPI osiTimerCreate (const osiTimerJumpTable *, osiTimerQueueId, void *pPrivate); -epicsShareFunc void epicsShareAPI osiTimerArm (osiTimerId, double delay); -epicsShareFunc void epicsShareAPI osiTimerCancel (osiTimerId); -epicsShareFunc double epicsShareAPI osiTimerTimeRemaining (osiTimerId); -epicsShareFunc epicsTimeStamp epicsShareAPI osiTimerExpirationDate (osiTimerId); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* osiTimerHInclude */ - diff --git a/src/libCom/timer/timer.cpp b/src/libCom/timer/timer.cpp index 2335eaff0..6e3016292 100644 --- a/src/libCom/timer/timer.cpp +++ b/src/libCom/timer/timer.cpp @@ -37,8 +37,8 @@ epicsMutex timer::freeListMutex; epicsTimer::~epicsTimer () {} -timer::timer ( epicsTimerNotify ¬ifyIn, timerQueue &queueIn ) : - curState ( stateLimbo ), notify ( notifyIn ), queue ( queueIn ) +timer::timer ( timerQueue &queueIn ) : + curState ( stateLimbo ), pNotify ( 0 ), queue ( queueIn ) { } @@ -47,21 +47,21 @@ timer::~timer() this->cancel (); } -void timer::start ( double delaySeconds ) +void timer::start ( epicsTimerNotify & notify, double delaySeconds ) { - this->start ( epicsTime::getCurrent () + delaySeconds ); + this->start ( notify, epicsTime::getCurrent () + delaySeconds ); } -void timer::start ( const epicsTime & expire ) +void timer::start ( epicsTimerNotify & notify, const epicsTime & expire ) { epicsAutoMutex locker ( this->queue.mutex ); - this->privateStart ( expire ); + this->privateCancel (); + this->privateStart ( notify, expire ); } -void timer::privateStart ( const epicsTime & expire ) +void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire ) { - this->privateCancel (); - + this->pNotify = & notify; this->exp = expire; # ifdef DEBUG @@ -100,12 +100,12 @@ void timer::privateStart ( const epicsTime & expire ) this->curState = timer::statePending; -# ifdef DEBUG +# if defined(DEBUG) && 0 this->show ( 10u ); this->queue.show ( 10u ); # endif - debugPrintf ( ("Arm of \"%s\" with delay %f at %p preempting %u\n", + debugPrintf ( ("Start of \"%s\" with delay %f at %p preempting %u\n", typeid ( this->notify ).name (), expire - epicsTime::getCurrent (), this, preemptCount ) ); @@ -113,49 +113,68 @@ void timer::privateStart ( const epicsTime & expire ) 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 (); - } + epicsAutoMutex locker ( this->queue.mutex ); + this->privateCancel (); } void timer::privateCancel () { - if ( this->curState == statePending ) { - this->queue.timerList.remove ( *this ); - this->curState = stateLimbo; + 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; + } } } -double timer::getExpireDelay () const +epicsTimer::expireInfo timer::getExpireInfo () const { epicsAutoMutex locker ( this->queue.mutex ); - return this->privateDelayToFirstExpire (); + 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 { - double delay = this->getExpireDelay (); - printf ( "%s, state = %s, delay to expire = %g\n", - typeid ( this->notify ).name (), - this->curState == statePending ? "pending" : "limbo", + epicsAutoMutex locker ( this->queue.mutex ); + const char * pName = ""; + 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->notify.show ( level - 1u ); + if ( level >= 1u && this->pNotify ) { + this->pNotify->show ( level - 1u ); } } diff --git a/src/libCom/timer/timerPrivate.h b/src/libCom/timer/timerPrivate.h index 6b328cc01..900c1d1eb 100644 --- a/src/libCom/timer/timerPrivate.h +++ b/src/libCom/timer/timerPrivate.h @@ -43,11 +43,11 @@ class timer : public epicsTimer, public tsDLNode < timer > { public: - timer ( epicsTimerNotify &, class timerQueue & ); - void start ( const epicsTime & ); - void start ( double delaySeconds ); + timer ( class timerQueue & ); + void start ( class epicsTimerNotify &, const epicsTime & ); + void start ( class epicsTimerNotify &, double delaySeconds ); void cancel (); - double getExpireDelay () const; + expireInfo getExpireInfo () const; void show ( unsigned int level ) const; void * operator new ( size_t size ); void operator delete ( void *pCadaver, size_t size ); @@ -58,11 +58,10 @@ private: enum state { statePending = 45, stateLimbo = 78 }; epicsTime exp; // experation time state curState; // current state - epicsTimerNotify ¬ify; // callback + epicsTimerNotify *pNotify; // callback timerQueue &queue; - void privateStart ( const epicsTime & ); + void privateStart ( epicsTimerNotify & notify, const epicsTime & ); void privateCancel (); - double privateDelayToFirstExpire () const; static tsFreeList < class timer, 0x20 > freeList; static epicsMutex freeListMutex; friend class timerQueue; @@ -72,8 +71,7 @@ class timerQueue { public: timerQueue ( epicsTimerQueueNotify ¬ify ); ~timerQueue (); - void process (); - double delayToFirstExpire () const; + double process ( const epicsTime & currentTime ); void show ( unsigned int level ) const; private: mutable epicsMutex mutex; @@ -102,7 +100,7 @@ class timerQueueActive : public epicsTimerQueueActive, public: timerQueueActive ( bool okToShare, unsigned priority ); ~timerQueueActive () = 0; - epicsTimer & createTimer ( epicsTimerNotify & ); + epicsTimer & createTimer (); void show ( unsigned int level ) const; bool sharingOK () const; int threadPriority () const; @@ -149,9 +147,8 @@ extern timerQueueActiveMgr queueMgr; class timerQueuePassive : public epicsTimerQueuePassive { public: timerQueuePassive ( epicsTimerQueueNotify & ); - epicsTimer & createTimer ( epicsTimerNotify & ); - void process (); - double getNextExpireDelay () const; + epicsTimer & createTimer (); + double process ( const epicsTime & currentTime ); void show ( unsigned int level ) const; void release (); timerQueue & getTimerQueue (); @@ -177,20 +174,6 @@ inline void timer::operator delete ( void *pCadaver, size_t size ) timer::freeList.release ( pCadaver, size ); } -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; - } -} - inline bool timerQueueActive::sharingOK () const { return this->okToShare; diff --git a/src/libCom/timer/timerQueue.cpp b/src/libCom/timer/timerQueue.cpp index 7ab8c28fb..a12684cee 100644 --- a/src/libCom/timer/timerQueue.cpp +++ b/src/libCom/timer/timerQueue.cpp @@ -48,39 +48,35 @@ timerQueue::~timerQueue () } } -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 () ); - +double timerQueue::process ( const epicsTime & currentTime ) +{ { epicsAutoMutex locker ( this->mutex ); if ( this->pExpireTmr ) { // if some other thread is processing the queue // (or if this is a recursive call) - return; + 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 epired tmr so that we can detect if call back + // is in progress when canceling the timer. + // this->pExpireTmr = this->timerList.first (); if ( this->pExpireTmr ) { - if ( cur >= this->pExpireTmr->exp ) { + if ( currentTime >= this->pExpireTmr->exp ) { this->timerList.remove ( *this->pExpireTmr ); - // - // Tag current epired tmr so that we can detect if call back - // is in progress when canceling the timer. - // this->pExpireTmr->curState = timer::stateLimbo; this->processThread = epicsThreadGetIdSelf (); # ifdef DEBUG @@ -88,13 +84,14 @@ void timerQueue::process () # endif } else { + double delay = this->pExpireTmr->exp - currentTime; this->pExpireTmr = 0; - debugPrintf ( ( "no activity process %f to next\n", this->pExpireTmr->exp - cur ) ); - return; + debugPrintf ( ( "no activity process %f to next\n", delay ) ); + return delay; } } else { - return; + return DBL_MAX; } } @@ -106,9 +103,10 @@ void timerQueue::process () debugPrintf ( ( "%5u expired \"%s\" with error %f sec\n", N++, typeid ( this->pExpireTmr->notify ).name (), - cur - this->pExpireTmr->exp ) ); + currentTime - this->pExpireTmr->exp ) ); - epicsTimerNotify::expireStatus expStat = this->pExpireTmr->notify.expire (); + epicsTimerNotify::expireStatus expStat = + this->pExpireTmr->pNotify->expire ( currentTime ); epicsAutoMutex locker ( this->mutex ); @@ -120,15 +118,21 @@ void timerQueue::process () // cancel() waits for this this->cancelPending = false; this->cancelBlockingEvent.signal (); + this->pExpireTmr->pNotify = 0; } // restart as nec else if ( expStat.restart() ) { - this->pExpireTmr->privateStart ( cur + expStat.expirationDelay() ); + this->pExpireTmr->privateStart ( + *this->pExpireTmr->pNotify, + currentTime + expStat.expirationDelay() ); + } + else { + this->pExpireTmr->pNotify = 0; } this->pExpireTmr = this->timerList.first (); if ( this->pExpireTmr ) { - if ( cur >= this->pExpireTmr->exp ) { + if ( currentTime >= this->pExpireTmr->exp ) { this->timerList.remove ( *this->pExpireTmr ); this->pExpireTmr->curState = timer::stateLimbo; # ifdef DEBUG @@ -136,14 +140,15 @@ void timerQueue::process () # endif } else { + double delay = this->pExpireTmr->exp - currentTime; this->pExpireTmr = 0; this->processThread = 0; - return; + return delay; } } else { this->processThread = 0; - return; + return DBL_MAX; } } } diff --git a/src/libCom/timer/timerQueueActive.cpp b/src/libCom/timer/timerQueueActive.cpp index dbabafe98..f72ea1c8e 100644 --- a/src/libCom/timer/timerQueueActive.cpp +++ b/src/libCom/timer/timerQueueActive.cpp @@ -63,22 +63,17 @@ void timerQueueActive::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 ); - } + double delay = this->queue.process ( epicsTime::getCurrent() ); + 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 & timerQueueActive::createTimer ( epicsTimerNotify & notify ) +epicsTimer & timerQueueActive::createTimer () { - timer *pTmr = new timer ( notify, this->queue ); + timer *pTmr = new timer ( this->queue ); if ( ! pTmr ) { throwWithLocation ( timer::noMemory () ); } diff --git a/src/libCom/timer/timerQueuePassive.cpp b/src/libCom/timer/timerQueuePassive.cpp index dec565992..87a63d40c 100644 --- a/src/libCom/timer/timerQueuePassive.cpp +++ b/src/libCom/timer/timerQueuePassive.cpp @@ -50,23 +50,18 @@ timerQueuePassive::timerQueuePassive ( epicsTimerQueueNotify ¬ifyIn ) : timerQueuePassive::~timerQueuePassive () {} -epicsTimer & timerQueuePassive::createTimer ( epicsTimerNotify & notifyIn ) +epicsTimer & timerQueuePassive::createTimer () { - timer *pTmr = new timer ( notifyIn, this->queue ); + timer *pTmr = new timer ( this->queue ); if ( ! pTmr ) { throwWithLocation ( timer::noMemory () ); } return *pTmr; } -void timerQueuePassive::process () +double timerQueuePassive::process ( const epicsTime & currentTime ) { - this->queue.process (); -} - -double timerQueuePassive::getNextExpireDelay () const -{ - return this->queue.delayToFirstExpire (); + return this->queue.process ( currentTime ); } void timerQueuePassive::show ( unsigned int level ) const