continuation of last commit

This commit is contained in:
Marty Kraimer
2010-12-08 07:10:01 -05:00
parent 381c6de7e9
commit 3c060afedb
35 changed files with 4353 additions and 0 deletions

310
pvDataApp/misc/timer.cpp Normal file
View File

@@ -0,0 +1,310 @@
/* timer.cpp */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdexcept>
#include "pvType.h"
#include "lock.h"
#include "noDefaultMethods.h"
#include "showConstructDestruct.h"
#include "linkedList.h"
#include "thread.h"
#include "timeStamp.h"
#include "timer.h"
#include "event.h"
namespace epics { namespace pvData {
static volatile int64 totalNodeConstruct = 0;
static volatile int64 totalNodeDestruct = 0;
static volatile int64 totalTimerConstruct = 0;
static volatile int64 totalTimerDestruct = 0;
static Mutex *globalMutex = 0;
static int64 getTotalTimerNodeConstruct()
{
Lock xx(globalMutex);
return totalNodeConstruct;
}
static int64 getTotalTimerNodeDestruct()
{
Lock xx(globalMutex);
return totalNodeDestruct;
}
static int64 getTotalTimerConstruct()
{
Lock xx(globalMutex);
return totalTimerConstruct;
}
static int64 getTotalTimerDestruct()
{
Lock xx(globalMutex);
return totalTimerDestruct;
}
static ConstructDestructCallback *pCDCallbackTimerNode;
static ConstructDestructCallback *pCDCallbackTimer;
static void init()
{
static Mutex mutex = Mutex();
Lock xx(&mutex);
if(globalMutex==0) {
globalMutex = new Mutex();
pCDCallbackTimerNode = new ConstructDestructCallback(
"timerNode",
getTotalTimerNodeConstruct,getTotalTimerNodeDestruct,0);
pCDCallbackTimer = new ConstructDestructCallback(
"timer",
getTotalTimerConstruct,getTotalTimerDestruct,0);
}
}
ConstructDestructCallback * TimerNode::getConstructDestructCallback()
{
init();
return pCDCallbackTimerNode;
}
ConstructDestructCallback * Timer::getConstructDestructCallback()
{
init();
return pCDCallbackTimer;
}
class TimerNodePvt;
typedef LinkedListNode<TimerNodePvt> TimerListNode;
typedef LinkedList<TimerNodePvt> TimerList;
class TimerNodePvt {
public:
TimerNode *timerNode;
TimerCallback *callback;
TimerListNode *timerListNode;
TimeStamp timeToRun;
TimerPvt *timerPvt;
double period;
TimerNodePvt(TimerNode *timerNode,TimerCallback *callback);
~TimerNodePvt();
};
TimerNodePvt::TimerNodePvt(TimerNode *timerNode,TimerCallback *callback)
: timerNode(timerNode),callback(callback),
timerListNode(new TimerListNode(this)),timeToRun(TimeStamp()),
timerPvt(0), period(0.0)
{}
TimerNodePvt::~TimerNodePvt()
{
delete timerListNode;
}
struct TimerPvt : public Runnable{
public:
TimerPvt(String threadName,ThreadPriority priority);
~TimerPvt();
virtual void run();
public: // only used by this source module
TimerList *timerList;
Mutex mutex;
Event *waitForWork;
Event *waitForDone;
volatile bool alive;
Thread *thread;
};
TimerPvt::TimerPvt(String threadName,ThreadPriority priority)
: timerList(new TimerList()),
mutex(Mutex()),
waitForWork(new Event(false)),
waitForDone(new Event(false)),
alive(true),
thread(new Thread(threadName,priority,this))
{}
TimerPvt::~TimerPvt()
{
delete thread;
delete waitForDone;
delete waitForWork;
delete timerList;
}
static void addElement(TimerPvt *timer,TimerNodePvt *node)
{
TimerList *timerList = timer->timerList;
TimerListNode *nextNode = timerList->getHead();
if(nextNode==0) {
timerList->addTail(node->timerListNode);
return;
}
while(true) {
TimerNodePvt *timerListNode = nextNode->getObject();
if((node->timeToRun)<(timerListNode->timeToRun)) {
timerList->insertBefore(timerListNode->timerListNode,node->timerListNode);
return;
}
nextNode = timerList->getNext(timerListNode->timerListNode);
if(nextNode==0) {
timerList->addTail(node->timerListNode);
return;
}
}
}
TimerNode::TimerNode(TimerCallback *callback)
: pImpl(new TimerNodePvt(this,callback))
{
init();
Lock xx(globalMutex);
totalNodeConstruct++;
}
TimerNode::~TimerNode()
{
cancel();
delete pImpl;
Lock xx(globalMutex);
totalNodeDestruct++;
}
void TimerNode::cancel()
{
TimerPvt *timerPvt = pImpl->timerPvt;
if(timerPvt==0) return;
Lock xx(&timerPvt->mutex);
if(pImpl->timerPvt==0) return;
pImpl->timerPvt->timerList->remove(pImpl);
pImpl->timerPvt = 0;
}
bool TimerNode::isScheduled()
{
TimerPvt *pvt = pImpl->timerPvt;
if(pvt==0) return false;
Lock xx(&pvt->mutex);
return pImpl->timerListNode->isOnList();
}
void TimerPvt::run()
{
TimeStamp currentTime;
while(alive) {
currentTime.getCurrent();
TimeStamp *timeToRun = 0;
double period = 0.0;
TimerNodePvt *nodeToCall = 0;
{
Lock xx(&mutex);
TimerListNode *timerListNode = timerList->getHead();
if(timerListNode!=0) {
TimerNodePvt *timerNodePvt = timerListNode->getObject();
timeToRun = &timerNodePvt->timeToRun;
double diff = TimeStamp::diff(
*timeToRun,currentTime);
if(diff<=0.0) {
nodeToCall = timerNodePvt;
timerList->removeHead();
period = timerNodePvt->period;
if(period>0.0) {
timerNodePvt->timeToRun += period;
addElement(this,timerNodePvt);
} else {
timerNodePvt->timerPvt = 0;
}
timerListNode = timerList->getHead();
if(timerListNode!=0) {
timerNodePvt = timerListNode->getObject();
timeToRun = &timerNodePvt->timeToRun;
} else {
timeToRun = 0;
}
}
}
}
if(nodeToCall!=0) {
nodeToCall->callback->callback();
}
if(!alive) break;
if(timeToRun==0) {
waitForWork->wait();
} else {
double delay = TimeStamp::diff(*timeToRun,currentTime);
waitForWork->wait(delay);
}
}
waitForDone->signal();
}
Timer::Timer(String threadName, ThreadPriority priority)
: pImpl(new TimerPvt(threadName,priority))
{
init();
Lock xx(globalMutex);
totalTimerConstruct++;
}
Timer::~Timer() {
{
Lock xx(&pImpl->mutex);
pImpl->alive = false;
}
pImpl->waitForWork->signal();
pImpl->waitForDone->wait();
TimerList *timerList = pImpl->timerList;
TimerListNode *node = 0;
while((node = timerList->removeHead())!=0) {
node->getObject()->callback->timerStopped();
}
delete pImpl;
Lock xx(globalMutex);
totalTimerDestruct++;
}
void Timer::scheduleAfterDelay(TimerNode *timerNode,double delay)
{
schedulePeriodic(timerNode,delay,0.0);
}
void Timer::schedulePeriodic(TimerNode *timerNode,double delay,double period)
{
TimerNodePvt *timerNodePvt = timerNode->pImpl;
if(timerNodePvt->timerListNode->isOnList()) {
throw std::logic_error(String("already queued"));
}
if(!pImpl->alive) {
timerNodePvt->callback->timerStopped();
return;
}
TimeStamp *timeStamp = &timerNodePvt->timeToRun;
timeStamp->getCurrent();
*timeStamp += delay;
timerNodePvt->period = period;
bool isFirst = false;
{
Lock xx(&pImpl->mutex);
timerNodePvt->timerPvt = pImpl;
addElement(pImpl,timerNodePvt);
TimerNodePvt *first = pImpl->timerList->getHead()->getObject();
if(first==timerNodePvt) isFirst = true;
}
if(isFirst) pImpl->waitForWork->signal();
}
}}