Merged changes from the 3.14 branch, to revno 12674

This commit is contained in:
Andrew Johnson
2016-10-20 15:32:06 -05:00
22 changed files with 389 additions and 281 deletions

View File

@@ -105,13 +105,17 @@ endif
PRODTARGETS += $(PRODNAME) $(MUNCHNAME) $(CTDT_SRCS) $(CTDT_OBJS) $(NMS)
#---------------------------------------------------------------
# Generate a test specification if any tests are defined.
# Test specifications and test result files
#
ifneq (,$(strip $(TESTS)))
TARGETS += testspec
endif
# Enable testing if this host can run tests on the current target
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
RUNTESTS_ENABLED = YES
TAPFILES += $(TESTSCRIPTS:.t=.tap)
endif
#---------------------------------------------------------------
# Libraries
@@ -324,7 +328,7 @@ $(MODNAME): %$(MODEXT): %$(EXE)
# Automated testing
runtests: $(TESTSCRIPTS)
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
ifdef RUNTESTS_ENABLED
-$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^
endif
@@ -340,7 +344,7 @@ tapfiles: $(TESTSCRIPTS) $(TAPFILES)
# A .tap file is the output from running the associated test script
%.tap: %.t
ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
ifdef RUNTESTS_ENABLED
-$(PERL) $< -tap > $@
endif

View File

@@ -10,6 +10,8 @@ VALID_BUILDS = Host Ioc
CMPLR_CLASS = msvc
OPT_WHOLE_PROGRAM = YES
#-------------------------------------------------------
WINLINK = link
@@ -42,11 +44,13 @@ WARN_CFLAGS_NO = -W1
# -Ox maximum optimizations
# -GL whole program optimization
# -Oy- re-enable creation of frame pointers
OPT_CFLAGS_YES = -Ox -GL -Oy-
OPT_CFLAGS_YES_YES = -Ox -GL -Oy-
OPT_CFLAGS_YES_NO = -Ox -Oy-
OPT_CFLAGS_YES = $(OPT_CFLAGS_YES_$(OPT_WHOLE_PROGRAM))
#
# -Zi generate program database for debugging information
# -RTCsu catch bugs occuring only inoptimized code
# -RTCsu enable run-time error checks
OPT_CFLAGS_NO = -Zi -RTCsu
# specify object file name and location
@@ -96,17 +100,19 @@ CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
# -w44355 set "'this' used in the base initializer list" to be level 4
# -w44344 "behavior change: use of explicit template arguments results in ..."
WARN_CXXFLAGS_YES = -W3 -w44355 -w44344
WARN_CXXFLAGS_NO = -W1
WARN_CXXFLAGS_NO = -W1
#
# -Ox maximum optimizations
# -GL whole program optimization
# -Oy- re-enable creation of frame pointers
OPT_CXXFLAGS_YES = -Ox -GL -Oy-
OPT_CXXFLAGS_YES_YES = -Ox -GL -Oy-
OPT_CXXFLAGS_YES_NO = -Ox -Oy-
OPT_CXXFLAGS_YES = $(OPT_CXXFLAGS_YES_$(OPT_WHOLE_PROGRAM))
#
# -Zi generate program database for debugging information
# -RTCsu catch bugs occurring only in optimized code
# -RTCsu enable run-time error checks
OPT_CXXFLAGS_NO = -RTCsu -Zi
# specify object file name and location
@@ -136,11 +142,14 @@ RANLIB=
# -fixed:no generate relocatable code
# -version:<major>.<minor> - only 2 components allowed, 0-65535 each
# -debug generate debugging info
LINK_OPT_FLAGS_YES = -LTCG -incremental:no -opt:ref \
-release $(PROD_VERSION:%=-version:%)
LINK_OPT_FLAGS_WHOLE_YES = -LTCG
LINK_OPT_FLAGS_YES = $(LINK_OPT_FLAGS_WHOLE_$(OPT_WHOLE_PROGRAM))
LINK_OPT_FLAGS_YES += -incremental:no -opt:ref
LINK_OPT_FLAGS_YES += -release $(PROD_VERSION:%=-version:%)
LINK_OPT_FLAGS_NO = -debug -incremental:no -fixed:no
OPT_LDFLAGS = $(LINK_OPT_FLAGS_$(HOST_OPT))
LIB_OPT_FLAGS_YES = -LTCG
LIB_OPT_FLAGS_YES = $(LINK_OPT_FLAGS_WHOLE_$(OPT_WHOLE_PROGRAM))
LIB_OPT_LDFLAGS = $(LIB_OPT_FLAGS_$(HOST_OPT))
ARCH_DEP_CFLAGS=

View File

@@ -0,0 +1,8 @@
# CONFIG_SITE.Common.win32-x86-static
#
# Site-specific settings for the win32-x86-static target
# Whole-program optimization doesn't work with Visual Studio 2010 when
# building static binaries. Newer versions of Visual Studio than 2010
# may work though, comment out or set this to YES to try.
OPT_WHOLE_PROGRAM = NO

View File

@@ -1,9 +1,8 @@
# CONFIG_SITE.Common.windows-x64-static
#
# Site Specific definitions for windows-x64-static target
# Only the local epics system manager should modify this file
# 64-bit Visual Studio 2010 builds fail when built optimized.
# If you are using a newer version you can try removing this:
HOST_OPT = NO
# Site-specific settings for the windows-x64-static target
# Whole-program optimization doesn't work with Visual Studio 2010 when
# building static binaries. Newer versions of Visual Studio than 2010
# may work though, comment out or set this to YES to try.
OPT_WHOLE_PROGRAM = NO

View File

@@ -32,6 +32,29 @@ of the dbStatic library that is not being built anymore.</p>
<h2 align="center">Changes from the 3.14 branch since 3.15.4</h2>
<!-- Insert inherited items immediately below here ... -->
<h3>Add dynamic (variable length) array support to PCAS</h3>
<p>Dynamic array sizing support was added to the IOC server (RSRV) in the
Base-3.14.12 release, but has not until now been supported in the <q>Portable
Channel Access Server</q> (PCAS). Channel Access server applications using the
PCAS may not need to be modified at all; if they already push monitors with
different gdd array lengths, those variable sizes will be forwarded to any CA
clients who have requested variable length updates. The example CAS server
application has been modified to demonstrate this feature.</p>
<p>In implementing the above, the gdd method <tt>gdd::put(const gdd *)</tt> now
copies the full-sized array from the source gdd if the destination gdd is of
type array, has no allocated memory and a boundary size of 0.</p>
<h3>Additional epicsTime conversion</h3>
<p>The EPICS timestamp library (epicsTime) inside libCom's OSI layer has
been extended by routines that convert from <tt>struct tm</tt> to the EPICS
internal <tt>epicsTime</tt> type, assuming UTC - i.e. without going through
the timezone mechanism. This solves issues with converting from the structured
type to the EPICS timestamp at driver level from multiple threads at a high
repetition rate, where the timezone mechanism was blocking on file access.</p>
<h3>MinGW Cross-builds from Linux</h3>
<p>The build configuration files that allow cross-building of the 32-bit

View File

@@ -149,9 +149,9 @@ cac::cac (
iiuExistenceCount ( 0u ),
cacShutdownInProgress ( false )
{
if ( ! osiSockAttach () ) {
throwWithLocation ( caErrorCode (ECA_INTERNAL) );
}
if ( ! osiSockAttach () ) {
throwWithLocation ( udpiiu :: noSocket () );
}
try {
long status;

View File

@@ -61,11 +61,6 @@ static const double CA_CONN_VERIFY_PERIOD = 30.0; /* (sec) how often to request
*/
static const unsigned contiguousMsgCountWhichTriggersFlowControl = 10u;
class caErrorCode {
public:
caErrorCode ( int ) {};
};
/*
* CA internal functions
*/

View File

@@ -44,12 +44,7 @@
using namespace std;
#if 0
const unsigned mSecPerSec = 1000u;
const unsigned uSecPerSec = 1000u * mSecPerSec;
#endif
tcpSendThread::tcpSendThread (
tcpSendThread::tcpSendThread (
class tcpiiu & iiuIn, const char * pName,
unsigned stackSize, unsigned priority ) :
thread ( *this, pName, stackSize, priority ), iiu ( iiuIn )
@@ -807,28 +802,6 @@ tcpiiu::tcpiiu (
}
}
# if 0
//
// windows has a really strange implementation of thess options
// and we can avoid the need for this by using pthread_kill on unix
//
{
struct timeval timeout;
double pollInterval = connectionTimeout / 8.0;
timeout.tv_sec = static_cast < long > ( pollInterval );
timeout.tv_usec = static_cast < long >
( ( pollInterval - timeout.tv_sec ) * uSecPerSec );
// intentionally ignore status as we dont expect that all systems
// will accept this request
setsockopt ( this->sock, SOL_SOCKET, SO_SNDTIMEO,
( char * ) & timeout, sizeof ( timeout ) );
// intentionally ignore status as we dont expect that all systems
// will accept this request
setsockopt ( this->sock, SOL_SOCKET, SO_RCVTIMEO,
( char * ) & timeout, sizeof ( timeout ) );
}
# endif
if ( isNameService() ) {
pSearchDest->setCircuit ( this );
}

View File

@@ -1355,8 +1355,9 @@ gddStatus gdd::put ( const gdd * dd )
}
aitUint32 srcAvailSize = srcElemCount - unusedSrcBelow;
if ( srcAvailSize > this->getBounds()->size() ) {
srcCopySize = this->getBounds()->size();
aitUint32 destSize = this->getBounds()->size();
if ( destSize > 0 && srcAvailSize > destSize ) {
srcCopySize = destSize;
}
else {
srcCopySize = srcAvailSize;

View File

@@ -30,7 +30,7 @@
# include "shareLib.h"
#endif
static const unsigned char CA_MINOR_PROTOCOL_REVISION = 12;
static const unsigned char CA_MINOR_PROTOCOL_REVISION = 13;
typedef ca_uint32_t caResId;

View File

@@ -40,8 +40,13 @@ class casIntfOS;
class casMonitor;
class casChannelI;
caStatus convertContainerMemberToAtomic ( class gdd & dd,
aitUint32 appType, aitUint32 elemCount );
caStatus convertContainerMemberToAtomic (class gdd & dd,
aitUint32 appType, aitUint32 requestedCount, aitUint32 nativeCount);
// Keep the old signature for backward compatibility
inline caStatus convertContainerMemberToAtomic (class gdd & dd,
aitUint32 appType, aitUint32 elemCount)
{ return convertContainerMemberToAtomic(dd, appType, elemCount, elemCount); }
class caServerI :
public caServerIO,

View File

@@ -18,6 +18,8 @@
#include "caHdrLargeArray.h"
class casStrmClient;
class casCtx {
public:
casCtx();
@@ -41,6 +43,7 @@ private:
casChannelI * pChannel;
casPVI * pPV;
unsigned nAsyncIO; // checks for improper use of async io
friend class casStrmClient;
};
inline const caHdrLargeArray * casCtx::getMsg() const

View File

@@ -388,14 +388,12 @@ caStatus casStrmClient::echoAction ( epicsGuard < casClientMutex > & )
//
// casStrmClient::verifyRequest()
//
caStatus casStrmClient::verifyRequest ( casChannelI * & pChan )
caStatus casStrmClient::verifyRequest (casChannelI * & pChan , bool allowdyn)
{
const caHdrLargeArray * mp = this->ctx.getMsg();
//
// channel exists for this resource id ?
//
chronIntId tmpId ( mp->m_cid );
chronIntId tmpId ( ctx.msg.m_cid );
pChan = this->chanTable.lookup ( tmpId );
if ( ! pChan ) {
return ECA_BADCHID;
@@ -404,14 +402,15 @@ caStatus casStrmClient::verifyRequest ( casChannelI * & pChan )
//
// data type out of range ?
//
if ( mp->m_dataType > ((unsigned)LAST_BUFFER_TYPE) ) {
if ( ctx.msg.m_dataType > ((unsigned)LAST_BUFFER_TYPE) ) {
return ECA_BADTYPE;
}
//
// element count out of range ?
//
if ( mp->m_count > pChan->getPVI().nativeCount() || mp->m_count == 0u ) {
if ( ctx.msg.m_count > pChan->getPVI().nativeCount() ||
( !allowdyn && ctx.msg.m_count == 0u ) ) {
return ECA_BADCOUNT;
}
@@ -444,7 +443,7 @@ caStatus casStrmClient::readAction ( epicsGuard < casClientMutex > & guard )
casChannelI * pChan;
{
caStatus status = this->verifyRequest ( pChan );
caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
if ( pChan ) {
return this->sendErr ( guard, mp, pChan->getCID(),
@@ -531,11 +530,15 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard,
pChan->getCID(), status, ECA_GETFAIL );
}
ca_uint32_t count = (msg.m_count == 0) ?
(ca_uint32_t)desc.getDataSizeElements() :
msg.m_count;
void * pPayload;
{
unsigned payloadSize = dbr_size_n ( msg.m_dataType, msg.m_count );
unsigned payloadSize = dbr_size_n ( msg.m_dataType, count );
caStatus localStatus = this->out.copyInHeader ( msg.m_cmmd, payloadSize,
msg.m_dataType, msg.m_count, pChan->getCID (),
msg.m_dataType, count, pChan->getCID (),
msg.m_available, & pPayload );
if ( localStatus ) {
if ( localStatus==S_cas_hugeRequest ) {
@@ -551,21 +554,21 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard,
// (places the data in network format)
//
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr(
pPayload, msg.m_count, desc, pChan->enumStringTable() );
pPayload, count, desc, pChan->enumStringTable() );
if ( mapDBRStatus < 0 ) {
desc.dump ();
errPrintf ( S_cas_badBounds, __FILE__, __LINE__, "- get with PV=%s type=%u count=%u",
pChan->getPVI().getName(), msg.m_dataType, msg.m_count );
pChan->getPVI().getName(), msg.m_dataType, count );
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_badBounds, ECA_GETFAIL );
}
int cacStatus = caNetConvert (
msg.m_dataType, pPayload, pPayload, true, msg.m_count );
msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_internal, cacStatus );
}
if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
if ( msg.m_dataType == DBR_STRING && count == 1u ) {
unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@@ -585,7 +588,7 @@ caStatus casStrmClient::readNotifyAction ( epicsGuard < casClientMutex > & guard
casChannelI * pChan;
{
caStatus status = this->verifyRequest ( pChan );
caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
return this->readNotifyFailureResponse ( guard, * mp, status );
}
@@ -656,11 +659,15 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua
return ecaStatus;
}
ca_uint32_t count = (msg.m_count == 0) ?
(ca_uint32_t)desc.getDataSizeElements() :
msg.m_count;
void *pPayload;
{
unsigned size = dbr_size_n ( msg.m_dataType, msg.m_count );
unsigned size = dbr_size_n ( msg.m_dataType, count );
caStatus status = this->out.copyInHeader ( msg.m_cmmd, size,
msg.m_dataType, msg.m_count, ECA_NORMAL,
msg.m_dataType, count, ECA_NORMAL,
msg.m_available, & pPayload );
if ( status ) {
if ( status == S_cas_hugeRequest ) {
@@ -675,23 +682,23 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua
// convert gdd to db_access type
//
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr ( pPayload,
msg.m_count, desc, pChan->enumStringTable() );
count, desc, pChan->enumStringTable() );
if ( mapDBRStatus < 0 ) {
desc.dump();
errPrintf ( S_cas_badBounds, __FILE__, __LINE__,
"- get notify with PV=%s type=%u count=%u",
pChan->getPVI().getName(), msg.m_dataType, msg.m_count );
pChan->getPVI().getName(), msg.m_dataType, count );
return this->readNotifyFailureResponse ( guard, msg, ECA_NOCONVERT );
}
int cacStatus = caNetConvert (
msg.m_dataType, pPayload, pPayload, true, msg.m_count );
msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_internal, cacStatus );
}
if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
if ( msg.m_dataType == DBR_STRING && count == 1u ) {
unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@@ -727,8 +734,8 @@ caStatus casStrmClient::readNotifyFailureResponse (
// to be more efficent if it discovers that the source has less data
// than the destination)
//
caStatus convertContainerMemberToAtomic ( gdd & dd,
aitUint32 appType, aitUint32 elemCount )
caStatus convertContainerMemberToAtomic ( gdd & dd,
aitUint32 appType, aitUint32 requestedCount, aitUint32 nativeCount )
{
gdd * pVal;
if ( dd.isContainer() ) {
@@ -755,13 +762,13 @@ caStatus convertContainerMemberToAtomic ( gdd & dd,
return S_cas_badType;
}
if ( elemCount <= 1 ) {
if ( nativeCount <= 1 ) {
return S_cas_success;
}
// convert to atomic
gddBounds bds;
bds.setSize ( elemCount );
bds.setSize ( requestedCount );
bds.setFirst ( 0u );
pVal->setDimension ( 1u, & bds );
return S_cas_success;
@@ -770,9 +777,9 @@ caStatus convertContainerMemberToAtomic ( gdd & dd,
//
// createDBRDD ()
//
static caStatus createDBRDD ( unsigned dbrType,
unsigned elemCount, gdd * & pDD )
{
static caStatus createDBRDD ( unsigned dbrType,
unsigned requestedCount, unsigned nativeCount, gdd * & pDD )
{
/*
* DBR type has already been checked, but it is possible
* that "gddDbrToAit" will not track with changes in
@@ -799,7 +806,7 @@ static caStatus createDBRDD ( unsigned dbrType,
// fix the value element count
caStatus status = convertContainerMemberToAtomic (
*pDescRet, gddAppType_value, elemCount );
*pDescRet, gddAppType_value, requestedCount, nativeCount );
if ( status != S_cas_success ) {
pDescRet->unreference ();
return status;
@@ -849,11 +856,15 @@ caStatus casStrmClient::monitorResponse (
casChannelI & chan, const caHdrLargeArray & msg,
const gdd & desc, const caStatus completionStatus )
{
ca_uint32_t count = (msg.m_count == 0) ?
(ca_uint32_t)desc.getDataSizeElements() :
msg.m_count;
void * pPayload = 0;
{
ca_uint32_t size = dbr_size_n ( msg.m_dataType, msg.m_count );
ca_uint32_t size = dbr_size_n ( msg.m_dataType, count );
caStatus status = out.copyInHeader ( msg.m_cmmd, size,
msg.m_dataType, msg.m_count, ECA_NORMAL,
msg.m_dataType, count, ECA_NORMAL,
msg.m_available, & pPayload );
if ( status ) {
if ( status == S_cas_hugeRequest ) {
@@ -871,7 +882,8 @@ caStatus casStrmClient::monitorResponse (
gdd * pDBRDD = 0;
if ( completionStatus == S_cas_success ) {
caStatus status = createDBRDD ( msg.m_dataType, msg.m_count, pDBRDD );
caStatus status = createDBRDD ( msg.m_dataType, count,
chan.getPVI().nativeCount(), pDBRDD );
if ( status != S_cas_success ) {
caStatus ecaStatus;
if ( status == S_cas_badType ) {
@@ -892,7 +904,7 @@ caStatus casStrmClient::monitorResponse (
pDBRDD->unreference ();
errPrintf ( S_cas_noConvert, __FILE__, __LINE__,
"no conversion between event app type=%d and DBR type=%d Element count=%d",
desc.applicationType (), msg.m_dataType, msg.m_count);
desc.applicationType (), msg.m_dataType, count);
return monitorFailureResponse ( guard, msg, ECA_NOCONVERT );
}
}
@@ -915,14 +927,14 @@ caStatus casStrmClient::monitorResponse (
}
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr (
pPayload, msg.m_count, *pDBRDD, chan.enumStringTable() );
pPayload, count, *pDBRDD, chan.enumStringTable() );
if ( mapDBRStatus < 0 ) {
pDBRDD->unreference ();
return monitorFailureResponse ( guard, msg, ECA_NOCONVERT );
}
int cacStatus = caNetConvert (
msg.m_dataType, pPayload, pPayload, true, msg.m_count );
msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
pDBRDD->unreference ();
return this->sendErrWithEpicsStatus (
@@ -932,7 +944,7 @@ caStatus casStrmClient::monitorResponse (
//
// force string message size to be the true size
//
if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
if ( msg.m_dataType == DBR_STRING && count == 1u ) {
ca_uint32_t reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@@ -1940,7 +1952,7 @@ caStatus casStrmClient::eventAddAction (
casChannelI *pciu;
{
caStatus status = casStrmClient::verifyRequest ( pciu );
caStatus status = casStrmClient::verifyRequest ( pciu, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
if ( pciu ) {
return this->sendErr ( guard, mp,
@@ -2601,8 +2613,8 @@ caStatus casStrmClient::read ()
{
gdd * pDD = 0;
caStatus status = createDBRDD ( pHdr->m_dataType,
pHdr->m_count, pDD );
caStatus status = createDBRDD ( pHdr->m_dataType, pHdr->m_count,
this->ctx.getChannel()->getPVI().nativeCount(), pDD );
if ( status != S_cas_success ) {
return status;
}

View File

@@ -69,7 +69,7 @@ private:
bool responseIsPending;
caStatus createChannel ( const char * pName );
caStatus verifyRequest ( casChannelI * & pChan );
caStatus verifyRequest ( casChannelI * & pChan, bool allowdyn = false );
typedef caStatus ( casStrmClient :: * pCASMsgHandler )
( epicsGuard < casClientMutex > & );
static pCASMsgHandler const msgHandlers[CA_PROTO_LAST_CMMD+1u];

View File

@@ -60,11 +60,13 @@ static const unsigned long NTP_TIME_AT_EPICS_EPOCH =
//
// epicsTime (const unsigned long secIn, const unsigned long nSecIn)
//
inline epicsTime::epicsTime (const unsigned long secIn,
const unsigned long nSecIn) :
secPastEpoch ( nSecIn / nSecPerSec + secIn ),
nSec ( nSecIn % nSecPerSec )
inline epicsTime::epicsTime (const unsigned long secIn, const unsigned long nSecIn) :
secPastEpoch ( secIn ), nSec ( nSecIn )
{
if (nSecIn >= nSecPerSec) {
this->secPastEpoch += nSecIn / nSecPerSec;
this->nSec = nSecIn % nSecPerSec;
}
}
//
@@ -113,47 +115,26 @@ epicsTimeLoadTimeInit::epicsTimeLoadTimeInit ()
}
//
// epicsTime::addNanoSec ()
// private epicsTime::addNanoSec ()
//
// The nano-second field of several of the the UNIX time stamp formats
// field is stored in the C type "long".
// Most formats keep the nSec value as an unsigned long, so are +ve.
// struct timeval's tv_usec may be -1, but I think that means error,
// so this private method never needs to handle -ve offsets.
//
void epicsTime :: addNanoSec ( long nSecAdj )
{
//
// After optimizing this function we now have a larger code which
// uses only unsigned integer, and not floating point, arithmetic.
// This change benefits embedded CPU's lacking a floating point
// co-processor at the expense of some additional code to maintain.
//
// We hope that all CPU's we run on provide at least an integer
// divide instruction which should enable this implementation
// to be more efficient than implementations based on branching;
// this is presuming that we will run on pipelined architectures.
//
// Overflow and underflow is expected; in the future we might
// operate close to, the modulo of, the EPICS epic.
//
// We are depending on the normalize operation in the private
// constructor used below.
//
// joh 11-04-2012
//
if ( nSecAdj >= 0 ) {
const unsigned long nSecPlus =
static_cast <unsigned long> ( nSecAdj );
const unsigned long nSecPlusAdj = nSecPlus % nSecPerSec;
const unsigned long secPlusAdj = nSecPlus / nSecPerSec;
*this = epicsTime ( this->secPastEpoch+secPlusAdj,
this->nSec+nSecPlusAdj );
if (nSecAdj <= 0)
return;
if (static_cast<unsigned long>(nSecAdj) >= nSecPerSec) {
this->secPastEpoch += nSecAdj / nSecPerSec;
nSecAdj %= nSecPerSec;
}
else {
const unsigned long nSecMinus =
static_cast <unsigned long> ( -nSecAdj );
const unsigned long nSecMinusAdj = nSecMinus % nSecPerSec;
const unsigned long secMinusAdj = nSecMinus / nSecPerSec;
*this = epicsTime ( this->secPastEpoch - secMinusAdj - 1u,
this->nSec + nSecPerSec - nSecMinusAdj );
this->nSec += nSecAdj; // Can't overflow
if (this->nSec >= nSecPerSec) {
this->secPastEpoch++;
this->nSec -= nSecPerSec;
}
}
@@ -317,20 +298,82 @@ epicsTime::operator gm_tm_nano_sec () const
//
epicsTime::epicsTime (const local_tm_nano_sec &tm)
{
static const time_t mktimeFailure = static_cast <time_t> (-1);
time_t_wrapper ansiTimeTicks;
struct tm tmp = tm.ansi_tm;
time_t_wrapper ansiTimeTicks = { mktime (&tmp) };
ansiTimeTicks.ts = mktime (&tmp);
if (ansiTimeTicks.ts == mktimeFailure) {
static const time_t mktimeError = static_cast <time_t> (-1);
if (ansiTimeTicks.ts == mktimeError) {
throwWithLocation ( formatProblemWithStructTM () );
}
*this = epicsTime (ansiTimeTicks);
*this = epicsTime(ansiTimeTicks);
this->addNanoSec(tm.nSec);
}
unsigned long nSecAdj = tm.nSec % nSecPerSec;
unsigned long secAdj = tm.nSec / nSecPerSec;
*this = epicsTime ( this->secPastEpoch+secAdj, this->nSec+nSecAdj );
//
// epicsTime (const gm_tm_nano_sec &tm)
//
// do conversion avoiding the timezone mechanism
static inline int is_leap(int year)
{
if (year % 400 == 0)
return 1;
if (year % 100 == 0)
return 0;
if (year % 4 == 0)
return 1;
return 0;
}
static inline int days_from_0(int year)
{
year--;
return 365 * year + (year / 400) - (year / 100) + (year / 4);
}
static inline int days_from_1970(int year)
{
static const int days_from_0_to_1970 = days_from_0(1970);
return days_from_0(year) - days_from_0_to_1970;
}
static inline int days_from_1jan(int year, int month, int day)
{
static const int days[2][12] =
{
{ 0,31,59,90,120,151,181,212,243,273,304,334},
{ 0,31,60,91,121,152,182,213,244,274,305,335}
};
return days[is_leap(year)][month-1] + day - 1;
}
epicsTime::epicsTime (const gm_tm_nano_sec &tm)
{
int year = tm.ansi_tm.tm_year + 1900;
int month = tm.ansi_tm.tm_mon;
if (month > 11) {
year += month / 12;
month %= 12;
} else if (month < 0) {
int years_diff = (-month + 11) / 12;
year -= years_diff;
month += 12 * years_diff;
}
month++;
int day = tm.ansi_tm.tm_mday;
int day_of_year = days_from_1jan(year, month, day);
int days_since_epoch = days_from_1970(year) + day_of_year;
time_t_wrapper ansiTimeTicks;
ansiTimeTicks.ts = ((days_since_epoch
* 24 + tm.ansi_tm.tm_hour)
* 60 + tm.ansi_tm.tm_min)
* 60 + tm.ansi_tm.tm_sec;
*this = epicsTime(ansiTimeTicks);
this->addNanoSec(tm.nSec);
}
//
@@ -729,7 +772,7 @@ double epicsTime::operator - (const epicsTime &rhs) const
// so the unsigned to signed conversion is ok
//
if (this->nSec>=rhs.nSec) {
nSecRes = this->nSec - rhs.nSec;
nSecRes = this->nSec - rhs.nSec;
}
else {
nSecRes = rhs.nSec - this->nSec;
@@ -944,6 +987,19 @@ extern "C" {
}
return epicsTimeOK;
}
epicsShareFunc int epicsShareAPI epicsTimeFromGMTM (epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc)
{
try {
gm_tm_nano_sec tmns;
tmns.ansi_tm = *pSrc;
tmns.nSec = nSecSrc;
*pDest = epicsTime (tmns);
}
catch (...) {
return epicsTimeERROR;
}
return epicsTimeOK;
}
epicsShareFunc int epicsShareAPI epicsTimeToTimespec (struct timespec *pDest, const epicsTimeStamp *pSrc)
{
try {
@@ -1075,4 +1131,3 @@ extern "C" {
}
}
}

View File

@@ -105,10 +105,12 @@ public:
epicsTime & operator = ( const local_tm_nano_sec & );
/*
* convert to ANSI Cs "struct tm" (with nano seconds)
* convert to and from ANSI Cs "struct tm" (with nano seconds)
* adjusted for GM time (UTC)
*/
operator gm_tm_nano_sec () const;
epicsTime ( const gm_tm_nano_sec & );
epicsTime & operator = ( const gm_tm_nano_sec & );
/* convert to and from POSIX RTs "struct timespec" */
operator struct timespec () const;
@@ -194,13 +196,15 @@ epicsShareFunc int epicsShareAPI epicsTimeToTime_t (
epicsShareFunc int epicsShareAPI epicsTimeFromTime_t (
epicsTimeStamp * pDest, time_t src );
/*convert to and from ANSI C's "struct tm" with nano seconds */
/* convert to and from ANSI C's "struct tm" with nano seconds */
epicsShareFunc int epicsShareAPI epicsTimeToTM (
struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc );
epicsShareFunc int epicsShareAPI epicsTimeToGMTM (
struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc );
epicsShareFunc int epicsShareAPI epicsTimeFromTM (
epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc );
epicsShareFunc int epicsShareAPI epicsTimeFromGMTM (
epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc );
/* convert to and from POSIX RT's "struct timespec" */
epicsShareFunc int epicsShareAPI epicsTimeToTimespec (
@@ -312,6 +316,11 @@ inline epicsTime & epicsTime::operator = ( const local_tm_nano_sec & rhs )
return *this = epicsTime ( rhs );
}
inline epicsTime & epicsTime::operator = ( const gm_tm_nano_sec & rhs )
{
return *this = epicsTime ( rhs );
}
inline epicsTime & epicsTime::operator = ( const struct timespec & rhs )
{
*this = epicsTime ( rhs );

View File

@@ -43,7 +43,7 @@ MAIN(epicsTimeTest)
const int wasteTime = 100000;
const int nTimes = 10;
testPlan(15 + nTimes * 18);
testPlan(15 + nTimes * 19);
try {
const epicsTimeStamp epochTS = {0, 0};
@@ -200,6 +200,11 @@ MAIN(epicsTimeTest)
epicsTime beginANSI = ansiDate;
testOk1(beginANSI + diff == now);
// test struct gmtm round-trip conversion
gm_tm_nano_sec ansiGmDate = begin;
epicsTime beginGMANSI = ansiGmDate;
testOk1(beginGMANSI + diff == now);
// test struct timespec round-trip conversion
struct timespec ts = begin;
epicsTime beginTS = ts;

View File

@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* 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.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
@@ -30,23 +29,23 @@ exAsyncPV::exAsyncPV ( exServer & cas, pvInfo & setup,
//
caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
{
exAsyncReadIO *pIO;
if ( this->simultAsychReadIOCount >= this->cas.maxSimultAsyncIO () ) {
return S_casApp_postponeAsyncIO;
}
exAsyncReadIO *pIO;
pIO = new exAsyncReadIO ( this->cas, ctx,
*this, valueIn, this->asyncDelay );
if ( ! pIO ) {
if ( this->simultAsychReadIOCount >= this->cas.maxSimultAsyncIO () ) {
return S_casApp_postponeAsyncIO;
}
pIO = new exAsyncReadIO ( this->cas, ctx,
*this, valueIn, this->asyncDelay );
if ( ! pIO ) {
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
return S_casApp_noMemory;
return S_casApp_noMemory;
}
}
this->simultAsychReadIOCount++;
}
this->simultAsychReadIOCount++;
return S_casApp_asyncCompletion;
}
@@ -54,24 +53,24 @@ caStatus exAsyncPV::read (const casCtx &ctx, gdd &valueIn)
// exAsyncPV::writeNotify()
//
caStatus exAsyncPV::writeNotify ( const casCtx &ctx, const gdd &valueIn )
{
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
return S_casApp_postponeAsyncIO;
}
{
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
return S_casApp_postponeAsyncIO;
}
exAsyncWriteIO * pIO = new
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
valueIn, this->asyncDelay );
if ( ! pIO ) {
if ( this->simultAsychReadIOCount > 0 ) {
return S_casApp_postponeAsyncIO;
}
else {
return S_casApp_noMemory;
return S_casApp_noMemory;
}
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
}
//
@@ -79,24 +78,24 @@ caStatus exAsyncPV::writeNotify ( const casCtx &ctx, const gdd &valueIn )
//
caStatus exAsyncPV::write ( const casCtx &ctx, const gdd &valueIn )
{
// implement the discard intermediate values, but last value
// implement the discard intermediate values, but last value
// sent always applied behavior that IOCs provide excepting
// that we will alow N requests to pend instead of a limit
// of only one imposed in the IOC
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
if ( this->simultAsychWriteIOCount >= this->cas.maxSimultAsyncIO() ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
}
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
return S_casApp_success;
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
exAsyncWriteIO * pIO = new
exAsyncWriteIO ( this->cas, ctx, *this,
valueIn, this->asyncDelay );
if ( ! pIO ) {
pStandbyValue.set ( & valueIn );
return S_casApp_success;
}
this->simultAsychWriteIOCount++;
return S_casApp_asyncCompletion;
}
// Implementing a specialized update for exAsyncPV
@@ -150,7 +149,7 @@ void exAsyncPV::removeWriteIO ()
exAsyncWriteIO::exAsyncWriteIO ( exServer & cas,
const casCtx & ctxIn, exAsyncPV & pvIn,
const gdd & valueIn, double asyncDelay ) :
casAsyncWriteIO ( ctxIn ), pv ( pvIn ),
casAsyncWriteIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer () ), pValue(valueIn)
{
this->timer.start ( *this, asyncDelay );
@@ -168,7 +167,7 @@ exAsyncWriteIO::~exAsyncWriteIO()
if ( this->pValue.valid () ) {
this->pv.updateFromAsyncWrite ( *this->pValue );
}
this->pv.removeWriteIO();
this->pv.removeWriteIO();
}
//
@@ -179,9 +178,9 @@ epicsTimerNotify::expireStatus exAsyncWriteIO::
expire ( const epicsTime & /* currentTime */ )
{
assert ( this->pValue.valid () );
caStatus status = this->pv.updateFromAsyncWrite ( *this->pValue );
this->pValue.set ( 0 );
this->postIOCompletion ( status );
caStatus status = this->pv.updateFromAsyncWrite ( *this->pValue );
this->pValue.set ( 0 );
this->postIOCompletion ( status );
return noRestart;
}
@@ -191,7 +190,7 @@ epicsTimerNotify::expireStatus exAsyncWriteIO::
exAsyncReadIO::exAsyncReadIO ( exServer & cas, const casCtx & ctxIn,
exAsyncPV & pvIn, gdd & protoIn,
double asyncDelay ) :
casAsyncReadIO ( ctxIn ), pv ( pvIn ),
casAsyncReadIO ( ctxIn ), pv ( pvIn ),
timer ( cas.createTimer() ), pProto ( protoIn )
{
this->timer.start ( *this, asyncDelay );
@@ -202,7 +201,7 @@ exAsyncReadIO::exAsyncReadIO ( exServer & cas, const casCtx & ctxIn,
//
exAsyncReadIO::~exAsyncReadIO()
{
this->pv.removeReadIO ();
this->pv.removeReadIO ();
this->timer.destroy ();
}
@@ -213,16 +212,16 @@ exAsyncReadIO::~exAsyncReadIO()
epicsTimerNotify::expireStatus
exAsyncReadIO::expire ( const epicsTime & /* currentTime */ )
{
//
// map between the prototype in and the
// current value
//
caStatus status = this->pv.exPV::readNoCtx ( this->pProto );
//
// map between the prototype in and the
// current value
//
caStatus status = this->pv.exPV::readNoCtx ( this->pProto );
//
// post IO completion
//
this->postIOCompletion ( status, *this->pProto );
//
// post IO completion
//
this->postIOCompletion ( status, *this->pProto );
return noRestart;
}

View File

@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* 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.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
@@ -42,7 +41,7 @@ exPV::exPV ( exServer & casIn, pvInfo & setup,
//
// no dataless PV allowed
//
assert (this->info.getElementCount()>=1u);
assert (this->info.getCapacity()>=1u);
//
// start a very slow background scan

View File

@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* 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.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// fileDescriptorManager.process(delay);
@@ -304,7 +303,7 @@ exPV *pvInfo::createPV ( exServer & cas, bool preCreateFlag,
// depending on the io type and the number
// of elements
//
if (this->elementCount==1u) {
if (this->capacity==1u) {
switch (this->ioType){
case excasIoSync:
pNewPV = new exScalarPV ( cas, *this, preCreateFlag, scanOn );

View File

@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* 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.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// Example EPICS CA server
@@ -76,8 +75,10 @@ public:
double getLopr () const;
aitEnum getType () const;
excasIoType getIOType () const;
unsigned getElementCount () const;
void unlinkPV ();
unsigned getCapacity () const;
unsigned getElementCount () const;
void setElementCount (unsigned);
void unlinkPV ();
exPV *createPV ( exServer & exCAS, bool preCreateFlag,
bool scanOn, double asyncDelay );
void deletePV ();
@@ -88,7 +89,8 @@ private:
const double lopr;
aitEnum type;
const excasIoType ioType;
const unsigned elementCount;
const unsigned capacity;
unsigned elementCount;
exPV * pPV;
pvInfo & operator = ( const pvInfo & );
};
@@ -441,8 +443,8 @@ inline pvInfo::pvInfo ( double scanPeriodIn, const char *pNameIn,
scanPeriod ( scanPeriodIn ), pName ( pNameIn ),
hopr ( hoprIn ), lopr ( loprIn ), type ( typeIn ),
ioType ( ioTypeIn ), elementCount ( countIn ),
pPV ( 0 )
ioType ( ioTypeIn ), capacity ( countIn ),
elementCount ( 0 ), pPV ( 0 )
{
}
@@ -454,8 +456,8 @@ inline pvInfo::pvInfo ( const pvInfo & copyIn ) :
scanPeriod ( copyIn.scanPeriod ), pName ( copyIn.pName ),
hopr ( copyIn.hopr ), lopr ( copyIn.lopr ), type ( copyIn.type ),
ioType ( copyIn.ioType ), elementCount ( copyIn.elementCount ),
pPV ( copyIn.pPV )
ioType ( copyIn.ioType ), capacity ( copyIn.capacity ),
elementCount ( copyIn.elementCount ), pPV ( copyIn.pPV )
{
}
@@ -509,12 +511,22 @@ inline excasIoType pvInfo::getIOType () const
return this->ioType;
}
inline unsigned pvInfo::getElementCount () const
{
return this->elementCount;
inline unsigned pvInfo::getCapacity () const
{
return this->capacity;
}
inline void pvInfo::unlinkPV ()
inline unsigned pvInfo::getElementCount () const
{
return this->elementCount;
}
inline void pvInfo::setElementCount (unsigned newCount)
{
this->elementCount = newCount;
}
inline void pvInfo::unlinkPV ()
{
this->pPV = NULL;
}

View File

@@ -3,9 +3,8 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* 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.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include "exServer.h"
@@ -48,7 +47,7 @@ unsigned exVectorPV::maxDimension() const
aitIndex exVectorPV::maxBound (unsigned dimension) const
{
if (dimension==0u) {
return this->info.getElementCount();
return this->info.getCapacity();
}
else {
return 0u;
@@ -60,26 +59,21 @@ aitIndex exVectorPV::maxBound (unsigned dimension) const
//
void exVectorPV::scan()
{
caStatus status;
double radians;
smartGDDPointer pDD;
aitFloat32 *pF, *pFE;
const aitFloat32 *pCF;
float newValue;
float limit;
exVecDestructor *pDest;
int gddStatus;
static epicsTime startTime = epicsTime::getCurrent();
//
// update current time (so we are not required to do
// this every time that we write the PV which impacts
// throughput under sunos4 because gettimeofday() is
// slow)
// update current time
//
this->currentTime = epicsTime::getCurrent();
pDD = new gddAtomic (gddAppType_value, aitEnumFloat64,
1u, this->info.getElementCount());
// demonstrate a changing array size
unsigned ramp = 15 & (unsigned) (this->currentTime - startTime);
unsigned newSize = this->info.getCapacity();
if (newSize > ramp) {
newSize -= ramp;
}
smartGDDPointer pDD = new gddAtomic (gddAppType_value, aitEnumFloat64,
1u, newSize);
if ( ! pDD.valid () ) {
return;
}
@@ -87,18 +81,18 @@ void exVectorPV::scan()
//
// smart pointer class manages reference count after this point
//
gddStatus = pDD->unreference();
assert (!gddStatus);
gddStatus gdds = pDD->unreference();
assert(!gdds);
//
// allocate array buffer
//
pF = new aitFloat32 [this->info.getElementCount()];
aitFloat64 * pF = new aitFloat64 [newSize];
if (!pF) {
return;
}
pDest = new exVecDestructor;
exVecDestructor * pDest = new exVecDestructor;
if (!pDest) {
delete [] pF;
return;
@@ -114,37 +108,39 @@ void exVectorPV::scan()
// double check for reasonable bounds on the
// current value
//
pCF=NULL;
if ( this->pValue.valid () ) {
if (this->pValue->dimension()==1u) {
const gddBounds *pB = this->pValue->getBounds();
if (pB[0u].size()==this->info.getElementCount()) {
pCF = *this->pValue;
}
}
const aitFloat64 *pCF = NULL, *pCFE = NULL;
if (this->pValue.valid () &&
this->pValue->dimension() == 1u) {
const gddBounds *pB = this->pValue->getBounds();
pCF = *this->pValue;
pCFE = &pCF[pB->size()];
}
pFE = &pF[this->info.getElementCount()];
while (pF<pFE) {
radians = (rand () * 2.0 * myPI)/RAND_MAX;
if (pCF) {
aitFloat64 * pFE = &pF[newSize];
while (pF < pFE) {
double radians = (rand () * 2.0 * myPI)/RAND_MAX;
double newValue;
if (pCF && pCF < pCFE) {
newValue = *pCF++;
}
else {
newValue = 0.0f;
}
newValue += (float) (sin (radians) / 10.0);
limit = (float) this->info.getHopr();
newValue += (sin (radians) / 10.0);
double limit = this->info.getHopr();
newValue = tsMin (newValue, limit);
limit = (float) this->info.getLopr();
limit = this->info.getLopr();
newValue = tsMax (newValue, limit);
*(pF++) = newValue;
*pF++ = newValue;
}
aitTimeStamp gddts = this->currentTime;
pDD->setTimeStamp ( & gddts );
status = this->update ( *pDD );
caStatus status = this->update ( *pDD );
this->info.setElementCount(newSize);
if ( status != S_casApp_success ) {
errMessage (status, "vector scan update failed\n");
}
@@ -166,7 +162,7 @@ void exVectorPV::scan()
//
caStatus exVectorPV::updateValue ( const gdd & value )
{
aitUint32 newSize = 0;
//
// Check bounds of incoming request
// (and see if we are replacing all elements -
@@ -183,7 +179,9 @@ caStatus exVectorPV::updateValue ( const gdd & value )
if ( pb[0u].first() != 0u ) {
return S_casApp_outOfBounds;
}
else if ( pb[0u].size() > this->info.getElementCount() ) {
newSize = pb[0u].size();
if ( newSize > this->info.getCapacity() ) {
return S_casApp_outOfBounds;
}
}
@@ -193,14 +191,14 @@ caStatus exVectorPV::updateValue ( const gdd & value )
//
return S_casApp_outOfBounds;
}
//
// Create a new array data descriptor
// (so that old values that may be referenced on the
// event queue are not replaced)
//
smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64,
1u, this->info.getElementCount() ) );
smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64,
1u, newSize ) );
if ( ! pNewValue.valid() ) {
return S_casApp_noMemory;
}
@@ -211,21 +209,20 @@ caStatus exVectorPV::updateValue ( const gdd & value )
//
gddStatus gdds = pNewValue->unreference( );
assert ( ! gdds );
//
// allocate array buffer
//
aitFloat64 * pF = new aitFloat64 [this->info.getElementCount()];
aitFloat64 * pF = new aitFloat64 [newSize];
if (!pF) {
return S_casApp_noMemory;
}
//
// Install (and initialize) array buffer
// if no old values exist
//
unsigned count = this->info.getElementCount();
for ( unsigned i = 0u; i < count; i++ ) {
for ( unsigned i = 0u; i < newSize; i++ ) {
pF[i] = 0.0f;
}
@@ -240,7 +237,7 @@ caStatus exVectorPV::updateValue ( const gdd & value )
// (do this before we increment pF)
//
pNewValue->putRef ( pF, pDest );
//
// copy in the values that they are writing
//
@@ -248,9 +245,10 @@ caStatus exVectorPV::updateValue ( const gdd & value )
if ( gdds ) {
return S_cas_noConvert;
}
this->pValue = pNewValue;
this->info.setElementCount(newSize);
return S_casApp_success;
}
@@ -261,6 +259,6 @@ caStatus exVectorPV::updateValue ( const gdd & value )
//
void exVecDestructor::run ( void *pUntyped )
{
aitFloat32 * pf = reinterpret_cast < aitFloat32 * > ( pUntyped );
aitFloat64 * pf = reinterpret_cast < aitFloat64 * > ( pUntyped );
delete [] pf;
}