more shared_pointer everywhere

This commit is contained in:
Marty Kraimer
2012-07-17 09:23:53 -04:00
parent 32790674d6
commit 5dcd864c58
25 changed files with 399 additions and 1507 deletions

View File

@@ -1,160 +0,0 @@
/* CDRMonitor.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 <epicsThread.h>
#include <pv/noDefaultMethods.h>
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/linkedList.h>
#include <pv/CDRMonitor.h>
#ifdef _WIN32
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
namespace epics { namespace pvData {
static
epicsThreadOnceId monitorInit = EPICS_THREAD_ONCE_INIT;
// Must use a pointer w/ lazy init due to lack of
// initialization order guarantees
CDRMonitor* CDRMonitor::theone = 0;
CDRMonitor&
CDRMonitor::get()
{
epicsThreadOnce(&monitorInit, &CDRMonitor::init, 0);
assert(theone);
return *theone;
}
void
CDRMonitor::init(void *)
{
//BUG: No idea how to handle allocation failure at this stage.
theone=new CDRMonitor;
}
void
CDRMonitor::destroy()
{
if (theone)
{
CDRNode *node = theone->first();
while (node)
{
CDRNode* tmp = node;
node = node->next();
delete tmp;
}
delete theone;
theone = 0;
}
}
CDRMonitor::CDRMonitor()
:firstNode(0)
{}
CDRCount
CDRMonitor::current()
{
CDRCount total;
for(CDRNode *cur=first(); !!cur; cur=cur->next())
{
total+=cur->get();
}
return total;
}
void
CDRMonitor::show(FILE *fd, bool destroy)
{
for(CDRNode *cur=first(); !!cur; cur=cur->next())
{
cur->show(fd);
}
if (destroy)
CDRMonitor::destroy();
}
void
CDRMonitor::show(std::ostream& out, bool destroy) const
{
for(CDRNode *cur=first(); !!cur; cur=cur->next())
{
cur->show(out);
}
if (destroy)
CDRMonitor::destroy();
}
void
CDRNode::show(FILE *fd)
{
Lock x(guard);
if(!current.cons && !current.dtys && !current.refs)
return;
fprintf(fd,"%s: totalConstruct %lu totalDestruct %lu",
nodeName.c_str(), (unsigned long)current.cons,
(unsigned long)current.dtys);
ssize_t alive=current.cons;
alive-=current.dtys;
if(current.refs)
fprintf(fd," totalReference %ld", current.refs);
if(alive)
fprintf(fd," ACTIVE %ld\n", (long)alive);
else
fprintf(fd,"\n");
}
void
CDRNode::show(std::ostream& out) const
{
Lock x(guard);
if(!current.cons && !current.dtys && !current.refs)
return;
out<<nodeName<<" totalConstruct "<<current.cons
<<" totalDestruct "<<current.dtys;
ssize_t alive=current.cons;
alive-=current.dtys;
if(current.refs)
out<<" totalReference "<<current.refs;
if(alive)
out<<" ACTIVE "<<alive;
out<<"\n";
}
void
onceNode(void* raw)
{
CDRNodeInstance* inst=static_cast<CDRNodeInstance*>(raw);
inst->node=new CDRNode(inst->name);
}
}} // namespace epics::pvData
std::ostream& operator<<(std::ostream& out,const epics::pvData::CDRMonitor& mon)
{
mon.show(out);
return out;
}
std::ostream& operator<<(std::ostream& out,const epics::pvData::CDRNode& node)
{
node.show(out);
return out;
}

View File

@@ -1,140 +0,0 @@
/* CDRMonitor.h */
/**
* 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.
*/
#ifndef CDRMONITOR_H
#define CDRMONITOR_H
#include <ostream>
#include <cstddef>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <epicsThread.h>
#include <pv/noDefaultMethods.h>
#include <pv/lock.h>
#include <pv/pvType.h>
namespace epics { namespace pvData {
//! Used to pass around snapshots
struct CDRCount { // default copy and assignment are ok
size_t cons, dtys;
long refs;
CDRCount():cons(0),dtys(0),refs(0){}
CDRCount& operator+=(const CDRCount& o)
{cons+=o.cons; dtys+=o.dtys; refs+=o.refs; return *this;}
CDRCount& operator=(size_t count) // reset counters
{cons=count; dtys=count; refs=count; return *this;}
};
class CDRNode;
//! @brief Global registrar for CDRNodes
class CDRMonitor : private NoDefaultMethods {
public:
static CDRMonitor& get();
static void destroy();
CDRNode* addNode(CDRNode& next)
{
CDRNode *ret=firstNode;
firstNode=&next;
return ret;
}
CDRCount current(); //!< current global count
CDRNode* first() const{return firstNode;}
void show(FILE*, bool destroy = false);
void show(std::ostream&, bool destroy = false) const;
private:
// Private ctor for singleton
CDRMonitor();
CDRNode *firstNode;
static CDRMonitor *theone;
static void init(void*);
};
//! Counters for Construction, Destruction, and References of one class
class CDRNode : private NoDefaultMethods {
public:
CDRNode(const String& name)
:nodeName(name)
,current()
,guard()
,nextNode(CDRMonitor::get().addNode(*this))
{}
void construct(){Lock x(guard); current.cons++;}
void destruct(){Lock x(guard); current.dtys++;}
void incRef(){Lock x(guard); current.refs++;}
void decRef(){Lock x(guard); current.refs--;}
CDRNode* next() const{return nextNode;}
CDRCount get() const{Lock x(guard); return current;}
void show(FILE*);
void show(std::ostream&) const;
private:
const String nodeName;
CDRCount current;
mutable Mutex guard;
CDRNode * const nextNode;
};
struct CDRNodeInstance
{
CDRNode *node;
epicsThreadOnceId once;
const char* const name;
};
void onceNode(void* raw);
static inline
CDRNode*
getNode(CDRNodeInstance *inst)
{
epicsThreadOnce(&inst->once,&onceNode,
static_cast<void*>(inst));
return inst->node;
}
#ifndef NDEBUG
#define PVDATA_REFCOUNT_MONITOR_DEFINE(NAME) \
static CDRNodeInstance NAME ## _node={0,EPICS_THREAD_ONCE_INIT,#NAME}
#define PVDATA_REFCOUNT_MONITOR_DESTRUCT(NAME) \
getNode(&NAME ## _node)->destruct()
#define PVDATA_REFCOUNT_MONITOR_CONSTRUCT(NAME) \
getNode(&NAME ## _node)->construct()
#define PVDATA_REFCOUNT_MONITOR_INCREF(NAME) \
getNode(&NAME ## _node)->incRef()
#define PVDATA_REFCOUNT_MONITOR_DECREF(NAME) \
getNode(&NAME ## _node)->decRef()
#else
#define PVDATA_REFCOUNT_MONITOR_DEFINE(NAME)
#define PVDATA_REFCOUNT_MONITOR_DESTRUCT(NAME)
#define PVDATA_REFCOUNT_MONITOR_CONSTRUCT(NAME)
#define PVDATA_REFCOUNT_MONITOR_INCREF(NAME)
#define PVDATA_REFCOUNT_MONITOR_DECREF(NAME)
#endif
}}
std::ostream& operator<<(std::ostream&,const epics::pvData::CDRMonitor&);
std::ostream& operator<<(std::ostream&,const epics::pvData::CDRNode&);
#endif /* CDRMONITOR_H */

View File

@@ -8,12 +8,10 @@
#include "stdio.h"
#include <pv/bitSet.h>
#include <pv/lock.h>
#include <pv/CDRMonitor.h>
#include <pv/serializeHelper.h>
namespace epics { namespace pvData {
PVDATA_REFCOUNT_MONITOR_DEFINE(bitSet);
BitSet::shared_pointer BitSet::create(uint32 nbits)
{
return BitSet::shared_pointer(new BitSet(nbits));
@@ -22,19 +20,15 @@ namespace epics { namespace pvData {
BitSet::BitSet() : words(0), wordsLength(0), wordsInUse(0) {
initWords(BITS_PER_WORD);
PVDATA_REFCOUNT_MONITOR_CONSTRUCT(bitSet);
}
BitSet::BitSet(uint32 nbits) : words(0), wordsLength(0), wordsInUse(0) {
initWords(nbits);
PVDATA_REFCOUNT_MONITOR_CONSTRUCT(bitSet);
}
BitSet::~BitSet() {
delete[] words;
PVDATA_REFCOUNT_MONITOR_DESTRUCT(bitSet);
}
void BitSet::initWords(uint32 nbits) {

View File

@@ -20,24 +20,20 @@
#include <pv/pvType.h>
#include <pv/lock.h>
#include <pv/event.h>
#include <pv/CDRMonitor.h>
namespace epics { namespace pvData {
PVDATA_REFCOUNT_MONITOR_DEFINE(event);
static String alreadyOn("already on list");
Event::~Event() {
epicsEventDestroy(id);
id = 0;
PVDATA_REFCOUNT_MONITOR_DESTRUCT(event);
}
Event::Event(bool full)
: id(epicsEventCreate(full?epicsEventFull : epicsEventEmpty))
{
PVDATA_REFCOUNT_MONITOR_CONSTRUCT(event);
}
void Event::signal()

View File

@@ -9,13 +9,17 @@
#include <memory>
#include <vector>
#include <epicsEvent.h>
#include <pv/noDefaultMethods.h>
#include <pv/pvType.h>
#include <pv/sharedPtr.h>
namespace epics { namespace pvData {
class Event : private NoDefaultMethods {
class Event;
typedef std::tr1::shared_ptr<Event> EventPtr;
class Event {
public:
POINTER_DEFINITIONS(Event);
explicit Event(bool = false);
~Event();
void signal();

View File

@@ -10,109 +10,55 @@
#include <string>
#include <cstdio>
#include <memory>
#include <vector>
#include <pv/linkedList.h>
#include <pv/lock.h>
#include <pv/thread.h>
#include <pv/event.h>
#include <pv/executor.h>
#include <pv/CDRMonitor.h>
namespace epics { namespace pvData {
// special instance to stop the executor thread
static
class ExecutorShutdown : public Command {
virtual void command(){};
} executorShutdown;
virtual void command();
};
void ExecutorShutdown::command()
{
}
static
Command *shutdown=&executorShutdown;
std::tr1::shared_ptr<Command> shutdown(new ExecutorShutdown());
PVDATA_REFCOUNT_MONITOR_DEFINE(executor);
typedef LinkedListNode<ExecutorNode> ExecutorListNode;
typedef LinkedList<ExecutorNode> ExecutorList;
class ExecutorNode {
public:
ExecutorNode(Command *command);
Command *command;
ExecutorListNode node;
ExecutorListNode runNode;
};
ExecutorNode::ExecutorNode(Command *command)
: command(command),
node(*this),
runNode(*this)
{}
class ExecutorPvt : public Runnable{
public:
ExecutorPvt(String threadName,ThreadPriority priority);
~ExecutorPvt();
ExecutorNode * createNode(Command *command);
void execute(ExecutorNode *node);
virtual void run();
private:
ExecutorList executorList;
ExecutorList runList;
Event moreWork;
Event stopped;
Mutex mutex;
Thread thread;
};
ExecutorPvt::ExecutorPvt(String threadName,ThreadPriority priority)
: executorList(),
runList(),
moreWork(),
stopped(),
mutex(),
thread(threadName,priority,this)
{}
ExecutorPvt::~ExecutorPvt()
Executor::Executor(String threadName,ThreadPriority priority)
: thread(threadName,priority,this)
{
ExecutorNode shutdownNode(shutdown);
}
execute(&shutdownNode);
Executor::~Executor()
{
execute(shutdown);
stopped.wait();
// The thread signals 'stopped' while still holding
// the lock. By taking it we wait for the run() function
// to actually return
Lock xx(mutex);
ExecutorListNode *node;
while((node=executorList.removeHead())!=0) {
delete &node->getObject();
}
head.reset();
tail.reset();
}
void ExecutorPvt::run()
void Executor::run()
{
Lock xx(mutex);
while(true) {
ExecutorListNode * executorListNode = 0;
while(runList.isEmpty()) {
while(head.get()==NULL) {
xx.unlock();
moreWork.wait();
xx.lock();
}
executorListNode = runList.removeHead();
if(!executorListNode) continue;
Command *cmd=executorListNode->getObject().command;
if(cmd==shutdown) break;
CommandPtr command = head;
if(command.get()==NULL) continue;
if(command.get()==shutdown.get()) break;
xx.unlock();
try {
executorListNode->getObject().command->command();
command->command();
}catch(std::exception& e){
//TODO: feed into logging mechanism
fprintf(stderr, "Executor: Unhandled exception: %s",e.what());
@@ -122,41 +68,20 @@ void ExecutorPvt::run()
xx.lock();
}
stopped.signal();
}
ExecutorNode * ExecutorPvt::createNode(Command *command)
void Executor::execute(CommandPtr const & command)
{
Lock xx(mutex);
ExecutorNode *executorNode = new ExecutorNode(command);
executorList.addTail(executorNode->node);
return executorNode;
command->next.reset();
if(head.get()==NULL) {
head = command;
moreWork.signal();
return;
}
if(tail.get()==NULL) return;
tail->next = command;
}
void ExecutorPvt::execute(ExecutorNode *node)
{
Lock xx(mutex);
if(node->runNode.isOnList()) return;
bool isEmpty = runList.isEmpty();
runList.addTail(node->runNode);
if(isEmpty) moreWork.signal();
}
Executor::Executor(String threadName,ThreadPriority priority)
: pImpl(new ExecutorPvt(threadName,priority))
{
PVDATA_REFCOUNT_MONITOR_CONSTRUCT(executor);
}
Executor::~Executor() {
delete pImpl;
PVDATA_REFCOUNT_MONITOR_DESTRUCT(executor);
}
ExecutorNode * Executor::createNode(Command*command)
{return pImpl->createNode(command);}
void Executor::execute(ExecutorNode *node) {pImpl->execute(node);}
}}

View File

@@ -7,30 +7,43 @@
#ifndef EXECUTOR_H
#define EXECUTOR_H
#include <memory>
#include <vector>
#include <pv/noDefaultMethods.h>
#include <pv/pvType.h>
#include <pv/lock.h>
#include <pv/event.h>
#include <pv/thread.h>
#include <pv/sharedPtr.h>
namespace epics { namespace pvData {
// This is created by Executor.createNode and passed to Executor.execute
class ExecutorNode;
class Command;
class Executor;
typedef std::tr1::shared_ptr<Command> CommandPtr;
typedef std::tr1::shared_ptr<Executor> ExecutorPtr;
class Command {
public:
POINTER_DEFINITIONS(Command);
virtual ~Command(){}
virtual void command() = 0;
private:
CommandPtr next;
friend class Executor;
};
class Executor : private NoDefaultMethods {
class Executor : public Runnable{
public:
POINTER_DEFINITIONS(Executor);
Executor(String threadName,ThreadPriority priority);
~Executor();
ExecutorNode * createNode(Command *command);
void execute(ExecutorNode *node);
void execute(CommandPtr const &node);
virtual void run();
private:
class ExecutorPvt *pImpl;
CommandPtr head;
CommandPtr tail;
epics::pvData::Mutex mutex;
epics::pvData::Event moreWork;
epics::pvData::Event stopped;
epics::pvData::Thread thread;
};
}}

View File

@@ -1,84 +0,0 @@
/* linkedList.h */
/**
* 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.
*/
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <pv/linkedListVoid.h>
namespace epics { namespace pvData {
template <typename T>
class LinkedList;
template <typename T>
class LinkedListNode : private LinkedListVoidNode {
public:
LinkedListNode(T &object) : LinkedListVoidNode(&object){}
~LinkedListNode() {}
T &getObject() { return *static_cast<T *>(LinkedListVoidNode::getObject());}
bool isOnList() {return LinkedListVoidNode::isOnList();}
friend class LinkedList<T>;
};
template <typename T>
class LinkedList : private LinkedListVoid {
public:
LinkedList() : LinkedListVoid() {}
~LinkedList() {}
int getLength() {return LinkedListVoid::getLength();}
void addTail(LinkedListNode<T> &listNode)
{
LinkedListVoid::addTail(static_cast<LinkedListVoidNode &>(listNode));
}
void addHead(LinkedListNode<T> &listNode)
{
LinkedListVoid::addHead(static_cast<LinkedListVoidNode &>(listNode));
}
void insertAfter(LinkedListNode<T> &listNode,
LinkedListNode<T> &addNode)
{
LinkedListVoid::insertAfter(
static_cast<LinkedListVoidNode &>(listNode),
static_cast<LinkedListVoidNode &>(addNode));
}
void insertBefore(LinkedListNode<T> &listNode,
LinkedListNode<T> &addNode)
{
LinkedListVoid::insertBefore(
static_cast<LinkedListVoidNode &>(listNode),
static_cast<LinkedListVoidNode &>(addNode));
}
LinkedListNode<T> *removeTail(){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::removeTail());
}
LinkedListNode<T> *removeHead(){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::removeHead());
}
void remove(LinkedListNode<T> &listNode){
LinkedListVoid::remove(static_cast<LinkedListVoidNode &>(listNode));
}
LinkedListNode<T> *getHead(){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::getHead());
}
LinkedListNode<T> *getTail(){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::getTail());
}
LinkedListNode<T> *getNext(LinkedListNode<T> &listNode){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::getNext(
static_cast<LinkedListVoidNode &>(listNode)));
}
LinkedListNode<T> *getPrev(LinkedListNode<T> &listNode){
return static_cast<LinkedListNode<T> *>(LinkedListVoid::getPrev(
static_cast<LinkedListVoidNode &>(listNode)));
}
bool isEmpty() { return LinkedListVoid::isEmpty();}
};
}}
#endif /* LINKEDLIST_H */

View File

@@ -1,210 +0,0 @@
/* linkedListVoid.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 <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <stdexcept>
#include <pv/lock.h>
#include <pv/pvType.h>
#include <pv/linkedListVoid.h>
#include <pv/CDRMonitor.h>
namespace epics { namespace pvData {
static String alreadyOnList("already on list");
PVDATA_REFCOUNT_MONITOR_DEFINE(LinkedListNode);
PVDATA_REFCOUNT_MONITOR_DEFINE(LinkedList);
LinkedListVoidNode::LinkedListVoidNode(void *object)
: object(object),before(0),after(0),linkedListVoid(0)
{
PVDATA_REFCOUNT_MONITOR_CONSTRUCT(LinkedListNode);
}
LinkedListVoidNode::LinkedListVoidNode(bool isHead)
: object(this),before(this),after(this)
{
PVDATA_REFCOUNT_MONITOR_CONSTRUCT(LinkedListNode);
}
LinkedListVoidNode::~LinkedListVoidNode()
{
PVDATA_REFCOUNT_MONITOR_DESTRUCT(LinkedListNode);
}
void *LinkedListVoidNode::getObject() {
return object;
}
bool LinkedListVoidNode::isOnList()
{
if(before==0 && after==0) return false;
return true;
}
LinkedListVoid::LinkedListVoid()
: head(new LinkedListVoidNode(true)),length(0)
{
PVDATA_REFCOUNT_MONITOR_CONSTRUCT(LinkedList);
}
LinkedListVoid::~LinkedListVoid()
{
delete head;
PVDATA_REFCOUNT_MONITOR_DESTRUCT(LinkedList);
}
int LinkedListVoid::getLength()
{
return length;
}
void LinkedListVoid::addTail(LinkedListVoidNode &node)
{
if(node.before!=0 || node.after!=0) {
throw std::logic_error(alreadyOnList);
}
node.linkedListVoid = this;
node.before = head->before;
node.after = head;
head->before->after = &node;
head->before = &node;
++length;
}
void LinkedListVoid::addHead(LinkedListVoidNode &node)
{
if(node.before!=0 || node.after!=0) {
throw std::logic_error(alreadyOnList);
}
node.linkedListVoid = this;
node.after = head->after;
node.before = head;
head->after->before = &node;
head->after = &node;
++length;
}
void LinkedListVoid::insertAfter(LinkedListVoidNode &node,
LinkedListVoidNode &addNode)
{
LinkedListVoidNode *existingNode = &node;
LinkedListVoidNode *newNode = &addNode;
if(existingNode->after==0 || existingNode->before==0) {
throw std::logic_error(String("listNode not on list"));
}
if(newNode->before!=0 || newNode->after!=0) {
throw std::logic_error(alreadyOnList);
}
if(node.linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
newNode->linkedListVoid = this;
newNode->after = existingNode->after;
newNode->before = existingNode;
existingNode->after->before = newNode;
existingNode->after = newNode;
++length;
}
void LinkedListVoid::insertBefore(LinkedListVoidNode &node,
LinkedListVoidNode &addNode)
{
LinkedListVoidNode *existingNode = &node;
LinkedListVoidNode *newNode = &addNode;
if(existingNode->after==0 || existingNode->before==0) {
throw std::logic_error(String("listNode not on list"));
}
if(newNode->before!=0 || newNode->after!=0) {
throw std::logic_error(alreadyOnList);
}
if(node.linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
newNode->linkedListVoid = this;
newNode->after = existingNode;
newNode->before = existingNode->before;
existingNode->before->after = newNode;
existingNode->before = newNode;
++length;
}
LinkedListVoidNode *LinkedListVoid::removeTail()
{
if(head->after==head) return 0;
LinkedListVoidNode *node = head->before;
remove(*head->before);
return node;
}
LinkedListVoidNode *LinkedListVoid::removeHead()
{
if(head->after==head) return 0;
LinkedListVoidNode *node = head->after;
remove(*head->after);
return node;
}
void LinkedListVoid::remove(LinkedListVoidNode &node)
{
if(node.before==0 || node.after==0) {
throw std::logic_error(String("node not on list"));
}
if(node.linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
node.linkedListVoid = 0;
LinkedListVoidNode *prev = node.before;
LinkedListVoidNode *next = node.after;
node.after = node.before = 0;
prev->after = next;
next->before = prev;
length--;
}
LinkedListVoidNode *LinkedListVoid::getHead()
{
if(head->after==head) return 0;
return head->after;
}
LinkedListVoidNode *LinkedListVoid::getTail()
{
if(head->after==head) return 0;
return head->before;
}
LinkedListVoidNode *LinkedListVoid::getNext(LinkedListVoidNode &listNode)
{
if(listNode.linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
if(listNode.after==head) return 0;
return listNode.after;
}
LinkedListVoidNode *LinkedListVoid::getPrev(LinkedListVoidNode &listNode)
{
if(listNode.linkedListVoid!=this) {
throw std::logic_error(String("node not on this list"));
}
if(listNode.before==head) return 0;
return listNode.before;
}
bool LinkedListVoid::isEmpty()
{
if(head->after==head) return true;
return false;
}
}}

View File

@@ -1,68 +0,0 @@
/* linkedListVoid.h */
/**
* 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.
*/
#ifndef LINKEDLISTVOID_H
#define LINKEDLISTVOID_H
#include <pv/pvType.h>
namespace epics { namespace pvData {
class LinkedListVoid;
class LinkedListVoidNode;
class LinkedListVoidNode {
public:
~LinkedListVoidNode();
void *getObject();
bool isOnList();
protected:
LinkedListVoidNode(void *object);
private:
LinkedListVoidNode(bool isHead);
friend class LinkedListVoid;
void *object;
LinkedListVoidNode *before;
LinkedListVoidNode *after;
LinkedListVoid *linkedListVoid;
// do not implement the following
LinkedListVoidNode(const LinkedListVoidNode&);
LinkedListVoidNode & operator=(const LinkedListVoidNode&);
};
class LinkedListVoid {
public:
~LinkedListVoid();
int getLength();
void addTail(LinkedListVoidNode &listNode);
void addHead(LinkedListVoidNode &listNode);
void insertAfter(LinkedListVoidNode &listNode,
LinkedListVoidNode &addNode);
void insertBefore(LinkedListVoidNode &listNode,
LinkedListVoidNode &addNode);
LinkedListVoidNode *removeTail();
LinkedListVoidNode *removeHead();
void remove(LinkedListVoidNode &listNode);
LinkedListVoidNode *getHead();
LinkedListVoidNode *getTail();
LinkedListVoidNode *getNext(LinkedListVoidNode &listNode);
LinkedListVoidNode *getPrev(LinkedListVoidNode &listNode);
bool isEmpty();
protected:
LinkedListVoid();
private:
friend class LinkedListVoidNode;
LinkedListVoidNode *head;
int length;
// do not implement the following
LinkedListVoid(const LinkedListVoid&);
LinkedListVoid & operator=(const LinkedListVoid&);
};
}}
#endif /* LINKEDLISTVOID_H */

View File

@@ -4,14 +4,19 @@
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <pv/noDefaultMethods.h>
#include <cstddef>
#include <cstdlib>
#include <cstddef>
#include <string>
#include <cstdio>
#include <pv/pvType.h>
#include <pv/timeStamp.h>
#include <pv/timeFunction.h>
namespace epics { namespace pvData {
TimeFunction::TimeFunction(TimeFunctionRequester *requester)
TimeFunction::TimeFunction(TimeFunctionRequesterPtr const &requester)
: requester(requester) {}

View File

@@ -6,24 +6,31 @@
*/
#ifndef TIMEFUNCTION_H
#define TIMEFUNCTION_H
#include <pv/noDefaultMethods.h>
#include <pv/pvType.h>
#include <pv/sharedPtr.h>
namespace epics { namespace pvData {
class TimeFunctionRequester;
class TimeFunction;
typedef std::tr1::shared_ptr<TimeFunctionRequester> TimeFunctionRequesterPtr;
typedef std::tr1::shared_ptr<TimeFunction> TimeFunctionPtr;
class TimeFunctionRequester {
public:
POINTER_DEFINITIONS(TimeFunctionRequester);
virtual ~TimeFunctionRequester(){}
virtual void function() = 0;
};
class TimeFunction : private NoDefaultMethods {
class TimeFunction {
public:
TimeFunction(TimeFunctionRequester *requester);
POINTER_DEFINITIONS(TimeFunction);
TimeFunction(TimeFunctionRequesterPtr const & requester);
~TimeFunction();
double timeCall();
private:
TimeFunctionRequester *requester;
TimeFunctionRequesterPtr requester;
};

View File

@@ -11,224 +11,201 @@
#include <stdio.h>
#include <stdexcept>
#include <pv/pvType.h>
#include <pv/lock.h>
#include <pv/noDefaultMethods.h>
#include <pv/CDRMonitor.h>
#include <pv/linkedList.h>
#include <pv/thread.h>
#include <pv/timeStamp.h>
#include <pv/timer.h>
#include <pv/event.h>
#include <pv/convert.h>
namespace epics { namespace pvData {
PVDATA_REFCOUNT_MONITOR_DEFINE(timerNode);
PVDATA_REFCOUNT_MONITOR_DEFINE(timer);
TimerCallback::TimerCallback()
: period(0.0),
onList(false)
{
}
typedef LinkedListNode<TimerNode::Pvt> TimerListNode;
typedef LinkedList<TimerNode::Pvt> TimerList;
class TimerNode::Pvt {
public:
TimerNode *timerNode;
TimerCallback *callback;
TimerListNode timerListNode;
TimeStamp timeToRun;
Timer::Pvt *timerPvt;
double period;
Pvt(TimerNode &timerNode,TimerCallback &callback);
~Pvt(){}
private:
};
TimerNode::Pvt::Pvt(TimerNode &timerNode,TimerCallback &callback)
: timerNode(&timerNode),callback(&callback),
timerListNode(*this),timeToRun(),
timerPvt(0), period(0.0)
{}
struct Timer::Pvt : public Runnable{
public:
Pvt(String threadName,ThreadPriority priority);
virtual void run();
public: // only used by this source module
TimerList timerList;
Mutex mutex;
Event waitForWork;
Event waitForDone;
bool alive;
Thread thread;
void addElement(TimerNode::Pvt &node);
};
Timer::Pvt::Pvt(String threadName,ThreadPriority priority)
: timerList(),
mutex(),
waitForWork(false),
Timer::Timer(String threadName,ThreadPriority priority)
: waitForWork(false),
waitForDone(false),
alive(true),
thread(threadName,priority,this)
{}
void Timer::Pvt::addElement(TimerNode::Pvt &node)
void Timer::addElement(TimerCallbackPtr const & timerCallback)
{
TimerListNode *nextNode = timerList.getHead();
if(nextNode==0) {
timerList.addTail(node.timerListNode);
timerCallback->onList = true;
if(head.get()==NULL) {
head = timerCallback;
timerCallback->next.reset();
return;
}
TimerCallbackPtr nextNode(head);
TimerCallbackPtr prevNode;
while(true) {
TimerNode::Pvt &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);
if(timerCallback->timeToRun < nextNode->timeToRun) {
if(prevNode.get()!=NULL) {
prevNode->next = timerCallback;
} else {
head = timerCallback;
}
timerCallback->next = nextNode;
return;
}
if(nextNode->next.get()==NULL) {
nextNode->next = timerCallback;
timerCallback->next.reset();
return;
}
prevNode = nextNode;
nextNode = nextNode->next;
}
}
TimerNode::TimerNode(TimerCallback &callback)
: pImpl(new Pvt(*this,callback))
void Timer::cancel(TimerCallbackPtr const &timerCallback)
{
PVDATA_REFCOUNT_MONITOR_CONSTRUCT(timerNode);
Lock xx(mutex);
if(!timerCallback->onList) return;
TimerCallbackPtr nextNode(head);
TimerCallbackPtr prevNode;
while(true) {
if(nextNode.get()==timerCallback.get()) {
if(prevNode.get()!=NULL) {
prevNode->next = timerCallback->next;
} else {
head = timerCallback->next;
}
timerCallback->next.reset();
timerCallback->onList = false;
return;
}
prevNode = nextNode;
nextNode = nextNode->next;
}
throw std::logic_error(String(""));
}
bool Timer::isScheduled(TimerCallbackPtr const &timerCallback)
{
Lock xx(mutex);
return timerCallback->onList;
}
TimerNode::~TimerNode()
{
cancel();
PVDATA_REFCOUNT_MONITOR_DESTRUCT(timerNode);
}
void TimerNode::cancel()
{
Timer::Pvt *timerPvt = pImpl->timerPvt;
if(timerPvt==0) return;
Lock xx(timerPvt->mutex);
if(pImpl->timerPvt==0) return;
pImpl->timerPvt->timerList.remove(pImpl->timerListNode);
pImpl->timerPvt = 0;
}
bool TimerNode::isScheduled()
{
Timer::Pvt *pvt = pImpl->timerPvt;
if(pvt==0) return false;
Lock xx(pvt->mutex);
return pImpl->timerListNode.isOnList();
}
void Timer::Pvt::run()
void Timer::run()
{
TimeStamp currentTime;
while(true) {
currentTime.getCurrent();
TimeStamp *timeToRun = 0;
double period = 0.0;
TimerNode::Pvt *nodeToCall = 0;
TimerCallbackPtr nodeToCall;
{
Lock xx(mutex);
currentTime.getCurrent();
if (!alive) break;
TimerListNode *timerListNode = timerList.getHead();
if(timerListNode!=0) {
TimerNode::Pvt *timerNodePvt = &timerListNode->getObject();
timeToRun = &timerNodePvt->timeToRun;
TimerCallbackPtr timerCallback = head;
if(timerCallback.get()!=NULL) {
double diff = TimeStamp::diff(
*timeToRun,currentTime);
timerCallback->timeToRun,currentTime);
if(diff<=0.0) {
nodeToCall = timerNodePvt;
timerList.removeHead();
period = timerNodePvt->period;
nodeToCall = timerCallback;
nodeToCall->onList = false;
head = head->next;
period = timerCallback->period;
if(period>0.0) {
timerNodePvt->timeToRun += period;
addElement(*timerNodePvt);
} else {
timerNodePvt->timerPvt = 0;
}
timerListNode = timerList.getHead();
if(timerListNode!=0) {
timerNodePvt = &timerListNode->getObject();
timeToRun = &timerNodePvt->timeToRun;
} else {
timeToRun = 0;
timerCallback->timeToRun += period;
addElement(timerCallback);
}
timerCallback = head;
}
}
}
if(nodeToCall!=0) {
nodeToCall->callback->callback();
if(nodeToCall.get()!=NULL) {
nodeToCall->callback();
}
{
Lock xx(mutex);
if(!alive) break;
}
if(timeToRun==0) {
if(head.get()==NULL) {
waitForWork.wait();
} else {
double delay = TimeStamp::diff(*timeToRun,currentTime);
double delay = TimeStamp::diff(head->timeToRun,currentTime);
waitForWork.wait(delay);
}
}
waitForDone.signal();
}
Timer::Timer(String threadName, ThreadPriority priority)
: pImpl(new Pvt(threadName,priority))
{
PVDATA_REFCOUNT_MONITOR_CONSTRUCT(timer);
}
Timer::~Timer() {
{
Lock xx(pImpl->mutex);
pImpl->alive = false;
Lock xx(mutex);
alive = false;
}
pImpl->waitForWork.signal();
pImpl->waitForDone.wait();
TimerListNode *node = 0;
while((node = pImpl->timerList.removeHead())!=0) {
node->getObject().callback->timerStopped();
waitForWork.signal();
waitForDone.wait();
TimerCallbackPtr timerCallback;
while(true) {
timerCallback = head;
if(head.get()==NULL) break;
head->timerStopped();
head = timerCallback->next;
timerCallback->next.reset();
timerCallback->onList = false;
}
PVDATA_REFCOUNT_MONITOR_DESTRUCT(timer);
}
void Timer::scheduleAfterDelay(TimerNode &timerNode,double delay)
void Timer::scheduleAfterDelay(
TimerCallbackPtr const &timerCallback,
double delay)
{
schedulePeriodic(timerNode,delay,0.0);
schedulePeriodic(timerCallback,delay,0.0);
}
void Timer::schedulePeriodic(TimerNode &timerNode,double delay,double period)
void Timer::schedulePeriodic(
TimerCallbackPtr const &timerCallback,
double delay,
double period)
{
TimerNode::Pvt *timerNodePvt = timerNode.pImpl.get();
if(timerNodePvt->timerListNode.isOnList()) {
if(isScheduled(timerCallback)) {
throw std::logic_error(String("already queued"));
}
{
Lock xx(pImpl->mutex);
if(!pImpl->alive) {
timerNodePvt->callback->timerStopped();
Lock xx(mutex);
if(!alive) {
timerCallback->timerStopped();
return;
}
}
TimeStamp *timeStamp = &timerNodePvt->timeToRun;
timeStamp->getCurrent();
*timeStamp += delay;
timerNodePvt->period = period;
TimeStamp timeStamp;
timeStamp.getCurrent();
timeStamp += delay;
timerCallback->timeToRun.getCurrent();
timerCallback->timeToRun += delay;
timerCallback->period = period;
bool isFirst = false;
{
Lock xx(pImpl->mutex);
timerNodePvt->timerPvt = pImpl.get();
pImpl->addElement(*timerNodePvt);
TimerNode::Pvt *first = &pImpl->timerList.getHead()->getObject();
if(first==timerNodePvt) isFirst = true;
Lock xx(mutex);
addElement(timerCallback);
if(timerCallback.get()==head.get()) isFirst = true;
}
if(isFirst) pImpl->waitForWork.signal();
if(isFirst) waitForWork.signal();
}
void Timer::toString(StringBuilder builder)
{
Lock xx(mutex);
if(!alive) return;
TimeStamp currentTime;
TimerCallbackPtr nodeToCall(head);
currentTime.getCurrent();
while(true) {
if(nodeToCall.get()==NULL) return;
TimeStamp timeToRun = nodeToCall->timeToRun;
double period = nodeToCall->period;
double diff = TimeStamp::diff(timeToRun,currentTime);
char buffer[50];
sprintf(buffer,"timeToRun %f period %f\n",diff,period);
*builder += buffer;
nodeToCall = nodeToCall->next;
}
}
}}

View File

@@ -15,44 +15,57 @@
#include <pv/pvType.h>
#include <pv/thread.h>
#include <pv/noDefaultMethods.h>
#include <pv/timeStamp.h>
#include <pv/event.h>
#include <pv/lock.h>
#include <pv/sharedPtr.h>
namespace epics { namespace pvData {
class TimerCallback;
class Timer;
typedef std::tr1::shared_ptr<TimerCallback> TimerCallbackPtr;
typedef std::tr1::shared_ptr<Timer> TimerPtr;
class TimerCallback {
public:
POINTER_DEFINITIONS(TimerCallback);
TimerCallback();
virtual ~TimerCallback(){}
virtual void callback() = 0;
virtual void timerStopped() = 0;
};
class TimerNode {
public:
TimerNode(TimerCallback &timerCallback);
~TimerNode();
void cancel();
bool isScheduled();
class Pvt;
private:
std::auto_ptr<Pvt> pImpl;
TimerCallbackPtr next;
TimeStamp timeToRun;
double period;
bool onList;
friend class Timer;
};
class Timer : private NoDefaultMethods {
class Timer : public Runnable {
public:
POINTER_DEFINITIONS(Timer);
Timer(String threadName, ThreadPriority priority);
~Timer();
void scheduleAfterDelay(TimerNode &timerNode,double delay);
void schedulePeriodic(TimerNode &timerNode,double delay,double period);
class Pvt;
virtual ~Timer();
virtual void run();
void scheduleAfterDelay(
TimerCallbackPtr const &timerCallback,
double delay);
void schedulePeriodic(
TimerCallbackPtr const &timerCallback,
double delay,
double period);
void cancel(TimerCallbackPtr const &timerCallback);
bool isScheduled(TimerCallbackPtr const &timerCallback);
void toString(StringBuilder builder);
private:
std::auto_ptr<Pvt> pImpl;
void addElement(TimerCallbackPtr const &timerCallback);
TimerCallbackPtr head;
Mutex mutex;
Event waitForWork;
Event waitForDone;
bool alive;
Thread thread;
};
}}