diff --git a/src/libCom/timer/epicsTimer.cpp b/src/libCom/timer/epicsTimer.cpp index 6acd82538..900db4e39 100644 --- a/src/libCom/timer/epicsTimer.cpp +++ b/src/libCom/timer/epicsTimer.cpp @@ -28,97 +28,175 @@ * */ -#include - #define epicsExportSharedSymbols #include "epicsTimer.h" -#if 0 -#include "tsFreeList.h" -#include "tsDLList.h" -#include "epicsMutex.h" -#include "locationException.h" -#include "errlog.h" -#endif +#include "epicsTimerPrivate.h" -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; +class epicsTimerNotifyForC : public epicsTimerNotify { public: - epicsTimerForC ( const epicsTimerJumpTable &jtIn, epicsTimerQueue &queue, void *pPrivateIn ); + epicsTimerNotifyForC ( epicsTimerCallback, void *pPrivateIn ); + void * operator new ( size_t size ); + void operator delete ( void *pCadaver, size_t size ); +protected: + virtual ~epicsTimerNotifyForC (); +private: + epicsTimerCallback pCallBack; + void * pPrivate; + expireStatus expire (); + static tsFreeList < epicsTimerNotifyForC > freeList; }; -epicsTimerForC::epicsTimerForC ( const epicsTimerJumpTable &jtIn, epicsTimerQueue &queue, void *pPrivateIn ) : - epicsTimer ( queue ), jt ( jtIn ), pPrivate ( pPrivateIn ) {} +tsFreeList < epicsTimerNotifyForC > epicsTimerNotifyForC::freeList; -void epicsTimerForC::expire () -{ - ( *this->jt.expire ) ( this->pPrivate ); +inline void * epicsTimerNotifyForC::operator new ( size_t size ) +{ + return epicsTimerNotifyForC::freeList.allocate ( size ); } -void epicsTimerForC::destroy () -{ - ( *this->jt.destroy ) ( this->pPrivate ); +inline void epicsTimerNotifyForC::operator delete ( void *pCadaver, size_t size ) +{ + epicsTimerNotifyForC::freeList.release ( pCadaver, size ); } -bool epicsTimerForC::again () const +epicsTimerNotifyForC::epicsTimerNotifyForC ( epicsTimerCallback pCBIn, void *pPrivateIn ) : + pCallBack ( pCBIn ), pPrivate ( pPrivateIn ) {} + + epicsTimerNotifyForC::~epicsTimerNotifyForC () {} + +epicsTimerNotify::expireStatus epicsTimerNotifyForC::expire () { - return ( *this->jt.again ) ( this->pPrivate ) ? true : false ; + ( *this->pCallBack ) ( this->pPrivate ); + return noRestart; } -double epicsTimerForC::delay () const +extern "C" epicsNonThreadedTimerQueueId epicsShareAPI + epicsNonThreadedTimerQueueAllocate () { - return ( *this->jt.delay ) ( this->pPrivate ); + try { + epicsNonThreadedTimerQueue &queue = + epicsNonThreadedTimerQueue::allocate (); + return &queue; + } + catch ( ... ) { + return 0; + } } -void epicsTimerForC::show ( unsigned level ) const +extern "C" void epicsShareAPI + epicsNonThreadedTimerQueueRelease ( epicsNonThreadedTimerQueueId pQueue ) { - ( *this->jt.show ) ( this->pPrivate, level ); + pQueue->release (); } -extern "C" epicsShareFunc epicsTimerId epicsShareAPI epicsTimerCreate ( - const epicsTimerJumpTable *pjtIn, epicsTimerQueueId queueIdIn, void *pPrivateIn ) +extern "C" void epicsShareAPI + epicsNonThreadedTimerQueueProcess ( epicsNonThreadedTimerQueueId pQueue ) { - assert ( pjtIn ); - assert ( queueIdIn ); - return ( epicsTimerId ) new epicsTimerForC - ( *pjtIn, *static_cast < epicsTimerQueue * > ( queueIdIn ), pPrivateIn ); + pQueue->process (); } -extern "C" epicsShareFunc void epicsShareAPI epicsTimerArm ( epicsTimerId tmrIdIn, double delay ) +extern "C" double epicsShareAPI + epicsNonThreadedTimerQueueGetDelayToNextExpire ( + epicsNonThreadedTimerQueueId pQueue ) { - epicsTimerForC *pTmr = static_cast < epicsTimerForC * > ( tmrIdIn ); - assert ( pTmr ); - pTmr->reschedule ( delay ); + return pQueue->getNextExpireDelay (); } -extern "C" epicsShareFunc void epicsShareAPI epicsTimerCancel ( epicsTimerId tmrIdIn ) +extern "C" epicsTimerId epicsShareAPI epicsNonThreadedTimerQueueCreateTimer ( + epicsNonThreadedTimerQueueId pQueue, + epicsTimerCallback pCallback, void *pArg ) +{ + try { + epicsTimerNotifyForC *pNotify = new epicsTimerNotifyForC ( pCallback, pArg ); + if ( ! pNotify ) { + throw timer::noMemory (); + } + epicsTimer &tmr = pQueue->createTimer ( *pNotify ); + return &tmr; + } + catch ( ... ) { + return 0; + } +} + +extern "C" void epicsShareAPI epicsNonThreadedTimerQueueShow ( + epicsNonThreadedTimerQueueId pQueue, unsigned int level ) +{ + pQueue->show ( level ); +} + +extern "C" epicsThreadedTimerQueueId epicsShareAPI + epicsThreadedTimerQueueCreate ( int okToShare, unsigned int threadPriority ) +{ + try { + epicsThreadedTimerQueue & queue = + epicsThreadedTimerQueue::allocate + ( okToShare ? true : false, threadPriority ); + return &queue; + } + catch ( ... ) { + return 0; + } +} + +extern "C" void epicsShareAPI epicsThreadedTimerQueueDelete ( epicsThreadedTimerQueueId pQueue ) +{ + pQueue->release (); +} + +extern "C" epicsTimerId epicsShareAPI epicsThreadedTimerQueueCreateTimer ( + epicsThreadedTimerQueueId pQueue, epicsTimerCallback pCallback, void *pArg ) +{ + try { + epicsTimerNotifyForC *pNotify = new epicsTimerNotifyForC ( pCallback, pArg ); + if ( ! pNotify ) { + throw timer::noMemory (); + } + epicsTimer &tmr = pQueue->createTimer ( *pNotify ); + return &tmr; + } + catch ( ... ) { + return 0; + } +} + +extern "C" void epicsShareAPI epicsThreadedTimerQueueShow ( + epicsThreadedTimerQueueId pQueue, unsigned int level ) +{ + pQueue->show ( level ); +} + +extern "C" void epicsShareAPI epicsTimerDestroy ( epicsTimerId pTmr ) +{ + delete pTmr; +} + +extern "C" void epicsShareAPI epicsTimerStartTime ( + epicsTimerId pTmr, const epicsTimeStamp *pTime ) +{ + pTmr->start ( *pTime ); +} + +extern "C" void epicsShareAPI epicsTimerStartDelay ( + epicsTimerId pTmr, double delaySeconds ) +{ + pTmr->start ( delaySeconds ); +} + +extern "C" void epicsShareAPI epicsTimerCancel ( epicsTimerId pTmr ) { - epicsTimerForC *pTmr = static_cast < epicsTimerForC * > ( tmrIdIn ); - assert ( pTmr ); pTmr->cancel (); } -extern "C" epicsShareFunc double epicsShareAPI epicsTimerTimeRemaining ( epicsTimerId idIn ) +extern "C" double epicsShareAPI epicsTimerGetExpireDelay ( epicsTimerId pTmr ) { - epicsTimerForC *pTmr = static_cast < epicsTimerForC * > ( idIn ); - assert ( pTmr ); - return pTmr->timeRemaining (); + return pTmr->getExpireDelay (); } -extern "C" epicsShareFunc epicsTimeStamp epicsShareAPI epicsTimerExpirationDate ( epicsTimerId idIn ) +extern "C" void epicsShareAPI epicsTimerShow ( + epicsTimerId pTmr, unsigned int level ) { - epicsTimerForC *pTmr = static_cast < epicsTimerForC * > ( idIn ); - assert ( pTmr ); - return pTmr->expirationDate (); + pTmr->show ( level ); } -#endif diff --git a/src/libCom/timer/epicsTimer.h b/src/libCom/timer/epicsTimer.h index 7b4865577..c490554de 100644 --- a/src/libCom/timer/epicsTimer.h +++ b/src/libCom/timer/epicsTimer.h @@ -39,7 +39,7 @@ public: virtual void show ( unsigned int level ) const; }; -class epicsShareClass epicsTimer { +struct epicsShareClass epicsTimer { public: virtual ~epicsTimer () = 0; virtual void start ( const epicsTime & ) = 0; @@ -49,27 +49,27 @@ public: virtual void show ( unsigned int level ) const = 0; }; -class epicsShareClass epicsTimerQueueThreaded { +struct epicsShareClass epicsThreadedTimerQueue { public: - static epicsTimerQueueThreaded & create ( + static epicsThreadedTimerQueue & allocate ( bool okToShare, int threadPriority = epicsThreadPriorityMin + 10 ); + virtual void release () = 0; virtual epicsTimer & createTimer ( epicsTimerNotify & ) = 0; virtual void show ( unsigned int level ) const = 0; - virtual void release () = 0; protected: - virtual ~epicsTimerQueueThreaded () = 0; + virtual ~epicsThreadedTimerQueue () = 0; }; -class epicsShareClass epicsTimerQueueNonThreaded { +struct epicsShareClass epicsNonThreadedTimerQueue { public: - static epicsTimerQueueNonThreaded & create (); + static epicsNonThreadedTimerQueue & allocate (); + virtual void release () = 0; virtual epicsTimer & createTimer ( epicsTimerNotify & ) = 0; virtual void process () = 0; virtual double getNextExpireDelay () const = 0; virtual void show ( unsigned int level ) const = 0; - virtual void release () = 0; protected: - virtual ~epicsTimerQueueNonThreaded () = 0; + virtual ~epicsNonThreadedTimerQueue () = 0; }; inline epicsTimerNotify::expireStatus::expireStatus ( restart_t restart ) : @@ -96,41 +96,50 @@ inline double epicsTimerNotify::expireStatus::expirationDelay () const return this->delay; } - extern "C" { #endif /* __cplusplus */ -typedef void *epicsTimerQueueId; - -epicsShareFunc epicsTimerQueueId* epicsShareAPI - epicsTimerQueueCreateNonThreaded (); -epicsShareFunc epicsTimerQueueId* epicsShareAPI - epicsTimerQueueCreateThreaded ( unsigned int threadPriority, int okToShare ); -epicsShareFunc void epicsShareAPI epicsTimerQueueDelete ( epicsTimerQueueId ); - -epicsShareFunc void epicsShareAPI epicsTimerQueueProcess ( epicsTimerQueueId ); -epicsShareFunc int epicsShareAPI epicsTimerQueueGetExpireTime ( - epicsTimerQueueId, epicsTimeStamp *time ); -epicsShareFunc void epicsShareAPI epicsTimerQueueShow ( - epicsTimerQueueId id, unsigned int level ); - -typedef void *epicsTimerId; +typedef struct epicsNonThreadedTimerQueue * epicsNonThreadedTimerQueueId; +typedef struct epicsThreadedTimerQueue * epicsThreadedTimerQueueId; +typedef struct epicsTimer * epicsTimerId; typedef void ( *epicsTimerCallback ) ( void * ); -epicsShareFunc epicsTimerId epicsShareAPI epicsTimerCreate ( - epicsTimerQueueId queueid,epicsTimerCallback callback, void *arg ); -epicsShareFunc void epicsShareAPI epicsTimerDestroy ( epicsTimerId id ); +epicsShareFunc epicsNonThreadedTimerQueueId epicsShareAPI + epicsNonThreadedTimerQueueAttach (); +epicsShareFunc void epicsShareAPI + epicsNonThreadedTimerQueueRelease ( epicsNonThreadedTimerQueueId ); +epicsShareFunc void epicsShareAPI + epicsNonThreadedTimerQueueProcess ( epicsNonThreadedTimerQueueId ); +epicsShareFunc double epicsShareAPI + epicsNonThreadedTimerQueueGetDelayToNextExpire ( + epicsNonThreadedTimerQueueId ); +epicsShareFunc epicsTimerId epicsShareAPI epicsNonThreadedTimerQueueCreateTimer ( + epicsNonThreadedTimerQueueId queueid, epicsTimerCallback pCallback, void *pArg ); +epicsShareFunc void epicsShareAPI epicsNonThreadedTimerQueueShow ( + epicsNonThreadedTimerQueueId id, unsigned int level ); -epicsShareFunc void epicsShareAPI epicsTimerStartTime ( - epicsTimerId id,epicsTimeStamp *time ); -epicsShareFunc void epicsShareAPI epicsTimerStartDelay ( - epicsTimerId id,double delaySeconds ); -epicsShareFunc void epicsShareAPI epicsTimerCancel ( epicsTimerId id ); -/* GetExpireTime returns (0,1) if time (is not, is) given a value */ -epicsShareFunc int epicsShareAPI epicsTimerGetExpireTime ( - epicsTimerId id, epicsTimeStamp *time); -epicsShareFunc void epicsShareAPI epicsTimerShow ( - epicsTimerId id, unsigned int level ); +epicsShareFunc epicsThreadedTimerQueueId epicsShareAPI + epicsThreadedTimerQueueAttach ( int okToShare, unsigned int threadPriority ); +epicsShareFunc void epicsShareAPI + epicsThreadedTimerQueueRelease ( epicsThreadedTimerQueueId ); +epicsShareFunc epicsTimerId epicsShareAPI + epicsThreadedTimerQueueCreateTimer ( epicsThreadedTimerQueueId queueid, + epicsTimerCallback callback, void *arg ); +epicsShareFunc void epicsShareAPI + epicsThreadedTimerQueueShow ( epicsThreadedTimerQueueId id, unsigned int level ); + +epicsShareFunc void epicsShareAPI + epicsTimerDestroy ( epicsTimerId id ); +epicsShareFunc void epicsShareAPI + epicsTimerStartTime ( epicsTimerId id, const epicsTimeStamp *pTime ); +epicsShareFunc void epicsShareAPI + epicsTimerStartDelay ( epicsTimerId id, double delaySeconds ); +epicsShareFunc void epicsShareAPI + epicsTimerCancel ( epicsTimerId id ); +epicsShareFunc double epicsShareAPI + epicsTimerGetExpireDelay ( epicsTimerId id ); +epicsShareFunc void epicsShareAPI + epicsTimerShow ( epicsTimerId id, unsigned int level ); #ifdef __cplusplus } diff --git a/src/libCom/timer/epicsTimerPrivate.h b/src/libCom/timer/epicsTimerPrivate.h index 318cb3b9c..322b9a787 100644 --- a/src/libCom/timer/epicsTimerPrivate.h +++ b/src/libCom/timer/epicsTimerPrivate.h @@ -100,7 +100,7 @@ private: friend class timerQueueThreadedMgr; }; -class timerQueueThreaded : public epicsTimerQueueThreaded, +class timerQueueThreaded : public epicsThreadedTimerQueue, public epicsThreadRunable, public timerQueueNotify, public timerQueueThreadedMgrPrivate, public tsDLNode < timerQueueThreaded > { @@ -131,7 +131,7 @@ private: class timerQueueThreadedMgr { public: ~timerQueueThreadedMgr (); - timerQueueThreaded & create ( bool okToShare, + timerQueueThreaded & allocate ( bool okToShare, int threadPriority = epicsThreadPriorityMin + 10 ); void release ( timerQueueThreaded & ); private: @@ -139,6 +139,25 @@ private: tsDLList < timerQueueThreaded > sharedQueueList; }; +class timerQueueNonThreaded : public epicsNonThreadedTimerQueue, + public timerQueueNotify { +public: + timerQueueNonThreaded (); + ~timerQueueNonThreaded (); + epicsTimer & createTimer ( epicsTimerNotify & ); + void process (); + double getNextExpireDelay () const; + void reschedule (); + void show ( unsigned int level ) const; + void release (); + static timerQueueNonThreaded & allocate (); +private: + timerQueue queue; + static epicsMutex mutex; + static timerQueueNonThreaded *pQueue; + static unsigned useCount; +}; + inline void * timer::operator new ( size_t size ) { return timer::freeList.allocate ( size ); diff --git a/src/libCom/timer/timerQueueNonThreaded.cpp b/src/libCom/timer/timerQueueNonThreaded.cpp new file mode 100644 index 000000000..787f632fc --- /dev/null +++ b/src/libCom/timer/timerQueueNonThreaded.cpp @@ -0,0 +1,125 @@ +/* + * $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" + +unsigned timerQueueNonThreaded::useCount; +timerQueueNonThreaded * timerQueueNonThreaded::pQueue; +epicsMutex timerQueueNonThreaded::mutex; + +epicsNonThreadedTimerQueue::~epicsNonThreadedTimerQueue () {} + +epicsNonThreadedTimerQueue &epicsNonThreadedTimerQueue::allocate () +{ + return epicsNonThreadedTimerQueue::allocate (); +} + +timerQueueNonThreaded &timerQueueNonThreaded::allocate () +{ + epicsAutoMutex locker ( timerQueueNonThreaded::mutex ); + if ( timerQueueNonThreaded::pQueue ) { + timerQueueNonThreaded::useCount++; + return *timerQueueNonThreaded::pQueue; + } + else { + timerQueueNonThreaded::pQueue = new timerQueueNonThreaded (); + if ( ! timerQueueNonThreaded::pQueue ) { + throw timer::noMemory (); + } + timerQueueNonThreaded::useCount = 1u; + return *timerQueueNonThreaded::pQueue; + } +} + +timerQueueNonThreaded::timerQueueNonThreaded () : + queue ( *this ) +{ +} + +timerQueueNonThreaded::~timerQueueNonThreaded () +{ + +} + +void timerQueueNonThreaded::release () +{ + epicsAutoMutex locker ( timerQueueNonThreaded::mutex ); + assert ( timerQueueNonThreaded::useCount >= 1u ); + timerQueueNonThreaded::useCount--; + if ( timerQueueNonThreaded::useCount == 0u ) { + delete timerQueueNonThreaded::pQueue; + timerQueueNonThreaded::pQueue = 0; + } +} + +epicsTimer & timerQueueNonThreaded::createTimer ( epicsTimerNotify & notify ) +{ + timer *pTmr = new timer ( notify, this->queue ); + if ( ! pTmr ) { + throwWithLocation ( timer::noMemory () ); + } + return *pTmr; +} + +void timerQueueNonThreaded::reschedule () +{ + // + // Only useful in a multi-threaded program ... + // + // If a select() based file descriptor manager was waiting + // in select () this routine should force it to wake up + // and rescheduale its delay, but since file descriptor managers + // typically are only be used in single-threaded programs, and + // in fact the file descriptor manager currently supplied + // with EPICS is not thread safe, then perhaps + // its not worth the effort to tightly integrate this with + // the file descriptor manager so that this can be implemented. + // +} + +void timerQueueNonThreaded::process () +{ + this->queue.process (); +} + +double timerQueueNonThreaded::getNextExpireDelay () const +{ + return this->queue.delayToFirstExpire (); +} + +void timerQueueNonThreaded::show ( unsigned int level ) const +{ + printf ( "EPICS non-threaded timer queue at %p\n", + static_cast ( this ) ); + if ( level >=1u ) { + this->queue.show ( level - 1u ); + } +} diff --git a/src/libCom/timer/timerQueueThreaded.cpp b/src/libCom/timer/timerQueueThreaded.cpp index 71bab0113..f45001ef2 100644 --- a/src/libCom/timer/timerQueueThreaded.cpp +++ b/src/libCom/timer/timerQueueThreaded.cpp @@ -33,11 +33,11 @@ static timerQueueThreadedMgr queueMgr; -epicsTimerQueueThreaded::~epicsTimerQueueThreaded () {} +epicsThreadedTimerQueue::~epicsThreadedTimerQueue () {} -epicsTimerQueueThreaded &epicsTimerQueueThreaded::create ( bool okToShare, int threadPriority ) +epicsThreadedTimerQueue &epicsThreadedTimerQueue::allocate ( bool okToShare, int threadPriority ) { - return queueMgr.create ( okToShare, threadPriority ); + return queueMgr.allocate ( okToShare, threadPriority ); } tsFreeList < class timerQueueThreaded, 0x8 > timerQueueThreaded::freeList; @@ -45,7 +45,7 @@ tsFreeList < class timerQueueThreaded, 0x8 > timerQueueThreaded::freeList; timerQueueThreaded::timerQueueThreaded ( bool okToShareIn, unsigned priority ) : queue ( *this ), thread ( *this, "epicsTimerQueue", epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ), - okToShare (okToShareIn), exitFlag ( false ), terminateFlag ( false ) + okToShare ( okToShareIn ), exitFlag ( false ), terminateFlag ( false ) { this->thread.start (); } diff --git a/src/libCom/timer/timerQueueThreadedMgr.cpp b/src/libCom/timer/timerQueueThreadedMgr.cpp index 916d7de74..9fd7e893d 100644 --- a/src/libCom/timer/timerQueueThreadedMgr.cpp +++ b/src/libCom/timer/timerQueueThreadedMgr.cpp @@ -38,7 +38,7 @@ timerQueueThreadedMgr::~timerQueueThreadedMgr () epicsAutoMutex locker ( this->mutex ); } -timerQueueThreaded & timerQueueThreadedMgr::create ( +timerQueueThreaded & timerQueueThreadedMgr::allocate ( bool okToShare, int threadPriority ) { epicsAutoMutex locker ( this->mutex );