44 Commits

Author SHA1 Message Date
Michael Davidsaver
499c03265f update release notes 2018-04-24 13:30:15 -07:00
Michael Davidsaver
7eaa613d4d try to fix dllimport error 2018-04-17 21:13:22 -07:00
Michael Davidsaver
19db72031c shared_vector add missing void swap
swap() of void and const void misses vtype
2018-04-13 12:40:22 -07:00
Michael Davidsaver
671f9cca4b anyscalar.h: move out of line
No reason to believe that inline was helping.
2018-04-08 15:53:21 -07:00
Michael Davidsaver
9ecdb80534 anyscalar.h: remove unnecesary vcast
what was I thinking...
2018-04-08 15:53:21 -07:00
Michael Davidsaver
e973422ee1 anyscalar.h: add ctor from type code and void*
also helper bufferUnsafe() to get storage pointer
or c_str().
2018-04-08 15:53:21 -07:00
Michael Davidsaver
8093c25b72 typeCast.h: allow cast from C string to numeric w/o copy
also re-enable compile test of string to int64 which
was disabled for some reason...
2018-04-08 15:53:21 -07:00
Michael Davidsaver
a7c9c620dd Timer avoid deadlock in timerStopped()
No code actually uses this hook, but lets make
sure nothing bad would happen.
2018-04-08 15:53:21 -07:00
Michael Davidsaver
1e1d94ed73 rework Timer
I'm not sure how I broke it, but I know I don't have the patience
to fix it.  So replacing intrusive list and custom sorting with
std::list and std::list::merge().
2018-04-04 21:03:11 -07:00
Michael Davidsaver
7b8ef390ce add Timer::close()
An aid to orderly shutdown
2018-04-02 15:54:48 -07:00
Michael Davidsaver
87ade13234 Timer cleanup and hide run() 2018-04-02 15:54:48 -07:00
Michael Davidsaver
32abde7f19 redo Timer to avoid data race
run() was accessing this->head w/o locking
2018-04-02 10:54:49 -07:00
Michael Davidsaver
fe413af177 timerTest: redo to avoid time related false positives 2018-04-02 09:34:15 -07:00
Michael Davidsaver
b4cd026fe5 byteBuffer cleanup 2018-03-23 10:05:31 -07:00
Michael Davidsaver
a51b308cc8 ByteBuffer avoid PPC alignment fault 2018-03-19 15:26:40 -07:00
Michael Davidsaver
1c09b42951 ByteBuffer change order of tests for optimized byte swap
Check __clang__ before __GNUC__ as clang
also identifies itself as gcc for compatibility.
2018-03-19 15:26:35 -07:00
Michael Davidsaver
e42bb46563 ByteBuffer collapse some trivial indirection 2018-03-19 15:26:35 -07:00
Michael Davidsaver
a7788f9847 remove rtemsConfig.c
no longer needed.
2018-03-19 09:11:37 -07:00
Michael Davidsaver
b597364419 simpler test harness main() 2018-03-13 18:44:54 -07:00
Andrew Johnson
a9a951d970 Move epicsExit() call into pvDataAllTests()
Needed on VxWorks to display the test summary.
2018-03-13 12:24:59 -05:00
Andrew Johnson
6ac879ec6a Rename vxTestHarness -> pvdTestHarness
Integrate with Michael's similar changes for RTEMS.
2018-03-13 12:24:00 -05:00
Michael Davidsaver
2422ef50b6 rename rtemsTestHarness -> pvdTestHarness
avoid name clash with rtemsTestHarness
from pvAccessCPP
2018-03-12 09:11:44 -07:00
Michael Davidsaver
06dbf96b65 missing test count 2018-03-12 09:11:44 -07:00
Michael Davidsaver
172046e78f Add AnyScalar::clear() 2018-02-21 11:17:49 -08:00
Michael Davidsaver
7e8c49f0a0 don't use shared_ptr::get() for null test
unnecesarily verbose
2018-02-21 11:17:49 -08:00
Michael Davidsaver
f2ad6292f5 cleanup 2018-02-06 13:12:06 -08:00
Michael Davidsaver
337e13b72e pvIntrospect.h mark OVERRIDE/FINAL 2018-02-06 10:12:38 -08:00
Michael Davidsaver
2ab2fc62dc move FINAL/OVERRIDE defs to pvIntrospect.h 2018-02-06 10:12:38 -08:00
Michael Davidsaver
786575c3de a little bit of cleanup and minor opt 2018-02-06 10:02:08 -08:00
Michael Davidsaver
4cca194000 drop *HashFunction
not really implemented
2018-02-06 10:02:08 -08:00
Michael Davidsaver
cd3ead0028 testThread drop dead code 2018-01-05 11:14:59 -08:00
Michael Davidsaver
a239b95ca1 remove previously deprecated executor.h, queue.h and timerFunction.h 2018-01-05 11:14:59 -08:00
Michael Davidsaver
09574c0e82 sharedVector more c++11
support std::move() and construct
from initializer list.
2018-01-05 11:14:59 -08:00
Michael Davidsaver
0b6b01ef83 shared_vector limit MSVC workaround
limit 207efca15c
to MSVC <= 2010.
2018-01-05 11:14:59 -08:00
Andrew Johnson
34145e459b Clean up compiler warnings. 2018-01-04 17:59:09 -06:00
Michael Davidsaver
207efca15c workaround for msvc pickyness
The MSVC STL implementation asserts that
pointer/itertors are not null, even
when they would not be dereferenced
(eg. empty input range).
2018-01-04 11:52:19 -08:00
Michael Davidsaver
3e25c2ea46 fix more printf specs 2018-01-04 11:52:19 -08:00
Michael Davidsaver
2046678caa drop emptyStringtring 2018-01-04 11:52:19 -08:00
Michael Davidsaver
cb7e4e858b clear some warnings 2018-01-04 11:52:19 -08:00
Michael Davidsaver
43ee4b9cb6 thread safe getFieldCreate() and getPVDataCreate()
Fully thread safe and ctor order safe on all targets
(not just c++11).  Never destroyed to avoid global
dtor order issues.
2017-12-28 11:52:47 -06:00
Michael Davidsaver
207c24a4fd deprecate LOCAL_STATIC_LOCK
This construct is fairly useless.
Doesn't prevent ctor ordering problems.
2017-12-28 11:52:47 -06:00
Michael Davidsaver
6465ab3b6d caseUnsafeV use switch instead of jump table
Change from jump table to switch.
reduces code size (~1k of 30k for rtems/mvme3100).
use indexed loop to help gcc vectorizer.

Helpfully won't fail to compile w/ gcc 4.1 (vxworks 6.6/6.7)
2017-12-28 11:52:47 -06:00
Ralph Lange
cf624bc679 jenkins-ci: fix/update CloudBees jobs 2017-12-19 09:08:27 +01:00
Andrew Johnson
df55a776c7 Update version number after tagging release 2017-12-14 18:28:03 -06:00
45 changed files with 1388 additions and 1832 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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");

View File

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

View File

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

View File

@@ -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
View 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

View File

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

View File

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

View File

@@ -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

View File

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

View File

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

View File

@@ -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

View File

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

View File

@@ -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{

View File

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

View File

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

View File

@@ -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
*

View File

@@ -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';

View File

@@ -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();
}
}
}

View File

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

View File

@@ -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;

View File

@@ -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
{ &copyV<epics::pvData::boolean>,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&noconvert,
&castVTyped<epics::pvData::boolean, string>,
},
// to pvByte
{&noconvert,
&copyV<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>,
&copyV<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>,
&copyV<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>,
&copyV<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>,
&copyV<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>,
&copyV<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>,
&copyV<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>,
&copyV<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>,
&copyV<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>,
&copyV<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>,
&copyV<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");
}
}}

View File

@@ -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();

View File

@@ -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

View File

@@ -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&);

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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());

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -23,7 +23,7 @@ struct MyTest {
MAIN(testUnitTest)
{
testPlan(0);
testPlan(10);
try {
TEST_METHOD(MyTest, test1);
TEST_METHOD(MyTest, test2);

View File

@@ -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();

View File

@@ -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();

View File

@@ -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 */
}

View File

@@ -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>

View File

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