Move all under modules/libcom
This commit is contained in:
17
modules/libcom/src/timer/Makefile
Normal file
17
modules/libcom/src/timer/Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# This is a Makefile fragment, see src/libCom/Makefile.
|
||||
|
||||
SRC_DIRS += $(LIBCOM)/timer
|
||||
INC += epicsTimer.h
|
||||
Com_SRCS += epicsTimer.cpp
|
||||
Com_SRCS += timer.cpp
|
||||
Com_SRCS += timerQueue.cpp
|
||||
Com_SRCS += timerQueueActive.cpp
|
||||
Com_SRCS += timerQueueActiveMgr.cpp
|
||||
Com_SRCS += timerQueuePassive.cpp
|
||||
276
modules/libcom/src/timer/epicsTimer.cpp
Normal file
276
modules/libcom/src/timer/epicsTimer.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsMath.h"
|
||||
#include "epicsTimer.h"
|
||||
#include "epicsGuard.h"
|
||||
#include "timerPrivate.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( push )
|
||||
# pragma warning ( disable:4660 )
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( pop )
|
||||
#endif
|
||||
|
||||
template class tsFreeList < epicsTimerForC, 0x20 >;
|
||||
|
||||
epicsTimer::~epicsTimer () {}
|
||||
|
||||
epicsTimerQueueNotify::~epicsTimerQueueNotify () {}
|
||||
|
||||
epicsTimerNotify::~epicsTimerNotify () {}
|
||||
|
||||
void epicsTimerNotify::show ( unsigned /* level */ ) const {}
|
||||
|
||||
epicsTimerForC::epicsTimerForC ( timerQueue &queue, epicsTimerCallback pCBIn, void *pPrivateIn ) :
|
||||
timer ( queue ), pCallBack ( pCBIn ), pPrivate ( pPrivateIn )
|
||||
{
|
||||
}
|
||||
|
||||
epicsTimerForC::~epicsTimerForC ()
|
||||
{
|
||||
}
|
||||
|
||||
void epicsTimerForC::destroy ()
|
||||
{
|
||||
timerQueue & queueTmp = this->queue;
|
||||
this->~epicsTimerForC ();
|
||||
queueTmp.timerForCFreeList.release ( this );
|
||||
}
|
||||
|
||||
epicsTimerNotify::expireStatus epicsTimerForC::expire ( const epicsTime & )
|
||||
{
|
||||
( *this->pCallBack ) ( this->pPrivate );
|
||||
return noRestart;
|
||||
}
|
||||
|
||||
epicsTimerQueueActiveForC ::
|
||||
epicsTimerQueueActiveForC ( RefMgr & refMgr,
|
||||
bool okToShare, unsigned priority ) :
|
||||
timerQueueActive ( refMgr, okToShare, priority )
|
||||
{
|
||||
timerQueueActive::start();
|
||||
}
|
||||
|
||||
epicsTimerQueueActiveForC::~epicsTimerQueueActiveForC ()
|
||||
{
|
||||
}
|
||||
|
||||
void epicsTimerQueueActiveForC::release ()
|
||||
{
|
||||
_refMgr->release ( *this );
|
||||
}
|
||||
|
||||
epicsTimerQueuePassiveForC::epicsTimerQueuePassiveForC (
|
||||
epicsTimerQueueNotifyReschedule pRescheduleCallbackIn,
|
||||
epicsTimerQueueNotifyQuantum pSleepQuantumCallbackIn,
|
||||
void * pPrivateIn ) :
|
||||
timerQueuePassive ( * static_cast < epicsTimerQueueNotify * > ( this ) ),
|
||||
pRescheduleCallback ( pRescheduleCallbackIn ),
|
||||
pSleepQuantumCallback ( pSleepQuantumCallbackIn ),
|
||||
pPrivate ( pPrivateIn )
|
||||
{
|
||||
}
|
||||
|
||||
epicsTimerQueuePassiveForC::~epicsTimerQueuePassiveForC ()
|
||||
{
|
||||
}
|
||||
|
||||
void epicsTimerQueuePassiveForC::reschedule ()
|
||||
{
|
||||
(*this->pRescheduleCallback) ( this->pPrivate );
|
||||
}
|
||||
|
||||
double epicsTimerQueuePassiveForC::quantum ()
|
||||
{
|
||||
return (*this->pSleepQuantumCallback) ( this->pPrivate );
|
||||
}
|
||||
|
||||
void epicsTimerQueuePassiveForC::destroy ()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
epicsShareFunc epicsTimerNotify::expireStatus::expireStatus ( restart_t restart ) :
|
||||
delay ( - DBL_MAX )
|
||||
{
|
||||
if ( restart != noRestart ) {
|
||||
throw std::logic_error
|
||||
( "timer restart was requested without specifying a delay?" );
|
||||
}
|
||||
}
|
||||
|
||||
epicsShareFunc epicsTimerNotify::expireStatus::expireStatus
|
||||
( restart_t restartIn, const double & expireDelaySec ) :
|
||||
delay ( expireDelaySec )
|
||||
{
|
||||
if ( restartIn != epicsTimerNotify::restart ) {
|
||||
throw std::logic_error
|
||||
( "no timer restart was requested, but a delay was specified?" );
|
||||
}
|
||||
if ( this->delay < 0.0 || !finite(this->delay) ) {
|
||||
throw std::logic_error
|
||||
( "timer restart was requested, but a negative delay was specified?" );
|
||||
}
|
||||
}
|
||||
|
||||
epicsShareFunc bool epicsTimerNotify::expireStatus::restart () const
|
||||
{
|
||||
return this->delay >= 0.0 && finite(this->delay);
|
||||
}
|
||||
|
||||
epicsShareFunc double epicsTimerNotify::expireStatus::expirationDelay () const
|
||||
{
|
||||
if ( this->delay < 0.0 || !finite(this->delay) ) {
|
||||
throw std::logic_error
|
||||
( "no timer restart was requested, but you are asking for a restart delay?" );
|
||||
}
|
||||
return this->delay;
|
||||
}
|
||||
|
||||
extern "C" epicsTimerQueuePassiveId epicsShareAPI
|
||||
epicsTimerQueuePassiveCreate (
|
||||
epicsTimerQueueNotifyReschedule pRescheduleCallbackIn,
|
||||
epicsTimerQueueNotifyQuantum pSleepQuantumCallbackIn,
|
||||
void * pPrivateIn )
|
||||
{
|
||||
try {
|
||||
return new epicsTimerQueuePassiveForC (
|
||||
pRescheduleCallbackIn,
|
||||
pSleepQuantumCallbackIn,
|
||||
pPrivateIn );
|
||||
}
|
||||
catch ( ... ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void epicsShareAPI
|
||||
epicsTimerQueuePassiveDestroy ( epicsTimerQueuePassiveId pQueue )
|
||||
{
|
||||
pQueue->destroy ();
|
||||
}
|
||||
|
||||
extern "C" double epicsShareAPI
|
||||
epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId pQueue )
|
||||
{
|
||||
try {
|
||||
return pQueue->process ( epicsTime::getCurrent() );
|
||||
}
|
||||
catch ( ... ) {
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" epicsTimerId epicsShareAPI epicsTimerQueuePassiveCreateTimer (
|
||||
epicsTimerQueuePassiveId pQueue, epicsTimerCallback pCallback, void *pArg )
|
||||
{
|
||||
try {
|
||||
return & pQueue->createTimerForC ( pCallback, pArg );
|
||||
}
|
||||
catch ( ... ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" epicsShareFunc void epicsShareAPI epicsTimerQueuePassiveDestroyTimer (
|
||||
epicsTimerQueuePassiveId /* pQueue */, epicsTimerId pTmr )
|
||||
{
|
||||
pTmr->destroy ();
|
||||
}
|
||||
|
||||
extern "C" void epicsShareAPI epicsTimerQueuePassiveShow (
|
||||
epicsTimerQueuePassiveId pQueue, unsigned int level )
|
||||
{
|
||||
pQueue->show ( level );
|
||||
}
|
||||
|
||||
extern "C" epicsTimerQueueId epicsShareAPI
|
||||
epicsTimerQueueAllocate ( int okToShare, unsigned int threadPriority )
|
||||
{
|
||||
try {
|
||||
epicsSingleton < timerQueueActiveMgr > :: reference ref =
|
||||
timerQueueMgrEPICS.getReference ();
|
||||
epicsTimerQueueActiveForC & tmr =
|
||||
ref->allocate ( ref, okToShare ? true : false, threadPriority );
|
||||
return &tmr;
|
||||
}
|
||||
catch ( ... ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void epicsShareAPI epicsTimerQueueRelease ( epicsTimerQueueId pQueue )
|
||||
{
|
||||
pQueue->release ();
|
||||
}
|
||||
|
||||
extern "C" epicsTimerId epicsShareAPI epicsTimerQueueCreateTimer (
|
||||
epicsTimerQueueId pQueue, epicsTimerCallback pCallback, void *pArg )
|
||||
{
|
||||
try {
|
||||
return & pQueue->createTimerForC ( pCallback, pArg );
|
||||
}
|
||||
catch ( ... ) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void epicsShareAPI epicsTimerQueueShow (
|
||||
epicsTimerQueueId pQueue, unsigned int level )
|
||||
{
|
||||
pQueue->show ( level );
|
||||
}
|
||||
|
||||
extern "C" void epicsShareAPI epicsTimerQueueDestroyTimer (
|
||||
epicsTimerQueueId /* pQueue */, epicsTimerId pTmr )
|
||||
{
|
||||
pTmr->destroy ();
|
||||
}
|
||||
|
||||
extern "C" void epicsShareAPI epicsTimerStartTime (
|
||||
epicsTimerId pTmr, const epicsTimeStamp *pTime )
|
||||
{
|
||||
pTmr->start ( *pTmr, *pTime );
|
||||
}
|
||||
|
||||
extern "C" void epicsShareAPI epicsTimerStartDelay (
|
||||
epicsTimerId pTmr, double delaySeconds )
|
||||
{
|
||||
pTmr->start ( *pTmr, delaySeconds );
|
||||
}
|
||||
|
||||
extern "C" void epicsShareAPI epicsTimerCancel ( epicsTimerId pTmr )
|
||||
{
|
||||
pTmr->cancel ();
|
||||
}
|
||||
|
||||
extern "C" double epicsShareAPI epicsTimerGetExpireDelay ( epicsTimerId pTmr )
|
||||
{
|
||||
return pTmr->getExpireDelay ();
|
||||
}
|
||||
|
||||
extern "C" void epicsShareAPI epicsTimerShow (
|
||||
epicsTimerId pTmr, unsigned int level )
|
||||
{
|
||||
pTmr->timer::show ( level );
|
||||
}
|
||||
|
||||
185
modules/libcom/src/timer/epicsTimer.h
Normal file
185
modules/libcom/src/timer/epicsTimer.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* epicsTimer.h */
|
||||
|
||||
/* Authors: Marty Kraimer, Jeff Hill */
|
||||
|
||||
#ifndef epicsTimerH
|
||||
#define epicsTimerH
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "epicsTime.h"
|
||||
#include "epicsThread.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/*
|
||||
* Notes:
|
||||
* 1) epicsTimer does not hold its lock when calling callbacks.
|
||||
*/
|
||||
|
||||
/* code using a timer must implement epicsTimerNotify */
|
||||
class epicsShareClass epicsTimerNotify {
|
||||
public:
|
||||
enum restart_t { noRestart, restart };
|
||||
class expireStatus {
|
||||
public:
|
||||
epicsShareFunc expireStatus ( restart_t );
|
||||
epicsShareFunc expireStatus ( restart_t, const double & expireDelaySec );
|
||||
epicsShareFunc bool restart () const;
|
||||
epicsShareFunc double expirationDelay () const;
|
||||
private:
|
||||
double delay;
|
||||
};
|
||||
|
||||
virtual ~epicsTimerNotify () = 0;
|
||||
/* return "noRestart" or "expireStatus ( restart, 30.0 )" */
|
||||
virtual expireStatus expire ( const epicsTime & currentTime ) = 0;
|
||||
virtual void show ( unsigned int level ) const;
|
||||
};
|
||||
|
||||
class epicsShareClass epicsTimer {
|
||||
public:
|
||||
/* calls cancel (see warning below) and then destroys the timer */
|
||||
virtual void destroy () = 0;
|
||||
virtual void start ( epicsTimerNotify &, const epicsTime & ) = 0;
|
||||
virtual void start ( epicsTimerNotify &, double delaySeconds ) = 0;
|
||||
/* WARNING: A deadlock will occur if you hold a lock while
|
||||
* calling this function that you also take within the timer
|
||||
* expiration callback.
|
||||
*/
|
||||
virtual void cancel () = 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;
|
||||
protected:
|
||||
virtual ~epicsTimer () = 0; /* protected => delete() must not be called */
|
||||
};
|
||||
|
||||
class epicsTimerQueue {
|
||||
public:
|
||||
virtual epicsTimer & createTimer () = 0;
|
||||
virtual void show ( unsigned int level ) const = 0;
|
||||
protected:
|
||||
epicsShareFunc virtual ~epicsTimerQueue () = 0;
|
||||
};
|
||||
|
||||
class epicsTimerQueueActive
|
||||
: public epicsTimerQueue {
|
||||
public:
|
||||
static epicsShareFunc epicsTimerQueueActive & allocate (
|
||||
bool okToShare, unsigned threadPriority = epicsThreadPriorityMin + 10 );
|
||||
virtual void release () = 0;
|
||||
protected:
|
||||
epicsShareFunc virtual ~epicsTimerQueueActive () = 0;
|
||||
};
|
||||
|
||||
class epicsTimerQueueNotify {
|
||||
public:
|
||||
/* called when a new timer is inserted into the queue and the */
|
||||
/* delay to the next expire has changed */
|
||||
virtual void reschedule () = 0;
|
||||
/* if there is a quantum in the scheduling of timer intervals */
|
||||
/* return this quantum in seconds. If unknown then return zero. */
|
||||
virtual double quantum () = 0;
|
||||
protected:
|
||||
epicsShareFunc virtual ~epicsTimerQueueNotify () = 0;
|
||||
};
|
||||
|
||||
class epicsTimerQueuePassive
|
||||
: public epicsTimerQueue {
|
||||
public:
|
||||
static epicsShareFunc epicsTimerQueuePassive & create ( epicsTimerQueueNotify & );
|
||||
epicsShareFunc virtual ~epicsTimerQueuePassive () = 0; /* ok to call delete */
|
||||
virtual double process ( const epicsTime & currentTime ) = 0; /* returns delay to next expire */
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
return - DBL_MAX;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct epicsTimerForC * epicsTimerId;
|
||||
typedef void ( *epicsTimerCallback ) ( void *pPrivate );
|
||||
|
||||
/* thread managed timer queue */
|
||||
typedef struct epicsTimerQueueActiveForC * epicsTimerQueueId;
|
||||
epicsShareFunc epicsTimerQueueId epicsShareAPI
|
||||
epicsTimerQueueAllocate ( int okToShare, unsigned int threadPriority );
|
||||
epicsShareFunc void epicsShareAPI
|
||||
epicsTimerQueueRelease ( epicsTimerQueueId );
|
||||
epicsShareFunc epicsTimerId epicsShareAPI
|
||||
epicsTimerQueueCreateTimer ( epicsTimerQueueId queueid,
|
||||
epicsTimerCallback callback, void *arg );
|
||||
epicsShareFunc void epicsShareAPI
|
||||
epicsTimerQueueDestroyTimer ( epicsTimerQueueId queueid, epicsTimerId id );
|
||||
epicsShareFunc void epicsShareAPI
|
||||
epicsTimerQueueShow ( epicsTimerQueueId id, unsigned int level );
|
||||
|
||||
/* passive timer queue */
|
||||
typedef struct epicsTimerQueuePassiveForC * epicsTimerQueuePassiveId;
|
||||
typedef void ( * epicsTimerQueueNotifyReschedule ) ( void * pPrivate );
|
||||
typedef double ( * epicsTimerQueueNotifyQuantum ) ( void * pPrivate );
|
||||
epicsShareFunc epicsTimerQueuePassiveId epicsShareAPI
|
||||
epicsTimerQueuePassiveCreate ( epicsTimerQueueNotifyReschedule,
|
||||
epicsTimerQueueNotifyQuantum, void *pPrivate );
|
||||
epicsShareFunc void epicsShareAPI
|
||||
epicsTimerQueuePassiveDestroy ( epicsTimerQueuePassiveId );
|
||||
epicsShareFunc epicsTimerId epicsShareAPI
|
||||
epicsTimerQueuePassiveCreateTimer (
|
||||
epicsTimerQueuePassiveId queueid, epicsTimerCallback pCallback, void *pArg );
|
||||
epicsShareFunc void epicsShareAPI
|
||||
epicsTimerQueuePassiveDestroyTimer ( epicsTimerQueuePassiveId queueid, epicsTimerId id );
|
||||
epicsShareFunc double epicsShareAPI
|
||||
epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId );
|
||||
epicsShareFunc void epicsShareAPI
|
||||
epicsTimerQueuePassiveShow ( epicsTimerQueuePassiveId id, unsigned int level );
|
||||
|
||||
/* timer */
|
||||
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
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* epicsTimerH */
|
||||
243
modules/libcom/src/timer/timer.cpp
Normal file
243
modules/libcom/src/timer/timer.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <typeinfo>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsGuard.h"
|
||||
#include "timerPrivate.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( push )
|
||||
# pragma warning ( disable:4660 )
|
||||
#endif
|
||||
|
||||
template class tsFreeList < timer, 0x20 >;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( pop )
|
||||
#endif
|
||||
|
||||
timer::timer ( timerQueue & queueIn ) :
|
||||
queue ( queueIn ), curState ( stateLimbo ), pNotify ( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
timer::~timer ()
|
||||
{
|
||||
this->cancel ();
|
||||
}
|
||||
|
||||
void timer::destroy ()
|
||||
{
|
||||
timerQueue & queueTmp = this->queue;
|
||||
this->~timer ();
|
||||
queueTmp.timerFreeList.release ( this );
|
||||
}
|
||||
|
||||
void timer::start ( epicsTimerNotify & notify, double delaySeconds )
|
||||
{
|
||||
this->start ( notify, epicsTime::getCurrent () + delaySeconds );
|
||||
}
|
||||
|
||||
void timer::start ( epicsTimerNotify & notify, const epicsTime & expire )
|
||||
{
|
||||
epicsGuard < epicsMutex > locker ( this->queue.mutex );
|
||||
this->privateStart ( notify, expire );
|
||||
}
|
||||
|
||||
void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire )
|
||||
{
|
||||
this->pNotify = & notify;
|
||||
this->exp = expire - ( this->queue.notify.quantum () / 2.0 );
|
||||
|
||||
bool reschedualNeeded = false;
|
||||
if ( this->curState == stateActive ) {
|
||||
// above expire time and notify will override any restart parameters
|
||||
// that may be returned from the timer expire callback
|
||||
return;
|
||||
}
|
||||
else if ( this->curState == statePending ) {
|
||||
this->queue.timerList.remove ( *this );
|
||||
if ( this->queue.timerList.first() == this &&
|
||||
this->queue.timerList.count() > 0 ) {
|
||||
reschedualNeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
# 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 ????
|
||||
//
|
||||
tsDLIter < timer > pTmr = this->queue.timerList.lastIter ();
|
||||
while ( true ) {
|
||||
if ( ! pTmr.valid () ) {
|
||||
//
|
||||
// add to the beginning of the list
|
||||
//
|
||||
this->queue.timerList.push ( *this );
|
||||
reschedualNeeded = true;
|
||||
break;
|
||||
}
|
||||
if ( pTmr->exp <= this->exp ) {
|
||||
//
|
||||
// add after the item found that expires earlier
|
||||
//
|
||||
this->queue.timerList.insertAfter ( *this, *pTmr );
|
||||
break;
|
||||
}
|
||||
# ifdef DEBUG
|
||||
preemptCount++;
|
||||
# endif
|
||||
--pTmr;
|
||||
}
|
||||
|
||||
this->curState = timer::statePending;
|
||||
|
||||
if ( reschedualNeeded ) {
|
||||
this->queue.notify.reschedule ();
|
||||
}
|
||||
|
||||
# if defined(DEBUG) && 0
|
||||
this->show ( 10u );
|
||||
this->queue.show ( 10u );
|
||||
# endif
|
||||
|
||||
debugPrintf ( ("Start of \"%s\" with delay %f at %p preempting %u\n",
|
||||
typeid ( this->notify ).name (),
|
||||
expire - epicsTime::getCurrent (),
|
||||
this, preemptCount ) );
|
||||
}
|
||||
|
||||
void timer::cancel ()
|
||||
{
|
||||
bool reschedual = false;
|
||||
bool wakeupCancelBlockingThreads = false;
|
||||
{
|
||||
epicsGuard < epicsMutex > locker ( this->queue.mutex );
|
||||
this->pNotify = 0;
|
||||
if ( this->curState == statePending ) {
|
||||
this->queue.timerList.remove ( *this );
|
||||
this->curState = stateLimbo;
|
||||
if ( this->queue.timerList.first() == this &&
|
||||
this->queue.timerList.count() > 0 ) {
|
||||
reschedual = true;
|
||||
}
|
||||
}
|
||||
else if ( this->curState == stateActive ) {
|
||||
this->queue.cancelPending = true;
|
||||
this->curState = timer::stateLimbo;
|
||||
if ( this->queue.processThread != epicsThreadGetIdSelf() ) {
|
||||
// make certain timer expire() does not run after cancel () returns,
|
||||
// but dont require that lock is applied while calling expire()
|
||||
while ( this->queue.cancelPending &&
|
||||
this->queue.pExpireTmr == this ) {
|
||||
epicsGuardRelease < epicsMutex > autoRelease ( locker );
|
||||
this->queue.cancelBlockingEvent.wait ();
|
||||
}
|
||||
// in case other threads are waiting
|
||||
wakeupCancelBlockingThreads = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( reschedual ) {
|
||||
this->queue.notify.reschedule ();
|
||||
}
|
||||
if ( wakeupCancelBlockingThreads ) {
|
||||
this->queue.cancelBlockingEvent.signal ();
|
||||
}
|
||||
}
|
||||
|
||||
epicsTimer::expireInfo timer::getExpireInfo () const
|
||||
{
|
||||
// taking a lock here guarantees that users will not
|
||||
// see brief intervals when a timer isnt active because
|
||||
// it is is canceled when start is called
|
||||
epicsGuard < epicsMutex > locker ( this->queue.mutex );
|
||||
if ( this->curState == statePending || this->curState == stateActive ) {
|
||||
return expireInfo ( true, this->exp );
|
||||
}
|
||||
return expireInfo ( false, epicsTime() );
|
||||
}
|
||||
|
||||
void timer::show ( unsigned int level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > locker ( this->queue.mutex );
|
||||
double delay;
|
||||
if ( this->curState == statePending || this->curState == stateActive ) {
|
||||
try {
|
||||
delay = this->exp - epicsTime::getCurrent();
|
||||
}
|
||||
catch ( ... ) {
|
||||
delay = - DBL_MAX;
|
||||
}
|
||||
}
|
||||
else {
|
||||
delay = -DBL_MAX;
|
||||
}
|
||||
const char *pStateName;
|
||||
if ( this->curState == statePending ) {
|
||||
pStateName = "pending";
|
||||
}
|
||||
else if ( this->curState == stateActive ) {
|
||||
pStateName = "active";
|
||||
}
|
||||
else if ( this->curState == stateLimbo ) {
|
||||
pStateName = "limbo";
|
||||
}
|
||||
else {
|
||||
pStateName = "corrupt";
|
||||
}
|
||||
printf ( "timer, state = %s, delay = %f\n",
|
||||
pStateName, delay );
|
||||
if ( level >= 1u && this->pNotify ) {
|
||||
this->pNotify->show ( level - 1u );
|
||||
}
|
||||
}
|
||||
|
||||
void timer::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
void epicsTimerForC::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
277
modules/libcom/src/timer/timerPrivate.h
Normal file
277
modules/libcom/src/timer/timerPrivate.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef epicsTimerPrivate_h
|
||||
#define epicsTimerPrivate_h
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
#include "tsFreeList.h"
|
||||
#include "epicsSingleton.h"
|
||||
#include "tsDLList.h"
|
||||
#include "epicsTimer.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
# define debugPrintf(ARGSINPAREN) printf ARGSINPAREN
|
||||
#else
|
||||
# define debugPrintf(ARGSINPAREN)
|
||||
#endif
|
||||
|
||||
template < class T > class epicsGuard;
|
||||
|
||||
class timer : public epicsTimer, public tsDLNode < timer > {
|
||||
public:
|
||||
void destroy ();
|
||||
void start ( class epicsTimerNotify &, const epicsTime & );
|
||||
void start ( class epicsTimerNotify &, double delaySeconds );
|
||||
void cancel ();
|
||||
expireInfo getExpireInfo () const;
|
||||
void show ( unsigned int level ) const;
|
||||
void * operator new ( size_t size, tsFreeList < timer, 0x20 > & );
|
||||
epicsPlacementDeleteOperator (( void *, tsFreeList < timer, 0x20 > & ))
|
||||
protected:
|
||||
timer ( class timerQueue & );
|
||||
~timer ();
|
||||
timerQueue & queue;
|
||||
private:
|
||||
enum state { statePending = 45, stateActive = 56, stateLimbo = 78 };
|
||||
epicsTime exp; // experation time
|
||||
state curState; // current state
|
||||
epicsTimerNotify * pNotify; // callback
|
||||
void privateStart ( epicsTimerNotify & notify, const epicsTime & );
|
||||
timer & operator = ( const timer & );
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
void operator delete ( void * );
|
||||
friend class timerQueue;
|
||||
};
|
||||
|
||||
struct epicsTimerForC : public epicsTimerNotify, public timer {
|
||||
public:
|
||||
void destroy ();
|
||||
protected:
|
||||
epicsTimerForC ( timerQueue &, epicsTimerCallback, void *pPrivateIn );
|
||||
~epicsTimerForC ();
|
||||
void * operator new ( size_t size, tsFreeList < epicsTimerForC, 0x20 > & );
|
||||
epicsPlacementDeleteOperator (( void *, tsFreeList < epicsTimerForC, 0x20 > & ))
|
||||
private:
|
||||
epicsTimerCallback pCallBack;
|
||||
void * pPrivate;
|
||||
expireStatus expire ( const epicsTime & currentTime );
|
||||
epicsTimerForC & operator = ( const epicsTimerForC & );
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
void operator delete ( void * );
|
||||
friend class timerQueue;
|
||||
};
|
||||
|
||||
using std :: type_info;
|
||||
|
||||
class timerQueue : public epicsTimerQueue {
|
||||
public:
|
||||
timerQueue ( epicsTimerQueueNotify ¬ify );
|
||||
virtual ~timerQueue ();
|
||||
epicsTimer & createTimer ();
|
||||
epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );
|
||||
double process ( const epicsTime & currentTime );
|
||||
void show ( unsigned int level ) const;
|
||||
private:
|
||||
tsFreeList < timer, 0x20 > timerFreeList;
|
||||
tsFreeList < epicsTimerForC, 0x20 > timerForCFreeList;
|
||||
mutable epicsMutex mutex;
|
||||
epicsEvent cancelBlockingEvent;
|
||||
tsDLList < timer > timerList;
|
||||
epicsTimerQueueNotify & notify;
|
||||
timer * pExpireTmr;
|
||||
epicsThreadId processThread;
|
||||
epicsTime exceptMsgTimeStamp;
|
||||
bool cancelPending;
|
||||
static const double exceptMsgMinPeriod;
|
||||
void printExceptMsg ( const char * pName,
|
||||
const type_info & type );
|
||||
timerQueue ( const timerQueue & );
|
||||
timerQueue & operator = ( const timerQueue & );
|
||||
friend class timer;
|
||||
friend struct epicsTimerForC;
|
||||
};
|
||||
|
||||
class timerQueueActiveMgrPrivate {
|
||||
public:
|
||||
timerQueueActiveMgrPrivate ();
|
||||
protected:
|
||||
virtual ~timerQueueActiveMgrPrivate () = 0;
|
||||
private:
|
||||
unsigned referenceCount;
|
||||
friend class timerQueueActiveMgr;
|
||||
};
|
||||
|
||||
class timerQueueActiveMgr;
|
||||
|
||||
class timerQueueActive : public epicsTimerQueueActive,
|
||||
public epicsThreadRunable, public epicsTimerQueueNotify,
|
||||
public timerQueueActiveMgrPrivate {
|
||||
public:
|
||||
typedef epicsSingleton < timerQueueActiveMgr > :: reference RefMgr;
|
||||
timerQueueActive ( RefMgr &, bool okToShare, unsigned priority );
|
||||
void start ();
|
||||
epicsTimer & createTimer ();
|
||||
epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );
|
||||
void show ( unsigned int level ) const;
|
||||
bool sharingOK () const;
|
||||
unsigned threadPriority () const;
|
||||
protected:
|
||||
~timerQueueActive ();
|
||||
RefMgr _refMgr;
|
||||
private:
|
||||
timerQueue queue;
|
||||
epicsEvent rescheduleEvent;
|
||||
epicsEvent exitEvent;
|
||||
epicsThread thread;
|
||||
const double sleepQuantum;
|
||||
bool okToShare;
|
||||
bool exitFlag;
|
||||
bool terminateFlag;
|
||||
void run ();
|
||||
void reschedule ();
|
||||
double quantum ();
|
||||
void _printLastChanceExceptionMessage (
|
||||
const char * pExceptionTypeName,
|
||||
const char * pExceptionContext );
|
||||
epicsTimerQueue & getEpicsTimerQueue ();
|
||||
timerQueueActive ( const timerQueueActive & );
|
||||
timerQueueActive & operator = ( const timerQueueActive & );
|
||||
};
|
||||
|
||||
class timerQueueActiveMgr {
|
||||
public:
|
||||
typedef epicsSingleton < timerQueueActiveMgr > :: reference RefThis;
|
||||
timerQueueActiveMgr ();
|
||||
~timerQueueActiveMgr ();
|
||||
epicsTimerQueueActiveForC & allocate ( RefThis &, bool okToShare,
|
||||
unsigned threadPriority = epicsThreadPriorityMin + 10 );
|
||||
void release ( epicsTimerQueueActiveForC & );
|
||||
private:
|
||||
epicsMutex mutex;
|
||||
tsDLList < epicsTimerQueueActiveForC > sharedQueueList;
|
||||
timerQueueActiveMgr ( const timerQueueActiveMgr & );
|
||||
timerQueueActiveMgr & operator = ( const timerQueueActiveMgr & );
|
||||
};
|
||||
|
||||
extern epicsSingleton < timerQueueActiveMgr > timerQueueMgrEPICS;
|
||||
|
||||
class timerQueuePassive : public epicsTimerQueuePassive {
|
||||
public:
|
||||
timerQueuePassive ( epicsTimerQueueNotify & );
|
||||
epicsTimer & createTimer ();
|
||||
epicsTimerForC & createTimerForC ( epicsTimerCallback pCallback, void *pArg );
|
||||
void show ( unsigned int level ) const;
|
||||
double process ( const epicsTime & currentTime );
|
||||
protected:
|
||||
timerQueue queue;
|
||||
~timerQueuePassive ();
|
||||
epicsTimerQueue & getEpicsTimerQueue ();
|
||||
timerQueuePassive ( const timerQueuePassive & );
|
||||
timerQueuePassive & operator = ( const timerQueuePassive & );
|
||||
};
|
||||
|
||||
struct epicsTimerQueuePassiveForC :
|
||||
public epicsTimerQueueNotify, public timerQueuePassive {
|
||||
public:
|
||||
epicsTimerQueuePassiveForC (
|
||||
epicsTimerQueueNotifyReschedule,
|
||||
epicsTimerQueueNotifyQuantum,
|
||||
void * pPrivate );
|
||||
void destroy ();
|
||||
protected:
|
||||
~epicsTimerQueuePassiveForC ();
|
||||
private:
|
||||
epicsTimerQueueNotifyReschedule pRescheduleCallback;
|
||||
epicsTimerQueueNotifyQuantum pSleepQuantumCallback;
|
||||
void * pPrivate;
|
||||
static epicsSingleton < tsFreeList < epicsTimerQueuePassiveForC, 0x10 > > pFreeList;
|
||||
void reschedule ();
|
||||
double quantum ();
|
||||
};
|
||||
|
||||
struct epicsTimerQueueActiveForC : public timerQueueActive,
|
||||
public tsDLNode < epicsTimerQueueActiveForC > {
|
||||
public:
|
||||
epicsTimerQueueActiveForC ( RefMgr &, bool okToShare, unsigned priority );
|
||||
void release ();
|
||||
void * operator new ( size_t );
|
||||
void operator delete ( void * );
|
||||
protected:
|
||||
virtual ~epicsTimerQueueActiveForC ();
|
||||
private:
|
||||
epicsTimerQueueActiveForC ( const epicsTimerQueueActiveForC & );
|
||||
epicsTimerQueueActiveForC & operator = ( const epicsTimerQueueActiveForC & );
|
||||
};
|
||||
|
||||
inline bool timerQueueActive::sharingOK () const
|
||||
{
|
||||
return this->okToShare;
|
||||
}
|
||||
|
||||
inline unsigned timerQueueActive::threadPriority () const
|
||||
{
|
||||
return thread.getPriority ();
|
||||
}
|
||||
|
||||
inline void * timer::operator new ( size_t size,
|
||||
tsFreeList < timer, 0x20 > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void timer::operator delete ( void * pCadaver,
|
||||
tsFreeList < timer, 0x20 > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void * epicsTimerForC::operator new ( size_t size,
|
||||
tsFreeList < epicsTimerForC, 0x20 > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void epicsTimerForC::operator delete ( void * pCadaver,
|
||||
tsFreeList < epicsTimerForC, 0x20 > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void * epicsTimerQueueActiveForC::operator new ( size_t size )
|
||||
{
|
||||
return ::operator new ( size );
|
||||
}
|
||||
|
||||
inline void epicsTimerQueueActiveForC::operator delete ( void * pCadaver )
|
||||
{
|
||||
::operator delete ( pCadaver );
|
||||
}
|
||||
|
||||
#endif // epicsTimerPrivate_h
|
||||
|
||||
225
modules/libcom/src/timer/timerQueue.cpp
Normal file
225
modules/libcom/src/timer/timerQueue.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <float.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsGuard.h"
|
||||
#include "timerPrivate.h"
|
||||
#include "errlog.h"
|
||||
|
||||
const double timerQueue :: exceptMsgMinPeriod = 60.0 * 5.0; // seconds
|
||||
|
||||
epicsTimerQueue::~epicsTimerQueue () {}
|
||||
|
||||
timerQueue::timerQueue ( epicsTimerQueueNotify & notifyIn ) :
|
||||
notify ( notifyIn ),
|
||||
pExpireTmr ( 0 ),
|
||||
processThread ( 0 ),
|
||||
exceptMsgTimeStamp (
|
||||
epicsTime :: getCurrent () - exceptMsgMinPeriod ),
|
||||
cancelPending ( false )
|
||||
{
|
||||
}
|
||||
|
||||
timerQueue::~timerQueue ()
|
||||
{
|
||||
timer *pTmr;
|
||||
while ( ( pTmr = this->timerList.get () ) ) {
|
||||
pTmr->curState = timer::stateLimbo;
|
||||
}
|
||||
}
|
||||
|
||||
void timerQueue ::
|
||||
printExceptMsg ( const char * pName, const type_info & type )
|
||||
{
|
||||
char date[64];
|
||||
double delay;
|
||||
try {
|
||||
epicsTime cur = epicsTime :: getCurrent ();
|
||||
delay = cur - this->exceptMsgTimeStamp;
|
||||
cur.strftime ( date, sizeof ( date ),
|
||||
"%a %b %d %Y %H:%M:%S.%f" );
|
||||
if ( delay >= exceptMsgMinPeriod ) {
|
||||
this->exceptMsgTimeStamp = cur;
|
||||
}
|
||||
}
|
||||
catch ( ... ) {
|
||||
delay = DBL_MAX;
|
||||
strcpy ( date, "UKN DATE" );
|
||||
}
|
||||
if ( delay >= exceptMsgMinPeriod ) {
|
||||
// we dont touch the typeid for the timer expiration
|
||||
// notify interface here because they might have
|
||||
// destroyed the timer during its callback
|
||||
errlogPrintf (
|
||||
"timerQueue: Unexpected C++ exception \"%s\" "
|
||||
"with type \"%s\" during timer expiration "
|
||||
"callback at %s\n",
|
||||
pName,
|
||||
type.name (),
|
||||
date );
|
||||
errlogFlush ();
|
||||
}
|
||||
}
|
||||
|
||||
double timerQueue::process ( const epicsTime & currentTime )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
if ( this->pExpireTmr ) {
|
||||
// if some other thread is processing the queue
|
||||
// (or if this is a recursive call)
|
||||
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.
|
||||
//
|
||||
if ( this->timerList.first () ) {
|
||||
if ( currentTime >= this->timerList.first ()->exp ) {
|
||||
this->pExpireTmr = this->timerList.first ();
|
||||
this->timerList.remove ( *this->pExpireTmr );
|
||||
this->pExpireTmr->curState = timer::stateActive;
|
||||
this->processThread = epicsThreadGetIdSelf ();
|
||||
# ifdef DEBUG
|
||||
this->pExpireTmr->show ( 0u );
|
||||
# endif
|
||||
}
|
||||
else {
|
||||
double delay = this->timerList.first ()->exp - currentTime;
|
||||
debugPrintf ( ( "no activity process %f to next\n", delay ) );
|
||||
return delay;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return DBL_MAX;
|
||||
}
|
||||
|
||||
# ifdef DEBUG
|
||||
unsigned N = 0u;
|
||||
# endif
|
||||
|
||||
double delay = DBL_MAX;
|
||||
while ( true ) {
|
||||
epicsTimerNotify *pTmpNotify = this->pExpireTmr->pNotify;
|
||||
this->pExpireTmr->pNotify = 0;
|
||||
epicsTimerNotify::expireStatus expStat ( epicsTimerNotify::noRestart );
|
||||
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
|
||||
debugPrintf ( ( "%5u expired \"%s\" with error %f sec\n",
|
||||
N++, typeid ( this->pExpireTmr->notify ).name (),
|
||||
currentTime - this->pExpireTmr->exp ) );
|
||||
try {
|
||||
expStat = pTmpNotify->expire ( currentTime );
|
||||
}
|
||||
catch ( std::exception & except ) {
|
||||
printExceptMsg ( except.what (), typeid ( except ) );
|
||||
}
|
||||
catch ( ... ) {
|
||||
printExceptMsg ( "non-standard exception", typeid ( void ) );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// only restart if they didnt cancel() the timer
|
||||
// while the call back was running
|
||||
//
|
||||
if ( this->cancelPending ) {
|
||||
// 1) if another thread is canceling then cancel() waits for
|
||||
// the event below
|
||||
// 2) if this thread is canceling in the timer callback then
|
||||
// dont touch timer or notify here because the cancel might
|
||||
// have occurred because they destroyed the timer in the
|
||||
// callback
|
||||
this->cancelPending = false;
|
||||
this->cancelBlockingEvent.signal ();
|
||||
}
|
||||
else {
|
||||
this->pExpireTmr->curState = timer::stateLimbo;
|
||||
if ( this->pExpireTmr->pNotify ) {
|
||||
// pNotify was cleared above so if it is valid now we know that
|
||||
// someone has started the timer from another thread and that
|
||||
// predominates over the restart parameters from expire.
|
||||
this->pExpireTmr->privateStart (
|
||||
*this->pExpireTmr->pNotify, this->pExpireTmr->exp );
|
||||
}
|
||||
else if ( expStat.restart() ) {
|
||||
// restart as nec
|
||||
this->pExpireTmr->privateStart (
|
||||
*pTmpNotify, currentTime + expStat.expirationDelay() );
|
||||
}
|
||||
}
|
||||
this->pExpireTmr = 0;
|
||||
|
||||
if ( this->timerList.first () ) {
|
||||
if ( currentTime >= this->timerList.first ()->exp ) {
|
||||
this->pExpireTmr = this->timerList.first ();
|
||||
this->timerList.remove ( *this->pExpireTmr );
|
||||
this->pExpireTmr->curState = timer::stateActive;
|
||||
# ifdef DEBUG
|
||||
this->pExpireTmr->show ( 0u );
|
||||
# endif
|
||||
}
|
||||
else {
|
||||
delay = this->timerList.first ()->exp - currentTime;
|
||||
this->processThread = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->processThread = 0;
|
||||
delay = DBL_MAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
epicsTimer & timerQueue::createTimer ()
|
||||
{
|
||||
return * new ( this->timerFreeList ) timer ( * this );
|
||||
}
|
||||
|
||||
epicsTimerForC & timerQueue::createTimerForC ( epicsTimerCallback pCallback, void *pArg )
|
||||
{
|
||||
return * new ( this->timerForCFreeList ) epicsTimerForC ( *this, pCallback, pArg );
|
||||
}
|
||||
|
||||
void timerQueue::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > locker ( this->mutex );
|
||||
printf ( "epicsTimerQueue with %u items pending\n", this->timerList.count () );
|
||||
if ( level >= 1u ) {
|
||||
tsDLIterConst < timer > iter = this->timerList.firstIter ();
|
||||
while ( iter.valid () ) {
|
||||
iter->show ( level - 1u );
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
modules/libcom/src/timer/timerQueueActive.cpp
Normal file
155
modules/libcom/src/timer/timerQueueActive.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2015 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "timerPrivate.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( push )
|
||||
# pragma warning ( disable:4660 )
|
||||
#endif
|
||||
|
||||
template class epicsSingleton < timerQueueActiveMgr >;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning ( pop )
|
||||
#endif
|
||||
|
||||
epicsSingleton < timerQueueActiveMgr > timerQueueMgrEPICS;
|
||||
|
||||
epicsTimerQueueActive::~epicsTimerQueueActive () {}
|
||||
|
||||
epicsTimerQueueActive & epicsTimerQueueActive::allocate ( bool okToShare, unsigned threadPriority )
|
||||
{
|
||||
epicsSingleton < timerQueueActiveMgr >::reference pMgr =
|
||||
timerQueueMgrEPICS.getReference ();
|
||||
return pMgr->allocate ( pMgr, okToShare, threadPriority );
|
||||
}
|
||||
|
||||
timerQueueActive ::
|
||||
timerQueueActive ( RefMgr & refMgr,
|
||||
bool okToShareIn, unsigned priority ) :
|
||||
_refMgr ( refMgr ), queue ( *this ), thread ( *this, "timerQueue",
|
||||
epicsThreadGetStackSize ( epicsThreadStackMedium ), priority ),
|
||||
sleepQuantum ( epicsThreadSleepQuantum() ), okToShare ( okToShareIn ),
|
||||
exitFlag ( false ), terminateFlag ( false )
|
||||
{
|
||||
}
|
||||
|
||||
void timerQueueActive::start ()
|
||||
{
|
||||
this->thread.start ();
|
||||
}
|
||||
|
||||
timerQueueActive::~timerQueueActive ()
|
||||
{
|
||||
this->terminateFlag = true;
|
||||
this->rescheduleEvent.signal ();
|
||||
while ( ! this->exitFlag ) {
|
||||
this->exitEvent.wait ( 1.0 );
|
||||
}
|
||||
// in case other threads are waiting here also
|
||||
this->exitEvent.signal ();
|
||||
}
|
||||
|
||||
void timerQueueActive :: _printLastChanceExceptionMessage (
|
||||
const char * pExceptionTypeName,
|
||||
const char * pExceptionContext )
|
||||
{
|
||||
char date[64];
|
||||
try {
|
||||
epicsTime cur = epicsTime :: getCurrent ();
|
||||
cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
|
||||
}
|
||||
catch ( ... ) {
|
||||
strcpy ( date, "<UKN DATE>" );
|
||||
}
|
||||
errlogPrintf (
|
||||
"timerQueueActive: Unexpected C++ exception \"%s\" with type \"%s\" "
|
||||
"while processing timer queue, at %s\n",
|
||||
pExceptionContext, pExceptionTypeName, date );
|
||||
}
|
||||
|
||||
|
||||
void timerQueueActive :: run ()
|
||||
{
|
||||
this->exitFlag = false;
|
||||
while ( ! this->terminateFlag ) {
|
||||
try {
|
||||
double delay = this->queue.process ( epicsTime::getCurrent() );
|
||||
debugPrintf ( ( "timer thread sleeping for %g sec (max)\n", delay ) );
|
||||
this->rescheduleEvent.wait ( delay );
|
||||
}
|
||||
catch ( std :: exception & except ) {
|
||||
_printLastChanceExceptionMessage (
|
||||
typeid ( except ).name (), except.what () );
|
||||
epicsThreadSleep ( 10.0 );
|
||||
}
|
||||
catch ( ... ) {
|
||||
_printLastChanceExceptionMessage (
|
||||
"catch ( ... )", "Non-standard C++ exception" );
|
||||
epicsThreadSleep ( 10.0 );
|
||||
}
|
||||
}
|
||||
this->exitFlag = true;
|
||||
this->exitEvent.signal (); // no access to queue after exitEvent signal
|
||||
}
|
||||
|
||||
epicsTimer & timerQueueActive::createTimer ()
|
||||
{
|
||||
return this->queue.createTimer();
|
||||
}
|
||||
|
||||
epicsTimerForC & timerQueueActive::createTimerForC ( epicsTimerCallback pCallback, void * pArg )
|
||||
{
|
||||
return this->queue.createTimerForC ( pCallback, pArg );
|
||||
}
|
||||
|
||||
void timerQueueActive::reschedule ()
|
||||
{
|
||||
this->rescheduleEvent.signal ();
|
||||
}
|
||||
|
||||
double timerQueueActive::quantum ()
|
||||
{
|
||||
return this->sleepQuantum;
|
||||
}
|
||||
|
||||
void timerQueueActive::show ( unsigned int level ) const
|
||||
{
|
||||
printf ( "EPICS threaded timer queue at %p\n",
|
||||
static_cast <const void *> ( this ) );
|
||||
if ( level > 0u ) {
|
||||
// specifying level one here avoids recursive
|
||||
// show callback
|
||||
this->thread.show ( 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' );
|
||||
}
|
||||
}
|
||||
|
||||
epicsTimerQueue & timerQueueActive::getEpicsTimerQueue ()
|
||||
{
|
||||
return static_cast < epicsTimerQueue &> ( * this );
|
||||
}
|
||||
|
||||
84
modules/libcom/src/timer/timerQueueActiveMgr.cpp
Normal file
84
modules/libcom/src/timer/timerQueueActiveMgr.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsGuard.h"
|
||||
#include "timerPrivate.h"
|
||||
|
||||
timerQueueActiveMgr::timerQueueActiveMgr ()
|
||||
{
|
||||
}
|
||||
|
||||
timerQueueActiveMgr::~timerQueueActiveMgr ()
|
||||
{
|
||||
epicsGuard < epicsMutex > locker ( this->mutex );
|
||||
}
|
||||
|
||||
epicsTimerQueueActiveForC & timerQueueActiveMgr ::
|
||||
allocate ( RefThis & refThis, bool okToShare, unsigned threadPriority )
|
||||
{
|
||||
epicsGuard < epicsMutex > locker ( this->mutex );
|
||||
if ( okToShare ) {
|
||||
tsDLIter < epicsTimerQueueActiveForC > iter = this->sharedQueueList.firstIter ();
|
||||
while ( iter.valid () ) {
|
||||
if ( iter->threadPriority () == threadPriority ) {
|
||||
assert ( iter->timerQueueActiveMgrPrivate::referenceCount < UINT_MAX );
|
||||
iter->timerQueueActiveMgrPrivate::referenceCount++;
|
||||
return *iter;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
epicsTimerQueueActiveForC & queue =
|
||||
* new epicsTimerQueueActiveForC ( refThis, okToShare, threadPriority );
|
||||
queue.timerQueueActiveMgrPrivate::referenceCount = 1u;
|
||||
if ( okToShare ) {
|
||||
this->sharedQueueList.add ( queue );
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
void timerQueueActiveMgr ::
|
||||
release ( epicsTimerQueueActiveForC & queue )
|
||||
{
|
||||
{
|
||||
epicsGuard < epicsMutex > locker ( this->mutex );
|
||||
assert ( queue.timerQueueActiveMgrPrivate::referenceCount > 0u );
|
||||
queue.timerQueueActiveMgrPrivate::referenceCount--;
|
||||
if ( queue.timerQueueActiveMgrPrivate::referenceCount > 0u ) {
|
||||
return;
|
||||
}
|
||||
else if ( queue.sharingOK () ) {
|
||||
this->sharedQueueList.remove ( queue );
|
||||
}
|
||||
}
|
||||
// delete only after we release the guard in case the embedded
|
||||
// reference is the last one and this object is destroyed
|
||||
// as a side effect
|
||||
timerQueueActiveMgrPrivate * pPriv = & queue;
|
||||
delete pPriv;
|
||||
}
|
||||
|
||||
timerQueueActiveMgrPrivate::timerQueueActiveMgrPrivate () :
|
||||
referenceCount ( 0u )
|
||||
{
|
||||
}
|
||||
|
||||
timerQueueActiveMgrPrivate::~timerQueueActiveMgrPrivate ()
|
||||
{
|
||||
}
|
||||
69
modules/libcom/src/timer/timerQueuePassive.cpp
Normal file
69
modules/libcom/src/timer/timerQueuePassive.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
//
|
||||
// Note, a free list for this class is not currently used because of
|
||||
// entanglements between the file scope free list destructor and a
|
||||
// file scope fdManager destructor which is trying to call a
|
||||
// destructor for a passive timer queue which is no longer valid
|
||||
// in pool.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "timerPrivate.h"
|
||||
|
||||
epicsTimerQueuePassive::~epicsTimerQueuePassive () {}
|
||||
|
||||
epicsTimerQueuePassive & epicsTimerQueuePassive::create ( epicsTimerQueueNotify ¬ify )
|
||||
{
|
||||
return * new timerQueuePassive ( notify );
|
||||
}
|
||||
|
||||
timerQueuePassive::timerQueuePassive ( epicsTimerQueueNotify ¬ifyIn ) :
|
||||
queue ( notifyIn ) {}
|
||||
|
||||
timerQueuePassive::~timerQueuePassive () {}
|
||||
|
||||
epicsTimer & timerQueuePassive::createTimer ()
|
||||
{
|
||||
return this->queue.createTimer ();
|
||||
}
|
||||
|
||||
epicsTimerForC & timerQueuePassive::createTimerForC ( epicsTimerCallback pCallback, void * pArg )
|
||||
{
|
||||
return this->queue.createTimerForC ( pCallback, pArg );
|
||||
}
|
||||
|
||||
double timerQueuePassive::process ( const epicsTime & currentTime )
|
||||
{
|
||||
return this->queue.process ( currentTime );
|
||||
}
|
||||
|
||||
void timerQueuePassive::show ( unsigned int level ) const
|
||||
{
|
||||
printf ( "EPICS non-threaded timer queue at %p\n",
|
||||
static_cast <const void *> ( this ) );
|
||||
if ( level >=1u ) {
|
||||
this->queue.show ( level - 1u );
|
||||
}
|
||||
}
|
||||
|
||||
epicsTimerQueue & timerQueuePassive::getEpicsTimerQueue ()
|
||||
{
|
||||
return static_cast < epicsTimerQueue &> ( * this );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user