Compare commits
44 Commits
7.0.0
...
7.1.0-pre1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
499c03265f | ||
|
|
7eaa613d4d | ||
|
|
19db72031c | ||
|
|
671f9cca4b | ||
|
|
9ecdb80534 | ||
|
|
e973422ee1 | ||
|
|
8093c25b72 | ||
|
|
a7c9c620dd | ||
|
|
1e1d94ed73 | ||
|
|
7b8ef390ce | ||
|
|
87ade13234 | ||
|
|
32abde7f19 | ||
|
|
fe413af177 | ||
|
|
b4cd026fe5 | ||
|
|
a51b308cc8 | ||
|
|
1c09b42951 | ||
|
|
e42bb46563 | ||
|
|
a7788f9847 | ||
|
|
b597364419 | ||
|
|
a9a951d970 | ||
|
|
6ac879ec6a | ||
|
|
2422ef50b6 | ||
|
|
06dbf96b65 | ||
|
|
172046e78f | ||
|
|
7e8c49f0a0 | ||
|
|
f2ad6292f5 | ||
|
|
337e13b72e | ||
|
|
2ab2fc62dc | ||
|
|
786575c3de | ||
|
|
4cca194000 | ||
|
|
cd3ead0028 | ||
|
|
a239b95ca1 | ||
|
|
09574c0e82 | ||
|
|
0b6b01ef83 | ||
|
|
34145e459b | ||
|
|
207efca15c | ||
|
|
3e25c2ea46 | ||
|
|
2046678caa | ||
|
|
cb7e4e858b | ||
|
|
43ee4b9cb6 | ||
|
|
207c24a4fd | ||
|
|
6465ab3b6d | ||
|
|
cf624bc679 | ||
|
|
df55a776c7 |
@@ -1,4 +1,4 @@
|
||||
EPICS_PVD_MAJOR_VERSION = 7
|
||||
EPICS_PVD_MINOR_VERSION = 0
|
||||
EPICS_PVD_MAINTENANCE_VERSION = 0
|
||||
EPICS_PVD_DEVELOPMENT_FLAG = 0
|
||||
EPICS_PVD_MAINTENANCE_VERSION = 1
|
||||
EPICS_PVD_DEVELOPMENT_FLAG = 1
|
||||
|
||||
@@ -2,8 +2,29 @@
|
||||
|
||||
@page release_notes Release Notes
|
||||
|
||||
Release 7.0 (XYZ 2017)
|
||||
======================
|
||||
Release 7.1.0 (UNRELEASED)
|
||||
==========================
|
||||
|
||||
- Deprecations
|
||||
- pv/localStaticLock.h
|
||||
- Removals
|
||||
- Remove previously deprecated executor.h, queue.h and timerFunction.h
|
||||
- Remove *HashFunction functors to "hash" Field sub-classes which were never fully implemented.
|
||||
- Fixes
|
||||
- Make thread safe getFieldCreate() and getPVDataCreate()
|
||||
- Workaround for MSVC pickyness that iterators be non-NULL, even when not de-referenced.
|
||||
- Fix alignment fault during (de)serialization on RTEMS/vxWorks.
|
||||
- Fix shared_vector::swap() for void specialization.
|
||||
- Changes in several Field sub-classes to return const ref. instead of a copy.
|
||||
- Additions
|
||||
- shared_vector add c++11 move and construct for initializer list.
|
||||
- Add AnyScalar::clear()
|
||||
- Add ctor AnyScalar(ScalarType, const void*) to allow construction from an untyped buffer.
|
||||
- Add Timer::close()
|
||||
- Allow castUnsafe() from const char* without first allocating a std::string.
|
||||
|
||||
Release 7.0.0 (Dec 2017)
|
||||
========================
|
||||
|
||||
- Removals
|
||||
- Remove requester.h, monitor.h, and destroyable.h.. Migrated to the pvAccessCPP module.
|
||||
|
||||
@@ -65,6 +65,6 @@ make distclean all
|
||||
make runtests
|
||||
|
||||
###########################################
|
||||
# Create distribution
|
||||
# Create cache
|
||||
|
||||
tar czf pvData.CB-dist.tar.gz lib include LICENSE
|
||||
tar czf pvData.CB-dist.tar.gz lib include cfg LICENSE
|
||||
|
||||
@@ -21,14 +21,7 @@ installE4 () {
|
||||
local module=$1
|
||||
local branch=$2
|
||||
|
||||
# If microbench version does not exist, try without
|
||||
if [ "${MB}" = "WITH_MICROBENCH" ]; then
|
||||
if ! wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=WITH_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz; then
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
else
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE},MB=NO_MICROBENCH/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
fi
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/e4-cpp-${module}-${branch}-build/BASE=${BASE}/lastSuccessfulBuild/artifact/${module}.CB-dist.tar.gz
|
||||
tar -xzf ${module}.CB-dist.tar.gz
|
||||
}
|
||||
|
||||
@@ -38,7 +31,6 @@ installE4 () {
|
||||
BASE=3.15.4
|
||||
PUBLISH=${PUBLISH:-NO}
|
||||
BRANCH=${BRANCH:-master}
|
||||
MB=NO_MICROBENCH
|
||||
|
||||
###########################################
|
||||
# Fetch and unpack dependencies
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/reftrack.h>
|
||||
@@ -26,7 +27,6 @@
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/factory.h>
|
||||
#include <pv/serializeHelper.h>
|
||||
#include <pv/localStaticLock.h>
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::size_t;
|
||||
@@ -460,11 +460,10 @@ string Structure::getID() const
|
||||
}
|
||||
|
||||
FieldConstPtr Structure::getField(string const & fieldName) const {
|
||||
size_t numberFields = fields.size();
|
||||
for(size_t i=0; i<numberFields; i++) {
|
||||
FieldConstPtr pfield = fields[i];
|
||||
int result = fieldName.compare(fieldNames[i]);
|
||||
if(result==0) return pfield;
|
||||
for(size_t i=0, N=fields.size(); i<N; i++) {
|
||||
if(fieldName==fieldNames[i]) {
|
||||
return fields[i];
|
||||
}
|
||||
}
|
||||
return FieldConstPtr();
|
||||
}
|
||||
@@ -1453,19 +1452,33 @@ FieldConstPtr FieldCreate::deserialize(ByteBuffer* buffer, DeserializableControl
|
||||
}
|
||||
}
|
||||
|
||||
// TODO replace with non-locking singleton pattern
|
||||
const FieldCreatePtr& FieldCreate::getFieldCreate()
|
||||
{
|
||||
LOCAL_STATIC_LOCK;
|
||||
static FieldCreatePtr fieldCreate;
|
||||
static Mutex mutex;
|
||||
|
||||
Lock xx(mutex);
|
||||
if(fieldCreate.get()==0) {
|
||||
fieldCreate = FieldCreatePtr(new FieldCreate());
|
||||
namespace detail {
|
||||
struct field_factory {
|
||||
FieldCreatePtr fieldCreate;
|
||||
field_factory() :fieldCreate(new FieldCreate()) {
|
||||
registerRefCounter("Field", &Field::num_instances);
|
||||
}
|
||||
return fieldCreate;
|
||||
};
|
||||
}
|
||||
|
||||
static detail::field_factory* field_factory_s;
|
||||
static epicsThreadOnceId field_factory_once = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
static void field_factory_init(void*)
|
||||
{
|
||||
try {
|
||||
field_factory_s = new detail::field_factory;
|
||||
}catch(std::exception& e){
|
||||
std::cerr<<"Error initializing getFieldCreate() : "<<e.what()<<"\n";
|
||||
}
|
||||
}
|
||||
|
||||
const FieldCreatePtr& FieldCreate::getFieldCreate()
|
||||
{
|
||||
epicsThreadOnce(&field_factory_once, &field_factory_init, 0);
|
||||
if(!field_factory_s->fieldCreate)
|
||||
throw std::logic_error("getFieldCreate() not initialized");
|
||||
return field_factory_s->fieldCreate;
|
||||
}
|
||||
|
||||
FieldCreate::FieldCreate()
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <cstdio>
|
||||
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/lock.h>
|
||||
@@ -604,19 +605,33 @@ PVUnionPtr PVDataCreate::createPVUnion(PVUnionPtr const & unionToClone)
|
||||
return punion;
|
||||
}
|
||||
|
||||
// TODO not thread-safe (local static initializers)
|
||||
// TODO replace with non-locking singleton pattern
|
||||
namespace detail {
|
||||
struct pvfield_factory {
|
||||
PVDataCreatePtr pvDataCreate;
|
||||
pvfield_factory() :pvDataCreate(new PVDataCreate()) {
|
||||
registerRefCounter("PVField", &PVField::num_instances);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static detail::pvfield_factory* pvfield_factory_s;
|
||||
static epicsThreadOnceId pvfield_factory_once = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
static void pvfield_factory_init(void*)
|
||||
{
|
||||
try {
|
||||
pvfield_factory_s = new detail::pvfield_factory;
|
||||
}catch(std::exception& e){
|
||||
std::cerr<<"Error initializing getFieldCreate() : "<<e.what()<<"\n";
|
||||
}
|
||||
}
|
||||
|
||||
const PVDataCreatePtr& PVDataCreate::getPVDataCreate()
|
||||
{
|
||||
static PVDataCreatePtr pvDataCreate;
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
|
||||
if(pvDataCreate.get()==0) {
|
||||
registerRefCounter("PVField", &PVField::num_instances);
|
||||
pvDataCreate = PVDataCreatePtr(new PVDataCreate());
|
||||
}
|
||||
return pvDataCreate;
|
||||
epicsThreadOnce(&pvfield_factory_once, &pvfield_factory_init, 0);
|
||||
if(!pvfield_factory_s->pvDataCreate)
|
||||
throw std::logic_error("getPVDataCreate() not initialized");
|
||||
return pvfield_factory_s->pvDataCreate;
|
||||
}
|
||||
|
||||
// explicitly instanciate to ensure that windows
|
||||
|
||||
@@ -64,12 +64,12 @@ void PVField::setImmutable() {immutable = true;}
|
||||
|
||||
void PVField::postPut()
|
||||
{
|
||||
if(postHandler.get()!=NULL) postHandler->postPut();
|
||||
if(postHandler) postHandler->postPut();
|
||||
}
|
||||
|
||||
void PVField::setPostHandler(PostHandlerPtr const &handler)
|
||||
{
|
||||
if(postHandler.get()!=NULL) {
|
||||
if(postHandler) {
|
||||
if(postHandler.get()==handler.get()) return;
|
||||
throw std::logic_error(
|
||||
"PVField::setPostHandler a postHandler is already registered");
|
||||
|
||||
@@ -76,14 +76,14 @@ void PVStructureArray::compress() {
|
||||
size_t newLength = 0;
|
||||
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(vec[i].get()!=NULL) {
|
||||
if(vec[i]) {
|
||||
newLength++;
|
||||
continue;
|
||||
}
|
||||
// find first non 0
|
||||
size_t notNull = 0;
|
||||
for(size_t j=i+1;j<length;j++) {
|
||||
if(vec[j].get()!=NULL) {
|
||||
if(vec[j]) {
|
||||
notNull = j;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -76,14 +76,14 @@ void PVUnionArray::compress() {
|
||||
size_t newLength = 0;
|
||||
|
||||
for(size_t i=0; i<length; i++) {
|
||||
if(vec[i].get()!=NULL) {
|
||||
if(vec[i]) {
|
||||
newLength++;
|
||||
continue;
|
||||
}
|
||||
// find first non 0
|
||||
size_t notNull = 0;
|
||||
for(size_t j=i+1;j<length;j++) {
|
||||
if(vec[j].get()!=NULL) {
|
||||
if(vec[j]) {
|
||||
notNull = j;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,7 @@ INC += pv/epicsException.h
|
||||
INC += pv/serializeHelper.h
|
||||
INC += pv/event.h
|
||||
INC += pv/thread.h
|
||||
INC += pv/executor.h
|
||||
INC += pv/timeFunction.h
|
||||
INC += pv/timer.h
|
||||
INC += pv/queue.h
|
||||
INC += pv/status.h
|
||||
INC += pv/sharedPtr.h
|
||||
INC += pv/debugPtr.h
|
||||
@@ -32,8 +29,6 @@ LIBSRCS += bitSet.cpp
|
||||
LIBSRCS += epicsException.cpp
|
||||
LIBSRCS += serializeHelper.cpp
|
||||
LIBSRCS += event.cpp
|
||||
LIBSRCS += executor.cpp
|
||||
LIBSRCS += timeFunction.cpp
|
||||
LIBSRCS += timer.cpp
|
||||
LIBSRCS += status.cpp
|
||||
LIBSRCS += localStaticLock.cpp
|
||||
@@ -42,3 +37,4 @@ LIBSRCS += parseToPOD.cpp
|
||||
LIBSRCS += pvUnitTest.cpp
|
||||
LIBSRCS += debugPtr.cpp
|
||||
LIBSRCS += reftrack.cpp
|
||||
LIBSRCS += anyscalar.cpp
|
||||
|
||||
161
src/misc/anyscalar.cpp
Normal file
161
src/misc/anyscalar.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
|
||||
#include <epicsAssert.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <shareLib.h>
|
||||
|
||||
#include "pv/anyscalar.h"
|
||||
|
||||
namespace epics {namespace pvData {
|
||||
|
||||
AnyScalar::AnyScalar(ScalarType type, const void *buf)
|
||||
{
|
||||
if(type==pvString) {
|
||||
new (_wrap.blob) std::string(*static_cast<const std::string*>(buf));
|
||||
|
||||
} else {
|
||||
memcpy(_wrap.blob, buf, ScalarTypeFunc::elementSize(type));
|
||||
}
|
||||
|
||||
_stype = type;
|
||||
}
|
||||
|
||||
AnyScalar::AnyScalar(const AnyScalar& o)
|
||||
:_stype(o._stype)
|
||||
{
|
||||
if(o._stype==pvString) {
|
||||
new (_wrap.blob) std::string(o._as<std::string>());
|
||||
} else if(o._stype!=(ScalarType)-1) {
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
}
|
||||
}
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
AnyScalar::AnyScalar(AnyScalar&& o)
|
||||
:_stype(o._stype)
|
||||
{
|
||||
typedef std::string string;
|
||||
if(o._stype==pvString) {
|
||||
new (_wrap.blob) std::string();
|
||||
_as<std::string>() = std::move(o._as<std::string>());
|
||||
o._as<string>().~string();
|
||||
} else if(o._stype!=(ScalarType)-1) {
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
}
|
||||
o._stype = (ScalarType)-1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void AnyScalar::clear() {
|
||||
if(_stype==pvString) {
|
||||
typedef std::string string;
|
||||
_as<string>().~string();
|
||||
}
|
||||
// other types need no cleanup
|
||||
_stype = (ScalarType)-1;
|
||||
}
|
||||
|
||||
void AnyScalar::swap(AnyScalar& o) {
|
||||
typedef std::string string;
|
||||
switch((int)_stype) {
|
||||
case -1:
|
||||
switch((int)o._stype) {
|
||||
case -1:
|
||||
// nil <-> nil
|
||||
break;
|
||||
case pvString:
|
||||
// nil <-> string
|
||||
new (_wrap.blob) std::string();
|
||||
_as<std::string>().swap(o._as<std::string>());
|
||||
o._as<std::string>().~string();
|
||||
break;
|
||||
default:
|
||||
// nil <-> non-string
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case pvString:
|
||||
switch((int)o._stype) {
|
||||
case -1:
|
||||
// string <-> nil
|
||||
new (o._wrap.blob) std::string();
|
||||
_as<std::string>().swap(o._as<std::string>());
|
||||
_as<std::string>().~string();
|
||||
break;
|
||||
case pvString:
|
||||
// string <-> string
|
||||
_as<std::string>().swap(o._as<std::string>());
|
||||
break;
|
||||
default: {
|
||||
// string <-> non-string
|
||||
std::string temp;
|
||||
temp.swap(_as<std::string>());
|
||||
|
||||
_as<std::string>().~string();
|
||||
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
|
||||
new (o._wrap.blob) std::string();
|
||||
temp.swap(o._as<std::string>());
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch((int)o._stype) {
|
||||
case -1:
|
||||
// non-string <-> nil
|
||||
memcpy(o._wrap.blob, _wrap.blob, sizeof(_largest_blob));
|
||||
break;
|
||||
case pvString: {
|
||||
// non-string <-> string
|
||||
std::string temp;
|
||||
temp.swap(o._as<std::string>());
|
||||
|
||||
o._as<std::string>().~string();
|
||||
|
||||
memcpy(o._wrap.blob, _wrap.blob, sizeof(_largest_blob));
|
||||
|
||||
new (_wrap.blob) std::string();
|
||||
temp.swap(_as<std::string>());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// non-string <-> non-string
|
||||
_largest_blob temp;
|
||||
memcpy(&temp, _wrap.blob, sizeof(_largest_blob));
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
memcpy(o._wrap.blob, &temp, sizeof(_largest_blob));
|
||||
// std::swap(o._wrap.blob, _wrap.blob); // gcc <=4.3 doesn't like this
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
std::swap(_stype, o._stype);
|
||||
}
|
||||
const void* AnyScalar::bufferUnsafe() const {
|
||||
if(_stype==pvString) {
|
||||
return as<std::string>().c_str();
|
||||
} else {
|
||||
return _wrap.blob;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& strm, const AnyScalar& v)
|
||||
{
|
||||
switch(v.type()) {
|
||||
#define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case pv ## PVACODE: strm<<v._as<PVATYPE>(); break;
|
||||
#define CASE_REAL_INT64
|
||||
#define CASE_STRING
|
||||
#include "pv/typemap.h"
|
||||
#undef CASE
|
||||
#undef CASE_REAL_INT64
|
||||
#undef CASE_STRING
|
||||
default:
|
||||
strm<<"(nil)"; break;
|
||||
}
|
||||
return strm;
|
||||
}
|
||||
|
||||
}} // namespace epics::pvData
|
||||
@@ -1,103 +0,0 @@
|
||||
/* executor.cpp */
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
// Suppress deprecation warnings for the implementation
|
||||
#include <compilerDependencies.h>
|
||||
#undef EPICS_DEPRECATED
|
||||
#define EPICS_DEPRECATED
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/executor.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
// special instance to stop the executor thread
|
||||
class ExecutorShutdown : public Command {
|
||||
virtual void command();
|
||||
};
|
||||
|
||||
void ExecutorShutdown::command()
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
std::tr1::shared_ptr<Command> shutdown(new ExecutorShutdown());
|
||||
|
||||
|
||||
Executor::Executor(string const & threadName,ThreadPriority priority)
|
||||
: thread(threadName,priority,this)
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
head.reset();
|
||||
tail.reset();
|
||||
}
|
||||
|
||||
void Executor::run()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
while(true) {
|
||||
while(!head.get()) {
|
||||
xx.unlock();
|
||||
moreWork.wait();
|
||||
xx.lock();
|
||||
}
|
||||
CommandPtr command = head;
|
||||
head = command->next;
|
||||
if(!command.get()) continue;
|
||||
if(command.get()==shutdown.get()) break;
|
||||
xx.unlock();
|
||||
try {
|
||||
command->command();
|
||||
}catch(std::exception& e){
|
||||
//TODO: feed into logging mechanism
|
||||
fprintf(stderr, "Executor: Unhandled exception: %s",e.what());
|
||||
}catch(...){
|
||||
fprintf(stderr, "Executor: Unhandled exception");
|
||||
}
|
||||
|
||||
xx.lock();
|
||||
}
|
||||
stopped.signal();
|
||||
}
|
||||
|
||||
void Executor::execute(CommandPtr const & command)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
command->next.reset();
|
||||
if(!head.get()) {
|
||||
head = command;
|
||||
moreWork.signal();
|
||||
return;
|
||||
}
|
||||
CommandPtr tail = head;
|
||||
while(tail->next) tail = tail->next;
|
||||
tail->next = command;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -507,20 +507,20 @@ void handleParseError(int err)
|
||||
|
||||
namespace epics { namespace pvData { namespace detail {
|
||||
|
||||
void parseToPOD(const string & in, boolean *out)
|
||||
void parseToPOD(const char* in, boolean *out)
|
||||
{
|
||||
if(epicsStrCaseCmp(in.c_str(),"true")==0)
|
||||
if(epicsStrCaseCmp(in,"true")==0)
|
||||
*out = 1;
|
||||
else if(epicsStrCaseCmp(in.c_str(),"false")==0)
|
||||
else if(epicsStrCaseCmp(in,"false")==0)
|
||||
*out = 0;
|
||||
else
|
||||
throw std::runtime_error("parseToPOD: string no match true/false");
|
||||
}
|
||||
|
||||
#define INTFN(T, S) \
|
||||
void parseToPOD(const string& in, T *out) { \
|
||||
void parseToPOD(const char* in, T *out) { \
|
||||
epics ## S temp; \
|
||||
int err = epicsParse ## S (in.c_str(), &temp, 0, NULL); \
|
||||
int err = epicsParse ## S (in, &temp, 0, NULL); \
|
||||
if(err) handleParseError(err); \
|
||||
else *out = temp; \
|
||||
}
|
||||
@@ -532,31 +532,31 @@ INTFN(uint16_t, UInt16);
|
||||
INTFN(int32_t, Int32);
|
||||
INTFN(uint32_t, UInt32);
|
||||
|
||||
void parseToPOD(const string& in, int64_t *out) {
|
||||
void parseToPOD(const char* in, int64_t *out) {
|
||||
#ifdef NEED_LONGLONG
|
||||
int err = epicsParseLongLong(in.c_str(), out, 0, NULL);
|
||||
int err = epicsParseLongLong(in, out, 0, NULL);
|
||||
#else
|
||||
int err = epicsParseLong(in.c_str(), out, 0, NULL);
|
||||
int err = epicsParseLong(in, out, 0, NULL);
|
||||
#endif
|
||||
if(err) handleParseError(err);
|
||||
}
|
||||
|
||||
void parseToPOD(const string& in, uint64_t *out) {
|
||||
void parseToPOD(const char* in, uint64_t *out) {
|
||||
#ifdef NEED_LONGLONG
|
||||
int err = epicsParseULongLong(in.c_str(), out, 0, NULL);
|
||||
int err = epicsParseULongLong(in, out, 0, NULL);
|
||||
#else
|
||||
int err = epicsParseULong(in.c_str(), out, 0, NULL);
|
||||
int err = epicsParseULong(in, out, 0, NULL);
|
||||
#endif
|
||||
if(err) handleParseError(err);
|
||||
}
|
||||
|
||||
void parseToPOD(const string& in, float *out) {
|
||||
int err = epicsParseFloat(in.c_str(), out, NULL);
|
||||
void parseToPOD(const char* in, float *out) {
|
||||
int err = epicsParseFloat(in, out, NULL);
|
||||
if(err) handleParseError(err);
|
||||
}
|
||||
|
||||
void parseToPOD(const string& in, double *out) {
|
||||
int err = epicsParseDouble(in.c_str(), out, NULL);
|
||||
void parseToPOD(const char* in, double *out) {
|
||||
int err = epicsParseDouble(in, out, NULL);
|
||||
if(err) handleParseError(err);
|
||||
#if defined(vxWorks)
|
||||
/* vxWorks strtod returns [-]epicsINF when it should return ERANGE error.
|
||||
@@ -564,7 +564,7 @@ void parseToPOD(const string& in, double *out) {
|
||||
* this into an ERANGE error
|
||||
*/
|
||||
else if (*out == epicsINF || *out == -epicsINF) {
|
||||
const char* s = in.c_str();
|
||||
const char* s = in;
|
||||
int c;
|
||||
|
||||
/* skip spaces and the sign */
|
||||
|
||||
@@ -48,7 +48,7 @@ constexpr size_t cmax(size_t A, size_t B) {
|
||||
assert(A.ref<double>()==5.0); // throws AnyScalar::bad_cast
|
||||
@endcode
|
||||
*/
|
||||
class AnyScalar {
|
||||
class epicsShareClass AnyScalar {
|
||||
public:
|
||||
struct bad_cast : public std::exception {
|
||||
#if __cplusplus>=201103L
|
||||
@@ -95,8 +95,11 @@ private:
|
||||
return *reinterpret_cast<const T*>(_wrap.blob);
|
||||
}
|
||||
public:
|
||||
//! Construct empty
|
||||
//! @post empty()==true
|
||||
AnyScalar() : _stype((ScalarType)-1) {}
|
||||
|
||||
//! Construct from provided value.
|
||||
template<typename T>
|
||||
explicit AnyScalar(T v)
|
||||
{
|
||||
@@ -112,149 +115,51 @@ public:
|
||||
_stype = (ScalarType)ScalarTypeID<TT>::value;
|
||||
}
|
||||
|
||||
AnyScalar(const AnyScalar& o)
|
||||
:_stype(o._stype)
|
||||
{
|
||||
if(o._stype==pvString) {
|
||||
new (_wrap.blob) std::string(o._as<std::string>());
|
||||
} else if(o._stype!=(ScalarType)-1) {
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
}
|
||||
}
|
||||
//! Construct from un-typed pointer.
|
||||
//! Caller is responsible to ensure that buf actually points to the provided type
|
||||
AnyScalar(ScalarType type, const void *buf);
|
||||
|
||||
AnyScalar(const AnyScalar& o);
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
AnyScalar(AnyScalar&& o)
|
||||
:_stype(o._stype)
|
||||
{
|
||||
typedef std::string string;
|
||||
if(o._stype==pvString) {
|
||||
new (_wrap.blob) std::string();
|
||||
_as<std::string>() = std::move(o._as<std::string>());
|
||||
o._as<string>().~string();
|
||||
} else if(o._stype!=(ScalarType)-1) {
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
}
|
||||
o._stype = (ScalarType)-1;
|
||||
}
|
||||
AnyScalar(AnyScalar&& o);
|
||||
#endif
|
||||
|
||||
~AnyScalar() {
|
||||
if(_stype==pvString) {
|
||||
typedef std::string string;
|
||||
_as<string>().~string();
|
||||
}
|
||||
// other types need no cleanup
|
||||
}
|
||||
inline ~AnyScalar() {clear();}
|
||||
|
||||
AnyScalar& operator=(const AnyScalar& o) {
|
||||
inline AnyScalar& operator=(const AnyScalar& o) {
|
||||
AnyScalar(o).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
AnyScalar& operator=(T v) {
|
||||
inline AnyScalar& operator=(T v) {
|
||||
AnyScalar(v).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
AnyScalar& operator=(AnyScalar&& o) {
|
||||
if(_stype==pvString) {
|
||||
typedef std::string string;
|
||||
_as<string>().~string();
|
||||
}
|
||||
_stype = (ScalarType)-1;
|
||||
inline AnyScalar& operator=(AnyScalar&& o) {
|
||||
clear();
|
||||
swap(o);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void swap(AnyScalar& o) {
|
||||
typedef std::string string;
|
||||
switch((int)_stype) {
|
||||
case -1:
|
||||
switch((int)o._stype) {
|
||||
case -1:
|
||||
// nil <-> nil
|
||||
break;
|
||||
case pvString:
|
||||
// nil <-> string
|
||||
new (_wrap.blob) std::string();
|
||||
_as<std::string>().swap(o._as<std::string>());
|
||||
o._as<std::string>().~string();
|
||||
break;
|
||||
default:
|
||||
// nil <-> non-string
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case pvString:
|
||||
switch((int)o._stype) {
|
||||
case -1:
|
||||
// string <-> nil
|
||||
new (o._wrap.blob) std::string();
|
||||
_as<std::string>().swap(o._as<std::string>());
|
||||
_as<std::string>().~string();
|
||||
break;
|
||||
case pvString:
|
||||
// string <-> string
|
||||
_as<std::string>().swap(o._as<std::string>());
|
||||
break;
|
||||
default: {
|
||||
// string <-> non-string
|
||||
std::string temp;
|
||||
temp.swap(_as<std::string>());
|
||||
//! Reset internal state.
|
||||
//! Added after 7.0.0
|
||||
//! @post empty()==true
|
||||
void clear();
|
||||
|
||||
_as<std::string>().~string();
|
||||
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
|
||||
new (o._wrap.blob) std::string();
|
||||
temp.swap(o._as<std::string>());
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch((int)o._stype) {
|
||||
case -1:
|
||||
// non-string <-> nil
|
||||
memcpy(o._wrap.blob, _wrap.blob, sizeof(_largest_blob));
|
||||
break;
|
||||
case pvString: {
|
||||
// non-string <-> string
|
||||
std::string temp;
|
||||
temp.swap(o._as<std::string>());
|
||||
|
||||
o._as<std::string>().~string();
|
||||
|
||||
memcpy(o._wrap.blob, _wrap.blob, sizeof(_largest_blob));
|
||||
|
||||
new (_wrap.blob) std::string();
|
||||
temp.swap(_as<std::string>());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// non-string <-> non-string
|
||||
_largest_blob temp;
|
||||
memcpy(&temp, _wrap.blob, sizeof(_largest_blob));
|
||||
memcpy(_wrap.blob, o._wrap.blob, sizeof(_largest_blob));
|
||||
memcpy(o._wrap.blob, &temp, sizeof(_largest_blob));
|
||||
// std::swap(o._wrap.blob, _wrap.blob); // gcc <=4.3 doesn't like this
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
std::swap(_stype, o._stype);
|
||||
}
|
||||
void swap(AnyScalar& o);
|
||||
|
||||
//! Type code of contained value. Or (ScalarType)-1 is empty.
|
||||
inline ScalarType type() const {
|
||||
return _stype;
|
||||
}
|
||||
|
||||
void* unsafe() { return _wrap.blob; }
|
||||
const void* unsafe() const { return _wrap.blob; }
|
||||
inline void* unsafe() { return _wrap.blob; }
|
||||
inline const void* unsafe() const { return _wrap.blob; }
|
||||
|
||||
inline bool empty() const { return _stype==(ScalarType)-1; }
|
||||
|
||||
@@ -267,8 +172,20 @@ public:
|
||||
operator bool_type() const { return !empty() ? &AnyScalar::swap : 0; }
|
||||
#endif
|
||||
|
||||
/** Return reference to wrapped value */
|
||||
//! Provide read-only access to underlying buffer.
|
||||
//! For a string this is std::string::c_str().
|
||||
const void* bufferUnsafe() const;
|
||||
|
||||
/** Return typed reference to wrapped value. Non-const reference allows value modification
|
||||
*
|
||||
@code
|
||||
AnyScalar v(42);
|
||||
v.ref<uint32>() = 42;
|
||||
assert(v.ref<uint32>() = 43);
|
||||
@endcode
|
||||
*/
|
||||
template<typename T>
|
||||
inline
|
||||
// T -> strip_const -> map to storage type -> add reference
|
||||
typename detail::any_storage_type<typename meta::strip_const<T>::type>::type&
|
||||
ref() {
|
||||
@@ -277,10 +194,18 @@ public:
|
||||
|
||||
if(_stype!=(ScalarType)ScalarTypeID<TT>::value)
|
||||
throw bad_cast();
|
||||
return _as<TT>();
|
||||
return reinterpret_cast<TT&>(_wrap.blob);
|
||||
}
|
||||
|
||||
/** Return typed reference to wrapped value. Const reference does not allow modification.
|
||||
*
|
||||
@code
|
||||
AnyScalar v(42);
|
||||
assert(v.ref<uint32>() = 42);
|
||||
@endcode
|
||||
*/
|
||||
template<typename T>
|
||||
inline
|
||||
// T -> strip_const -> map to storage type -> add const reference
|
||||
typename meta::decorate_const<typename detail::any_storage_type<typename meta::strip_const<T>::type>::type>::type&
|
||||
ref() const {
|
||||
@@ -289,11 +214,12 @@ public:
|
||||
|
||||
if(_stype!=(ScalarType)ScalarTypeID<TT>::value)
|
||||
throw bad_cast();
|
||||
return _as<TT>();
|
||||
return reinterpret_cast<typename meta::decorate_const<TT>::type&>(_wrap.blob);
|
||||
}
|
||||
|
||||
/** copy out wrapped value, with a value conversion. */
|
||||
template<typename T>
|
||||
inline
|
||||
T as() const {
|
||||
typedef typename meta::strip_const<T>::type T2;
|
||||
typedef typename detail::any_storage_type<T2>::type TT;
|
||||
@@ -307,25 +233,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
friend std::ostream& operator<<(std::ostream& strm, const AnyScalar& v);
|
||||
friend epicsShareFunc std::ostream& operator<<(std::ostream& strm, const AnyScalar& v);
|
||||
};
|
||||
|
||||
inline
|
||||
std::ostream& operator<<(std::ostream& strm, const AnyScalar& v)
|
||||
{
|
||||
switch(v.type()) {
|
||||
#define CASE(BASETYPE, PVATYPE, DBFTYPE, PVACODE) case pv ## PVACODE: strm<<v._as<PVATYPE>(); break;
|
||||
#define CASE_REAL_INT64
|
||||
#define CASE_STRING
|
||||
#include "pv/typemap.h"
|
||||
#undef CASE
|
||||
#undef CASE_REAL_INT64
|
||||
#undef CASE_STRING
|
||||
default:
|
||||
strm<<"(nil)"; break;
|
||||
}
|
||||
return strm;
|
||||
}
|
||||
epicsShareExtern
|
||||
std::ostream& operator<<(std::ostream& strm, const AnyScalar& v);
|
||||
|
||||
}} // namespace epics::pvData
|
||||
|
||||
|
||||
@@ -29,16 +29,7 @@
|
||||
/* various compilers provide builtins for byte order swaps.
|
||||
* conditions based on boost endian library
|
||||
*/
|
||||
#if defined(__GNUC__) && ((__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=3))
|
||||
|
||||
#if (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=8)
|
||||
#define _PVA_swap16(X) __builtin_bswap16(X)
|
||||
#endif
|
||||
|
||||
#define _PVA_swap32(X) __builtin_bswap32(X)
|
||||
#define _PVA_swap64(X) __builtin_bswap64(X)
|
||||
|
||||
#elif defined(__clang__)
|
||||
#if defined(__clang__)
|
||||
|
||||
#if __has_builtin(__builtin_bswap16)
|
||||
#define _PVA_swap16(X) __builtin_bswap16(X)
|
||||
@@ -50,6 +41,15 @@
|
||||
#define _PVA_swap64(X) __builtin_bswap64(X)
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__) && ((__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=3))
|
||||
|
||||
#if (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=8)
|
||||
#define _PVA_swap16(X) __builtin_bswap16(X)
|
||||
#endif
|
||||
|
||||
#define _PVA_swap32(X) __builtin_bswap32(X)
|
||||
#define _PVA_swap64(X) __builtin_bswap64(X)
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#define _PVA_swap16(X) _byteswap_ushort(X)
|
||||
@@ -148,6 +148,58 @@ struct swap<8> {
|
||||
#undef _PVA_swap32
|
||||
#undef _PVA_swap64
|
||||
|
||||
/* PVD serialization doesn't pay attention to alignement,
|
||||
* which some targets really care about and treat unaligned
|
||||
* access as a fault, or with a heavy penalty (~= to a syscall).
|
||||
*
|
||||
* For those targets,, we will have to live with the increase
|
||||
* in execution time and/or object code size of byte-wise copy.
|
||||
*/
|
||||
|
||||
#ifdef _ARCH_PPC
|
||||
|
||||
template<typename T>
|
||||
union alignu {
|
||||
T val;
|
||||
char bytes[sizeof(T)];
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val)
|
||||
{
|
||||
alignu<T> A;
|
||||
A.val = val;
|
||||
for(unsigned i=0, N=sizeof(T); i<N; i++) {
|
||||
buf[i] = A.bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
EPICS_ALWAYS_INLINE T load_unaligned(const char *buf)
|
||||
{
|
||||
alignu<T> A;
|
||||
for(unsigned i=0, N=sizeof(T); i<N; i++) {
|
||||
A.bytes[i] = buf[i];
|
||||
}
|
||||
return A.val;
|
||||
}
|
||||
|
||||
#else /* alignement */
|
||||
|
||||
template<typename T>
|
||||
EPICS_ALWAYS_INLINE void store_unaligned(char *buf, T val)
|
||||
{
|
||||
*reinterpret_cast<T*>(buf) = val;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
EPICS_ALWAYS_INLINE T load_unaligned(const char *buf)
|
||||
{
|
||||
return *reinterpret_cast<const T*>(buf);
|
||||
}
|
||||
|
||||
#endif /* alignement */
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//! Unconditional byte order swap.
|
||||
@@ -344,7 +396,7 @@ public:
|
||||
*
|
||||
* @return The size of the raw data buffer.
|
||||
*/
|
||||
inline std::size_t getSize() const
|
||||
EPICS_ALWAYS_INLINE std::size_t getSize() const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
@@ -463,43 +515,43 @@ public:
|
||||
*
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putBoolean( bool value) { put< int8>(value ? 1 : 0); }
|
||||
EPICS_ALWAYS_INLINE void putBoolean( bool value) { put< int8>(value ? 1 : 0); }
|
||||
/**
|
||||
* Put a byte value into the byte buffer.
|
||||
*
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putByte ( int8 value) { put< int8>(value); }
|
||||
EPICS_ALWAYS_INLINE void putByte ( int8 value) { put< int8>(value); }
|
||||
/**
|
||||
* Put a short value into the byte buffer.
|
||||
*
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putShort ( int16 value) { put< int16>(value); }
|
||||
EPICS_ALWAYS_INLINE void putShort ( int16 value) { put< int16>(value); }
|
||||
/**
|
||||
* Put an int value into the byte buffer.
|
||||
*
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putInt ( int32 value) { put< int32>(value); }
|
||||
EPICS_ALWAYS_INLINE void putInt ( int32 value) { put< int32>(value); }
|
||||
/**
|
||||
* Put a long value into the byte buffer.
|
||||
*
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putLong ( int64 value) { put< int64>(value); }
|
||||
EPICS_ALWAYS_INLINE void putLong ( int64 value) { put< int64>(value); }
|
||||
/**
|
||||
* Put a float value into the byte buffer.
|
||||
*
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putFloat ( float value) { put< float>(value); }
|
||||
EPICS_ALWAYS_INLINE void putFloat ( float value) { put< float>(value); }
|
||||
/**
|
||||
* Put a double value into the byte buffer.
|
||||
*
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putDouble (double value) { put<double>(value); }
|
||||
EPICS_ALWAYS_INLINE void putDouble (double value) { put<double>(value); }
|
||||
|
||||
/**
|
||||
* Put a boolean value into the byte buffer at the specified index.
|
||||
@@ -507,143 +559,143 @@ public:
|
||||
* @param index The offset in the byte buffer,
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putBoolean(std::size_t index, bool value) { put< int8>(index, value); }
|
||||
EPICS_ALWAYS_INLINE void putBoolean(std::size_t index, bool value) { put< int8>(index, value); }
|
||||
/**
|
||||
* Put a byte value into the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer,
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putByte (std::size_t index, int8 value) { put< int8>(index, value); }
|
||||
EPICS_ALWAYS_INLINE void putByte (std::size_t index, int8 value) { put< int8>(index, value); }
|
||||
/**
|
||||
* Put a short value into the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer,
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putShort (std::size_t index, int16 value) { put< int16>(index, value); }
|
||||
EPICS_ALWAYS_INLINE void putShort (std::size_t index, int16 value) { put< int16>(index, value); }
|
||||
/**
|
||||
* Put an int value into the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer,
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putInt (std::size_t index, int32 value) { put< int32>(index, value); }
|
||||
EPICS_ALWAYS_INLINE void putInt (std::size_t index, int32 value) { put< int32>(index, value); }
|
||||
/**
|
||||
* Put a long value into the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer,
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putLong (std::size_t index, int64 value) { put< int64>(index, value); }
|
||||
EPICS_ALWAYS_INLINE void putLong (std::size_t index, int64 value) { put< int64>(index, value); }
|
||||
/**
|
||||
* Put a float value into the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer,
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putFloat (std::size_t index, float value) { put< float>(index, value); }
|
||||
EPICS_ALWAYS_INLINE void putFloat (std::size_t index, float value) { put< float>(index, value); }
|
||||
/**
|
||||
* Put a double value into the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer,
|
||||
* @param value The value.
|
||||
*/
|
||||
inline void putDouble (std::size_t index, double value) { put<double>(index, value); }
|
||||
EPICS_ALWAYS_INLINE void putDouble (std::size_t index, double value) { put<double>(index, value); }
|
||||
/**
|
||||
* Get a boolean value from the byte buffer.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
inline bool getBoolean() { return GET( int8) != 0; }
|
||||
EPICS_ALWAYS_INLINE bool getBoolean() { return GET( int8) != 0; }
|
||||
/**
|
||||
* Get a byte value from the byte buffer.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
inline int8 getByte () { return GET( int8); }
|
||||
EPICS_ALWAYS_INLINE int8 getByte () { return GET( int8); }
|
||||
/**
|
||||
* Get a short value from the byte buffer.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
inline int16 getShort () { return GET( int16); }
|
||||
EPICS_ALWAYS_INLINE int16 getShort () { return GET( int16); }
|
||||
/**
|
||||
* Get a int value from the byte buffer.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
inline int32 getInt () { return GET( int32); }
|
||||
EPICS_ALWAYS_INLINE int32 getInt () { return GET( int32); }
|
||||
/**
|
||||
* Get a long value from the byte buffer.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
inline int64 getLong () { return GET( int64); }
|
||||
EPICS_ALWAYS_INLINE int64 getLong () { return GET( int64); }
|
||||
/**
|
||||
* Get a float value from the byte buffer.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
inline float getFloat () { return GET( float); }
|
||||
EPICS_ALWAYS_INLINE float getFloat () { return GET( float); }
|
||||
/**
|
||||
* Get a double value from the byte buffer.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
inline double getDouble () { return GET(double); }
|
||||
EPICS_ALWAYS_INLINE double getDouble () { return GET(double); }
|
||||
/**
|
||||
* Get a boolean value from the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
inline bool getBoolean(std::size_t index) { return get< int8>(index) != 0; }
|
||||
EPICS_ALWAYS_INLINE bool getBoolean(std::size_t index) { return get< int8>(index) != 0; }
|
||||
/**
|
||||
* Get a byte value from the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
inline int8 getByte (std::size_t index) { return get< int8>(index); }
|
||||
EPICS_ALWAYS_INLINE int8 getByte (std::size_t index) { return get< int8>(index); }
|
||||
/**
|
||||
* Get a short value from the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
inline int16 getShort (std::size_t index) { return get< int16>(index); }
|
||||
EPICS_ALWAYS_INLINE int16 getShort (std::size_t index) { return get< int16>(index); }
|
||||
/**
|
||||
* Get an int value from the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
inline int32 getInt (std::size_t index) { return get< int32>(index); }
|
||||
EPICS_ALWAYS_INLINE int32 getInt (std::size_t index) { return get< int32>(index); }
|
||||
/**
|
||||
* Get a long value from the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
inline int64 getLong (std::size_t index) { return get< int64>(index); }
|
||||
EPICS_ALWAYS_INLINE int64 getLong (std::size_t index) { return get< int64>(index); }
|
||||
/**
|
||||
* Get a float value from the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
inline float getFloat (std::size_t index) { return get< float>(index); }
|
||||
EPICS_ALWAYS_INLINE float getFloat (std::size_t index) { return get< float>(index); }
|
||||
/**
|
||||
* Get a boolean value from the byte buffer at the specified index.
|
||||
*
|
||||
* @param index The offset in the byte buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
inline double getDouble (std::size_t index) { return get<double>(index); }
|
||||
EPICS_ALWAYS_INLINE double getDouble (std::size_t index) { return get<double>(index); }
|
||||
|
||||
// TODO remove
|
||||
inline const char* getArray() const
|
||||
EPICS_ALWAYS_INLINE const char* getArray() const
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
@@ -660,31 +712,31 @@ private:
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool ByteBuffer::reverse<bool>() const
|
||||
EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<bool>() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool ByteBuffer::reverse<int8>() const
|
||||
EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<int8>() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool ByteBuffer::reverse<uint8>() const
|
||||
EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<uint8>() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool ByteBuffer::reverse<float>() const
|
||||
EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<float>() const
|
||||
{
|
||||
return _reverseFloatEndianess;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool ByteBuffer::reverse<double>() const
|
||||
EPICS_ALWAYS_INLINE bool ByteBuffer::reverse<double>() const
|
||||
{
|
||||
return _reverseFloatEndianess;
|
||||
}
|
||||
@@ -699,8 +751,7 @@ private:
|
||||
if(reverse<T>())
|
||||
value = swap<T>(value);
|
||||
|
||||
//assert(is_aligned(_position, sizeof(T)));
|
||||
*((T*)_position) = value;
|
||||
detail::store_unaligned(_position, value);
|
||||
_position += sizeof(T);
|
||||
}
|
||||
|
||||
@@ -712,8 +763,7 @@ private:
|
||||
if(reverse<T>())
|
||||
value = swap<T>(value);
|
||||
|
||||
//assert(is_aligned(_buffer+index, sizeof(T))); //TODO: special case for targets which support unaligned access
|
||||
*((T*)(_buffer+index)) = value;
|
||||
detail::store_unaligned(_buffer+index, value);
|
||||
}
|
||||
|
||||
#if defined (__GNUC__) && (__GNUC__ < 3)
|
||||
@@ -726,8 +776,7 @@ private:
|
||||
{
|
||||
assert(sizeof(T)<=getRemaining());
|
||||
|
||||
//assert(is_aligned(_position, sizeof(T)));
|
||||
T value = *((T*)_position);
|
||||
T value = detail::load_unaligned<T>(_position);
|
||||
_position += sizeof(T);
|
||||
|
||||
if(reverse<T>())
|
||||
@@ -740,8 +789,7 @@ private:
|
||||
{
|
||||
assert(_buffer+index<=_limit);
|
||||
|
||||
//assert(is_aligned(_position, sizeof(T)));
|
||||
T value = *((T*)(_buffer + index));
|
||||
T value = detail::load_unaligned<T>(_buffer + index);
|
||||
|
||||
if(reverse<T>())
|
||||
value = swap<T>(value);
|
||||
@@ -751,17 +799,15 @@ private:
|
||||
template<typename T>
|
||||
inline void ByteBuffer::putArray(const T* values, std::size_t count)
|
||||
{
|
||||
// we require aligned arrays...
|
||||
//assert(is_aligned(_position, sizeof(T)));
|
||||
T* start = (T*)_position;
|
||||
size_t n = sizeof(T)*count; // bytes
|
||||
assert(n<=getRemaining());
|
||||
|
||||
if (reverse<T>()) {
|
||||
for(std::size_t i=0; i<count; i++)
|
||||
start[i] = swap<T>(values[i]);
|
||||
for(std::size_t i=0; i<n; i+=sizeof(T)) {
|
||||
detail::store_unaligned(_position+i, swap<T>(values[i]));
|
||||
}
|
||||
} else {
|
||||
memcpy(start, values, n);
|
||||
memcpy(_position, values, n);
|
||||
}
|
||||
_position += n;
|
||||
}
|
||||
@@ -769,17 +815,15 @@ private:
|
||||
template<typename T>
|
||||
inline void ByteBuffer::getArray(T* values, std::size_t count)
|
||||
{
|
||||
// we require aligned arrays...
|
||||
//assert(is_aligned(_position, sizeof(T)));
|
||||
const T* start = (T*)_position;
|
||||
size_t n = sizeof(T)*count; // bytes
|
||||
assert(n<=getRemaining());
|
||||
|
||||
if (reverse<T>()) {
|
||||
for(std::size_t i=0; i<count; i++)
|
||||
values[i] = swap<T>(start[i]);
|
||||
for(std::size_t i=0; i<n; i+=sizeof(T)) {
|
||||
values[i] = swap<T>(detail::load_unaligned<T>(_position+i));
|
||||
}
|
||||
} else {
|
||||
memcpy(values, start, n);
|
||||
memcpy(values, _position, n);
|
||||
}
|
||||
_position += n;
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/* executor.h */
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
#ifndef EXECUTOR_H
|
||||
#define EXECUTOR_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <compilerDependencies.h>
|
||||
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/lock.h>
|
||||
#include <pv/event.h>
|
||||
#include <pv/thread.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
class Command;
|
||||
class Executor;
|
||||
typedef std::tr1::shared_ptr<Command> CommandPtr;
|
||||
typedef std::tr1::shared_ptr<Executor> ExecutorPtr;
|
||||
|
||||
/**
|
||||
* @brief A command to be called by Executor
|
||||
*
|
||||
*/
|
||||
class epicsShareClass EPICS_DEPRECATED Command {
|
||||
public:
|
||||
POINTER_DEFINITIONS(Command);
|
||||
/**
|
||||
*
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Command(){}
|
||||
/**
|
||||
*
|
||||
* The command that is executed.
|
||||
*/
|
||||
virtual void command() = 0;
|
||||
private:
|
||||
CommandPtr next;
|
||||
friend class Executor;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class that executes commands.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass EPICS_DEPRECATED Executor : public Runnable{
|
||||
public:
|
||||
POINTER_DEFINITIONS(Executor);
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param threadName name for the executor thread.
|
||||
* @param priority The thread priority.
|
||||
*/
|
||||
Executor(std::string const & threadName,ThreadPriority priority);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Executor();
|
||||
/**
|
||||
*
|
||||
* Request to execute a command.
|
||||
* @param command A shared pointer to the command instance.
|
||||
*/
|
||||
void execute(CommandPtr const &command);
|
||||
/**
|
||||
*
|
||||
* The thread run method.
|
||||
*/
|
||||
virtual void run();
|
||||
private:
|
||||
CommandPtr head;
|
||||
CommandPtr tail;
|
||||
epics::pvData::Mutex mutex;
|
||||
epics::pvData::Event moreWork;
|
||||
epics::pvData::Event stopped;
|
||||
epics::pvData::Thread thread;
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* EXECUTOR_H */
|
||||
@@ -9,11 +9,13 @@
|
||||
#ifndef LOCALSTATICLOCK_H
|
||||
#define LOCALSTATICLOCK_H
|
||||
|
||||
#include <compilerDependencies.h>
|
||||
|
||||
#include <pv/lock.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
epicsShareExtern epics::pvData::Mutex& getLocalStaticInitMutex();
|
||||
epicsShareExtern epics::pvData::Mutex& getLocalStaticInitMutex() EPICS_DEPRECATED;
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
// noop
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
/* queue.h */
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <compilerDependencies.h>
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
/**
|
||||
* @brief Template class for a bounded queue.
|
||||
*
|
||||
* An instance can make a queueElement be any class desired
|
||||
* but must create a std::vector of shared_ptr to queueElements.
|
||||
*/
|
||||
template <typename T>
|
||||
class EPICS_DEPRECATED Queue
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(Queue);
|
||||
typedef std::tr1::shared_ptr<T> queueElementPtr;
|
||||
typedef std::vector<queueElementPtr> queueElementPtrArray;
|
||||
/**
|
||||
* Constructor
|
||||
* @param elementArray The vector of shared_ptr to queue elements.
|
||||
*/
|
||||
Queue(queueElementPtrArray & elementArray);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Queue();
|
||||
/**
|
||||
* Clear the queue.
|
||||
*/
|
||||
void clear();
|
||||
/**
|
||||
* get the capacity of the queue, i. e. number of queue elements,
|
||||
* @return The capacity.
|
||||
*/
|
||||
int capacity();
|
||||
/**
|
||||
* Get the number of free elements in the queue.
|
||||
* @return The number.
|
||||
*/
|
||||
int getNumberFree();
|
||||
/**
|
||||
* Get the number of used elements in the queue.
|
||||
* This is the number that have been setUsed but not released.
|
||||
* @return The number.
|
||||
*/
|
||||
int getNumberUsed();
|
||||
/**
|
||||
* Get the next free element.
|
||||
* @return a shared_ptr to the queue element.
|
||||
* This is null if queue was full.
|
||||
*/
|
||||
queueElementPtr getFree();
|
||||
/**
|
||||
* Set the element returned by getFree as used.
|
||||
* Until this is called getUsed will not return it.
|
||||
* @param element The element. It must be the element returned
|
||||
* by the most recent call to getUsed.
|
||||
*/
|
||||
void setUsed(queueElementPtr const &element);
|
||||
/**
|
||||
* Get the oldest used element;
|
||||
* @return a shared_ptr to the queue element.
|
||||
* This is null if no used element is available.`
|
||||
*/
|
||||
queueElementPtr getUsed();
|
||||
/**
|
||||
* Release the element obtained by the most recent call to getUsed.
|
||||
* @param element The element.
|
||||
*/
|
||||
void releaseUsed(queueElementPtr const &element);
|
||||
private:
|
||||
queueElementPtrArray elements;
|
||||
// TODO use size_t instead
|
||||
int size;
|
||||
int numberFree;
|
||||
int numberUsed;
|
||||
int nextGetFree;
|
||||
int nextSetUsed;
|
||||
int nextGetUsed;
|
||||
int nextReleaseUsed;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Queue<T>::Queue(std::vector<queueElementPtr> &xxx)
|
||||
: size(static_cast<int>(xxx.size())),
|
||||
numberFree(size),
|
||||
numberUsed(0),
|
||||
nextGetFree(0),
|
||||
nextSetUsed(0),
|
||||
nextGetUsed(0),
|
||||
nextReleaseUsed(0)
|
||||
{
|
||||
elements.swap(xxx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Queue<T>::~Queue(){}
|
||||
|
||||
template <typename T>
|
||||
int Queue<T>::capacity(){return size;}
|
||||
|
||||
template <typename T>
|
||||
int Queue<T>::getNumberFree(){return numberFree;}
|
||||
|
||||
template <typename T>
|
||||
int Queue<T>::getNumberUsed(){return numberUsed;}
|
||||
|
||||
template <typename T>
|
||||
void Queue<T>::clear()
|
||||
{
|
||||
numberFree = size;
|
||||
numberUsed = 0;
|
||||
nextGetFree = 0;
|
||||
nextSetUsed = 0;
|
||||
nextGetUsed = 0;
|
||||
nextReleaseUsed = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::tr1::shared_ptr<T> Queue<T>::getFree()
|
||||
{
|
||||
if(numberFree==0) return queueElementPtr();
|
||||
numberFree--;
|
||||
int ind = nextGetFree;
|
||||
std::tr1::shared_ptr<T> queueElement = elements[nextGetFree++];
|
||||
if(nextGetFree>=size) nextGetFree = 0;
|
||||
return elements[ind];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Queue<T>::setUsed(std::tr1::shared_ptr<T> const &element)
|
||||
{
|
||||
if(element!=elements[nextSetUsed++]) {
|
||||
throw std::logic_error("not correct queueElement");
|
||||
}
|
||||
numberUsed++;
|
||||
if(nextSetUsed>=size) nextSetUsed = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::tr1::shared_ptr<T> Queue<T>::getUsed()
|
||||
{
|
||||
if(numberUsed==0) return queueElementPtr();
|
||||
int ind = nextGetUsed;
|
||||
std::tr1::shared_ptr<T> queueElement = elements[nextGetUsed++];
|
||||
if(nextGetUsed>=size) nextGetUsed = 0;
|
||||
return elements[ind];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Queue<T>::releaseUsed(std::tr1::shared_ptr<T> const &element)
|
||||
{
|
||||
if(element!=elements[nextReleaseUsed++]) {
|
||||
throw std::logic_error(
|
||||
"not queueElement returned by last call to getUsed");
|
||||
}
|
||||
if(nextReleaseUsed>=size) nextReleaseUsed = 0;
|
||||
numberUsed--;
|
||||
numberFree++;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
#endif /* QUEUE_H */
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
#include <stdexcept>
|
||||
#include <iterator>
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
# include <initializer_list>
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "pv/sharedPtr.h"
|
||||
@@ -70,18 +74,24 @@ namespace detail {
|
||||
*/
|
||||
|
||||
public:
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
//! @brief Empty vector (not very interesting)
|
||||
constexpr shared_vector_base() noexcept
|
||||
:m_sdata(), m_offset(0), m_count(0), m_total(0)
|
||||
{}
|
||||
#else
|
||||
//! @brief Empty vector (not very interesting)
|
||||
shared_vector_base()
|
||||
:m_sdata(), m_offset(0), m_count(0), m_total(0)
|
||||
{}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// helper for constructors
|
||||
// Ensure that offset and size are zero when we are constructed with NULL
|
||||
void _null_input()
|
||||
{
|
||||
if(!m_sdata.get()) {
|
||||
if(!m_sdata) {
|
||||
m_offset = m_total = m_count = 0;
|
||||
} else {
|
||||
// ensure we won't have integer overflows later
|
||||
@@ -90,19 +100,12 @@ namespace detail {
|
||||
}
|
||||
public:
|
||||
|
||||
#ifdef _WIN32
|
||||
template<typename A>
|
||||
shared_vector_base(A* v, size_t o, size_t c)
|
||||
:m_sdata(v, detail::default_array_deleter<A*>())
|
||||
,m_offset(o), m_count(c), m_total(c)
|
||||
{_null_input();}
|
||||
#else
|
||||
template<typename A>
|
||||
shared_vector_base(A v, size_t o, size_t c)
|
||||
:m_sdata(v, detail::default_array_deleter<A>())
|
||||
,m_offset(o), m_count(c), m_total(c)
|
||||
{_null_input();}
|
||||
#endif
|
||||
|
||||
shared_vector_base(const std::tr1::shared_ptr<E>& d, size_t o, size_t c)
|
||||
:m_sdata(d), m_offset(o), m_count(c), m_total(c)
|
||||
{_null_input();}
|
||||
@@ -118,6 +121,17 @@ namespace detail {
|
||||
,m_count(O.m_count), m_total(O.m_total)
|
||||
{}
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
shared_vector_base(shared_vector_base &&O)
|
||||
:m_sdata(std::move(O.m_sdata))
|
||||
,m_offset(O.m_offset)
|
||||
,m_count(O.m_count)
|
||||
,m_total(O.m_total)
|
||||
{
|
||||
O.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
typedef typename meta::strip_const<E>::type _E_non_const;
|
||||
public:
|
||||
@@ -132,7 +146,11 @@ namespace detail {
|
||||
{
|
||||
if(!O.unique())
|
||||
throw std::runtime_error("Can't freeze non-unique vector");
|
||||
#if __cplusplus >= 201103L
|
||||
m_sdata = std::move(O.m_sdata);
|
||||
#else
|
||||
m_sdata = O.m_sdata;
|
||||
#endif
|
||||
O.clear();
|
||||
}
|
||||
|
||||
@@ -146,7 +164,11 @@ namespace detail {
|
||||
,m_total(O.m_total)
|
||||
{
|
||||
O.make_unique();
|
||||
#if __cplusplus >= 201103L
|
||||
m_sdata = std::move(std::tr1::const_pointer_cast<E>(O.m_sdata));
|
||||
#else
|
||||
m_sdata = std::tr1::const_pointer_cast<E>(O.m_sdata);
|
||||
#endif
|
||||
O.clear();
|
||||
}
|
||||
|
||||
@@ -162,6 +184,21 @@ namespace detail {
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
//! @brief Move an existing vector
|
||||
shared_vector_base& operator=(shared_vector_base&& o)
|
||||
{
|
||||
if(&o!=this) {
|
||||
m_sdata=std::move(o.m_sdata);
|
||||
m_offset=o.m_offset;
|
||||
m_count=o.m_count;
|
||||
m_total=o.m_total;
|
||||
o.clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
//! @brief Swap the contents of this vector with another
|
||||
void swap(shared_vector_base& o) {
|
||||
if(&o!=this) {
|
||||
@@ -180,11 +217,12 @@ namespace detail {
|
||||
}
|
||||
|
||||
//! @brief Data is not shared?
|
||||
bool unique() const {return !m_sdata || m_sdata.unique();}
|
||||
bool unique() const {return !m_sdata || m_sdata.use_count()<=1;}
|
||||
|
||||
|
||||
//! @brief Number of elements visible through this vector
|
||||
size_t size() const{return m_count;}
|
||||
//! @brief shorthand for size()==0
|
||||
bool empty() const{return !m_count;}
|
||||
|
||||
|
||||
@@ -272,9 +310,22 @@ public:
|
||||
// allow specialization for all E to be friends
|
||||
template<typename E1, class Enable1> friend class shared_vector;
|
||||
|
||||
|
||||
//! @brief Empty vector (not very interesting)
|
||||
#if __cplusplus>=201103L
|
||||
constexpr shared_vector() noexcept :base_t() {}
|
||||
#else
|
||||
shared_vector() :base_t() {}
|
||||
#endif
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
template<typename A>
|
||||
shared_vector(std::initializer_list<A> L)
|
||||
:base_t(new _E_non_const[L.size()], 0, L.size())
|
||||
{
|
||||
_E_non_const *raw = const_cast<_E_non_const*>(data());
|
||||
std::copy(L.begin(), L.end(), raw);
|
||||
}
|
||||
#endif
|
||||
|
||||
//! @brief Allocate (with new[]) a new vector of size c
|
||||
explicit shared_vector(size_t c)
|
||||
@@ -321,6 +372,11 @@ public:
|
||||
//! @brief Copy an existing vector of same type
|
||||
shared_vector(const shared_vector& o) :base_t(o) {}
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
//! @brief Move an existing vector of same type
|
||||
shared_vector(shared_vector&& o) :base_t(std::move(o)) {}
|
||||
#endif
|
||||
|
||||
//! @internal
|
||||
//! Internal for static_shared_vector_cast
|
||||
template<typename FROM>
|
||||
@@ -342,6 +398,20 @@ public:
|
||||
:base_t(O,t)
|
||||
{}
|
||||
|
||||
inline shared_vector& operator=(const shared_vector& o)
|
||||
{
|
||||
this->base_t::operator=(o);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
inline shared_vector& operator=(shared_vector&& o)
|
||||
{
|
||||
this->base_t::operator=(std::move(o));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t max_size() const{return ((size_t)-1)/sizeof(E);}
|
||||
|
||||
size_t capacity() const { return this->m_total; }
|
||||
@@ -353,6 +423,9 @@ public:
|
||||
* does not increase.
|
||||
*
|
||||
* For notes on copying see docs for make_unique().
|
||||
*
|
||||
* @throws std::bad_alloc if requested allocation can not be made
|
||||
* @throws other exceptions from element copy ctor
|
||||
*/
|
||||
void reserve(size_t i) {
|
||||
if(this->unique() && i<=this->m_total)
|
||||
@@ -377,13 +450,16 @@ public:
|
||||
* as if make_unique() were called. This holds even if the size does not change.
|
||||
*
|
||||
* For notes on copying see docs for make_unique().
|
||||
*
|
||||
* @throws std::bad_alloc if requested allocation can not be made
|
||||
* @throws other exceptions from element copy ctor
|
||||
*/
|
||||
void resize(size_t i) {
|
||||
if(i==this->m_count) {
|
||||
make_unique();
|
||||
return;
|
||||
}
|
||||
if(this->m_sdata && this->m_sdata.unique()) {
|
||||
if(this->m_sdata && this->m_sdata.use_count()==1) {
|
||||
// we have data and exclusive ownership of it
|
||||
if(i<=this->m_total) {
|
||||
// We have room to grow (or shrink)!
|
||||
@@ -438,10 +514,14 @@ public:
|
||||
}
|
||||
assert(original.unique());
|
||||
@endcode
|
||||
*
|
||||
* @throws std::bad_alloc if requested allocation can not be made
|
||||
* @throws other exceptions from element copy ctor
|
||||
*/
|
||||
void make_unique() {
|
||||
if(this->unique())
|
||||
return;
|
||||
// at this point we know that !!m_sdata, so get()!=NULL
|
||||
_E_non_const *d = new _E_non_const[this->m_total];
|
||||
try {
|
||||
std::copy(this->m_sdata.get()+this->m_offset,
|
||||
@@ -455,13 +535,27 @@ public:
|
||||
this->m_offset=0;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
/* Hack alert.
|
||||
* For reasons of simplicity and efficiency, we want to use raw pointers for iteration.
|
||||
* However, shared_ptr::get() isn't defined when !m_sdata, although practically it gives NULL.
|
||||
* Unfortunately, many of the MSVC (<= VS 2010) STL methods assert() that iterators are never NULL.
|
||||
* So we fudge here by abusing 'this' so that our iterators are always !NULL.
|
||||
*/
|
||||
inline E* base_ptr() const {
|
||||
#if defined(_MSC_VER) && _MSC_VER<=1600
|
||||
return this->m_count ? this->m_sdata.get() : (E*)(this-1);
|
||||
#else
|
||||
return this->m_sdata.get();
|
||||
#endif
|
||||
}
|
||||
public:
|
||||
// STL iterators
|
||||
|
||||
iterator begin() const{return this->m_sdata.get()+this->m_offset;}
|
||||
iterator begin() const{return this->base_ptr()+this->m_offset;}
|
||||
const_iterator cbegin() const{return begin();}
|
||||
|
||||
iterator end() const{return this->m_sdata.get()+this->m_offset+this->m_count;}
|
||||
iterator end() const{return this->base_ptr()+this->m_offset+this->m_count;}
|
||||
const_iterator cend() const{return end();}
|
||||
|
||||
reverse_iterator rbegin() const{return reverse_iterator(end());}
|
||||
@@ -513,10 +607,15 @@ public:
|
||||
|
||||
// data access
|
||||
|
||||
//! @brief Return Base pointer
|
||||
pointer data() const{return this->m_sdata.get()+this->m_offset;}
|
||||
|
||||
//! @brief Member access
|
||||
//! Undefined if empty()==true.
|
||||
reference operator[](size_t i) const {return this->m_sdata.get()[this->m_offset+i];}
|
||||
|
||||
//! @brief Member access
|
||||
//! @throws std::out_of_range if i>=size().
|
||||
reference at(size_t i) const
|
||||
{
|
||||
if(i>this->m_count)
|
||||
@@ -563,7 +662,11 @@ public:
|
||||
|
||||
typedef std::tr1::shared_ptr<E> shared_pointer_type;
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
constexpr shared_vector() noexcept :base_t(), m_vtype((ScalarType)-1) {}
|
||||
#else
|
||||
shared_vector() :base_t(), m_vtype((ScalarType)-1) {}
|
||||
#endif
|
||||
|
||||
shared_vector(pointer v, size_t o, size_t c)
|
||||
:base_t(v,o,c), m_vtype((ScalarType)-1) {}
|
||||
@@ -579,6 +682,11 @@ public:
|
||||
shared_vector(const shared_vector& o)
|
||||
:base_t(o), m_vtype(o.m_vtype) {}
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
shared_vector(shared_vector&& o)
|
||||
:base_t(std::move(o)), m_vtype(o.m_vtype) {}
|
||||
#endif
|
||||
|
||||
//! @internal
|
||||
//! Internal for static_shared_vector_cast
|
||||
template<typename FROM>
|
||||
@@ -609,6 +717,22 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus>=201103L
|
||||
shared_vector& operator=(shared_vector&& o)
|
||||
{
|
||||
if(&o!=this) {
|
||||
this->base_t::operator=(std::move(o));
|
||||
m_vtype = o.m_vtype;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void swap(shared_vector& o) {
|
||||
base_t::swap(o);
|
||||
std::swap(m_vtype, o.m_vtype);
|
||||
}
|
||||
|
||||
size_t max_size() const{return (size_t)-1;}
|
||||
|
||||
pointer data() const{
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/* timeFunction.h */
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
#ifndef TIMEFUNCTION_H
|
||||
#define TIMEFUNCTION_H
|
||||
|
||||
#include <compilerDependencies.h>
|
||||
|
||||
#include <pv/sharedPtr.h>
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
class TimeFunctionRequester;
|
||||
class TimeFunction;
|
||||
typedef std::tr1::shared_ptr<TimeFunctionRequester> TimeFunctionRequesterPtr;
|
||||
typedef std::tr1::shared_ptr<TimeFunction> TimeFunctionPtr;
|
||||
|
||||
/**
|
||||
* @brief Class that must be implemented by timeFunction requester.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass EPICS_DEPRECATED TimeFunctionRequester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(TimeFunctionRequester);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~TimeFunctionRequester(){}
|
||||
/**
|
||||
* function to be timed.
|
||||
* It will get called multiple times.
|
||||
*/
|
||||
virtual void function() = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Class for measuring time it takes to execute a function.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass EPICS_DEPRECATED TimeFunction {
|
||||
public:
|
||||
POINTER_DEFINITIONS(TimeFunction);
|
||||
/**
|
||||
* Constructor
|
||||
* @param requester The class that has a function method.
|
||||
*/
|
||||
TimeFunction(TimeFunctionRequesterPtr const & requester);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~TimeFunction();
|
||||
/**
|
||||
* Time the function.
|
||||
* @return the time in seconds to execute the function.
|
||||
* Note that the function may be called many times.
|
||||
*/
|
||||
double timeCall();
|
||||
private:
|
||||
TimeFunctionRequesterPtr requester;
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
#endif /* TIMEFUNCTION_H */
|
||||
@@ -9,6 +9,8 @@
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
#include <memory>
|
||||
#include <list>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -55,34 +57,28 @@ public:
|
||||
*/
|
||||
virtual void timerStopped() = 0;
|
||||
private:
|
||||
TimerCallbackPtr next;
|
||||
TimeStamp timeToRun;
|
||||
epicsTime timeToRun;
|
||||
double period;
|
||||
bool onList;
|
||||
friend class Timer;
|
||||
struct IncreasingTime;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Support for delayed or periodic callback execution.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass Timer : public Runnable {
|
||||
class epicsShareClass Timer : private Runnable {
|
||||
public:
|
||||
POINTER_DEFINITIONS(Timer);
|
||||
/**
|
||||
* Constructor
|
||||
/** Create a new timer queue
|
||||
* @param threadName name for the timer thread.
|
||||
* @param priority thread priority
|
||||
*/
|
||||
Timer(std::string threadName, ThreadPriority priority);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Timer();
|
||||
/**
|
||||
* The thread run method. This is called automatically.
|
||||
*/
|
||||
virtual void run();
|
||||
//! Prevent new callbacks from being scheduled, and cancel pending callbacks
|
||||
void close();
|
||||
/**
|
||||
* schedule a callback after a delay.
|
||||
* @param timerCallback the timerCallback instance.
|
||||
@@ -104,30 +100,37 @@ public:
|
||||
/**
|
||||
* cancel a callback.
|
||||
* @param timerCallback the timerCallback to cancel.
|
||||
* @returns true if the timer was queued, and now is cancelled
|
||||
*/
|
||||
void cancel(TimerCallbackPtr const &timerCallback);
|
||||
bool cancel(TimerCallbackPtr const &timerCallback);
|
||||
/**
|
||||
* Is the callback scheduled to be called?
|
||||
* @param timerCallback the timerCallback.
|
||||
* @return (false,true) if (not, is) scheduled.
|
||||
*/
|
||||
bool isScheduled(TimerCallbackPtr const &timerCallback);
|
||||
bool isScheduled(TimerCallbackPtr const &timerCallback) const;
|
||||
/**
|
||||
* show the elements in the timer queue.
|
||||
* @param o The output stream for the output
|
||||
*/
|
||||
void dump(std::ostream& o);
|
||||
void dump(std::ostream& o) const;
|
||||
|
||||
private:
|
||||
virtual void run();
|
||||
|
||||
// call with mutex held
|
||||
void addElement(TimerCallbackPtr const &timerCallback);
|
||||
TimerCallbackPtr head;
|
||||
Mutex mutex;
|
||||
|
||||
typedef std::list<TimerCallbackPtr> queue_t;
|
||||
|
||||
mutable Mutex mutex;
|
||||
queue_t queue;
|
||||
Event waitForWork;
|
||||
bool alive;
|
||||
Thread thread;
|
||||
};
|
||||
|
||||
epicsShareExtern std::ostream& operator<<(std::ostream& o, Timer& timer);
|
||||
epicsShareExtern std::ostream& operator<<(std::ostream& o, const Timer& timer);
|
||||
|
||||
}}
|
||||
#endif /* TIMER_H */
|
||||
|
||||
@@ -22,17 +22,29 @@ namespace epics { namespace pvData {
|
||||
namespace detail {
|
||||
// parseToPOD wraps the epicsParse*() functions in one name
|
||||
// and throws exceptions
|
||||
epicsShareExtern void parseToPOD(const std::string&, boolean *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, int8 *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, uint8 *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, int16_t *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, uint16_t *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, int32_t *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, uint32_t *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, int64_t *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, uint64_t *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, float *out);
|
||||
epicsShareExtern void parseToPOD(const std::string&, double *out);
|
||||
epicsShareExtern void parseToPOD(const char*, boolean *out);
|
||||
epicsShareExtern void parseToPOD(const char*, int8 *out);
|
||||
epicsShareExtern void parseToPOD(const char*, uint8 *out);
|
||||
epicsShareExtern void parseToPOD(const char*, int16_t *out);
|
||||
epicsShareExtern void parseToPOD(const char*, uint16_t *out);
|
||||
epicsShareExtern void parseToPOD(const char*, int32_t *out);
|
||||
epicsShareExtern void parseToPOD(const char*, uint32_t *out);
|
||||
epicsShareExtern void parseToPOD(const char*, int64_t *out);
|
||||
epicsShareExtern void parseToPOD(const char*, uint64_t *out);
|
||||
epicsShareExtern void parseToPOD(const char*, float *out);
|
||||
epicsShareExtern void parseToPOD(const char*, double *out);
|
||||
|
||||
static inline void parseToPOD(const std::string& str, boolean *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, int8 *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, uint8 *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, int16_t *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, uint16_t *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, int32_t *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, uint32_t *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, int64_t *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, uint64_t *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, float *out) { return parseToPOD(str.c_str(), out); }
|
||||
static inline void parseToPOD(const std::string& str, double *out) { return parseToPOD(str.c_str(), out); }
|
||||
|
||||
/* want to pass POD types by value,
|
||||
* and std::string by const reference
|
||||
@@ -108,13 +120,28 @@ namespace detail {
|
||||
}
|
||||
};
|
||||
|
||||
// parse POD from C string
|
||||
// TO!=const char*
|
||||
template<typename TO>
|
||||
struct cast_helper<TO, const char*,
|
||||
typename meta::_and<
|
||||
typename meta::not_same_type<TO,const char*>,
|
||||
typename meta::not_same_type<TO,std::string>
|
||||
>::type> {
|
||||
static FORCE_INLINE TO op(const char* from) {
|
||||
TO ret;
|
||||
parseToPOD(from, &ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
} // end detail
|
||||
|
||||
/** @brief Casting/converting between supported scalar types.
|
||||
*
|
||||
* Supported types: uint8_t, int8_t, uint16_t, int16_t,
|
||||
* uint32_t, int32_t, uint64_t, int64_t,
|
||||
* float, double, std::string
|
||||
* float, double, std::string, const char* (only FROM)
|
||||
*
|
||||
* As defined in pvType.h
|
||||
*
|
||||
|
||||
@@ -265,7 +265,6 @@ void RefMonitor::current()
|
||||
|
||||
void RefMonitor::show(const RefSnapshot &snap, bool complete)
|
||||
{
|
||||
epicsTime now(epicsTime::getCurrent());
|
||||
char buf[80];
|
||||
epicsTime::getCurrent().strftime(buf, sizeof(buf), "%a %b %d %Y %H:%M:%S.%f");
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
|
||||
@@ -98,8 +98,6 @@ namespace epics {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static string emptyStringtring;
|
||||
|
||||
string SerializeHelper::deserializeString(ByteBuffer* buffer,
|
||||
DeserializableControl* control) {
|
||||
@@ -139,7 +137,7 @@ namespace epics {
|
||||
}
|
||||
}
|
||||
else
|
||||
return emptyStringtring;
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/* timeFunction.cpp */
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
*/
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
#include <epicsTime.h>
|
||||
|
||||
// Suppress deprecation warnings for the implementation
|
||||
#include <compilerDependencies.h>
|
||||
#undef EPICS_DEPRECATED
|
||||
#define EPICS_DEPRECATED
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/timeFunction.h>
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
TimeFunction::TimeFunction(TimeFunctionRequesterPtr const &requester)
|
||||
: requester(requester) {}
|
||||
|
||||
|
||||
TimeFunction::~TimeFunction() {}
|
||||
|
||||
double TimeFunction::timeCall()
|
||||
{
|
||||
TimeStamp startTime;
|
||||
TimeStamp endTime;
|
||||
double perCall = 0.0;
|
||||
long ntimes = 1;
|
||||
while(true) {
|
||||
startTime.getCurrent();
|
||||
for(long i=0; i<ntimes; i++) requester->function();
|
||||
endTime.getCurrent();
|
||||
double diff = TimeStamp::diff(endTime,startTime);
|
||||
if(diff>=1.0) {
|
||||
perCall = diff/(double)ntimes;
|
||||
break;
|
||||
}
|
||||
ntimes *= 2;
|
||||
}
|
||||
return perCall;
|
||||
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <epicsGuard.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/timer.h>
|
||||
@@ -36,61 +37,47 @@ Timer::Timer(string threadName,ThreadPriority priority)
|
||||
thread(threadName,priority,this)
|
||||
{}
|
||||
|
||||
struct TimerCallback::IncreasingTime {
|
||||
bool operator()(const TimerCallbackPtr& lhs, const TimerCallbackPtr& rhs) {
|
||||
assert(lhs && rhs);
|
||||
return lhs->timeToRun < rhs->timeToRun;
|
||||
}
|
||||
};
|
||||
|
||||
// call with mutex held
|
||||
void Timer::addElement(TimerCallbackPtr const & timerCallback)
|
||||
{
|
||||
assert(!timerCallback->onList);
|
||||
|
||||
queue_t temp;
|
||||
temp.push_back(timerCallback);
|
||||
|
||||
timerCallback->onList = true;
|
||||
if(head.get()==NULL) {
|
||||
head = timerCallback;
|
||||
timerCallback->next.reset();
|
||||
return;
|
||||
}
|
||||
TimerCallbackPtr nextNode(head);
|
||||
TimerCallbackPtr prevNode;
|
||||
while(true) {
|
||||
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;
|
||||
}
|
||||
|
||||
// merge sorted lists.
|
||||
// for us effectively insertion sort.
|
||||
queue.merge(temp, TimerCallback::IncreasingTime());
|
||||
}
|
||||
|
||||
|
||||
void Timer::cancel(TimerCallbackPtr const &timerCallback)
|
||||
bool Timer::cancel(TimerCallbackPtr const &timerCallback)
|
||||
{
|
||||
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;
|
||||
if(!timerCallback->onList) return false;
|
||||
for(queue_t::iterator it(queue.begin()), end(queue.end()); it != end; ++it)
|
||||
{
|
||||
TimerCallbackPtr& cur = *it;
|
||||
if(cur.get() == timerCallback.get()) {
|
||||
queue.erase(it);
|
||||
cur->onList = false;
|
||||
// iteration now invalid
|
||||
return true;
|
||||
}
|
||||
prevNode = nextNode;
|
||||
nextNode = nextNode->next;
|
||||
}
|
||||
throw std::logic_error(string(""));
|
||||
throw std::logic_error("Timer::cancel() onList==true, but not found");
|
||||
}
|
||||
|
||||
bool Timer::isScheduled(TimerCallbackPtr const &timerCallback)
|
||||
bool Timer::isScheduled(TimerCallbackPtr const &timerCallback) const
|
||||
{
|
||||
Lock xx(mutex);
|
||||
return timerCallback->onList;
|
||||
@@ -99,62 +86,72 @@ bool Timer::isScheduled(TimerCallbackPtr const &timerCallback)
|
||||
|
||||
void Timer::run()
|
||||
{
|
||||
TimeStamp currentTime;
|
||||
while(true) {
|
||||
double period = 0.0;
|
||||
TimerCallbackPtr nodeToCall;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
currentTime.getCurrent();
|
||||
if (!alive) break;
|
||||
TimerCallbackPtr timerCallback = head;
|
||||
if(timerCallback.get()!=NULL) {
|
||||
double diff = TimeStamp::diff(
|
||||
timerCallback->timeToRun,currentTime);
|
||||
if(diff<=0.0) {
|
||||
nodeToCall = timerCallback;
|
||||
nodeToCall->onList = false;
|
||||
head = head->next;
|
||||
period = timerCallback->period;
|
||||
if(period>0.0) {
|
||||
timerCallback->timeToRun += period;
|
||||
addElement(timerCallback);
|
||||
}
|
||||
timerCallback = head;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(nodeToCall.get()!=NULL) {
|
||||
nodeToCall->callback();
|
||||
}
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(!alive) break;
|
||||
}
|
||||
if(head.get()==NULL) {
|
||||
epicsGuard<epicsMutex> G(mutex);
|
||||
|
||||
epicsTime now(epicsTime::getCurrent());
|
||||
|
||||
while(alive) {
|
||||
double waitfor;
|
||||
|
||||
if(queue.empty()) {
|
||||
// no jobs, just go to sleep
|
||||
epicsGuardRelease<epicsMutex> U(G);
|
||||
|
||||
waitForWork.wait();
|
||||
} else {
|
||||
double delay = TimeStamp::diff(head->timeToRun,currentTime);
|
||||
waitForWork.wait(delay);
|
||||
}
|
||||
}
|
||||
now = epicsTime::getCurrent();
|
||||
|
||||
} else if((waitfor = queue.front()->timeToRun - now) <= 0) {
|
||||
// execute first expired job
|
||||
|
||||
TimerCallbackPtr work;
|
||||
work.swap(queue.front());
|
||||
work->onList = false;
|
||||
queue.pop_front();
|
||||
|
||||
{
|
||||
epicsGuardRelease<epicsMutex> U(G);
|
||||
|
||||
work->callback();
|
||||
}
|
||||
|
||||
if(work->period > 0.0) {
|
||||
work->timeToRun += work->period;
|
||||
addElement(work);
|
||||
}
|
||||
|
||||
// don't update 'now' until all expired jobs run
|
||||
|
||||
} else {
|
||||
// wait for first un-expired
|
||||
epicsGuardRelease<epicsMutex> U(G);
|
||||
|
||||
waitForWork.wait(waitfor);
|
||||
now = epicsTime::getCurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer::~Timer() {
|
||||
close();
|
||||
}
|
||||
|
||||
void Timer::close() {
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(!alive)
|
||||
return; // already closed
|
||||
alive = false;
|
||||
}
|
||||
waitForWork.signal();
|
||||
thread.exitWait();
|
||||
TimerCallbackPtr timerCallback;
|
||||
while(true) {
|
||||
timerCallback = head;
|
||||
if(head.get()==NULL) break;
|
||||
|
||||
queue_t temp;
|
||||
temp.swap(queue);
|
||||
|
||||
for(;!temp.empty(); temp.pop_front()) {
|
||||
TimerCallbackPtr& head = temp.front();
|
||||
head->onList = false;
|
||||
head->timerStopped();
|
||||
head = timerCallback->next;
|
||||
timerCallback->next.reset();
|
||||
timerCallback->onList = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,49 +167,44 @@ void Timer::schedulePeriodic(
|
||||
double delay,
|
||||
double period)
|
||||
{
|
||||
if(isScheduled(timerCallback)) {
|
||||
throw std::logic_error(string("already queued"));
|
||||
}
|
||||
epicsTime now(epicsTime::getCurrent());
|
||||
|
||||
bool wasempty;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(timerCallback->onList) {
|
||||
throw std::logic_error(string("already queued"));
|
||||
}
|
||||
|
||||
if(!alive) {
|
||||
xx.unlock();
|
||||
timerCallback->timerStopped();
|
||||
return;
|
||||
}
|
||||
}
|
||||
TimeStamp timeStamp;
|
||||
timeStamp.getCurrent();
|
||||
timeStamp += delay;
|
||||
timerCallback->timeToRun.getCurrent();
|
||||
timerCallback->timeToRun += delay;
|
||||
timerCallback->period = period;
|
||||
bool isFirst = false;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
|
||||
timerCallback->timeToRun = now + delay;
|
||||
timerCallback->period = period;
|
||||
|
||||
wasempty = queue.empty();
|
||||
addElement(timerCallback);
|
||||
if(timerCallback.get()==head.get()) isFirst = true;
|
||||
}
|
||||
if(isFirst) waitForWork.signal();
|
||||
if(wasempty) waitForWork.signal();
|
||||
}
|
||||
|
||||
void Timer::dump(std::ostream& o)
|
||||
void Timer::dump(std::ostream& o) const
|
||||
{
|
||||
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);
|
||||
o << "timeToRun " << diff << " period " << period << std::endl;
|
||||
nodeToCall = nodeToCall->next;
|
||||
}
|
||||
epicsTime now(epicsTime::getCurrent());
|
||||
|
||||
for(queue_t::const_iterator it(queue.begin()), end(queue.end()); it!=end; ++it) {
|
||||
const TimerCallbackPtr& nodeToCall = *it;
|
||||
o << "timeToRun " << (nodeToCall->timeToRun - now)
|
||||
<< " period " << nodeToCall->period << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, Timer& timer)
|
||||
std::ostream& operator<<(std::ostream& o, const Timer& timer)
|
||||
{
|
||||
timer.dump(o);
|
||||
return o;
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <epicsConvert.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
@@ -18,7 +20,7 @@ using std::string;
|
||||
|
||||
namespace {
|
||||
|
||||
static void noconvert(size_t, void*, const void*)
|
||||
static void noconvert()
|
||||
{
|
||||
throw std::runtime_error("castUnsafeV: Conversion not supported");
|
||||
}
|
||||
@@ -31,12 +33,10 @@ static void castVTyped(size_t count, void *draw, const void *sraw)
|
||||
|
||||
//std::transform(src, src+count, dest, castUnsafe<TO,FROM>);
|
||||
|
||||
const FROM *last = src+count;
|
||||
try {
|
||||
while (src != last) {
|
||||
*dest = castUnsafe<TO,FROM>(*src);
|
||||
++dest; ++src;
|
||||
}
|
||||
for(size_t i=0; i<count; i++) {
|
||||
dest[i] = castUnsafe<TO,FROM>(src[i]);
|
||||
}
|
||||
} catch (std::exception& ex) {
|
||||
// do not report index for scalars (or arrays with one element)
|
||||
if (count > 1)
|
||||
@@ -59,182 +59,11 @@ static void copyV(size_t count, void *draw, const void *sraw)
|
||||
std::copy(src, src+count, dest);
|
||||
}
|
||||
|
||||
typedef void (*convertfn)(size_t, void*, const void*);
|
||||
|
||||
/* lookup table of converter functions.
|
||||
* first dimension is TO, second is FROM
|
||||
*/
|
||||
static convertfn converters[pvString+1][pvString+1] =
|
||||
template<int N>
|
||||
static void copyMem(size_t count, void *draw, const void *sraw)
|
||||
{
|
||||
// to pvBoolean
|
||||
{ ©V<epics::pvData::boolean>,
|
||||
&noconvert,
|
||||
&noconvert,
|
||||
&noconvert,
|
||||
&noconvert,
|
||||
&noconvert,
|
||||
&noconvert,
|
||||
&noconvert,
|
||||
&noconvert,
|
||||
&noconvert,
|
||||
&noconvert,
|
||||
&castVTyped<epics::pvData::boolean, string>,
|
||||
},
|
||||
// to pvByte
|
||||
{&noconvert,
|
||||
©V<int8_t>,
|
||||
&castVTyped<int8_t, int16_t>,
|
||||
&castVTyped<int8_t, int32_t>,
|
||||
&castVTyped<int8_t, int64_t>,
|
||||
&castVTyped<int8_t, uint8_t>,
|
||||
&castVTyped<int8_t, uint16_t>,
|
||||
&castVTyped<int8_t, uint32_t>,
|
||||
&castVTyped<int8_t, uint64_t>,
|
||||
&castVTyped<int8_t, float>,
|
||||
&castVTyped<int8_t, double>,
|
||||
&castVTyped<int8_t, string>,
|
||||
},
|
||||
// to pvShort
|
||||
{&noconvert,
|
||||
&castVTyped<int16_t, int8_t>,
|
||||
©V<int16_t>,
|
||||
&castVTyped<int16_t, int32_t>,
|
||||
&castVTyped<int16_t, int64_t>,
|
||||
&castVTyped<int16_t, uint8_t>,
|
||||
&castVTyped<int16_t, uint16_t>,
|
||||
&castVTyped<int16_t, uint32_t>,
|
||||
&castVTyped<int16_t, uint64_t>,
|
||||
&castVTyped<int16_t, float>,
|
||||
&castVTyped<int16_t, double>,
|
||||
&castVTyped<int16_t, string>,
|
||||
},
|
||||
// to pvInt
|
||||
{&noconvert,
|
||||
&castVTyped<int32_t, int8_t>,
|
||||
&castVTyped<int32_t, int16_t>,
|
||||
©V<int32_t>,
|
||||
&castVTyped<int32_t, int64_t>,
|
||||
&castVTyped<int32_t, uint8_t>,
|
||||
&castVTyped<int32_t, uint16_t>,
|
||||
&castVTyped<int32_t, uint32_t>,
|
||||
&castVTyped<int32_t, uint64_t>,
|
||||
&castVTyped<int32_t, float>,
|
||||
&castVTyped<int32_t, double>,
|
||||
&castVTyped<int32_t, string>,
|
||||
},
|
||||
// to pvLong
|
||||
{&noconvert,
|
||||
&castVTyped<int64_t, int8_t>,
|
||||
&castVTyped<int64_t, int16_t>,
|
||||
&castVTyped<int64_t, int32_t>,
|
||||
©V<int64_t>,
|
||||
&castVTyped<int64_t, uint8_t>,
|
||||
&castVTyped<int64_t, uint16_t>,
|
||||
&castVTyped<int64_t, uint32_t>,
|
||||
&castVTyped<int64_t, uint64_t>,
|
||||
&castVTyped<int64_t, float>,
|
||||
&castVTyped<int64_t, double>,
|
||||
&castVTyped<int64_t, string>,
|
||||
},
|
||||
// to pvUByte
|
||||
{&noconvert,
|
||||
&castVTyped<uint8_t, int8_t>,
|
||||
&castVTyped<uint8_t, int16_t>,
|
||||
&castVTyped<uint8_t, int32_t>,
|
||||
&castVTyped<uint8_t, uint64_t>,
|
||||
©V<uint8_t>,
|
||||
&castVTyped<uint8_t, uint16_t>,
|
||||
&castVTyped<uint8_t, uint32_t>,
|
||||
&castVTyped<uint8_t, uint64_t>,
|
||||
&castVTyped<uint8_t, float>,
|
||||
&castVTyped<uint8_t, double>,
|
||||
&castVTyped<uint8_t, string>,
|
||||
},
|
||||
// to pvUShort
|
||||
{&noconvert,
|
||||
&castVTyped<uint16_t, int8_t>,
|
||||
&castVTyped<uint16_t, int16_t>,
|
||||
&castVTyped<uint16_t, int32_t>,
|
||||
&castVTyped<uint16_t, uint64_t>,
|
||||
&castVTyped<uint16_t, uint8_t>,
|
||||
©V<uint16_t>,
|
||||
&castVTyped<uint16_t, uint32_t>,
|
||||
&castVTyped<uint16_t, uint64_t>,
|
||||
&castVTyped<uint16_t, float>,
|
||||
&castVTyped<uint16_t, double>,
|
||||
&castVTyped<uint16_t, string>,
|
||||
},
|
||||
// to pvUInt
|
||||
{&noconvert,
|
||||
&castVTyped<uint32_t, int8_t>,
|
||||
&castVTyped<uint32_t, int16_t>,
|
||||
&castVTyped<uint32_t, int32_t>,
|
||||
&castVTyped<uint32_t, uint64_t>,
|
||||
&castVTyped<uint32_t, uint8_t>,
|
||||
&castVTyped<uint32_t, uint16_t>,
|
||||
©V<uint32_t>,
|
||||
&castVTyped<uint32_t, uint64_t>,
|
||||
&castVTyped<uint32_t, float>,
|
||||
&castVTyped<uint32_t, double>,
|
||||
&castVTyped<uint32_t, string>,
|
||||
},
|
||||
// to pvULong
|
||||
{&noconvert,
|
||||
&castVTyped<uint64_t, int8_t>,
|
||||
&castVTyped<uint64_t, int16_t>,
|
||||
&castVTyped<uint64_t, int32_t>,
|
||||
&castVTyped<uint64_t, uint64_t>,
|
||||
&castVTyped<uint64_t, uint8_t>,
|
||||
&castVTyped<uint64_t, uint16_t>,
|
||||
&castVTyped<uint64_t, uint32_t>,
|
||||
©V<uint64_t>,
|
||||
&castVTyped<uint64_t, float>,
|
||||
&castVTyped<uint64_t, double>,
|
||||
&castVTyped<uint64_t, string>,
|
||||
},
|
||||
// to pvFloat
|
||||
{&noconvert,
|
||||
&castVTyped<float, int8_t>,
|
||||
&castVTyped<float, int16_t>,
|
||||
&castVTyped<float, int32_t>,
|
||||
&castVTyped<float, uint64_t>,
|
||||
&castVTyped<float, uint8_t>,
|
||||
&castVTyped<float, uint16_t>,
|
||||
&castVTyped<float, uint32_t>,
|
||||
&castVTyped<float, uint64_t>,
|
||||
©V<float>,
|
||||
&castVTyped<float, double>,
|
||||
&castVTyped<float, string>,
|
||||
},
|
||||
// to pvDouble
|
||||
{&noconvert,
|
||||
&castVTyped<double, int8_t>,
|
||||
&castVTyped<double, int16_t>,
|
||||
&castVTyped<double, int32_t>,
|
||||
&castVTyped<double, uint64_t>,
|
||||
&castVTyped<double, uint8_t>,
|
||||
&castVTyped<double, uint16_t>,
|
||||
&castVTyped<double, uint32_t>,
|
||||
&castVTyped<double, uint64_t>,
|
||||
&castVTyped<double, float>,
|
||||
©V<double>,
|
||||
&castVTyped<double, string>,
|
||||
},
|
||||
// to pvString
|
||||
{&castVTyped<string, epics::pvData::boolean>,
|
||||
&castVTyped<string, int8_t>,
|
||||
&castVTyped<string, int16_t>,
|
||||
&castVTyped<string, int32_t>,
|
||||
&castVTyped<string, uint64_t>,
|
||||
&castVTyped<string, uint8_t>,
|
||||
&castVTyped<string, uint16_t>,
|
||||
&castVTyped<string, uint32_t>,
|
||||
&castVTyped<string, uint64_t>,
|
||||
&castVTyped<string, float>,
|
||||
&castVTyped<string, double>,
|
||||
©V<string>,
|
||||
},
|
||||
};
|
||||
memcpy(draw, sraw, count*N);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
@@ -242,12 +71,207 @@ namespace epics { namespace pvData {
|
||||
|
||||
void castUnsafeV(size_t count, ScalarType to, void *dest, ScalarType from, const void *src)
|
||||
{
|
||||
unsigned int ito=to, ifrom=from;
|
||||
#define COPYMEM(N) copyMem<N>(count, dest, src)
|
||||
#define CAST(TO, FROM) castVTyped<TO, FROM>(count, dest, src)
|
||||
|
||||
if(ito>pvString || ifrom>pvString)
|
||||
throw std::runtime_error("castUnsafeV: Invalid types");
|
||||
switch(to) {
|
||||
case pvBoolean:
|
||||
switch(from) {
|
||||
case pvBoolean: COPYMEM(1); return;
|
||||
case pvString: CAST(boolean, std::string); return;
|
||||
default: noconvert(); return;
|
||||
}
|
||||
break;
|
||||
|
||||
converters[ito][ifrom](count, dest, src);
|
||||
case pvByte:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte:
|
||||
case pvUByte: COPYMEM(1); return;
|
||||
case pvShort: CAST(int8, int16); return;
|
||||
case pvUShort: CAST(int8, uint16); return;
|
||||
case pvInt: CAST(int8, int32); return;
|
||||
case pvUInt: CAST(int8, uint32); return;
|
||||
case pvLong: CAST(int8, int64); return;
|
||||
case pvULong: CAST(int8, uint64); return;
|
||||
case pvFloat: CAST(int8, float); return;
|
||||
case pvDouble: CAST(int8, double); return;
|
||||
case pvString: CAST(int8, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvUByte:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte:
|
||||
case pvUByte: COPYMEM(1); return;
|
||||
case pvShort: CAST(uint8, int16); return;
|
||||
case pvUShort: CAST(uint8, uint16); return;
|
||||
case pvInt: CAST(uint8, int32); return;
|
||||
case pvUInt: CAST(uint8, uint32); return;
|
||||
case pvLong: CAST(uint8, int64); return;
|
||||
case pvULong: CAST(uint8, uint64); return;
|
||||
case pvFloat: CAST(uint8, float); return;
|
||||
case pvDouble: CAST(uint8, double); return;
|
||||
case pvString: CAST(uint8, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvShort:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte: CAST(int16, int8); return;
|
||||
case pvUByte: CAST(int16, uint8); return;
|
||||
case pvShort:
|
||||
case pvUShort: COPYMEM(2); return;
|
||||
case pvInt: CAST(int16, int32); return;
|
||||
case pvUInt: CAST(int16, uint32); return;
|
||||
case pvLong: CAST(int16, int64); return;
|
||||
case pvULong: CAST(int16, uint64); return;
|
||||
case pvFloat: CAST(int16, float); return;
|
||||
case pvDouble: CAST(int16, double); return;
|
||||
case pvString: CAST(int16, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvUShort:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte: CAST(uint16, int8); return;
|
||||
case pvUByte: CAST(uint16, uint8); return;
|
||||
case pvShort:
|
||||
case pvUShort: COPYMEM(2); return;
|
||||
case pvInt: CAST(uint16, int32); return;
|
||||
case pvUInt: CAST(uint16, uint32); return;
|
||||
case pvLong: CAST(uint16, int64); return;
|
||||
case pvULong: CAST(uint16, uint64); return;
|
||||
case pvFloat: CAST(uint16, float); return;
|
||||
case pvDouble: CAST(uint16, double); return;
|
||||
case pvString: CAST(uint16, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvInt:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte: CAST(int32, int8); return;
|
||||
case pvUByte: CAST(int32, uint8); return;
|
||||
case pvShort: CAST(int32, int16); return;
|
||||
case pvUShort: CAST(int32, uint16); return;
|
||||
case pvInt:
|
||||
case pvUInt: COPYMEM(4); return;
|
||||
case pvLong: CAST(int32, int64); return;
|
||||
case pvULong: CAST(int32, uint64); return;
|
||||
case pvFloat: CAST(int32, float); return;
|
||||
case pvDouble: CAST(int32, double); return;
|
||||
case pvString: CAST(int32, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvUInt:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte: CAST(uint32, int8); return;
|
||||
case pvUByte: CAST(uint32, uint8); return;
|
||||
case pvShort: CAST(uint32, int16); return;
|
||||
case pvUShort: CAST(uint32, uint16); return;
|
||||
case pvInt:
|
||||
case pvUInt: COPYMEM(4); return;
|
||||
case pvLong: CAST(uint32, int64); return;
|
||||
case pvULong: CAST(uint32, uint64); return;
|
||||
case pvFloat: CAST(uint32, float); return;
|
||||
case pvDouble: CAST(uint32, double); return;
|
||||
case pvString: CAST(uint32, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvLong:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte: CAST(int64, int8); return;
|
||||
case pvUByte: CAST(int64, uint8); return;
|
||||
case pvShort: CAST(int64, int16); return;
|
||||
case pvUShort: CAST(int64, uint16); return;
|
||||
case pvInt: CAST(int64, int32); return;
|
||||
case pvUInt: CAST(int64, uint32); return;
|
||||
case pvLong:
|
||||
case pvULong: COPYMEM(8); return;
|
||||
case pvFloat: CAST(int64, float); return;
|
||||
case pvDouble: CAST(int64, double); return;
|
||||
case pvString: CAST(int64, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvULong:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte: CAST(uint64, int8); return;
|
||||
case pvUByte: CAST(uint64, uint8); return;
|
||||
case pvShort: CAST(uint64, int16); return;
|
||||
case pvUShort: CAST(uint64, uint16); return;
|
||||
case pvInt: CAST(uint64, int32); return;
|
||||
case pvUInt: CAST(uint64, uint32); return;
|
||||
case pvLong:
|
||||
case pvULong: COPYMEM(8); return;
|
||||
case pvFloat: CAST(uint64, float); return;
|
||||
case pvDouble: CAST(uint64, double); return;
|
||||
case pvString: CAST(uint64, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvFloat:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte: CAST(float, int8); return;
|
||||
case pvUByte: CAST(float, uint8); return;
|
||||
case pvShort: CAST(float, int16); return;
|
||||
case pvUShort: CAST(float, uint16); return;
|
||||
case pvInt: CAST(float, int32); return;
|
||||
case pvUInt: CAST(float, uint32); return;
|
||||
case pvLong: CAST(float, int64); return;
|
||||
case pvULong: CAST(float, uint64); return;
|
||||
case pvFloat: COPYMEM(4); return;
|
||||
case pvDouble: CAST(float, double); return;
|
||||
case pvString: CAST(float, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvDouble:
|
||||
switch(from) {
|
||||
case pvBoolean: noconvert(); return;
|
||||
case pvByte: CAST(double, int8); return;
|
||||
case pvUByte: CAST(double, uint8); return;
|
||||
case pvShort: CAST(double, int16); return;
|
||||
case pvUShort: CAST(double, uint16); return;
|
||||
case pvInt: CAST(double, int32); return;
|
||||
case pvUInt: CAST(double, uint32); return;
|
||||
case pvLong: CAST(double, int64); return;
|
||||
case pvULong: CAST(double, uint64); return;
|
||||
case pvFloat: CAST(double, float); return;
|
||||
case pvDouble: COPYMEM(8); return;
|
||||
case pvString: CAST(double, std::string); return;
|
||||
}
|
||||
break;
|
||||
|
||||
case pvString:
|
||||
switch(from) {
|
||||
case pvBoolean: CAST(std::string, boolean); return;
|
||||
case pvByte: CAST(std::string, int8); return;
|
||||
case pvUByte: CAST(std::string, uint8); return;
|
||||
case pvShort: CAST(std::string, int16); return;
|
||||
case pvUShort: CAST(std::string, uint16); return;
|
||||
case pvInt: CAST(std::string, int32); return;
|
||||
case pvUInt: CAST(std::string, uint32); return;
|
||||
case pvLong: CAST(std::string, int64); return;
|
||||
case pvULong: CAST(std::string, uint64); return;
|
||||
case pvFloat: CAST(std::string, float); return;
|
||||
case pvDouble: CAST(std::string, double); return;
|
||||
case pvString: copyV<std::string>(count, dest, src); return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
THROW_EXCEPTION2(std::logic_error, "Undefined cast");
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -30,14 +30,14 @@ bool PVTimeStamp::attach(PVFieldPtr const & pvField)
|
||||
PVStructure* pvStructure = xxx.get();
|
||||
while(true) {
|
||||
PVLongPtr pvLong = pvStructure->getSubField<PVLong>("secondsPastEpoch");
|
||||
if(pvLong.get()!=NULL) {
|
||||
if(pvLong) {
|
||||
pvSecs = pvLong;
|
||||
pvNano = pvStructure->getSubField<PVInt>("nanoseconds");
|
||||
pvUserTag = pvStructure->getSubField<PVInt>("userTag");
|
||||
}
|
||||
if(pvSecs.get()!=NULL
|
||||
&& pvNano.get()!=NULL
|
||||
&& pvUserTag.get()!=NULL) return true;
|
||||
if(pvSecs
|
||||
&& pvNano
|
||||
&& pvUserTag) return true;
|
||||
detach();
|
||||
// look up the tree for a timeSyamp
|
||||
pvStructure = pvStructure->getParent();
|
||||
|
||||
@@ -33,31 +33,6 @@
|
||||
typedef class std::ios std::ios_base;
|
||||
#endif
|
||||
|
||||
/* C++11 keywords
|
||||
@code
|
||||
struct Base {
|
||||
virtual void foo();
|
||||
};
|
||||
struct Class : public Base {
|
||||
virtual void foo() OVERRIDE FINAL;
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
#ifndef FINAL
|
||||
# if __cplusplus>=201103L
|
||||
# define FINAL final
|
||||
# else
|
||||
# define FINAL
|
||||
# endif
|
||||
#endif
|
||||
#ifndef OVERRIDE
|
||||
# if __cplusplus>=201103L
|
||||
# define OVERRIDE override
|
||||
# else
|
||||
# define OVERRIDE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
/** @defgroup pvcontainer Value containers
|
||||
@@ -1475,11 +1450,16 @@ typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
|
||||
typedef PVValueArray<std::string> PVStringArray;
|
||||
typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
|
||||
|
||||
namespace detail {
|
||||
struct pvfield_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This is a singleton class for creating data instances.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass PVDataCreate {
|
||||
friend struct detail::pvfield_factory;
|
||||
public:
|
||||
/**
|
||||
* get the singleton
|
||||
|
||||
@@ -21,6 +21,31 @@
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
/* C++11 keywords
|
||||
@code
|
||||
struct Base {
|
||||
virtual void foo();
|
||||
};
|
||||
struct Class : public Base {
|
||||
virtual void foo() OVERRIDE FINAL;
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
#ifndef FINAL
|
||||
# if __cplusplus>=201103L
|
||||
# define FINAL final
|
||||
# else
|
||||
# define FINAL
|
||||
# endif
|
||||
#endif
|
||||
#ifndef OVERRIDE
|
||||
# if __cplusplus>=201103L
|
||||
# define OVERRIDE override
|
||||
# else
|
||||
# define OVERRIDE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
namespace format {
|
||||
@@ -295,9 +320,6 @@ public:
|
||||
static size_t num_instances;
|
||||
|
||||
POINTER_DEFINITIONS(Field);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Field();
|
||||
/**
|
||||
* Get the field type.
|
||||
@@ -346,9 +368,6 @@ epicsShareExtern std::ostream& operator<<(std::ostream& o, const Field& field);
|
||||
class epicsShareClass Scalar : public Field{
|
||||
public:
|
||||
POINTER_DEFINITIONS(Scalar);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Scalar();
|
||||
typedef Scalar& reference;
|
||||
typedef const Scalar& const_reference;
|
||||
@@ -358,12 +377,12 @@ public:
|
||||
*/
|
||||
ScalarType getScalarType() const {return scalarType;}
|
||||
|
||||
virtual std::string getID() const;
|
||||
virtual std::string getID() const OVERRIDE;
|
||||
|
||||
virtual std::ostream& dump(std::ostream& o) const;
|
||||
virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;
|
||||
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;
|
||||
|
||||
protected:
|
||||
Scalar(ScalarType scalarType);
|
||||
@@ -384,16 +403,13 @@ private:
|
||||
class epicsShareClass BoundedString : public Scalar{
|
||||
public:
|
||||
POINTER_DEFINITIONS(BoundedString);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~BoundedString();
|
||||
typedef BoundedString& reference;
|
||||
typedef const BoundedString& const_reference;
|
||||
|
||||
virtual std::string getID() const;
|
||||
virtual std::string getID() const OVERRIDE FINAL;
|
||||
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
|
||||
|
||||
std::size_t getMaximumLength() const;
|
||||
|
||||
@@ -411,9 +427,6 @@ private:
|
||||
class epicsShareClass Array : public Field{
|
||||
public:
|
||||
POINTER_DEFINITIONS(Array);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Array();
|
||||
typedef Array& reference;
|
||||
typedef const Array& const_reference;
|
||||
@@ -462,21 +475,18 @@ public:
|
||||
*/
|
||||
ScalarType getElementType() const {return elementType;}
|
||||
|
||||
virtual ArraySizeType getArraySizeType() const {return Array::variable;}
|
||||
virtual ArraySizeType getArraySizeType() const OVERRIDE {return Array::variable;}
|
||||
|
||||
virtual std::size_t getMaximumCapacity() const {return 0;}
|
||||
virtual std::size_t getMaximumCapacity() const OVERRIDE {return 0;}
|
||||
|
||||
virtual std::string getID() const;
|
||||
virtual std::string getID() const OVERRIDE;
|
||||
|
||||
virtual std::ostream& dump(std::ostream& o) const;
|
||||
virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;
|
||||
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~ScalarArray();
|
||||
private:
|
||||
const std::string getIDScalarArrayLUT() const;
|
||||
@@ -503,18 +513,15 @@ public:
|
||||
*/
|
||||
BoundedScalarArray(ScalarType scalarType, std::size_t size);
|
||||
|
||||
virtual ArraySizeType getArraySizeType() const {return Array::bounded;}
|
||||
virtual ArraySizeType getArraySizeType() const OVERRIDE FINAL {return Array::bounded;}
|
||||
|
||||
virtual std::size_t getMaximumCapacity() const {return size;}
|
||||
virtual std::size_t getMaximumCapacity() const OVERRIDE FINAL {return size;}
|
||||
|
||||
virtual std::string getID() const;
|
||||
virtual std::string getID() const OVERRIDE FINAL;
|
||||
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~BoundedScalarArray();
|
||||
private:
|
||||
std::size_t size;
|
||||
@@ -538,18 +545,15 @@ public:
|
||||
*/
|
||||
FixedScalarArray(ScalarType scalarType, std::size_t size);
|
||||
|
||||
virtual ArraySizeType getArraySizeType() const {return Array::fixed;}
|
||||
virtual ArraySizeType getArraySizeType() const OVERRIDE FINAL {return Array::fixed;}
|
||||
|
||||
virtual std::size_t getMaximumCapacity() const {return size;}
|
||||
virtual std::size_t getMaximumCapacity() const OVERRIDE FINAL {return size;}
|
||||
|
||||
virtual std::string getID() const;
|
||||
virtual std::string getID() const OVERRIDE FINAL;
|
||||
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~FixedScalarArray();
|
||||
private:
|
||||
std::size_t size;
|
||||
@@ -570,18 +574,18 @@ public:
|
||||
* Get the introspection interface for the array elements.
|
||||
* @return The introspection interface.
|
||||
*/
|
||||
StructureConstPtr getStructure() const {return pstructure;}
|
||||
const StructureConstPtr& getStructure() const {return pstructure;}
|
||||
|
||||
virtual ArraySizeType getArraySizeType() const {return Array::variable;}
|
||||
virtual ArraySizeType getArraySizeType() const OVERRIDE FINAL {return Array::variable;}
|
||||
|
||||
virtual std::size_t getMaximumCapacity() const {return 0;}
|
||||
virtual std::size_t getMaximumCapacity() const OVERRIDE FINAL {return 0;}
|
||||
|
||||
virtual std::string getID() const;
|
||||
virtual std::string getID() const OVERRIDE FINAL;
|
||||
|
||||
virtual std::ostream& dump(std::ostream& o) const;
|
||||
virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;
|
||||
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -589,9 +593,6 @@ protected:
|
||||
* @param structure The introspection interface for the elements.
|
||||
*/
|
||||
StructureArray(StructureConstPtr const & structure);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~StructureArray();
|
||||
private:
|
||||
StructureConstPtr pstructure;
|
||||
@@ -614,16 +615,16 @@ public:
|
||||
*/
|
||||
UnionConstPtr getUnion() const {return punion;}
|
||||
|
||||
virtual ArraySizeType getArraySizeType() const {return Array::variable;}
|
||||
virtual ArraySizeType getArraySizeType() const OVERRIDE FINAL {return Array::variable;}
|
||||
|
||||
virtual std::size_t getMaximumCapacity() const {return 0;}
|
||||
virtual std::size_t getMaximumCapacity() const OVERRIDE FINAL {return 0;}
|
||||
|
||||
virtual std::string getID() const;
|
||||
virtual std::string getID() const OVERRIDE FINAL;
|
||||
|
||||
virtual std::ostream& dump(std::ostream& o) const;
|
||||
virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;
|
||||
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -631,9 +632,6 @@ protected:
|
||||
* @param _punion The introspection interface for the elements.
|
||||
*/
|
||||
UnionArray(UnionConstPtr const & _punion);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~UnionArray();
|
||||
private:
|
||||
UnionConstPtr punion;
|
||||
@@ -659,9 +657,6 @@ public:
|
||||
*/
|
||||
static const std::string & defaultId();
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Structure();
|
||||
typedef Structure& reference;
|
||||
typedef const Structure& const_reference;
|
||||
@@ -682,8 +677,8 @@ public:
|
||||
template<typename FT>
|
||||
std::tr1::shared_ptr<const FT> getField(std::string const &fieldName) const
|
||||
{
|
||||
FieldConstPtr field = getField(fieldName);
|
||||
if (field.get())
|
||||
FieldConstPtr field(getField(fieldName));
|
||||
if (field)
|
||||
return std::tr1::dynamic_pointer_cast<const FT>(field);
|
||||
else
|
||||
return std::tr1::shared_ptr<const FT>();
|
||||
@@ -695,13 +690,13 @@ public:
|
||||
* @return The introspection interface.
|
||||
* This will hold a null pointer if the field is not in the structure.
|
||||
*/
|
||||
FieldConstPtr getField(std::size_t index) const {return fields.at(index);}
|
||||
const FieldConstPtr& getField(std::size_t index) const {return fields.at(index);}
|
||||
|
||||
template<typename FT>
|
||||
std::tr1::shared_ptr<const FT> getField(std::size_t index) const
|
||||
{
|
||||
FieldConstPtr field = getField(index);
|
||||
if (field.get())
|
||||
const FieldConstPtr& field(getField(index));
|
||||
if (field)
|
||||
return std::tr1::dynamic_pointer_cast<const FT>(field);
|
||||
else
|
||||
return std::tr1::shared_ptr<const FT>();
|
||||
@@ -728,14 +723,14 @@ public:
|
||||
* @param fieldIndex The index of the desired field.
|
||||
* @return The fieldName.
|
||||
*/
|
||||
std::string getFieldName(std::size_t fieldIndex) const {return fieldNames.at(fieldIndex);}
|
||||
const std::string& getFieldName(std::size_t fieldIndex) const {return fieldNames.at(fieldIndex);}
|
||||
|
||||
virtual std::string getID() const;
|
||||
virtual std::string getID() const OVERRIDE FINAL;
|
||||
|
||||
virtual std::ostream& dump(std::ostream& o) const;
|
||||
virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;
|
||||
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;
|
||||
|
||||
protected:
|
||||
Structure(StringArray const & fieldNames, FieldConstPtrArray const & fields, std::string const & id = defaultId());
|
||||
@@ -744,7 +739,7 @@ private:
|
||||
FieldConstPtrArray fields;
|
||||
std::string id;
|
||||
|
||||
virtual void dumpFields(std::ostream& o) const;
|
||||
void dumpFields(std::ostream& o) const;
|
||||
|
||||
friend class FieldCreate;
|
||||
friend class Union;
|
||||
@@ -780,9 +775,6 @@ public:
|
||||
*/
|
||||
static const std::string & anyId();
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Union();
|
||||
typedef Union& reference;
|
||||
typedef const Union& const_reference;
|
||||
@@ -804,7 +796,7 @@ public:
|
||||
std::tr1::shared_ptr<const FT> getField(std::string const &fieldName) const
|
||||
{
|
||||
FieldConstPtr field = getField(fieldName);
|
||||
if (field.get())
|
||||
if (field)
|
||||
return std::tr1::dynamic_pointer_cast<const FT>(field);
|
||||
else
|
||||
return std::tr1::shared_ptr<const FT>();
|
||||
@@ -822,7 +814,7 @@ public:
|
||||
std::tr1::shared_ptr<const FT> getField(std::size_t index) const
|
||||
{
|
||||
FieldConstPtr field = getField(index);
|
||||
if (field.get())
|
||||
if (field)
|
||||
return std::tr1::dynamic_pointer_cast<const FT>(field);
|
||||
else
|
||||
return std::tr1::shared_ptr<const FT>();
|
||||
@@ -867,12 +859,12 @@ public:
|
||||
*/
|
||||
int32 guess(Type t, ScalarType s) const;
|
||||
|
||||
virtual std::string getID() const;
|
||||
virtual std::string getID() const OVERRIDE FINAL;
|
||||
|
||||
virtual std::ostream& dump(std::ostream& o) const;
|
||||
virtual std::ostream& dump(std::ostream& o) const OVERRIDE FINAL;
|
||||
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
||||
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const OVERRIDE FINAL;
|
||||
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control) OVERRIDE FINAL;
|
||||
|
||||
protected:
|
||||
Union();
|
||||
@@ -882,7 +874,7 @@ private:
|
||||
FieldConstPtrArray fields;
|
||||
std::string id;
|
||||
|
||||
virtual void dumpFields(std::ostream& o) const;
|
||||
void dumpFields(std::ostream& o) const;
|
||||
|
||||
friend class FieldCreate;
|
||||
friend class Structure;
|
||||
@@ -1065,11 +1057,16 @@ private:
|
||||
const bool createNested; // true - endNested() creates in parent, false - endNested() appends to parent
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
struct field_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This is a singleton class for creating introspection interfaces.
|
||||
*
|
||||
*/
|
||||
class epicsShareClass FieldCreate {
|
||||
friend struct detail::field_factory;
|
||||
public:
|
||||
static const FieldCreatePtr &getFieldCreate();
|
||||
/**
|
||||
@@ -1270,41 +1267,6 @@ OP(pvDouble, double)
|
||||
OP(pvString, std::string)
|
||||
#undef OP
|
||||
|
||||
/**
|
||||
* @brief Hash a Scalar
|
||||
*
|
||||
*/
|
||||
struct ScalarHashFunction {
|
||||
size_t operator() (const Scalar& scalar) const { return scalar.getScalarType(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Hash a ScalarArray
|
||||
*
|
||||
*/
|
||||
struct ScalarArrayHashFunction {
|
||||
size_t operator() (const ScalarArray& scalarArray) const { return 0x10 | scalarArray.getElementType(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Hash a Structure
|
||||
*
|
||||
*/
|
||||
struct StructureHashFunction {
|
||||
size_t operator() (const Structure& /*structure*/) const { return 0; }
|
||||
// TODO hash
|
||||
// final int PRIME = 31;
|
||||
// return PRIME * Arrays.hashCode(fieldNames) + Arrays.hashCode(fields);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Hash a StructureArray
|
||||
*
|
||||
*/
|
||||
struct StructureArrayHashFunction {
|
||||
size_t operator() (const StructureArray& structureArray) const { StructureHashFunction shf; return (0x10 | shf(*(structureArray.getStructure()))); }
|
||||
};
|
||||
|
||||
bool epicsShareExtern operator==(const Field&, const Field&);
|
||||
bool epicsShareExtern operator==(const Scalar&, const Scalar&);
|
||||
bool epicsShareExtern operator==(const ScalarArray&, const ScalarArray&);
|
||||
|
||||
@@ -12,18 +12,22 @@ include $(PVDATA_TEST)/pv/Makefile
|
||||
include $(PVDATA_TEST)/property/Makefile
|
||||
include $(PVDATA_TEST)/copy/Makefile
|
||||
|
||||
# The testHarness runs all the test programs in a known working order.
|
||||
# pvDataAllTests runs all the test programs in a known working order.
|
||||
testHarness_SRCS += pvDataAllTests.c
|
||||
|
||||
PROD_vxWorks = vxTestHarness
|
||||
vxTestHarness_SRCS += $(testHarness_SRCS)
|
||||
TESTSPEC_vxWorks = vxTestHarness.$(MUNCH_SUFFIX); pvDataAllTests
|
||||
# Name the application pvdTestHarness
|
||||
pvdTestHarness_SRCS = $(testHarness_SRCS)
|
||||
|
||||
PROD_RTEMS += rtemsTestHarness
|
||||
rtemsTestHarness_SRCS += rtemsTestHarness.c rtemsConfig.c
|
||||
rtemsTestHarness_SRCS += $(testHarness_SRCS)
|
||||
TESTSPEC_RTEMS = rtemsTestHarness.$(MUNCH_SUFFIX); pvDataAllTests
|
||||
# Build for vxWorks
|
||||
PROD_vxWorks += pvdTestHarness
|
||||
TESTSPEC_vxWorks = pvdTestHarness.$(MUNCH_SUFFIX); pvDataAllTests
|
||||
|
||||
# Build for RTEMS, with harness code & OS configuration
|
||||
PROD_RTEMS += pvdTestHarness
|
||||
pvdTestHarness_SRCS_RTEMS = rtemsTestHarness.c
|
||||
TESTSPEC_RTEMS = pvdTestHarness.$(MUNCH_SUFFIX); pvDataAllTests
|
||||
|
||||
# Build test scripts for hosts
|
||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -41,7 +41,6 @@ static void testPVScalar(
|
||||
PVScalarPtr pvValueMaster;
|
||||
PVScalarPtr pvValueCopy;
|
||||
BitSetPtr bitSet;
|
||||
size_t offset;
|
||||
ConvertPtr convert = getConvert();
|
||||
|
||||
pvValueMaster = pvMaster->getSubField<PVScalar>(valueNameMaster);
|
||||
@@ -58,7 +57,7 @@ static void testPVScalar(
|
||||
testOk1(convert->toDouble(pvValueCopy)==.06);
|
||||
testOk1(bitSet->get(pvValueCopy->getFieldOffset()));
|
||||
|
||||
offset = pvCopy->getCopyOffset(pvValueMaster);
|
||||
pvCopy->getCopyOffset(pvValueMaster);
|
||||
|
||||
bitSet->clear();
|
||||
convert->fromDouble(pvValueMaster,1.0);
|
||||
@@ -87,7 +86,6 @@ static void testPVScalarArray(
|
||||
PVScalarArrayPtr pvValueMaster;
|
||||
PVScalarArrayPtr pvValueCopy;
|
||||
BitSetPtr bitSet;
|
||||
size_t offset;
|
||||
size_t n = 5;
|
||||
shared_vector<double> values(n);
|
||||
shared_vector<const double> cvalues;
|
||||
@@ -113,7 +111,7 @@ static void testPVScalarArray(
|
||||
pvValueCopy->getAs(cvalues);
|
||||
testOk1(cvalues[0]==0.06);
|
||||
|
||||
offset = pvCopy->getCopyOffset(pvValueMaster);
|
||||
pvCopy->getCopyOffset(pvValueMaster);
|
||||
|
||||
bitSet->clear();
|
||||
values.resize(n);
|
||||
|
||||
@@ -59,11 +59,6 @@ testTimeStamp_SRCS += testTimeStamp.cpp
|
||||
testHarness_SRCS += testTimeStamp.cpp
|
||||
TESTS += testTimeStamp
|
||||
|
||||
TESTPROD_HOST += testQueue
|
||||
testQueue_SRCS += testQueue.cpp
|
||||
testHarness_SRCS += testQueue.cpp
|
||||
TESTS += testQueue
|
||||
|
||||
TESTPROD_HOST += testTypeCast
|
||||
testTypeCast_SRCS += testTypeCast.cpp
|
||||
testHarness_SRCS += testTypeCast.cpp
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
/*
|
||||
* testQueue.cpp
|
||||
*
|
||||
* Created on: 2010.12
|
||||
* Author: Marty Kraimer
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
#include <epicsUnitTest.h>
|
||||
#include <testMain.h>
|
||||
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include <pv/lock.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/queue.h>
|
||||
#include <pv/event.h>
|
||||
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
struct Data {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
typedef std::tr1::shared_ptr<Data> DataPtr;
|
||||
typedef std::vector<DataPtr> DataPtrArray;
|
||||
|
||||
static const int numElements = 5;
|
||||
typedef Queue<Data> DataQueue;
|
||||
|
||||
class Sink;
|
||||
typedef std::tr1::shared_ptr<Sink> SinkPtr;
|
||||
|
||||
class Sink : public epicsThreadRunable {
|
||||
public:
|
||||
static SinkPtr create(DataQueue &queue);
|
||||
Sink(DataQueue &queue);
|
||||
~Sink();
|
||||
void stop();
|
||||
void look();
|
||||
virtual void run();
|
||||
private:
|
||||
DataQueue &queue;
|
||||
bool isStopped;
|
||||
Event *wait;
|
||||
Event *stopped;
|
||||
Event *waitReturn;
|
||||
Event *waitEmpty;
|
||||
epicsThread *thread;
|
||||
};
|
||||
|
||||
SinkPtr Sink::create(DataQueue &queue)
|
||||
{
|
||||
return SinkPtr(new Sink(queue));
|
||||
}
|
||||
|
||||
Sink::Sink(DataQueue &queue)
|
||||
: queue(queue),
|
||||
isStopped(false),
|
||||
wait(new Event()),
|
||||
stopped(new Event()),
|
||||
waitReturn(new Event()),
|
||||
waitEmpty(new Event()),
|
||||
thread(new epicsThread(*this,"sink",epicsThreadGetStackSize(epicsThreadStackSmall)))
|
||||
{
|
||||
thread->start();
|
||||
}
|
||||
|
||||
Sink::~Sink() {
|
||||
delete thread;
|
||||
delete waitEmpty;
|
||||
delete waitReturn;
|
||||
delete stopped;
|
||||
delete wait;
|
||||
}
|
||||
|
||||
void Sink::stop()
|
||||
{
|
||||
isStopped = true;
|
||||
wait->signal();
|
||||
stopped->wait();
|
||||
}
|
||||
|
||||
void Sink::look()
|
||||
{
|
||||
wait->signal();
|
||||
waitEmpty->wait();
|
||||
}
|
||||
|
||||
void Sink::run()
|
||||
{
|
||||
while(!isStopped) {
|
||||
wait->wait();
|
||||
if(isStopped) break;
|
||||
while(true) {
|
||||
DataPtr data = queue.getUsed();
|
||||
if(data.get()==NULL) {
|
||||
waitEmpty->signal();
|
||||
break;
|
||||
}
|
||||
printf(" sink a %d b %d\n",data->a,data->b);
|
||||
queue.releaseUsed(data);
|
||||
}
|
||||
}
|
||||
stopped->signal();
|
||||
}
|
||||
|
||||
static void testBasic() {
|
||||
DataPtrArray dataArray;
|
||||
dataArray.reserve(numElements);
|
||||
for(int i=0; i<numElements; i++) {
|
||||
dataArray.push_back(DataPtr(new Data()));
|
||||
}
|
||||
DataQueue queue(dataArray);
|
||||
DataPtr data = queue.getFree();
|
||||
int value = 0;
|
||||
while(data.get()!=NULL) {
|
||||
data->a = value;
|
||||
data->b = value*10;
|
||||
value++;
|
||||
queue.setUsed(data);
|
||||
data = queue.getFree();
|
||||
}
|
||||
SinkPtr sink = SinkPtr(new Sink(queue));
|
||||
queue.clear();
|
||||
while(true) {
|
||||
data = queue.getFree();
|
||||
if(data.get()==NULL) break;
|
||||
printf("source a %d b %d\n",data->a,data->b);
|
||||
queue.setUsed(data);
|
||||
}
|
||||
sink->look();
|
||||
// now alternate
|
||||
for(int i=0; i<numElements; i++) {
|
||||
data = queue.getFree();
|
||||
testOk1(data.get()!=NULL);
|
||||
printf("source a %d b %d\n",data->a,data->b);
|
||||
queue.setUsed(data);
|
||||
sink->look();
|
||||
}
|
||||
sink->stop();
|
||||
printf("PASSED\n");
|
||||
}
|
||||
|
||||
|
||||
MAIN(testQueue)
|
||||
{
|
||||
testPlan(5);
|
||||
testDiag("Tests queue");
|
||||
testBasic();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <epicsUnitTest.h>
|
||||
#include <pv/pvUnitTest.h>
|
||||
#include <testMain.h>
|
||||
|
||||
#include "pv/sharedVector.h"
|
||||
@@ -20,16 +20,21 @@
|
||||
using std::string;
|
||||
using namespace epics::pvData;
|
||||
|
||||
static void testEmpty()
|
||||
namespace {
|
||||
|
||||
void testEmpty()
|
||||
{
|
||||
testDiag("Test empty vector");
|
||||
epics::pvData::shared_vector<int32> empty, empty2;
|
||||
epics::pvData::shared_vector<int32> empty, empty2, empty3(0u);
|
||||
|
||||
testOk1(empty.size()==0);
|
||||
testOk1(empty.empty());
|
||||
testOk1(empty.begin()==empty.end());
|
||||
testOk1(empty.unique());
|
||||
|
||||
testOk1(empty3.empty());
|
||||
testOk1(empty3.unique());
|
||||
|
||||
testOk1(empty.data()==NULL);
|
||||
|
||||
testOk1(empty==empty);
|
||||
@@ -38,7 +43,7 @@ static void testEmpty()
|
||||
testOk1(!(empty!=empty2));
|
||||
}
|
||||
|
||||
static void testInternalAlloc()
|
||||
void testInternalAlloc()
|
||||
{
|
||||
testDiag("Test vector alloc w/ new[]");
|
||||
|
||||
@@ -75,19 +80,17 @@ static void testInternalAlloc()
|
||||
testOk1(internal.data()==NULL);
|
||||
}
|
||||
|
||||
namespace {
|
||||
//Note: STL shared_ptr requires that deletors be copy constructable
|
||||
template<typename E>
|
||||
struct callCounter {
|
||||
std::tr1::shared_ptr<int32> count;
|
||||
callCounter():count(new int32){*count=0;}
|
||||
callCounter(const callCounter& o):count(o.count) {};
|
||||
callCounter& operator=(const callCounter& o){count=o.count;}
|
||||
void operator()(E){*count=1;}
|
||||
};
|
||||
}
|
||||
//Note: STL shared_ptr requires that deletors be copy constructable
|
||||
template<typename E>
|
||||
struct callCounter {
|
||||
std::tr1::shared_ptr<int32> count;
|
||||
callCounter():count(new int32){*count=0;}
|
||||
callCounter(const callCounter& o):count(o.count) {}
|
||||
callCounter& operator=(const callCounter& o){count=o.count;}
|
||||
void operator()(E){(*count)++;}
|
||||
};
|
||||
|
||||
static void testExternalAlloc()
|
||||
void testExternalAlloc()
|
||||
{
|
||||
testDiag("Test vector external alloc");
|
||||
|
||||
@@ -133,7 +136,7 @@ static void testExternalAlloc()
|
||||
testOk1(*tracker.count==1);
|
||||
}
|
||||
|
||||
static void testShare()
|
||||
void testShare()
|
||||
{
|
||||
testDiag("Test vector Sharing");
|
||||
|
||||
@@ -195,7 +198,7 @@ static void testShare()
|
||||
testOk1(two[19]==5000);
|
||||
}
|
||||
|
||||
static void testConst()
|
||||
void testConst()
|
||||
{
|
||||
testDiag("Test constant vector");
|
||||
|
||||
@@ -236,7 +239,7 @@ static void testConst()
|
||||
testOk1(rodata.data()!=rodata2.data());
|
||||
}
|
||||
|
||||
static void testSlice()
|
||||
void testSlice()
|
||||
{
|
||||
testDiag("Test vector slicing");
|
||||
|
||||
@@ -286,7 +289,7 @@ static void testSlice()
|
||||
testOk1(half2.data()==NULL);
|
||||
}
|
||||
|
||||
static void testCapacity()
|
||||
void testCapacity()
|
||||
{
|
||||
testDiag("Test vector capacity");
|
||||
|
||||
@@ -328,7 +331,7 @@ static void testCapacity()
|
||||
testOk1(vect[1]==124);
|
||||
}
|
||||
|
||||
static void testPush()
|
||||
void testPush()
|
||||
{
|
||||
epics::pvData::shared_vector<int32> vect;
|
||||
|
||||
@@ -353,7 +356,7 @@ static void testPush()
|
||||
testOk1(nallocs==26);
|
||||
}
|
||||
|
||||
static void testVoid()
|
||||
void testVoid()
|
||||
{
|
||||
testDiag("Test vector cast to/from void");
|
||||
|
||||
@@ -373,7 +376,7 @@ static void testVoid()
|
||||
VV.clear();
|
||||
}
|
||||
|
||||
static void testConstVoid()
|
||||
void testConstVoid()
|
||||
{
|
||||
testDiag("Test vector cast to/from const void");
|
||||
|
||||
@@ -401,7 +404,7 @@ static void testConstVoid()
|
||||
|
||||
struct dummyStruct {};
|
||||
|
||||
static void testNonPOD()
|
||||
void testNonPOD()
|
||||
{
|
||||
testDiag("Test vector of non-POD types");
|
||||
|
||||
@@ -429,7 +432,7 @@ static void testNonPOD()
|
||||
testOk1(structs2[1].get()==temp);
|
||||
}
|
||||
|
||||
static void testVectorConvert()
|
||||
void testVectorConvert()
|
||||
{
|
||||
testDiag("Test shared_vector_convert");
|
||||
|
||||
@@ -474,7 +477,7 @@ static void testVectorConvert()
|
||||
testOk1(strings.at(0)=="42");
|
||||
}
|
||||
|
||||
static void testWeak()
|
||||
void testWeak()
|
||||
{
|
||||
testDiag("Test weak_ptr counting");
|
||||
|
||||
@@ -499,7 +502,7 @@ static void testWeak()
|
||||
testOk1(!data.unique());
|
||||
}
|
||||
|
||||
static void testICE()
|
||||
void testICE()
|
||||
{
|
||||
testDiag("Test freeze and thaw");
|
||||
|
||||
@@ -563,7 +566,6 @@ static void testICE()
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void testBad()
|
||||
{
|
||||
epics::pvData::shared_vector<int> I;
|
||||
@@ -620,7 +622,6 @@ void testBad()
|
||||
//I = epics::pvData::that(CF);
|
||||
}
|
||||
|
||||
static
|
||||
void testAutoSwap()
|
||||
{
|
||||
epics::auto_ptr<int> A(new int(42)), B(new int(43));
|
||||
@@ -631,9 +632,71 @@ void testAutoSwap()
|
||||
testOk1(42==*B);
|
||||
}
|
||||
|
||||
void testCXX11Move()
|
||||
{
|
||||
#if __cplusplus>=201103L
|
||||
testDiag("Check std::move()");
|
||||
shared_vector<int32> A(4, 42),
|
||||
B(std::move(A));
|
||||
|
||||
testOk1(A.unique());
|
||||
testOk1(B.unique());
|
||||
testOk1(A.empty());
|
||||
testOk1(B.size()==4);
|
||||
testOk1(!B.empty() && B[0]==42);
|
||||
|
||||
A = std::move(B);
|
||||
|
||||
testOk1(A.unique());
|
||||
testOk1(B.unique());
|
||||
testOk1(B.empty());
|
||||
testOk1(A.size()==4);
|
||||
testOk1(!A.empty() && A[0]==42);
|
||||
|
||||
shared_vector<void> C(shared_vector_convert<void>(A)),
|
||||
D(std::move(C));
|
||||
A.clear();
|
||||
|
||||
testOk1(C.unique());
|
||||
testOk1(D.unique());
|
||||
testOk1(C.empty());
|
||||
testOk1(D.size()==4*4);
|
||||
|
||||
C = std::move(D);
|
||||
|
||||
testOk1(C.unique());
|
||||
testOk1(D.unique());
|
||||
testOk1(C.size()==4*4);
|
||||
testOk1(D.empty());
|
||||
#else
|
||||
testSkip(18, "Not -std=c++11");
|
||||
#endif
|
||||
}
|
||||
|
||||
void testCXX11Init()
|
||||
{
|
||||
#if __cplusplus>=201103L
|
||||
testDiag("Check c++11 style array initialization");
|
||||
|
||||
shared_vector<const int32> A = {1.0, 2.0, 3.0};
|
||||
|
||||
testOk1(A.size()==3);
|
||||
|
||||
int32 sum = 0;
|
||||
for (auto V: A) {
|
||||
sum += V;
|
||||
}
|
||||
testOk1(sum==6);
|
||||
#else
|
||||
testSkip(2, "Not -std=c++11");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MAIN(testSharedVector)
|
||||
{
|
||||
testPlan(169);
|
||||
testPlan(191);
|
||||
testDiag("Tests for shared_vector");
|
||||
|
||||
testDiag("sizeof(shared_vector<int32>)=%lu",
|
||||
@@ -655,5 +718,7 @@ MAIN(testSharedVector)
|
||||
testICE();
|
||||
testBad();
|
||||
testAutoSwap();
|
||||
testCXX11Move();
|
||||
testCXX11Init();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
#include <pv/event.h>
|
||||
#include <pv/thread.h>
|
||||
#include <pv/executor.h>
|
||||
#include <pv/timeFunction.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using std::string;
|
||||
@@ -65,49 +63,6 @@ static void testThreadRun() {
|
||||
testDiag("testThreadRun PASSED");
|
||||
}
|
||||
|
||||
class Basic;
|
||||
typedef std::tr1::shared_ptr<Basic> BasicPtr;
|
||||
|
||||
class Basic :
|
||||
public Command,
|
||||
public std::tr1::enable_shared_from_this<Basic>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(Basic);
|
||||
Basic(ExecutorPtr const &executor)
|
||||
: executor(executor) {}
|
||||
~Basic()
|
||||
{
|
||||
}
|
||||
void run()
|
||||
{
|
||||
executor->execute(getPtrSelf());
|
||||
bool result = wait.wait();
|
||||
testOk1(result==true);
|
||||
if(result==false) testDiag("basic::run wait returned false");
|
||||
}
|
||||
virtual void command()
|
||||
{
|
||||
wait.signal();
|
||||
}
|
||||
private:
|
||||
Basic::shared_pointer getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
ExecutorPtr executor;
|
||||
Event wait;
|
||||
};
|
||||
|
||||
typedef std::tr1::shared_ptr<Basic> BasicPtr;
|
||||
|
||||
static void testBasic() {
|
||||
ExecutorPtr executor(new Executor(string("basic"),middlePriority));
|
||||
BasicPtr basic( new Basic(executor));
|
||||
basic->run();
|
||||
testDiag("testBasic PASSED");
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct fninfo {
|
||||
int cnt;
|
||||
@@ -197,49 +152,11 @@ static void testBinders()
|
||||
#endif
|
||||
}
|
||||
|
||||
class MyFunc : public TimeFunctionRequester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(MyFunc);
|
||||
MyFunc(BasicPtr const &basic);
|
||||
virtual void function();
|
||||
private:
|
||||
BasicPtr basic;
|
||||
};
|
||||
|
||||
MyFunc::MyFunc(BasicPtr const &basic)
|
||||
: basic(basic)
|
||||
{}
|
||||
void MyFunc::function()
|
||||
{
|
||||
basic->run();
|
||||
}
|
||||
|
||||
|
||||
typedef std::tr1::shared_ptr<MyFunc> MyFuncPtr;
|
||||
|
||||
#ifdef TESTTHREADCONTEXT
|
||||
|
||||
static void testThreadContext() {
|
||||
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;
|
||||
testDiag("time per call %f microseconds",perCall);
|
||||
testDiag("testThreadContext PASSED");
|
||||
}
|
||||
#endif
|
||||
|
||||
MAIN(testThread)
|
||||
{
|
||||
testPlan(7);
|
||||
testPlan(6);
|
||||
testDiag("Tests thread");
|
||||
testThreadRun();
|
||||
testBasic();
|
||||
testBinders();
|
||||
#ifdef TESTTHREADCONTEXT
|
||||
testThreadContext();
|
||||
#endif
|
||||
return testDone();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ void testTimeStampInternal()
|
||||
testOk1(nanoSecPerSec==1000000000);
|
||||
TimeStamp current;
|
||||
current.getCurrent();
|
||||
testDiag("current %lli %i milliSec %lli\n",
|
||||
testDiag("current %lld %d milliSec %lld\n",
|
||||
(long long)current.getSecondsPastEpoch(),
|
||||
(int)current.getNanoseconds(),
|
||||
(long long)current.getMilliseconds());
|
||||
@@ -46,7 +46,7 @@ void testTimeStampInternal()
|
||||
(ctm.tm_isdst==0) ? "false" : "true");
|
||||
tt = time(&tt);
|
||||
current.fromTime_t(tt);
|
||||
testDiag("fromTime_t\ncurrent %lli %i milliSec %lli\n",
|
||||
testDiag("fromTime_t\ncurrent %lld %d milliSec %lld\n",
|
||||
(long long)current.getSecondsPastEpoch(),
|
||||
(int)current.getNanoseconds(),
|
||||
(long long)current.getMilliseconds());
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
#include <epicsUnitTest.h>
|
||||
#include <testMain.h>
|
||||
#include <epicsGuard.h>
|
||||
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/event.h>
|
||||
@@ -27,175 +29,214 @@
|
||||
using namespace epics::pvData;
|
||||
using std::string;
|
||||
|
||||
static TimeStamp currentTimeStamp;
|
||||
static double oneDelay = 4.0;
|
||||
static double twoDelay = 2.0;
|
||||
static double threeDelay = 1.0;
|
||||
static int ntimes = 3;
|
||||
static const double delays[3] = {1.0, 2.0, 4.0};
|
||||
static const unsigned ntimes = 3;
|
||||
|
||||
class MyCallback;
|
||||
typedef std::tr1::shared_ptr<MyCallback> MyCallbackPtr;
|
||||
namespace {
|
||||
|
||||
class MyCallback : public TimerCallback {
|
||||
public:
|
||||
POINTER_DEFINITIONS(MyCallback);
|
||||
MyCallback(string name,EventPtr const & wait)
|
||||
: name(name),
|
||||
wait(wait)
|
||||
{
|
||||
}
|
||||
~MyCallback()
|
||||
{
|
||||
}
|
||||
struct Marker : public TimerCallback
|
||||
{
|
||||
POINTER_DEFINITIONS(Marker);
|
||||
|
||||
Event wait, hold;
|
||||
virtual ~Marker() {}
|
||||
virtual void callback()
|
||||
{
|
||||
timeStamp.getCurrent();
|
||||
wait->signal();
|
||||
wait.signal();
|
||||
hold.wait();
|
||||
}
|
||||
virtual void timerStopped() {}
|
||||
};
|
||||
|
||||
struct MyCallback : public TimerCallback {
|
||||
POINTER_DEFINITIONS(MyCallback);
|
||||
|
||||
MyCallback(const string& name)
|
||||
:name(name)
|
||||
,counter(0)
|
||||
,first_gbl(0)
|
||||
{}
|
||||
virtual ~MyCallback() {}
|
||||
virtual void callback()
|
||||
{
|
||||
testDiag("expire %s",name.c_str());
|
||||
{
|
||||
epicsGuard<Mutex> G(gbl_mutex);
|
||||
counter++;
|
||||
if(first_gbl==0) {
|
||||
first_gbl = ++gbl_counter;
|
||||
}
|
||||
}
|
||||
wait.signal();
|
||||
}
|
||||
virtual void timerStopped()
|
||||
{
|
||||
printf("timerStopped %s\n",name.c_str());
|
||||
testDiag("timerStopped %s",name.c_str());
|
||||
}
|
||||
TimeStamp &getTimeStamp() { return timeStamp;}
|
||||
private:
|
||||
string name;
|
||||
EventPtr wait;
|
||||
TimeStamp timeStamp;
|
||||
void clear() {
|
||||
epicsGuard<Mutex> G(gbl_mutex);
|
||||
counter = gbl_counter = 0;
|
||||
}
|
||||
|
||||
const string name;
|
||||
unsigned counter, first_gbl;
|
||||
Event wait;
|
||||
|
||||
static unsigned gbl_counter;
|
||||
static Mutex gbl_mutex;
|
||||
};
|
||||
|
||||
static void testBasic()
|
||||
unsigned MyCallback::gbl_counter;
|
||||
Mutex MyCallback::gbl_mutex;
|
||||
|
||||
typedef std::tr1::shared_ptr<MyCallback> MyCallbackPtr;
|
||||
|
||||
}// namespace
|
||||
|
||||
static void testBasic(unsigned oneOrd, unsigned twoOrd, unsigned threeOrd)
|
||||
{
|
||||
testDiag("\n\ntestBasic oneDelay %lf twoDelay %lf threeDaley %lf\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testDiag("testBasic oneOrd %u twoOrd %u threeOrd %u",
|
||||
oneOrd,twoOrd,threeOrd);
|
||||
|
||||
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,eventOne));
|
||||
MyCallbackPtr callbackTwo(new MyCallback(two,eventTwo));
|
||||
MyCallbackPtr callbackThree(new MyCallback(three,eventThree));
|
||||
for(int n=0; n<ntimes; n++) {
|
||||
currentTimeStamp.getCurrent();
|
||||
testOk1(!timer->isScheduled(callbackOne));
|
||||
testOk1(!timer->isScheduled(callbackTwo));
|
||||
testOk1(!timer->isScheduled(callbackThree));
|
||||
timer->scheduleAfterDelay(callbackOne,oneDelay);
|
||||
timer->scheduleAfterDelay(callbackTwo,twoDelay);
|
||||
timer->scheduleAfterDelay(callbackThree,threeDelay);
|
||||
if(oneDelay>.1) testOk1(timer->isScheduled(callbackOne));
|
||||
if(twoDelay>.1) testOk1(timer->isScheduled(callbackTwo));
|
||||
if(threeDelay>.1) testOk1(timer->isScheduled(callbackThree));
|
||||
Timer timer("timer" ,middlePriority);
|
||||
|
||||
eventOne->wait();
|
||||
eventTwo->wait();
|
||||
eventThree->wait();
|
||||
double diff;
|
||||
double delta;
|
||||
diff = TimeStamp::diff(
|
||||
callbackOne->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - oneDelay;
|
||||
Marker::shared_pointer marker(new Marker);
|
||||
MyCallbackPtr callbackOne(new MyCallback("one"));
|
||||
MyCallbackPtr callbackTwo(new MyCallback("two"));
|
||||
MyCallbackPtr callbackThree(new MyCallback("three"));
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
diff = TimeStamp::diff(
|
||||
callbackTwo->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - twoDelay;
|
||||
for(unsigned n=0; n<ntimes; n++) {
|
||||
testDiag("iteration %u", n);
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
diff = TimeStamp::diff(
|
||||
callbackThree->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - threeDelay;
|
||||
testOk1(!timer.isScheduled(marker));
|
||||
timer.scheduleAfterDelay(marker, 0.01);
|
||||
marker->wait.wait();
|
||||
// timer worker is blocked
|
||||
|
||||
testOk1(!timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(!timer.isScheduled(callbackThree));
|
||||
|
||||
callbackOne->clear();
|
||||
callbackTwo->clear();
|
||||
callbackThree->clear();
|
||||
|
||||
timer.scheduleAfterDelay(callbackOne,delays[oneOrd]);
|
||||
timer.scheduleAfterDelay(callbackTwo,delays[twoOrd]);
|
||||
timer.scheduleAfterDelay(callbackThree,delays[threeOrd]);
|
||||
|
||||
testOk1(timer.isScheduled(callbackOne));
|
||||
testOk1(timer.isScheduled(callbackTwo));
|
||||
testOk1(timer.isScheduled(callbackThree));
|
||||
|
||||
marker->hold.signal(); // let the worker loose
|
||||
|
||||
callbackOne->wait.wait();
|
||||
callbackTwo->wait.wait();
|
||||
callbackThree->wait.wait();
|
||||
|
||||
testOk1(!timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(!timer.isScheduled(callbackThree));
|
||||
|
||||
{
|
||||
epicsGuard<Mutex> G(MyCallback::gbl_mutex);
|
||||
testOk(callbackOne->counter==1, "%s counter %u = 1", callbackOne->name.c_str(), callbackOne->counter);
|
||||
testOk(callbackTwo->counter==1, "%s counter %u = 1", callbackTwo->name.c_str(), callbackTwo->counter);
|
||||
testOk(callbackThree->counter==1, "%s counter %u = 1", callbackThree->name.c_str(), callbackThree->counter);
|
||||
|
||||
testOk(callbackOne->first_gbl==oneOrd+1, "%s first_gbl %u = %u", callbackOne->name.c_str(), callbackOne->first_gbl, oneOrd+1);
|
||||
testOk(callbackTwo->first_gbl==twoOrd+1, "%s first_gbl %u = %u", callbackTwo->name.c_str(), callbackTwo->first_gbl, twoOrd+1);
|
||||
testOk(callbackThree->first_gbl==threeOrd+1, "%s first_gbl %u = %u", callbackThree->name.c_str(), callbackThree->first_gbl, threeOrd+1);
|
||||
}
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
}
|
||||
printf("testBasic PASSED\n");
|
||||
}
|
||||
|
||||
static void testCancel()
|
||||
static void testCancel(unsigned oneOrd, unsigned twoOrd, unsigned threeOrd,
|
||||
unsigned oneReal, unsigned threeReal)
|
||||
{
|
||||
testDiag("\n\ntestCancel oneDelay %lf twoDelay %lf threeDaley %lf\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testDiag("testCancel oneOrd %u twoOrd %u threeOrd %u",
|
||||
oneOrd,twoOrd,threeOrd);
|
||||
|
||||
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,eventOne));
|
||||
MyCallbackPtr callbackTwo(new MyCallback(two,eventTwo));
|
||||
MyCallbackPtr callbackThree(new MyCallback(three,eventThree));
|
||||
for(int n=0; n<ntimes; n++) {
|
||||
currentTimeStamp.getCurrent();
|
||||
testOk1(!timer->isScheduled(callbackOne));
|
||||
testOk1(!timer->isScheduled(callbackTwo));
|
||||
testOk1(!timer->isScheduled(callbackThree));
|
||||
timer->scheduleAfterDelay(callbackOne,oneDelay);
|
||||
timer->scheduleAfterDelay(callbackTwo,twoDelay);
|
||||
timer->scheduleAfterDelay(callbackThree,threeDelay);
|
||||
timer->cancel(callbackTwo);
|
||||
if(oneDelay>.1) testOk1(timer->isScheduled(callbackOne));
|
||||
testOk1(!timer->isScheduled(callbackTwo));
|
||||
if(threeDelay>.1) testOk1(timer->isScheduled(callbackThree));
|
||||
Timer timer("timer" ,middlePriority);
|
||||
|
||||
eventOne->wait();
|
||||
eventThree->wait();
|
||||
double diff;
|
||||
double delta;
|
||||
diff = TimeStamp::diff(
|
||||
callbackOne->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - oneDelay;
|
||||
Marker::shared_pointer marker(new Marker);
|
||||
MyCallbackPtr callbackOne(new MyCallback("one"));
|
||||
MyCallbackPtr callbackTwo(new MyCallback("two"));
|
||||
MyCallbackPtr callbackThree(new MyCallback("three"));
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
diff = TimeStamp::diff(
|
||||
callbackThree->getTimeStamp(),currentTimeStamp);
|
||||
delta = diff - threeDelay;
|
||||
for(unsigned n=0; n<ntimes; n++) {
|
||||
testDiag("iteration %u", n);
|
||||
|
||||
testOk1(!timer.isScheduled(marker));
|
||||
timer.scheduleAfterDelay(marker, 0.01);
|
||||
marker->wait.wait();
|
||||
// timer worker is blocked
|
||||
|
||||
testOk1(!timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(!timer.isScheduled(callbackThree));
|
||||
|
||||
callbackOne->clear();
|
||||
callbackTwo->clear();
|
||||
callbackThree->clear();
|
||||
|
||||
timer.scheduleAfterDelay(callbackOne,delays[oneOrd]);
|
||||
timer.scheduleAfterDelay(callbackTwo,delays[twoOrd]);
|
||||
timer.scheduleAfterDelay(callbackThree,delays[threeOrd]);
|
||||
|
||||
testOk1(timer.isScheduled(callbackOne));
|
||||
testOk1(timer.isScheduled(callbackTwo));
|
||||
testOk1(timer.isScheduled(callbackThree));
|
||||
|
||||
timer.cancel(callbackTwo);
|
||||
|
||||
testOk1(timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(timer.isScheduled(callbackThree));
|
||||
|
||||
marker->hold.signal(); // let the worker loose
|
||||
|
||||
callbackOne->wait.wait();
|
||||
callbackThree->wait.wait();
|
||||
|
||||
testOk1(!timer.isScheduled(callbackOne));
|
||||
testOk1(!timer.isScheduled(callbackTwo));
|
||||
testOk1(!timer.isScheduled(callbackThree));
|
||||
|
||||
{
|
||||
epicsGuard<Mutex> G(MyCallback::gbl_mutex);
|
||||
testOk(callbackOne->counter==1, "%s counter %u = 1", callbackOne->name.c_str(), callbackOne->counter);
|
||||
testOk(callbackTwo->counter==0, "%s counter %u = 0", callbackTwo->name.c_str(), callbackTwo->counter);
|
||||
testOk(callbackThree->counter==1, "%s counter %u = 1", callbackThree->name.c_str(), callbackThree->counter);
|
||||
|
||||
testOk(callbackOne->first_gbl==oneReal+1, "%s first_gbl %u = %u", callbackOne->name.c_str(), callbackOne->first_gbl, oneOrd+1);
|
||||
testOk(callbackTwo->first_gbl==0, "%s first_gbl %u = %u", callbackTwo->name.c_str(), callbackTwo->first_gbl, 0);
|
||||
testOk(callbackThree->first_gbl==threeReal+1, "%s first_gbl %u = %u", callbackThree->name.c_str(), callbackThree->first_gbl, threeOrd+1);
|
||||
}
|
||||
|
||||
if(delta<0.0) delta = -delta;
|
||||
testOk1(delta<.1);
|
||||
}
|
||||
printf("testCancel PASSED\n");
|
||||
}
|
||||
|
||||
MAIN(testTimer)
|
||||
{
|
||||
testPlan(171);
|
||||
testDiag("Tests timer");
|
||||
oneDelay = .4;
|
||||
twoDelay = .2;
|
||||
threeDelay = .1;
|
||||
printf("oneDelay %f twoDelay %f threeDelay %f\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testBasic();
|
||||
testCancel();
|
||||
oneDelay = .1;
|
||||
twoDelay = .2;
|
||||
threeDelay = .4;
|
||||
printf("oneDelay %f twoDelay %f threeDelay %f\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testBasic();
|
||||
testCancel();
|
||||
oneDelay = .1;
|
||||
twoDelay = .4;
|
||||
threeDelay = .2;
|
||||
printf("oneDelay %f twoDelay %f threeDelay %f\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testBasic();
|
||||
testCancel();
|
||||
oneDelay = .0;
|
||||
twoDelay = .0;
|
||||
threeDelay = .0;
|
||||
printf("oneDelay %f twoDelay %f threeDelay %f\n",
|
||||
oneDelay,twoDelay,threeDelay);
|
||||
testBasic();
|
||||
testCancel();
|
||||
testPlan(315);
|
||||
try {
|
||||
testDiag("Tests timer");
|
||||
|
||||
testBasic(2, 1, 0);
|
||||
testCancel(2, 1, 0, 1, 0);
|
||||
|
||||
testBasic(0, 1, 2);
|
||||
testCancel(0, 1, 2, 0, 1);
|
||||
|
||||
testBasic(0, 2, 1);
|
||||
testCancel(0, 2, 1, 0, 1);
|
||||
|
||||
}catch(std::exception& e) {
|
||||
testFail("Unhandled exception: %s", e.what());
|
||||
}
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace {
|
||||
|
||||
MAIN(testTypeCast)
|
||||
{
|
||||
testPlan(123);
|
||||
testPlan(124);
|
||||
|
||||
try {
|
||||
|
||||
@@ -138,10 +138,12 @@ try {
|
||||
float xfloat=0.0;
|
||||
double xdouble=0.0;
|
||||
string xstring("0");
|
||||
const char* xcstring = "0";
|
||||
|
||||
typedef float float_t;
|
||||
typedef double double_t;
|
||||
typedef string string_t;
|
||||
typedef const char* cstring_t;
|
||||
|
||||
// force all possibilities to be compiled
|
||||
#define CHECK(M, N) x## M = ::epics::pvData::castUnsafe<M ##_t>(x## N); \
|
||||
@@ -158,6 +160,7 @@ try {
|
||||
CHECK(int8, float);
|
||||
CHECK(int8, double);
|
||||
CHECK(int8, string);
|
||||
CHECK(int8, cstring);
|
||||
|
||||
CHECK(uint8, int8);
|
||||
CHECK(uint8, uint8);
|
||||
@@ -170,6 +173,7 @@ try {
|
||||
CHECK(uint8, float);
|
||||
CHECK(uint8, double);
|
||||
CHECK(uint8, string);
|
||||
CHECK(uint8, cstring);
|
||||
|
||||
CHECK(int16, int8);
|
||||
CHECK(int16, uint8);
|
||||
@@ -182,6 +186,7 @@ try {
|
||||
CHECK(int16, float);
|
||||
CHECK(int16, double);
|
||||
CHECK(int16, string);
|
||||
CHECK(int16, cstring);
|
||||
|
||||
CHECK(uint16, int8);
|
||||
CHECK(uint16, uint8);
|
||||
@@ -194,6 +199,7 @@ try {
|
||||
CHECK(uint16, float);
|
||||
CHECK(uint16, double);
|
||||
CHECK(uint16, string);
|
||||
CHECK(uint16, cstring);
|
||||
|
||||
CHECK(int32, int8);
|
||||
CHECK(int32, uint8);
|
||||
@@ -206,6 +212,7 @@ try {
|
||||
CHECK(int32, float);
|
||||
CHECK(int32, double);
|
||||
CHECK(int32, string);
|
||||
CHECK(int32, cstring);
|
||||
|
||||
CHECK(uint32, int8);
|
||||
CHECK(uint32, uint8);
|
||||
@@ -218,6 +225,7 @@ try {
|
||||
CHECK(uint32, float);
|
||||
CHECK(uint32, double);
|
||||
CHECK(uint32, string);
|
||||
CHECK(uint32, cstring);
|
||||
|
||||
CHECK(int64, int8);
|
||||
CHECK(int64, uint8);
|
||||
@@ -229,7 +237,8 @@ try {
|
||||
CHECK(int64, uint64);
|
||||
CHECK(int64, float);
|
||||
CHECK(int64, double);
|
||||
//CHECK(int64, string);
|
||||
CHECK(int64, string);
|
||||
CHECK(int64, cstring);
|
||||
|
||||
CHECK(uint64, int8);
|
||||
CHECK(uint64, uint8);
|
||||
@@ -241,7 +250,8 @@ try {
|
||||
CHECK(uint64, uint64);
|
||||
CHECK(uint64, float);
|
||||
CHECK(uint64, double);
|
||||
//CHECK(uint64, string);
|
||||
CHECK(uint64, string);
|
||||
CHECK(uint64, cstring);
|
||||
|
||||
CHECK(float, int8);
|
||||
CHECK(float, uint8);
|
||||
@@ -254,6 +264,7 @@ try {
|
||||
CHECK(float, float);
|
||||
CHECK(float, double);
|
||||
CHECK(float, string);
|
||||
CHECK(float, cstring);
|
||||
|
||||
CHECK(double, int8);
|
||||
CHECK(double, uint8);
|
||||
@@ -266,6 +277,7 @@ try {
|
||||
CHECK(double, float);
|
||||
CHECK(double, double);
|
||||
CHECK(double, string);
|
||||
CHECK(double, cstring);
|
||||
|
||||
CHECK(string, int8);
|
||||
CHECK(string, uint8);
|
||||
@@ -278,6 +290,9 @@ try {
|
||||
CHECK(string, float);
|
||||
CHECK(string, double);
|
||||
CHECK(string, string);
|
||||
CHECK(string, cstring);
|
||||
|
||||
// cast to const char* not supported
|
||||
#undef CHECK
|
||||
|
||||
testDiag("Integer signed <=> unsigned");
|
||||
@@ -344,6 +359,7 @@ try {
|
||||
TEST2(string, "1.1e-100", double, 1.1e-100);
|
||||
|
||||
TEST(double, 1.1e100, string, "1.1E+100");
|
||||
TEST(double, 1.1e100, const char*, "1.1E+100");
|
||||
|
||||
// any non-zero value is true
|
||||
TEST(string, "true", epics::pvData::boolean, 100);
|
||||
|
||||
@@ -23,7 +23,7 @@ struct MyTest {
|
||||
|
||||
MAIN(testUnitTest)
|
||||
{
|
||||
testPlan(0);
|
||||
testPlan(10);
|
||||
try {
|
||||
TEST_METHOD(MyTest, test1);
|
||||
TEST_METHOD(MyTest, test2);
|
||||
|
||||
@@ -42,6 +42,23 @@ void test_ctor()
|
||||
testEqual(D.ref<std::string>(), "bar");
|
||||
}
|
||||
|
||||
void test_ctor_void()
|
||||
{
|
||||
testDiag("test_ctor_void()");
|
||||
|
||||
pvd::int32 i = 42;
|
||||
pvd::AnyScalar A(pvd::pvInt, (void*)&i);
|
||||
|
||||
testEqual(A.type(), pvd::pvInt);
|
||||
testEqual(A.ref<pvd::int32>(), 42);
|
||||
|
||||
std::string s("hello");
|
||||
pvd::AnyScalar B(pvd::pvString, (void*)&s);
|
||||
|
||||
testEqual(B.type(), pvd::pvString);
|
||||
testEqual(B.ref<std::string>(), "hello");
|
||||
}
|
||||
|
||||
void test_basic()
|
||||
{
|
||||
testDiag("test_basic()");
|
||||
@@ -56,6 +73,14 @@ void test_basic()
|
||||
testEqual(I.as<double>(), 42.0);
|
||||
testEqual(I.as<std::string>(), "42");
|
||||
|
||||
const pvd::AnyScalar I2(I);
|
||||
|
||||
testEqual(I2.type(), pvd::pvInt);
|
||||
testEqual(I2.ref<pvd::int32>(), 42);
|
||||
testEqual(I2.as<pvd::int32>(), 42);
|
||||
testEqual(I2.as<double>(), 42.0);
|
||||
testEqual(I2.as<std::string>(), "42");
|
||||
|
||||
testThrows(pvd::AnyScalar::bad_cast, I.ref<double>());
|
||||
|
||||
{
|
||||
@@ -213,10 +238,11 @@ void test_move()
|
||||
|
||||
MAIN(testanyscalar)
|
||||
{
|
||||
testPlan(66);
|
||||
testPlan(75);
|
||||
try {
|
||||
test_empty();
|
||||
test_ctor();
|
||||
test_ctor_void();
|
||||
test_basic();
|
||||
test_swap();
|
||||
test_move();
|
||||
|
||||
@@ -56,10 +56,10 @@ MAIN(testPVType)
|
||||
int64 longInt = 0x7fffffff;
|
||||
longInt <<= 32;
|
||||
longInt |= 0xffffffff;
|
||||
printf("int8 max %lli",(long long)longInt);
|
||||
printf("int8 max %lld",(long long)longInt);
|
||||
longInt = intValue = 0x80000000;;
|
||||
longInt <<= 32;
|
||||
printf(" min %lli\n",(long long)longInt);
|
||||
printf(" min %lld\n",(long long)longInt);
|
||||
|
||||
printf("PASSED\n");
|
||||
return testDone();
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <stdio.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsUnitTest.h>
|
||||
#include <epicsExit.h>
|
||||
|
||||
/* copy */
|
||||
int testCreateRequest(void);
|
||||
@@ -22,7 +23,6 @@ int testBaseException(void);
|
||||
int testBitSet(void);
|
||||
int testByteBuffer(void);
|
||||
int testOverrunBitSet(void);
|
||||
int testQueue(void);
|
||||
int testSerialization(void);
|
||||
int testSharedVector(void);
|
||||
int testThread(void);
|
||||
@@ -71,7 +71,6 @@ void pvDataAllTests(void)
|
||||
runTest(testBitSet);
|
||||
runTest(testByteBuffer);
|
||||
runTest(testOverrunBitSet);
|
||||
runTest(testQueue);
|
||||
runTest(testSerialization);
|
||||
runTest(testSharedVector);
|
||||
runTest(testThread);
|
||||
@@ -86,5 +85,6 @@ void pvDataAllTests(void)
|
||||
|
||||
/* property */
|
||||
runTest(testCreateRequest);
|
||||
}
|
||||
|
||||
epicsExit(0); /* Trigger test harness */
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Saskatchewan
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* RTEMS configuration for EPICS
|
||||
* Revision-Id: anj@aps.anl.gov-20101005192737-disfz3vs0f3fiixd
|
||||
* Author: W. Eric Norum
|
||||
* norume@aps.anl.gov
|
||||
* (630) 252-4793
|
||||
*/
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
/*
|
||||
***********************************************************************
|
||||
* RTEMS CONFIGURATION *
|
||||
***********************************************************************
|
||||
*/
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#if __RTEMS_MAJOR__>4 || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
|
||||
# define CONFIGURE_UNIFIED_WORK_AREAS
|
||||
#else
|
||||
# define CONFIGURE_EXECUTIVE_RAM_SIZE (2000*1024)
|
||||
#endif
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(30)
|
||||
#define CONFIGURE_MAXIMUM_SEMAPHORES rtems_resource_unlimited(500)
|
||||
#define CONFIGURE_MAXIMUM_TIMERS rtems_resource_unlimited(20)
|
||||
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES rtems_resource_unlimited(5)
|
||||
#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
|
||||
|
||||
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 150
|
||||
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
|
||||
#define CONFIGURE_MAXIMUM_DRIVERS 8
|
||||
|
||||
#define CONFIGURE_MICROSECONDS_PER_TICK 20000
|
||||
|
||||
#define CONFIGURE_INIT_TASK_PRIORITY 80
|
||||
|
||||
#define CONFIGURE_MALLOC_STATISTICS 1
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
#define CONFIGURE_INIT_TASK_INITIAL_MODES (RTEMS_PREEMPT | \
|
||||
RTEMS_NO_TIMESLICE | \
|
||||
RTEMS_NO_ASR | \
|
||||
RTEMS_INTERRUPT_LEVEL(0))
|
||||
#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_FLOATING_POINT | RTEMS_LOCAL)
|
||||
#define CONFIGURE_INIT_TASK_STACK_SIZE (16*1024)
|
||||
rtems_task Init (rtems_task_argument argument);
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
|
||||
#define CONFIGURE_FILESYSTEM_NFS
|
||||
#define CONFIGURE_FILESYSTEM_IMFS
|
||||
|
||||
/*
|
||||
* This should be made BSP dependent, not CPU dependent but I know of no
|
||||
* appropriate conditionals to use.
|
||||
* The new general time support makes including the RTC driver less important.
|
||||
*/
|
||||
#if !defined(mpc604) && !defined(__mc68040__) && !defined(__mcf5200__) && !defined(mpc7455) && !defined(__arm__) /* don't have RTC code */
|
||||
#define CONFIGURE_APPLICATION_NEEDS_RTC_DRIVER
|
||||
#endif
|
||||
|
||||
|
||||
#include <bsp.h>
|
||||
#include <rtems/confdefs.h>
|
||||
@@ -2,40 +2,11 @@
|
||||
* Copyright information and license terms for this software can be
|
||||
* found in the file LICENSE that is included with the distribution
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
#include <rtems/error.h>
|
||||
|
||||
#include "rtemsNetworking.h"
|
||||
extern void pvDataAllTests(void);
|
||||
|
||||
#include <epicsExit.h>
|
||||
#include <osdTime.h>
|
||||
|
||||
rtems_task
|
||||
Init (rtems_task_argument ignored)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
rtems_bsdnet_initialize_network ();
|
||||
//rtems_bsdnet_show_if_stats ();
|
||||
|
||||
rtems_time_of_day timeOfDay;
|
||||
if (rtems_clock_get(RTEMS_CLOCK_GET_TOD,&timeOfDay) != RTEMS_SUCCESSFUL) {
|
||||
timeOfDay.year = 2014;
|
||||
timeOfDay.month = 1;
|
||||
timeOfDay.day = 1;
|
||||
timeOfDay.hour = 0;
|
||||
timeOfDay.minute = 0;
|
||||
timeOfDay.second = 0;
|
||||
timeOfDay.ticks = 0;
|
||||
|
||||
rtems_status_code ret = rtems_clock_set(&timeOfDay);
|
||||
if (ret != RTEMS_SUCCESSFUL) {
|
||||
printf("**** Can't set time %s\n", rtems_status_text(ret));
|
||||
}
|
||||
}
|
||||
osdTimeRegister();
|
||||
|
||||
extern void pvDataAllTests(void);
|
||||
pvDataAllTests();
|
||||
epicsExit(0);
|
||||
pvDataAllTests(); /* calls epicsExit(0) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user