more shared_pointer everywhere
This commit is contained in:
@@ -16,9 +16,6 @@ INC += serializeHelper.h
|
||||
INC += event.h
|
||||
INC += thread.h
|
||||
INC += executor.h
|
||||
INC += linkedList.h
|
||||
INC += linkedListVoid.h
|
||||
INC += CDRMonitor.h
|
||||
INC += timeFunction.h
|
||||
INC += timer.h
|
||||
INC += queue.h
|
||||
@@ -27,13 +24,11 @@ INC += destroyable.h
|
||||
INC += status.h
|
||||
INC += sharedPtr.h
|
||||
|
||||
LIBSRCS += CDRMonitor.cpp
|
||||
LIBSRCS += byteBuffer.cpp
|
||||
LIBSRCS += bitSet.cpp
|
||||
LIBSRCS += epicsException.cpp
|
||||
LIBSRCS += requester.cpp
|
||||
LIBSRCS += serializeHelper.cpp
|
||||
LIBSRCS += linkedListVoid.cpp
|
||||
LIBSRCS += event.cpp
|
||||
LIBSRCS += executor.cpp
|
||||
LIBSRCS += timeFunction.cpp
|
||||
|
||||
@@ -3316,9 +3316,6 @@ size_t copyNumericArray(PVScalarArray *from, size_t offset, PVScalarArray *to, s
|
||||
}
|
||||
return ncopy;
|
||||
}
|
||||
#ifdef XXXXXXXXX
|
||||
|
||||
#endif ///MARTY REMOVE THIS XXXXXXX
|
||||
|
||||
ConvertPtr Convert::getConvert()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);}
|
||||
|
||||
}}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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 */
|
||||
|
||||
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
@@ -42,10 +42,6 @@ PROD_HOST += testMessageQueue
|
||||
testMessageQueue_SRCS += testMessageQueue.cpp
|
||||
testMessageQueue_LIBS += pvData Com
|
||||
|
||||
PROD_HOST += testLinkedList
|
||||
testLinkedList_SRCS += testLinkedList.cpp
|
||||
testLinkedList_LIBS += pvData Com
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <pv/bitSet.h>
|
||||
#include <pv/CDRMonitor.h>
|
||||
|
||||
#include <epicsAssert.h>
|
||||
#include <epicsExit.h>
|
||||
@@ -150,8 +149,6 @@ int main(int argc,char *argv[])
|
||||
}
|
||||
testGetSetClearFlip(fd);
|
||||
testOperators(fd);
|
||||
epicsExitCallAtExits();
|
||||
CDRMonitor::get().show(fd);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,450 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* testLinkedList.cpp
|
||||
*
|
||||
* Created on: 2010.11
|
||||
* Author: Marty Kraimer
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
|
||||
#include <epicsAssert.h>
|
||||
#include <epicsExit.h>
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/linkedList.h>
|
||||
#include <pv/CDRMonitor.h>
|
||||
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
static const int numNodes = 5;
|
||||
class Basic;
|
||||
typedef LinkedListNode<Basic> BasicListNode;
|
||||
typedef LinkedList<Basic> BasicList;
|
||||
|
||||
class Basic {
|
||||
public:
|
||||
Basic(int i): index(i),node(*this) {}
|
||||
~Basic() { }
|
||||
int index;
|
||||
BasicListNode node;
|
||||
};
|
||||
|
||||
static void testBasic(FILE * fd ) {
|
||||
LinkedList<Basic> basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
basicList.addTail(basics[i]->node);
|
||||
assert(basicList.getLength()==i+1);
|
||||
}
|
||||
BasicListNode *basicNode = basicList.getHead();
|
||||
fprintf(fd,"basic addTail");
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
basicNode = basicList.getNext(*basicNode);
|
||||
}
|
||||
assert(basicList.isEmpty()==false);
|
||||
basicNode = basicList.getTail();
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
assert(basicNode->isOnList());
|
||||
basicNode = basicList.getPrev(*basicNode);
|
||||
}
|
||||
fprintf(fd,"\n");
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basicNode = basicList.getHead();
|
||||
assert(basicNode!=0);
|
||||
Basic &basic = basicNode->getObject();
|
||||
assert(basic.index==i);
|
||||
assert(basics[i]->node.isOnList()==true);
|
||||
basicList.remove(basics[i]->node);
|
||||
assert(basics[i]->node.isOnList()==false);
|
||||
int length = basicList.getLength();
|
||||
assert(length==(numNodes-i-1));
|
||||
}
|
||||
assert(basicList.isEmpty());
|
||||
for(int i=numNodes-1; i>=0; i--) {
|
||||
basicList.addHead(basics[i]->node);
|
||||
assert(basicList.getLength()==numNodes-i);
|
||||
}
|
||||
basicNode = basicList.getHead();
|
||||
fprintf(fd,"basic addHead");
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
basicNode = basicList.getNext(*basicNode);
|
||||
}
|
||||
fprintf(fd,"\n");
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basicNode = basicList.getHead();
|
||||
assert(basicNode!=0);
|
||||
Basic &basic = basicNode->getObject();
|
||||
assert(basic.index==i);
|
||||
basicList.removeHead();
|
||||
assert(basic.node.isOnList()==false);
|
||||
int length = basicList.getLength();
|
||||
assert(length==(numNodes-i-1));
|
||||
}
|
||||
assert(basicList.isEmpty());
|
||||
basicList.addTail(basics[0]->node);
|
||||
basicNode = basicList.getTail();
|
||||
assert(basicNode->getObject().index==0);
|
||||
for(int i=1;i<numNodes;i++) {
|
||||
basicList.insertAfter(*basicNode,basics[i]->node);
|
||||
basicNode = basicList.getTail();
|
||||
assert(basicList.getLength()==i+1);
|
||||
}
|
||||
fprintf(fd,"basic addTail insertAfter");
|
||||
basicNode = basicList.getHead();
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
basicNode = basicList.getNext(*basicNode);
|
||||
}
|
||||
fprintf(fd,"\n");
|
||||
for(int i=numNodes-1; i>=0; i--) {
|
||||
Basic &basic = basicList.getTail()->getObject();
|
||||
assert(basic.index==i);
|
||||
basicList.removeTail();
|
||||
assert(basic.node.isOnList()==false);
|
||||
int length = basicList.getLength();
|
||||
assert(length==i);
|
||||
}
|
||||
assert(basicList.isEmpty());
|
||||
basicList.addHead(basics[numNodes-1]->node);
|
||||
basicNode = basicList.getHead();
|
||||
assert(basicNode->getObject().index==4);
|
||||
for(int i=numNodes-2; i>=0; i--) {
|
||||
basicList.insertBefore(*basicNode,basics[i]->node);
|
||||
basicNode = basicList.getHead();
|
||||
assert(basicList.getLength()==numNodes-i);
|
||||
}
|
||||
fprintf(fd,"basic addTail insertBefore");
|
||||
basicNode = basicList.getHead();
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
basicNode = basicList.getNext(*basicNode);
|
||||
}
|
||||
fprintf(fd,"\n");
|
||||
for(int i=numNodes-1; i>=0; i--) {
|
||||
Basic &basic = basicList.getTail()->getObject();
|
||||
assert(basic.index==i);
|
||||
basicList.remove(basic.node);
|
||||
assert(basic.node.isOnList()==false);
|
||||
int length = basicList.getLength();
|
||||
assert(length==i);
|
||||
}
|
||||
assert(basicList.isEmpty());
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
static void testQueue(FILE * fd ) {
|
||||
LinkedList<Basic> basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
}
|
||||
fprintf(fd,"\nQueue test\n");
|
||||
for(int i=0;i<numNodes;i++) {
|
||||
basicList.addTail(basics[i]->node);
|
||||
assert(basicList.getLength()==i+1);
|
||||
}
|
||||
BasicListNode *basicNode = basicList.removeHead();
|
||||
while(basicNode!=0) basicNode = basicList.removeHead();
|
||||
for(int i=0;i<numNodes;i++) basicList.addTail(basics[i]->node);
|
||||
basicNode = basicList.removeHead();
|
||||
fprintf(fd,"queue");
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
basicNode = basicList.removeHead();
|
||||
}
|
||||
fprintf(fd,"\n");
|
||||
assert(basicList.isEmpty());
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
static void testStack(FILE * fd ) {
|
||||
LinkedList<Basic> basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
}
|
||||
fprintf(fd,"\nStack test\n");
|
||||
for(int i=0;i<numNodes;i++) {
|
||||
basicList.addHead(basics[i]->node);
|
||||
assert(basicList.getLength()==i+1);
|
||||
}
|
||||
BasicListNode *basicNode = basicList.removeHead();
|
||||
while(basicNode!=0) basicNode = basicList.removeHead();
|
||||
for(int i=0;i<numNodes;i++) basicList.addHead(basics[i]->node);
|
||||
basicNode = basicList.removeHead();
|
||||
fprintf(fd,"stack");
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
basicNode = basicList.removeHead();
|
||||
}
|
||||
fprintf(fd,"\n");
|
||||
assert(basicList.isEmpty());
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
static void testList(FILE * fd ) {
|
||||
LinkedList<Basic> basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
}
|
||||
fprintf(fd,"\ntestList\n");
|
||||
for(int i=0;i<numNodes;i++) basicList.addTail(basics[i]->node);
|
||||
fprintf(fd,"list");
|
||||
BasicListNode *basicNode = basicList.removeHead();
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
basicNode = basicList.removeHead();
|
||||
}
|
||||
fprintf(fd,"\n");
|
||||
assert(basicList.isEmpty());
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
static void testRandomInsertRemove(FILE * fd ) {
|
||||
LinkedList<Basic> basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
}
|
||||
fprintf(fd,"\nRandom insert/remove test\n");
|
||||
basicList.addHead(basics[4]->node);
|
||||
basicList.insertAfter(basics[4]->node,basics[3]->node);
|
||||
basicList.insertAfter(basics[3]->node,basics[2]->node);
|
||||
basicList.addTail(basics[1]->node);
|
||||
basicList.addTail(basics[0]->node);
|
||||
BasicListNode *basicNode = basicList.removeHead();
|
||||
fprintf(fd,"stack");
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
basicNode = basicList.removeHead();
|
||||
}
|
||||
fprintf(fd,"\n");
|
||||
assert(basicList.isEmpty());
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
static void testOrderedQueue(FILE * fd ) {
|
||||
LinkedList<Basic> basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
}
|
||||
BasicListNode *basicNode = 0;
|
||||
fprintf(fd,"\nOrdered Queue test\n");
|
||||
basicList.addHead(basics[2]->node);
|
||||
for(int i=0;i<numNodes;i++) {
|
||||
if(basics[i]->node.isOnList()) continue;
|
||||
basicNode = basicList.getHead();
|
||||
while(basicNode!=0) {
|
||||
if(basicNode->getObject().index>=basics[i]->index) {
|
||||
basicList.insertBefore(*basicNode,basics[i]->node);
|
||||
break;
|
||||
}
|
||||
basicNode = basicList.getNext(*basicNode);
|
||||
}
|
||||
if(basics[i]->node.isOnList()) continue;
|
||||
basicList.addTail(basics[i]->node);
|
||||
}
|
||||
fprintf(fd,"list");
|
||||
basicNode = basicList.removeHead();
|
||||
while(basicNode!=0) {
|
||||
fprintf(fd," %d",basicNode->getObject().index);
|
||||
basicNode = basicList.removeHead();
|
||||
}
|
||||
fprintf(fd,"\n");
|
||||
assert(basicList.isEmpty());
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
static void testTime(FILE *auxFd) {
|
||||
TimeStamp startTime;
|
||||
TimeStamp endTime;
|
||||
const int numNodes = 1000;
|
||||
|
||||
LinkedList<Basic> basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
}
|
||||
fprintf(auxFd,"\nTime test\n");
|
||||
int ntimes = 1000;
|
||||
startTime.getCurrent();
|
||||
for(int i=0; i<ntimes; i++) {
|
||||
for(int j=0;j<numNodes;j++) basicList.addTail(basics[j]->node);
|
||||
BasicListNode *basicNode = basicList.removeHead();
|
||||
while(basicNode!=0) basicNode = basicList.removeHead();
|
||||
}
|
||||
endTime.getCurrent();
|
||||
double diff = TimeStamp::diff(endTime,startTime);
|
||||
diff *= 1000.0;
|
||||
fprintf(auxFd,"diff %f milliSeconds\n",diff);
|
||||
diff = diff/1000.0; // convert from milliseconds to seconds
|
||||
diff = diff/ntimes; // seconds per outer loop
|
||||
diff = diff*1e6; // converty to microseconds
|
||||
fprintf(auxFd,"time per iteration %f microseconds\n",diff);
|
||||
diff = diff/(numNodes*2); // convert to per addTail/removeHead
|
||||
fprintf(auxFd,"time per addTail/removeHead %f microseconds\n",diff);
|
||||
assert(basicList.isEmpty());
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
static void testTimeLocked(FILE *auxFd) {
|
||||
TimeStamp startTime;
|
||||
TimeStamp endTime;
|
||||
Mutex mutex;
|
||||
const int numNodes = 1000;
|
||||
|
||||
LinkedList<Basic> basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
}
|
||||
fprintf(auxFd,"\nTime test locked\n");
|
||||
int ntimes = 1000;
|
||||
startTime.getCurrent();
|
||||
for(int i=0; i<ntimes; i++) {
|
||||
for(int j=0;j<numNodes;j++) {
|
||||
Lock xx(mutex);
|
||||
basicList.addTail(basics[j]->node);
|
||||
}
|
||||
BasicListNode *basicNode = 0;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
basicNode = basicList.removeHead();
|
||||
}
|
||||
while(basicNode!=0) {
|
||||
Lock xx(mutex);
|
||||
basicNode = basicList.removeHead();
|
||||
}
|
||||
}
|
||||
endTime.getCurrent();
|
||||
double diff = TimeStamp::diff(endTime,startTime);
|
||||
diff *= 1000.0;
|
||||
fprintf(auxFd,"diff %f milliSeconds\n",diff);
|
||||
diff = diff/1000.0; // convert from milliseconds to seconds
|
||||
diff = diff/ntimes; // seconds per outer loop
|
||||
diff = diff*1e6; // converty to microseconds
|
||||
fprintf(auxFd,"time per iteration %f microseconds\n",diff);
|
||||
diff = diff/(numNodes*2); // convert to per addTail/removeHead
|
||||
fprintf(auxFd,"time per addTail/removeHead %f microseconds\n",diff);
|
||||
assert(basicList.isEmpty());
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
typedef std::list<Basic *> stdList;
|
||||
static void testStdListTime(FILE *auxFd) {
|
||||
TimeStamp startTime;
|
||||
TimeStamp endTime;
|
||||
const int numNodes = 1000;
|
||||
|
||||
stdList basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
}
|
||||
fprintf(auxFd,"\nTime std::list test\n");
|
||||
int ntimes = 1000;
|
||||
startTime.getCurrent();
|
||||
for(int i=0; i<ntimes; i++) {
|
||||
for(int j=0;j<numNodes;j++) basicList.push_back(basics[j]);
|
||||
while(basicList.size()>0) {
|
||||
basicList.begin();
|
||||
basicList.pop_front();
|
||||
}
|
||||
}
|
||||
endTime.getCurrent();
|
||||
double diff = TimeStamp::diff(endTime,startTime);
|
||||
diff *= 1000.0;
|
||||
fprintf(auxFd,"diff %f milliSeconds\n",diff);
|
||||
diff = diff/1000.0; // convert from milliseconds to seconds
|
||||
diff = diff/ntimes; // seconds per outer loop
|
||||
diff = diff*1e6; // converty to microseconds
|
||||
fprintf(auxFd,"time per iteration %f microseconds\n",diff);
|
||||
diff = diff/(numNodes*2); // convert to per addTail/removeHead
|
||||
fprintf(auxFd,"time per addTail/removeHead %f microseconds\n",diff);
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
static void testStdListTimeLocked(FILE *auxFd) {
|
||||
TimeStamp startTime;
|
||||
TimeStamp endTime;
|
||||
const int numNodes = 1000;
|
||||
Mutex mutex;
|
||||
|
||||
stdList basicList;
|
||||
Basic *basics[numNodes];
|
||||
for(int i=0; i<numNodes; i++) {
|
||||
basics[i] = new Basic(i);
|
||||
}
|
||||
fprintf(auxFd,"\nTime std::list test locked\n");
|
||||
int ntimes = 1000;
|
||||
startTime.getCurrent();
|
||||
for(int i=0; i<ntimes; i++) {
|
||||
for(int j=0;j<numNodes;j++) {
|
||||
Lock xx(mutex);
|
||||
basicList.push_back(basics[j]);
|
||||
}
|
||||
while(basicList.size()>0) {
|
||||
Lock xx(mutex);
|
||||
basicList.begin();
|
||||
basicList.pop_front();
|
||||
}
|
||||
}
|
||||
endTime.getCurrent();
|
||||
double diff = TimeStamp::diff(endTime,startTime);
|
||||
diff *= 1000.0;
|
||||
fprintf(auxFd,"diff %f milliSeconds\n",diff);
|
||||
diff = diff/1000.0; // convert from milliseconds to seconds
|
||||
diff = diff/ntimes; // seconds per outer loop
|
||||
diff = diff*1e6; // converty to microseconds
|
||||
fprintf(auxFd,"time per iteration %f microseconds\n",diff);
|
||||
diff = diff/(numNodes*2); // convert to per addTail/removeHead
|
||||
fprintf(auxFd,"time per addTail/removeHead %f microseconds\n",diff);
|
||||
for(int i=0; i<numNodes; i++) delete basics[i];
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *fileName = 0;
|
||||
if(argc>1) fileName = argv[1];
|
||||
FILE * fd = stdout;
|
||||
if(fileName!=0 && fileName[0]!=0) {
|
||||
fd = fopen(fileName,"w+");
|
||||
}
|
||||
char *auxFileName = 0;
|
||||
if(argc>2) auxFileName = argv[2];
|
||||
FILE *auxFd = stdout;
|
||||
if(auxFileName!=0 && auxFileName[0]!=0) {
|
||||
auxFd = fopen(auxFileName,"w+");
|
||||
}
|
||||
testBasic(fd);
|
||||
testQueue(fd);
|
||||
testStack(fd);
|
||||
testList(fd);
|
||||
testRandomInsertRemove(fd);
|
||||
testOrderedQueue(fd);
|
||||
testTime(auxFd);
|
||||
testTimeLocked(auxFd);
|
||||
testStdListTime(auxFd);
|
||||
testStdListTimeLocked(auxFd);
|
||||
epicsExitCallAtExits();
|
||||
CDRMonitor::get().show(fd);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/requester.h>
|
||||
#include <pv/messageQueue.h>
|
||||
#include <pv/CDRMonitor.h>
|
||||
#include <pv/event.h>
|
||||
#include <pv/thread.h>
|
||||
#include <pv/executor.h>
|
||||
@@ -89,8 +88,6 @@ int main(int argc, char *argv[]) {
|
||||
auxfd = fopen(auxFileName,"w+");
|
||||
}
|
||||
testBasic(fd,auxfd);
|
||||
epicsExitCallAtExits();
|
||||
CDRMonitor::get().show(fd);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <pv/serialize.h>
|
||||
#include <pv/noDefaultMethods.h>
|
||||
#include <pv/byteBuffer.h>
|
||||
#include <pv/CDRMonitor.h>
|
||||
#include <pv/convert.h>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
@@ -661,8 +660,6 @@ int main(int argc, char *argv[]) {
|
||||
delete flusher;
|
||||
|
||||
epicsExitCallAtExits();
|
||||
(*out)<<"Done.\n"<<CDRMonitor::get();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <pv/event.h>
|
||||
#include <pv/thread.h>
|
||||
#include <pv/executor.h>
|
||||
#include <pv/CDRMonitor.h>
|
||||
#include <pv/timeFunction.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
@@ -39,7 +38,7 @@ public:
|
||||
begin.signal();
|
||||
bool waited=end.wait();
|
||||
actuallyRan=true;
|
||||
fprintf(out, "Action1 %s\n", waited?"true":"false");
|
||||
fprintf(out, "Action %s\n", waited?"true":"false");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -49,81 +48,89 @@ static void testThreadRun(FILE *fd) {
|
||||
{
|
||||
Thread tr("Action", lowPriority, &ax);
|
||||
bool w=ax.begin.wait();
|
||||
fprintf(fd, "main1 %s\n", w?"true":"false");
|
||||
fprintf(fd, "main %s\n", w?"true":"false");
|
||||
fprintf(fd, "Action is %s\n", ax.actuallyRan?"true":"false");
|
||||
ax.end.signal();
|
||||
}
|
||||
fprintf(fd, "Action is %s\n", ax.actuallyRan?"true":"false");
|
||||
}
|
||||
|
||||
class Basic : public Command {
|
||||
class Basic :
|
||||
public Command,
|
||||
public std::tr1::enable_shared_from_this<Basic>
|
||||
{
|
||||
public:
|
||||
Basic(Executor *executor);
|
||||
POINTER_DEFINITIONS(Basic);
|
||||
Basic(ExecutorPtr const &executor);
|
||||
~Basic();
|
||||
void run();
|
||||
virtual void command();
|
||||
private:
|
||||
Executor *executor;
|
||||
ExecutorNode *executorNode;
|
||||
Event *wait;
|
||||
Basic::shared_pointer getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
ExecutorPtr executor;
|
||||
Event wait;
|
||||
};
|
||||
|
||||
Basic::Basic(Executor *executor)
|
||||
: executor(executor),
|
||||
executorNode(executor->createNode(this)),
|
||||
wait(new Event())
|
||||
typedef std::tr1::shared_ptr<Basic> BasicPtr;
|
||||
|
||||
Basic::Basic(ExecutorPtr const &executor)
|
||||
: executor(executor)
|
||||
{
|
||||
}
|
||||
|
||||
Basic::~Basic() {
|
||||
delete wait;
|
||||
}
|
||||
|
||||
void Basic::run()
|
||||
{
|
||||
executor->execute(executorNode);
|
||||
bool result = wait->wait();
|
||||
executor->execute(getPtrSelf());
|
||||
bool result = wait.wait();
|
||||
if(result==false) printf("basic::run wait returned false\n");
|
||||
}
|
||||
|
||||
void Basic::command()
|
||||
{
|
||||
wait->signal();
|
||||
wait.signal();
|
||||
}
|
||||
|
||||
|
||||
static void testBasic(FILE *fd) {
|
||||
Executor *executor = new Executor(String("basic"),middlePriority);
|
||||
Basic *basic = new Basic(executor);
|
||||
ExecutorPtr executor( new Executor(String("basic"),middlePriority));
|
||||
BasicPtr basic( new Basic(executor));
|
||||
basic->run();
|
||||
delete basic;
|
||||
String buf("");
|
||||
delete executor;
|
||||
}
|
||||
|
||||
class MyFunc : public TimeFunctionRequester {
|
||||
public:
|
||||
MyFunc(Basic *basic)
|
||||
: basic(basic)
|
||||
{}
|
||||
virtual void function()
|
||||
{
|
||||
basic->run();
|
||||
}
|
||||
POINTER_DEFINITIONS(MyFunc);
|
||||
MyFunc(BasicPtr const &basic);
|
||||
virtual void function();
|
||||
private:
|
||||
Basic *basic;
|
||||
BasicPtr basic;
|
||||
};
|
||||
|
||||
MyFunc::MyFunc(BasicPtr const &basic)
|
||||
: basic(basic)
|
||||
{}
|
||||
void MyFunc::function()
|
||||
{
|
||||
basic->run();
|
||||
}
|
||||
|
||||
|
||||
typedef std::tr1::shared_ptr<MyFunc> MyFuncPtr;
|
||||
|
||||
static void testThreadContext(FILE *fd,FILE *auxFd) {
|
||||
Executor *executor = new Executor(String("basic"),middlePriority);
|
||||
Basic *basic = new Basic(executor);
|
||||
MyFunc myFunc(basic);
|
||||
TimeFunction timeFunction(&myFunc);
|
||||
double perCall = timeFunction.timeCall();
|
||||
ExecutorPtr executor(new Executor(String("basic"),middlePriority));
|
||||
BasicPtr basic(new Basic(executor));
|
||||
MyFuncPtr myFunc(new MyFunc(basic));
|
||||
TimeFunctionPtr timeFunction(new TimeFunction(myFunc));
|
||||
double perCall = timeFunction->timeCall();
|
||||
perCall *= 1e6;
|
||||
fprintf(auxFd,"time per call %f microseconds\n",perCall);
|
||||
delete basic;
|
||||
delete executor;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
@@ -142,7 +149,5 @@ int main(int argc, char *argv[]) {
|
||||
testThreadRun(fd);
|
||||
testBasic(fd);
|
||||
testThreadContext(fd,auxFd);
|
||||
epicsExitCallAtExits();
|
||||
CDRMonitor::get().show(fd);
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -22,19 +22,26 @@
|
||||
#include <pv/event.h>
|
||||
#include <pv/timer.h>
|
||||
#include <pv/thread.h>
|
||||
#include <pv/CDRMonitor.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
static TimeStamp currentTimeStamp;
|
||||
static double oneDelay = 4.0;
|
||||
static double twoDelay = 2.0;
|
||||
static double threeDelay = 1.0;
|
||||
static int ntimes = 3;
|
||||
|
||||
class MyCallback;
|
||||
typedef std::tr1::shared_ptr<MyCallback> MyCallbackPtr;
|
||||
|
||||
class MyCallback : public TimerCallback {
|
||||
public:
|
||||
MyCallback(String name,FILE *fd,FILE *auxfd,Event *wait)
|
||||
: name(name),fd(fd),auxfd(auxfd),wait(wait),
|
||||
timerNode(*this),timeStamp(TimeStamp())
|
||||
POINTER_DEFINITIONS(MyCallback);
|
||||
MyCallback(String name,FILE *fd,FILE *auxfd,EventPtr const & wait)
|
||||
: name(name),
|
||||
fd(fd),
|
||||
auxfd(auxfd),
|
||||
wait(wait)
|
||||
{
|
||||
}
|
||||
~MyCallback()
|
||||
@@ -49,45 +56,115 @@ public:
|
||||
{
|
||||
fprintf(fd,"timerStopped %s\n",name.c_str());
|
||||
}
|
||||
TimerNode &getTimerNode() { return timerNode;}
|
||||
TimeStamp &getTimeStamp() { return timeStamp;}
|
||||
private:
|
||||
String name;
|
||||
FILE *fd;
|
||||
FILE *auxfd;
|
||||
Event *wait;
|
||||
TimerNode timerNode;
|
||||
EventPtr wait;
|
||||
TimeStamp timeStamp;
|
||||
};
|
||||
|
||||
static void testBasic(FILE *fd, FILE *auxfd)
|
||||
{
|
||||
printf("\n\ntestBasic oneDelay %lf twoDelay %lf threeDaley %lf\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
String one("one");
|
||||
String two("two");
|
||||
Event *eventOne = new Event();
|
||||
Event *eventTwo = new Event();
|
||||
Timer *timer = new Timer(String("timer"),middlePriority);
|
||||
MyCallback *callbackOne = new MyCallback(
|
||||
one,fd,auxfd,eventOne);
|
||||
MyCallback *callbackTwo = new MyCallback(
|
||||
two,fd,auxfd,eventTwo);
|
||||
currentTimeStamp.getCurrent();
|
||||
timer->scheduleAfterDelay(callbackOne->getTimerNode(),oneDelay);
|
||||
timer->scheduleAfterDelay(callbackTwo->getTimerNode(),twoDelay);
|
||||
eventOne->wait();
|
||||
eventTwo->wait();
|
||||
double diff;
|
||||
diff = TimeStamp::diff(
|
||||
callbackOne->getTimeStamp(),currentTimeStamp);
|
||||
fprintf(auxfd,"one requested %f diff %f seconds\n",oneDelay,diff);
|
||||
diff = TimeStamp::diff(
|
||||
callbackTwo->getTimeStamp(),currentTimeStamp);
|
||||
fprintf(auxfd,"two requested %f diff %f seconds\n",twoDelay,diff);
|
||||
delete timer;
|
||||
delete callbackTwo;
|
||||
delete callbackOne;
|
||||
delete eventTwo;
|
||||
delete eventOne;
|
||||
String three("three");
|
||||
EventPtr eventOne(new Event());
|
||||
EventPtr eventTwo(new Event());
|
||||
EventPtr eventThree(new Event());
|
||||
TimerPtr timer(new Timer(String("timer"),middlePriority));
|
||||
MyCallbackPtr callbackOne(new MyCallback(one,fd,auxfd,eventOne));
|
||||
MyCallbackPtr callbackTwo(new MyCallback(two,fd,auxfd,eventTwo));
|
||||
MyCallbackPtr callbackThree(new MyCallback(three,fd,auxfd,eventThree));
|
||||
for(int n=0; n<ntimes; n++) {
|
||||
currentTimeStamp.getCurrent();
|
||||
assert(!timer->isScheduled(callbackOne));
|
||||
assert(!timer->isScheduled(callbackTwo));
|
||||
assert(!timer->isScheduled(callbackThree));
|
||||
timer->scheduleAfterDelay(callbackOne,oneDelay);
|
||||
timer->scheduleAfterDelay(callbackTwo,twoDelay);
|
||||
timer->scheduleAfterDelay(callbackThree,threeDelay);
|
||||
if(oneDelay>.1) assert(timer->isScheduled(callbackOne));
|
||||
if(twoDelay>.1) assert(timer->isScheduled(callbackTwo));
|
||||
if(threeDelay>.1) assert(timer->isScheduled(callbackThree));
|
||||
String builder;
|
||||
timer->toString(&builder);
|
||||
printf("timerQueue\n%s",builder.c_str());
|
||||
eventOne->wait();
|
||||
eventTwo->wait();
|
||||
eventThree->wait();
|
||||
double diff;
|
||||
double delta;
|
||||
diff = TimeStamp::diff(
|
||||
callbackOne->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - oneDelay;
|
||||
fprintf(auxfd,"one requested %f actual %f delta %f\n",oneDelay,diff,delta);
|
||||
if(delta<0.0) delta = -delta;
|
||||
assert(delta<.1);
|
||||
diff = TimeStamp::diff(
|
||||
callbackTwo->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - twoDelay;
|
||||
fprintf(auxfd,"two requested %f actual %f delta %f\n",twoDelay,diff,delta);
|
||||
if(delta<0.0) delta = -delta;
|
||||
assert(delta<.1);
|
||||
diff = TimeStamp::diff(
|
||||
callbackThree->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - threeDelay;
|
||||
fprintf(auxfd,"three requested %f actual %f delta %f\n",threeDelay,diff,delta);
|
||||
if(delta<0.0) delta = -delta;
|
||||
assert(delta<.1);
|
||||
}
|
||||
}
|
||||
|
||||
static void testCancel(FILE *fd, FILE *auxfd)
|
||||
{
|
||||
printf("\n\ntestCancel oneDelay %lf twoDelay %lf threeDaley %lf\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
String one("one");
|
||||
String two("two");
|
||||
String three("three");
|
||||
EventPtr eventOne(new Event());
|
||||
EventPtr eventTwo(new Event());
|
||||
EventPtr eventThree(new Event());
|
||||
TimerPtr timer(new Timer(String("timer"),middlePriority));
|
||||
MyCallbackPtr callbackOne(new MyCallback(one,fd,auxfd,eventOne));
|
||||
MyCallbackPtr callbackTwo(new MyCallback(two,fd,auxfd,eventTwo));
|
||||
MyCallbackPtr callbackThree(new MyCallback(three,fd,auxfd,eventThree));
|
||||
for(int n=0; n<ntimes; n++) {
|
||||
currentTimeStamp.getCurrent();
|
||||
assert(!timer->isScheduled(callbackOne));
|
||||
assert(!timer->isScheduled(callbackTwo));
|
||||
assert(!timer->isScheduled(callbackThree));
|
||||
timer->scheduleAfterDelay(callbackOne,oneDelay);
|
||||
timer->scheduleAfterDelay(callbackTwo,twoDelay);
|
||||
timer->scheduleAfterDelay(callbackThree,threeDelay);
|
||||
timer->cancel(callbackTwo);
|
||||
if(oneDelay>.1) assert(timer->isScheduled(callbackOne));
|
||||
assert(!timer->isScheduled(callbackTwo));
|
||||
if(threeDelay>.1) assert(timer->isScheduled(callbackThree));
|
||||
String builder;
|
||||
timer->toString(&builder);
|
||||
printf("timerQueue\n%s",builder.c_str());
|
||||
eventOne->wait();
|
||||
eventThree->wait();
|
||||
double diff;
|
||||
double delta;
|
||||
diff = TimeStamp::diff(
|
||||
callbackOne->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - oneDelay;
|
||||
fprintf(auxfd,"one requested %f actual %f delta %f\n",oneDelay,diff,delta);
|
||||
if(delta<0.0) delta = -delta;
|
||||
assert(delta<.1);
|
||||
diff = TimeStamp::diff(
|
||||
callbackThree->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - threeDelay;
|
||||
fprintf(auxfd,"three requested %f actual %f delta %f\n",threeDelay,diff,delta);
|
||||
if(delta<0.0) delta = -delta;
|
||||
assert(delta<.1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
@@ -105,14 +182,24 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
oneDelay = .4;
|
||||
twoDelay = .2;
|
||||
threeDelay = .1;
|
||||
testBasic(fd,auxfd);
|
||||
oneDelay = .2;
|
||||
testCancel(fd,auxfd);
|
||||
oneDelay = .1;
|
||||
twoDelay = .2;
|
||||
threeDelay = .4;
|
||||
testBasic(fd,auxfd);
|
||||
testCancel(fd,auxfd);
|
||||
oneDelay = .1;
|
||||
twoDelay = .4;
|
||||
threeDelay = .2;
|
||||
testBasic(fd,auxfd);
|
||||
testCancel(fd,auxfd);
|
||||
oneDelay = .0;
|
||||
twoDelay = .0;
|
||||
threeDelay = .0;
|
||||
testBasic(fd,auxfd);
|
||||
testCancel(fd,auxfd);
|
||||
epicsExitCallAtExits();
|
||||
CDRMonitor::get().show(fd);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/CDRMonitor.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ void testPowerSupplyArray(FILE * fd) {
|
||||
powerSupplyArray->remove(2,1);
|
||||
buffer.clear();
|
||||
powerSupplyArrayStruct->toString(&buffer);
|
||||
fprintf(fd,"after remove 0,1,3%s\n",buffer.c_str());
|
||||
fprintf(fd,"after remove 2,1%s\n",buffer.c_str());
|
||||
powerSupplyArray->compress();
|
||||
buffer.clear();
|
||||
powerSupplyArrayStruct->toString(&buffer);
|
||||
|
||||
Reference in New Issue
Block a user