Move all under modules/libcom

This commit is contained in:
Ralph Lange
2018-06-19 11:24:03 +02:00
parent 49f42945b9
commit 833648c977
607 changed files with 0 additions and 101 deletions

View 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

View 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 );
}

View 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 */

View 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__ );
}

View 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 &notify );
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

View 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;
}
}
}

View 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 );
}

View 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 ()
{
}

View 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 &notify )
{
return * new timerQueuePassive ( notify );
}
timerQueuePassive::timerQueuePassive ( epicsTimerQueueNotify &notifyIn ) :
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 );
}