Compare commits
18 Commits
end-of-dat
...
ca-4.13.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
524ceee2c8 | ||
|
|
37e6c875ba | ||
|
|
796279cc0d | ||
|
|
ee10014a62 | ||
|
|
7a6fff0334 | ||
|
|
5dfd1fc0f0 | ||
|
|
c3a6cfcf0d | ||
|
|
9ac5f7fbc1 | ||
|
|
2ebd193681 | ||
|
|
b6c78adaaa | ||
|
|
ed7798ba08 | ||
|
|
abb8136817 | ||
|
|
33f503722e | ||
|
|
79739f3eec | ||
|
|
7458569f10 | ||
|
|
701309fc4a | ||
|
|
765b53e3fd | ||
|
|
c55fb421ce |
@@ -52,7 +52,6 @@ add_base_module() {
|
||||
git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
|
||||
( cd epics-base && git log -n1 )
|
||||
add_base_module libcom "${BRLIBCOM:-master}"
|
||||
add_base_module ca "${BRCA:-master}"
|
||||
|
||||
EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ install:
|
||||
script:
|
||||
- ./.ci/travis-build.sh
|
||||
env:
|
||||
- BRCORE=master BRLIBCOM=master BRCA=master
|
||||
- CMPLR=clang
|
||||
- USR_CXXFLAGS=-std=c++11
|
||||
- CMPLR=clang USR_CXXFLAGS=-std=c++11
|
||||
- BRCORE=master BRLIBCOM=master TEST=NO
|
||||
- CMPLR=clang TEST=NO
|
||||
- USR_CXXFLAGS=-std=c++11 TEST=NO
|
||||
- CMPLR=clang USR_CXXFLAGS=-std=c++11 TEST=NO
|
||||
- WINE=32 TEST=NO STATIC=YES
|
||||
- WINE=32 TEST=NO STATIC=NO
|
||||
- RTEMS=4.10 TEST=NO
|
||||
|
||||
5
Makefile
5
Makefile
@@ -11,9 +11,8 @@ TOP = .
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
DIRS += configure src
|
||||
|
||||
src_DEPEND_DIRS = configure
|
||||
|
||||
DIRS += test
|
||||
test_DEPEND_DIRS = src
|
||||
|
||||
include $(TOP)/configure/RULES_TOP
|
||||
|
||||
|
||||
@@ -13,20 +13,12 @@ ifdef T_A
|
||||
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
|
||||
endif
|
||||
|
||||
BUILDING_DATABASE = DEFINED
|
||||
|
||||
CONFIG = $(RULES)/configure
|
||||
include $(CONFIG)/CONFIG
|
||||
|
||||
# Override the Base definition:
|
||||
INSTALL_LOCATION = $(TOP)
|
||||
|
||||
# Use new RSET definition
|
||||
BASE_CPPFLAGS += -DUSE_TYPED_RSET
|
||||
|
||||
# Shared library ABI version.
|
||||
SHRLIB_VERSION = 3.17.0
|
||||
|
||||
# CONFIG_SITE files contain other build configuration settings
|
||||
include $(TOP)/configure/CONFIG_SITE
|
||||
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
|
||||
# Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
menu(menuPost) {
|
||||
choice(menuPost_OnChange, "On Change")
|
||||
choice(menuPost_Always, "Always")
|
||||
}
|
||||
# Libraries needed to link a host tool
|
||||
EPICS_BASE_HOST_LIBS = ca Com
|
||||
4
configure/CONFIG_CA_VERSION
Normal file
4
configure/CONFIG_CA_VERSION
Normal file
@@ -0,0 +1,4 @@
|
||||
EPICS_CA_MAJOR_VERSION = 4
|
||||
EPICS_CA_MINOR_VERSION = 13
|
||||
EPICS_CA_MAINTENANCE_VERSION = 1
|
||||
EPICS_CA_DEVELOPMENT_FLAG = 0
|
||||
@@ -1,26 +0,0 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
# Set EPICS_DATABASE if necessary
|
||||
ifndef EPICS_DATABASE
|
||||
EPICS_DATABASE = $(if $(BUILDING_DATABASE),$(INSTALL_LOCATION),$(EPICS_BASE))
|
||||
|
||||
# Paths to tools built here
|
||||
EPICS_DATABASE_HOST_BIN = $(EPICS_DATABASE)/bin/$(EPICS_HOST_ARCH)
|
||||
endif
|
||||
|
||||
# Set location of locally-built tools
|
||||
MAKEBPT = $(EPICS_DATABASE_HOST_BIN)/makeBpt$(HOSTEXE)
|
||||
DBEXPAND = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdExpand.pl
|
||||
DBTORECORDTYPEH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToRecordtypeH.pl
|
||||
DBTOMENUH = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToMenuH.pl
|
||||
DBDTOHTML = $(PERL) $(EPICS_DATABASE_HOST_BIN)/dbdToHtml.pl
|
||||
REGISTERRECORDDEVICEDRIVER = $(PERL) $(EPICS_DATABASE_HOST_BIN)/registerRecordDeviceDriver.pl
|
||||
MSI3_15 = $(EPICS_DATABASE_HOST_BIN)/msi$(HOSTEXE)
|
||||
|
||||
# Libraries needed to link a basic IOC
|
||||
EPICS_BASE_IOC_LIBS = dbRecStd dbCore ca Com
|
||||
@@ -1,4 +0,0 @@
|
||||
EPICS_DATABASE_MAJOR_VERSION = 3
|
||||
EPICS_DATABASE_MINOR_VERSION = 17
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 1
|
||||
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
|
||||
@@ -9,7 +9,7 @@ include $(TOP)/configure/CONFIG
|
||||
TARGETS = $(CONFIG_TARGETS)
|
||||
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
|
||||
|
||||
CFG += CONFIG_DATABASE_MODULE
|
||||
CFG += CONFIG_DATABASE_VERSION
|
||||
CFG += CONFIG_CA_MODULE
|
||||
CFG += CONFIG_CA_VERSION
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#MYMODULE = $(MODULES)/my-module
|
||||
|
||||
# If building the EPICS modules individually, set these:
|
||||
#EPICS_CA = $(MODULES)/ca-4.13.1
|
||||
#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0
|
||||
#EPICS_BASE = $(MODULES)/core-7.0.1
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#RULES.ioc
|
||||
include $(CONFIG)/RULES.ioc
|
||||
18
src/Makefile
18
src/Makefile
@@ -10,21 +10,15 @@
|
||||
TOP = ..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
# PDB Tools
|
||||
# Channel Access Client
|
||||
|
||||
DIRS += client
|
||||
|
||||
DIRS += tools
|
||||
tools_DEPEND_DIRS = client
|
||||
|
||||
# PDB Core
|
||||
|
||||
DIRS += ioc
|
||||
ioc_DEPEND_DIRS = tools
|
||||
|
||||
# PDB Standard Record Definitions
|
||||
|
||||
DIRS += std
|
||||
std_DEPEND_DIRS = ioc
|
||||
|
||||
# Templates
|
||||
DIRS += perl
|
||||
perl_DEPEND_DIRS = client
|
||||
|
||||
DIRS += template
|
||||
|
||||
|
||||
308
src/client/CASG.cpp
Normal file
308
src/client/CASG.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Jeffrey O. Hill
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "syncGroup.h"
|
||||
#include "oldAccess.h"
|
||||
#include "cac.h"
|
||||
#include "sgAutoPtr.h"
|
||||
|
||||
CASG::CASG ( epicsGuard < epicsMutex > & guard, ca_client_context & cacIn ) :
|
||||
client ( cacIn ), magic ( CASG_MAGIC )
|
||||
{
|
||||
client.installCASG ( guard, *this );
|
||||
}
|
||||
|
||||
CASG::~CASG ()
|
||||
{
|
||||
}
|
||||
|
||||
void CASG::destructor (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
|
||||
if ( this->verify ( guard ) ) {
|
||||
this->reset ( cbGuard, guard );
|
||||
this->client.uninstallCASG ( guard, *this );
|
||||
this->magic = 0;
|
||||
}
|
||||
else {
|
||||
this->printFormated ( "cac: attempt to destroy invalid sync group ignored\n" );
|
||||
}
|
||||
this->~CASG ();
|
||||
}
|
||||
|
||||
bool CASG::verify ( epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return ( this->magic == CASG_MAGIC );
|
||||
}
|
||||
|
||||
/*
|
||||
* CASG::block ()
|
||||
*/
|
||||
int CASG::block (
|
||||
epicsGuard < epicsMutex > * pcbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
double timeout )
|
||||
{
|
||||
epicsTime cur_time;
|
||||
epicsTime beg_time;
|
||||
double delay;
|
||||
double remaining;
|
||||
int status;
|
||||
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
|
||||
// prevent recursion nightmares by disabling blocking
|
||||
// for IO from within a CA callback.
|
||||
if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) {
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
|
||||
if ( timeout < 0.0 ) {
|
||||
return ECA_TIMEOUT;
|
||||
}
|
||||
|
||||
cur_time = epicsTime::getCurrent ();
|
||||
|
||||
this->client.flush ( guard );
|
||||
|
||||
beg_time = cur_time;
|
||||
delay = 0.0;
|
||||
|
||||
while ( 1 ) {
|
||||
if ( this->ioPendingList.count() == 0u ) {
|
||||
status = ECA_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
remaining = timeout - delay;
|
||||
if ( remaining <= CAC_SIGNIFICANT_DELAY ) {
|
||||
/*
|
||||
* Make sure that we take care of
|
||||
* recv backlog at least once
|
||||
*/
|
||||
status = ECA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( pcbGuard ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > uncbGuard ( *pcbGuard );
|
||||
this->sem.wait ( remaining );
|
||||
}
|
||||
}
|
||||
else {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
this->sem.wait ( remaining );
|
||||
}
|
||||
|
||||
/*
|
||||
* force a time update
|
||||
*/
|
||||
cur_time = epicsTime::getCurrent ();
|
||||
|
||||
delay = cur_time - beg_time;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void CASG::reset (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->destroyCompletedIO ( cbGuard, guard );
|
||||
this->destroyPendingIO ( cbGuard, guard );
|
||||
}
|
||||
|
||||
// lock must be applied
|
||||
void CASG::destroyCompletedIO (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
syncGroupNotify * pNotify;
|
||||
while ( ( pNotify = this->ioCompletedList.get () ) ) {
|
||||
pNotify->destroy ( cbGuard, guard );
|
||||
}
|
||||
}
|
||||
|
||||
void CASG::destroyPendingIO (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
while ( syncGroupNotify * pNotify = this->ioPendingList.first () ) {
|
||||
pNotify->cancel ( cbGuard, guard );
|
||||
// cancel must release the guard while
|
||||
// canceling put callbacks so we
|
||||
// must double check list membership
|
||||
if ( pNotify->ioPending ( guard ) ) {
|
||||
this->ioPendingList.remove ( *pNotify );
|
||||
}
|
||||
else {
|
||||
this->ioCompletedList.remove ( *pNotify );
|
||||
}
|
||||
pNotify->destroy ( cbGuard, guard );
|
||||
}
|
||||
}
|
||||
|
||||
void CASG::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->client.mutexRef () );
|
||||
this->show ( guard, level );
|
||||
}
|
||||
|
||||
void CASG::show (
|
||||
epicsGuard < epicsMutex > & guard, unsigned level ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
::printf ( "Sync Group: id=%u, magic=%u, opPend=%u\n",
|
||||
this->getId (), this->magic, this->ioPendingList.count () );
|
||||
if ( level ) {
|
||||
::printf ( "\tPending" );
|
||||
tsDLIterConst < syncGroupNotify > notifyPending =
|
||||
this->ioPendingList.firstIter ();
|
||||
while ( notifyPending.valid () ) {
|
||||
notifyPending->show ( guard, level - 1u );
|
||||
notifyPending++;
|
||||
}
|
||||
::printf ( "\tCompleted" );
|
||||
tsDLIterConst < syncGroupNotify > notifyCompleted =
|
||||
this->ioCompletedList.firstIter ();
|
||||
while ( notifyCompleted.valid () ) {
|
||||
notifyCompleted->show ( guard, level - 1u );
|
||||
notifyCompleted++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CASG::ioComplete (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->destroyCompletedIO ( cbGuard, guard );
|
||||
return this->ioPendingList.count () == 0u;
|
||||
}
|
||||
|
||||
void CASG::put ( epicsGuard < epicsMutex > & guard, chid pChan,
|
||||
unsigned type, arrayElementCount count, const void * pValue )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this );
|
||||
pNotify = syncGroupWriteNotify::factory (
|
||||
this->freeListWriteOP, *this, & CASG :: recycleWriteNotifyIO, pChan );
|
||||
pNotify->begin ( guard, type, count, pValue );
|
||||
pNotify.release ();
|
||||
}
|
||||
|
||||
void CASG::get ( epicsGuard < epicsMutex > & guard, chid pChan,
|
||||
unsigned type, arrayElementCount count, void *pValue )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this );
|
||||
pNotify = syncGroupReadNotify::factory (
|
||||
this->freeListReadOP, *this, & CASG :: recycleReadNotifyIO, pChan, pValue );
|
||||
pNotify->begin ( guard, type, count );
|
||||
pNotify.release ();
|
||||
}
|
||||
|
||||
void CASG::completionNotify (
|
||||
epicsGuard < epicsMutex > & guard, syncGroupNotify & notify )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->ioPendingList.remove ( notify );
|
||||
this->ioCompletedList.add ( notify );
|
||||
if ( this->ioPendingList.count () == 0u ) {
|
||||
this->sem.signal ();
|
||||
}
|
||||
}
|
||||
|
||||
void CASG :: recycleReadNotifyIO ( epicsGuard < epicsMutex > & guard,
|
||||
syncGroupReadNotify & io )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->freeListReadOP.release ( & io );
|
||||
}
|
||||
|
||||
void CASG :: recycleWriteNotifyIO ( epicsGuard < epicsMutex > & guard,
|
||||
syncGroupWriteNotify & io )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->freeListWriteOP.release ( & io );
|
||||
}
|
||||
|
||||
int CASG :: printFormated ( const char *pformat, ... )
|
||||
{
|
||||
va_list theArgs;
|
||||
int status;
|
||||
|
||||
va_start ( theArgs, pformat );
|
||||
|
||||
status = this->client.varArgsPrintFormated ( pformat, theArgs );
|
||||
|
||||
va_end ( theArgs );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void CASG::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
this->client.exception (
|
||||
guard, status, pContext, pFileName, lineNo );
|
||||
}
|
||||
}
|
||||
|
||||
void CASG::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo, oldChannelNotify & chan,
|
||||
unsigned type, arrayElementCount count, unsigned op )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
this->client.exception (
|
||||
guard, status, pContext, pFileName,
|
||||
lineNo, chan, type, count, op );
|
||||
}
|
||||
}
|
||||
|
||||
void CASG::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
4489
src/client/CAref.html
Normal file
4489
src/client/CAref.html
Normal file
File diff suppressed because it is too large
Load Diff
136
src/client/Makefile
Normal file
136
src/client/Makefile
Normal file
@@ -0,0 +1,136 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
TOP = ../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
HTMLS += CAref.html
|
||||
|
||||
#
|
||||
# includes to install from this subproject
|
||||
#
|
||||
INC += cadef.h
|
||||
INC += caerr.h
|
||||
INC += caeventmask.h
|
||||
INC += caProto.h
|
||||
INC += db_access.h
|
||||
INC += addrList.h
|
||||
INC += cacIO.h
|
||||
INC += caDiagnostics.h
|
||||
INC += net_convert.h
|
||||
INC += caVersion.h
|
||||
INC += caVersionNum.h
|
||||
|
||||
LIBSRCS += cac.cpp
|
||||
LIBSRCS += cacChannel.cpp
|
||||
LIBSRCS += cacChannelNotify.cpp
|
||||
LIBSRCS += cacContextNotify.cpp
|
||||
LIBSRCS += cacReadNotify.cpp
|
||||
LIBSRCS += cacWriteNotify.cpp
|
||||
LIBSRCS += cacStateNotify.cpp
|
||||
LIBSRCS += access.cpp
|
||||
LIBSRCS += iocinf.cpp
|
||||
LIBSRCS += convert.cpp
|
||||
LIBSRCS += test_event.cpp
|
||||
LIBSRCS += repeater.cpp
|
||||
LIBSRCS += searchTimer.cpp
|
||||
LIBSRCS += disconnectGovernorTimer.cpp
|
||||
LIBSRCS += repeaterSubscribeTimer.cpp
|
||||
LIBSRCS += baseNMIU.cpp
|
||||
LIBSRCS += nciu.cpp
|
||||
LIBSRCS += netiiu.cpp
|
||||
LIBSRCS += udpiiu.cpp
|
||||
LIBSRCS += tcpiiu.cpp
|
||||
LIBSRCS += noopiiu.cpp
|
||||
LIBSRCS += netReadNotifyIO.cpp
|
||||
LIBSRCS += netWriteNotifyIO.cpp
|
||||
LIBSRCS += netSubscription.cpp
|
||||
LIBSRCS += tcpSendWatchdog.cpp
|
||||
LIBSRCS += tcpRecvWatchdog.cpp
|
||||
LIBSRCS += bhe.cpp
|
||||
LIBSRCS += ca_client_context.cpp
|
||||
LIBSRCS += oldChannelNotify.cpp
|
||||
LIBSRCS += oldSubscription.cpp
|
||||
LIBSRCS += getCallback.cpp
|
||||
LIBSRCS += getCopy.cpp
|
||||
LIBSRCS += putCallback.cpp
|
||||
LIBSRCS += syncgrp.cpp
|
||||
LIBSRCS += CASG.cpp
|
||||
LIBSRCS += syncGroupNotify.cpp
|
||||
LIBSRCS += syncGroupReadNotify.cpp
|
||||
LIBSRCS += syncGroupWriteNotify.cpp
|
||||
LIBSRCS += localHostName.cpp
|
||||
LIBSRCS += comQueRecv.cpp
|
||||
LIBSRCS += comQueSend.cpp
|
||||
LIBSRCS += comBuf.cpp
|
||||
LIBSRCS += hostNameCache.cpp
|
||||
LIBSRCS += msgForMultiplyDefinedPV.cpp
|
||||
|
||||
LIBRARY=ca
|
||||
|
||||
ca_RCS = ca.rc
|
||||
|
||||
ca_LIBS = Com
|
||||
|
||||
ca_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
# libs needed for PROD and TESTPRODUCT
|
||||
PROD_LIBS = ca Com
|
||||
# needed when its an object library build
|
||||
PROD_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
PROD_DEFAULT += caRepeater catime acctst caConnTest casw caEventRate
|
||||
PROD_vxWorks = -nil-
|
||||
PROD_RTEMS = -nil-
|
||||
PROD_iOS = -nil-
|
||||
|
||||
OBJS_vxWorks = catime acctst caConnTest casw caEventRate acctstRegister
|
||||
|
||||
caRepeater_SRCS = caRepeater.cpp
|
||||
catime_SRCS = catimeMain.c catime.c
|
||||
acctst_SRCS = acctstMain.c acctst.c
|
||||
caEventRate_SRCS = caEventRateMain.cpp caEventRate.cpp
|
||||
casw_SRCS = casw.cpp
|
||||
caConnTest_SRCS = caConnTestMain.cpp caConnTest.cpp
|
||||
|
||||
casw_SYS_LIBS_solaris = socket
|
||||
|
||||
SCRIPTS_HOST = S99caRepeater
|
||||
SCRIPTS_Linux = caRepeater.service
|
||||
|
||||
EXPAND += S99caRepeater@
|
||||
EXPAND += caRepeater.service@
|
||||
EXPAND_VARS = INSTALL_BIN=$(abspath $(INSTALL_BIN))
|
||||
|
||||
SRC_DIRS += $(TOP)/src/client/test
|
||||
PROD_HOST += ca_test
|
||||
ca_test_SRCS = ca_test_main.c ca_test.c
|
||||
ca_test_LIBS = ca Com
|
||||
ca_test_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
OBJS_vxWorks += ca_test
|
||||
|
||||
EXPANDVARS += EPICS_CA_MAJOR_VERSION
|
||||
EXPANDVARS += EPICS_CA_MINOR_VERSION
|
||||
EXPANDVARS += EPICS_CA_MAINTENANCE_VERSION
|
||||
EXPANDVARS += EPICS_CA_DEVELOPMENT_FLAG
|
||||
|
||||
EXPANDFLAGS += $(foreach var,$(EXPANDVARS),-D$(var)="$(strip $($(var)))")
|
||||
|
||||
# shared library ABI version.
|
||||
SHRLIB_VERSION = 4.13.1
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
# Can't use EXPAND as generated headers must appear
|
||||
# in O.Common, but EXPAND emits rules for O.$(T_A)
|
||||
../O.Common/caVersionNum.h: ../caVersionNum.h@
|
||||
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
|
||||
28
src/client/S99caRepeater@
Normal file
28
src/client/S99caRepeater@
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# System-V init script for the EPICS CA Repeater.
|
||||
#
|
||||
|
||||
INSTALL_BIN=@INSTALL_BIN@
|
||||
|
||||
# To change the default values for the EPICS environment parameters,
|
||||
# uncomment and modify the relevant lines below. These are the only
|
||||
# EPICS environment variables that the CA Repeater makes use of.
|
||||
|
||||
# EPICS_CA_REPEATER_PORT="5065" export EPICS_CA_REPEATER_PORT
|
||||
|
||||
if [ $1 = "start" ]; then
|
||||
if [ -x $INSTALL_BIN/caRepeater ]; then
|
||||
echo "Starting EPICS CA Repeater "
|
||||
$INSTALL_BIN/caRepeater &
|
||||
fi
|
||||
else
|
||||
if [ $1 = "stop" ]; then
|
||||
pid=`ps -e | sed -ne '/caRepeat/s/^ *\([1-9][0-9]*\).*$/\1/p'`
|
||||
if [ "${pid}" != "" ]; then
|
||||
echo "Stopping EPICS CA Repeater "
|
||||
kill ${pid}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
39
src/client/SearchDest.h
Normal file
39
src/client/SearchDest.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef SearchDest_h
|
||||
#define SearchDest_h
|
||||
|
||||
#include <osiSock.h>
|
||||
#include <epicsTime.h>
|
||||
#include <tsDLList.h>
|
||||
#include "caProto.h"
|
||||
|
||||
class channelNode;
|
||||
class epicsMutex;
|
||||
template < class T > class epicsGuard;
|
||||
|
||||
struct SearchDest :
|
||||
public tsDLNode < SearchDest > {
|
||||
virtual ~SearchDest () {};
|
||||
struct Callback {
|
||||
virtual ~Callback () {};
|
||||
virtual void notify (
|
||||
const caHdr & msg, const void * pPayload,
|
||||
const osiSockAddr & addr, const epicsTime & ) = 0;
|
||||
virtual void show (
|
||||
epicsGuard < epicsMutex > &, unsigned level ) const = 0;
|
||||
};
|
||||
virtual void searchRequest ( epicsGuard < epicsMutex > &,
|
||||
const char * pbuf, size_t len ) = 0;
|
||||
virtual void show ( epicsGuard < epicsMutex > &, unsigned level ) const = 0;
|
||||
};
|
||||
|
||||
#endif // SearchDest_h
|
||||
1118
src/client/access.cpp
Normal file
1118
src/client/access.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3555
src/client/acctst.c
Normal file
3555
src/client/acctst.c
Normal file
File diff suppressed because it is too large
Load Diff
70
src/client/acctstMain.c
Normal file
70
src/client/acctstMain.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cadef.h"
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
int main ( int argc, char **argv )
|
||||
{
|
||||
unsigned progressLoggingLevel;
|
||||
unsigned channelCount;
|
||||
unsigned repetitionCount;
|
||||
enum ca_preemptive_callback_select preempt;
|
||||
int aBoolean;
|
||||
|
||||
|
||||
if ( argc < 2 || argc > 6 ) {
|
||||
printf ("usage: %s <PV name> [progress logging level] [channel count] "
|
||||
"[repetition count] [enable preemptive callback]\n",
|
||||
argv[0] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( argc >= 3 ) {
|
||||
progressLoggingLevel = atoi ( argv[2] );
|
||||
}
|
||||
else {
|
||||
progressLoggingLevel = 0;
|
||||
}
|
||||
|
||||
if ( argc >= 4 ) {
|
||||
channelCount = atoi ( argv[3] );
|
||||
}
|
||||
else {
|
||||
channelCount = 20000;
|
||||
}
|
||||
|
||||
if ( argc >= 5 ) {
|
||||
repetitionCount = atoi ( argv[4] );
|
||||
}
|
||||
else {
|
||||
repetitionCount = 1;
|
||||
}
|
||||
|
||||
if ( argc >= 6 ) {
|
||||
aBoolean = atoi ( argv[5] );
|
||||
}
|
||||
else {
|
||||
aBoolean = 0;
|
||||
}
|
||||
if ( aBoolean ) {
|
||||
preempt = ca_enable_preemptive_callback;
|
||||
}
|
||||
else {
|
||||
preempt = ca_disable_preemptive_callback;
|
||||
}
|
||||
|
||||
acctst ( argv[1], progressLoggingLevel, channelCount, repetitionCount, preempt );
|
||||
|
||||
return 0;
|
||||
}
|
||||
69
src/client/acctstRegister.cpp
Normal file
69
src/client/acctstRegister.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* CA client library diagnostics IOC shell registration
|
||||
* Authors:
|
||||
* Jeff Hill
|
||||
*/
|
||||
|
||||
#include <iocsh.h>
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
/* Information needed by iocsh */
|
||||
static const iocshArg acctstArg0 = { "channel name", iocshArgString };
|
||||
static const iocshArg acctstArg1 = { "interest level", iocshArgInt };
|
||||
static const iocshArg acctstArg2 = { "channel count", iocshArgInt };
|
||||
static const iocshArg acctstArg3 = { "repetition count", iocshArgInt };
|
||||
static const iocshArg acctstArg4 = { "preemptive callback select", iocshArgInt };
|
||||
|
||||
static const iocshArg *acctstArgs[] =
|
||||
{
|
||||
&acctstArg0,
|
||||
&acctstArg1,
|
||||
&acctstArg2,
|
||||
&acctstArg3,
|
||||
&acctstArg4
|
||||
};
|
||||
static const iocshFuncDef acctstFuncDef = {"acctst", 5, acctstArgs};
|
||||
|
||||
|
||||
/* Wrapper called by iocsh, selects the argument types that print needs */
|
||||
static void acctstCallFunc(const iocshArgBuf *args) {
|
||||
if ( args[1].ival < 0 ) {
|
||||
printf ( "negative interest level not allowed\n" );
|
||||
return;
|
||||
}
|
||||
if ( args[2].ival < 0 ) {
|
||||
printf ( "negative channel count not allowed\n" );
|
||||
return;
|
||||
}
|
||||
if ( args[3].ival < 0 ) {
|
||||
printf ( "negative repetition count not allowed\n" );
|
||||
return;
|
||||
}
|
||||
acctst (
|
||||
args[0].sval, /* channel name */
|
||||
( unsigned ) args[1].ival, /* interest level */
|
||||
( unsigned ) args[2].ival, /* channel count */
|
||||
( unsigned ) args[3].ival, /* repetition count */
|
||||
( ca_preemptive_callback_select ) args[4].ival ); /* preemptive callback select */
|
||||
}
|
||||
|
||||
struct AutoInit {
|
||||
AutoInit ();
|
||||
};
|
||||
|
||||
AutoInit :: AutoInit ()
|
||||
{
|
||||
iocshRegister ( &acctstFuncDef, acctstCallFunc );
|
||||
}
|
||||
|
||||
AutoInit autoInit;
|
||||
|
||||
40
src/client/addrList.h
Normal file
40
src/client/addrList.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef addrListh
|
||||
#define addrListh
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "envDefs.h"
|
||||
#include "osiSock.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareFunc void epicsShareAPI configureChannelAccessAddressList
|
||||
( struct ELLLIST *pList, SOCKET sock, unsigned short port );
|
||||
|
||||
epicsShareFunc int epicsShareAPI addAddrToChannelAccessAddressList
|
||||
( struct ELLLIST *pList, const ENV_PARAM *pEnv,
|
||||
unsigned short port, int ignoreNonDefaultPort );
|
||||
|
||||
epicsShareFunc void epicsShareAPI printChannelAccessAddressList
|
||||
( const struct ELLLIST *pList );
|
||||
|
||||
epicsShareFunc void epicsShareAPI removeDuplicateAddresses
|
||||
( struct ELLLIST *pDestList, ELLLIST *pSrcList, int silent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ifndef addrListh */
|
||||
|
||||
104
src/client/autoPtrFreeList.h
Normal file
104
src/client/autoPtrFreeList.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef autoPtrFreeListh
|
||||
#define autoPtrFreeListh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define autoPtrFreeListh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "tsFreeList.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef autoPtrFreeListh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
template < class T, unsigned N = 0x400, class MUTEX = epicsMutex >
|
||||
class autoPtrFreeList {
|
||||
public:
|
||||
autoPtrFreeList ( tsFreeList < T, N, MUTEX > &, T * );
|
||||
~autoPtrFreeList ();
|
||||
T & operator * () const;
|
||||
T * operator -> () const;
|
||||
T * get () const;
|
||||
T * release ();
|
||||
private:
|
||||
T * p;
|
||||
tsFreeList < T, N, MUTEX > & freeList;
|
||||
// not implemented
|
||||
autoPtrFreeList & operator = ( const autoPtrFreeList & );
|
||||
autoPtrFreeList ( const autoPtrFreeList < T, N, MUTEX > & );
|
||||
};
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline autoPtrFreeList < T, N, MUTEX >::autoPtrFreeList (
|
||||
tsFreeList < T, N, MUTEX > & freeListIn, T * pIn ) :
|
||||
p ( pIn ), freeList ( freeListIn ) {}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline autoPtrFreeList < T, N, MUTEX >::~autoPtrFreeList ()
|
||||
{
|
||||
if ( this->p ) {
|
||||
this->p->~T();
|
||||
// its probably a good idea to require that the class has placement delete
|
||||
// by calling it during cleanup if the compiler supports it
|
||||
# if defined ( CXX_PLACEMENT_DELETE )
|
||||
T::operator delete ( this->p, this->freeList );
|
||||
# else
|
||||
this->freeList.release ( this->p );
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline T & autoPtrFreeList < T, N, MUTEX >::operator * () const
|
||||
{
|
||||
return * this->p;
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline T * autoPtrFreeList < T, N, MUTEX >::operator -> () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline T * autoPtrFreeList < T, N, MUTEX >::get () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline T * autoPtrFreeList < T, N, MUTEX >::release ()
|
||||
{
|
||||
T *pTmp = this->p;
|
||||
this->p = 0;
|
||||
return pTmp;
|
||||
}
|
||||
|
||||
#endif // #ifdef autoPtrFreeListh
|
||||
92
src/client/autoPtrRecycle.h
Normal file
92
src/client/autoPtrRecycle.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef autoPtrRecycleh
|
||||
#define autoPtrRecycleh
|
||||
|
||||
template < class T >
|
||||
class autoPtrRecycle {
|
||||
public:
|
||||
autoPtrRecycle (
|
||||
epicsGuard < epicsMutex > &, chronIntIdResTable < baseNMIU > &,
|
||||
cacRecycle &, T * );
|
||||
~autoPtrRecycle ();
|
||||
T & operator * () const;
|
||||
T * operator -> () const;
|
||||
T * get () const;
|
||||
T * release ();
|
||||
private:
|
||||
T * p;
|
||||
cacRecycle & r;
|
||||
chronIntIdResTable < baseNMIU > & ioTable;
|
||||
epicsGuard < epicsMutex > & guard;
|
||||
// not implemented
|
||||
autoPtrRecycle ( const autoPtrRecycle & );
|
||||
autoPtrRecycle & operator = ( const autoPtrRecycle & );
|
||||
};
|
||||
|
||||
template < class T >
|
||||
inline autoPtrRecycle<T>::autoPtrRecycle (
|
||||
epicsGuard < epicsMutex > & guardIn, chronIntIdResTable < baseNMIU > & tbl,
|
||||
cacRecycle & rIn, T * pIn ) :
|
||||
p ( pIn ), r ( rIn ), ioTable ( tbl ), guard ( guardIn ) {}
|
||||
|
||||
template < class T >
|
||||
inline autoPtrRecycle<T>::~autoPtrRecycle ()
|
||||
{
|
||||
if ( this->p ) {
|
||||
baseNMIU *pb = this->p;
|
||||
this->ioTable.remove ( *pb );
|
||||
pb->destroy ( this->guard, this->r );
|
||||
}
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T & autoPtrRecycle<T>::operator * () const
|
||||
{
|
||||
return * this->p;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * autoPtrRecycle<T>::operator -> () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * autoPtrRecycle<T>::get () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * autoPtrRecycle<T>::release ()
|
||||
{
|
||||
T *pTmp = this->p;
|
||||
this->p = 0;
|
||||
return pTmp;
|
||||
}
|
||||
|
||||
#endif // #ifdef autoPtrRecycleh
|
||||
@@ -7,31 +7,33 @@
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* Breakpoint Tables
|
||||
|
||||
/*
|
||||
*
|
||||
* Author: Marty Kraimer
|
||||
* Date: 11-7-90
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, the Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#ifndef INCcvtTableh
|
||||
#define INCcvtTableh 1
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "iocinf.h"
|
||||
#include "nciu.h"
|
||||
#include "netIO.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Global Routines*/
|
||||
epicsShareFunc long cvtEngToRawBpt(
|
||||
double *pval,short linr,short init,void **ppbrk,short *plbrk);
|
||||
|
||||
epicsShareFunc long cvtRawToEngBpt(
|
||||
double *pval,short linr,short init,void **ppbrk, short *plbrk);
|
||||
|
||||
#ifdef __cplusplus
|
||||
baseNMIU::~baseNMIU ()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
void baseNMIU::forceSubscriptionUpdate (
|
||||
epicsGuard < epicsMutex > &, nciu & )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
358
src/client/bhe.cpp
Normal file
358
src/client/bhe.cpp
Normal file
@@ -0,0 +1,358 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "virtualCircuit.h"
|
||||
#include "bhe.h"
|
||||
|
||||
/*
|
||||
* set average to -1.0 so that when the next beacon
|
||||
* occurs we can distinguish between:
|
||||
* o new server
|
||||
* o existing server's beacon we are seeing
|
||||
* for the first time shortly after program
|
||||
* start up
|
||||
*
|
||||
* if creating this in response to a search reply
|
||||
* and not in response to a beacon then
|
||||
* we set the beacon time stamp to
|
||||
* zero (so we can correctly compute the period
|
||||
* between the 1st and 2nd beacons)
|
||||
*/
|
||||
bhe::bhe ( epicsMutex & mutexIn, const epicsTime & initialTimeStamp,
|
||||
unsigned initialBeaconNumber, const inetAddrID & addr ) :
|
||||
inetAddrID ( addr ), timeStamp ( initialTimeStamp ), averagePeriod ( - DBL_MAX ),
|
||||
mutex ( mutexIn ), pIIU ( 0 ), lastBeaconNumber ( initialBeaconNumber )
|
||||
{
|
||||
# ifdef DEBUG
|
||||
{
|
||||
char name[64];
|
||||
addr.name ( name, sizeof ( name ) );
|
||||
::printf ( "created beacon entry for %s\n", name );
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
bhe::~bhe ()
|
||||
{
|
||||
}
|
||||
|
||||
void bhe::beaconAnomalyNotify ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->pIIU ) {
|
||||
this->pIIU->beaconAnomalyNotify ( guard );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void bhe::logBeacon ( const char * pDiagnostic,
|
||||
const double & currentPeriod,
|
||||
const epicsTime & currentTime )
|
||||
{
|
||||
if ( this->pIIU ) {
|
||||
char name[64];
|
||||
this->name ( name, sizeof ( name ) );
|
||||
char date[64];
|
||||
currentTime.strftime ( date, sizeof ( date ),
|
||||
"%a %b %d %Y %H:%M:%S.%f");
|
||||
::printf ( "%s cp=%g ap=%g %s %s\n",
|
||||
pDiagnostic, currentPeriod,
|
||||
this->averagePeriod, name, date );
|
||||
}
|
||||
}
|
||||
#else
|
||||
inline void bhe::logBeacon ( const char * /* pDiagnostic */,
|
||||
const double & /* currentPeriod */,
|
||||
const epicsTime & /* currentTime */ )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
void bhe::logBeaconDiscard ( unsigned beaconAdvance,
|
||||
const epicsTime & currentTime )
|
||||
{
|
||||
if ( this->pIIU ) {
|
||||
char name[64];
|
||||
this->name ( name, sizeof ( name ) );
|
||||
char date[64];
|
||||
currentTime.strftime ( date, sizeof ( date ),
|
||||
"%a %b %d %Y %H:%M:%S.%f");
|
||||
::printf ( "bb %u %s %s\n",
|
||||
beaconAdvance, name, date );
|
||||
}
|
||||
}
|
||||
#else
|
||||
void bhe::logBeaconDiscard ( unsigned /* beaconAdvance */,
|
||||
const epicsTime & /* currentTime */ )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* update beacon period
|
||||
*
|
||||
* updates beacon period, and looks for beacon anomalies
|
||||
*/
|
||||
bool bhe::updatePeriod (
|
||||
epicsGuard < epicsMutex > & guard, const epicsTime & programBeginTime,
|
||||
const epicsTime & currentTime, ca_uint32_t beaconNumber,
|
||||
unsigned protocolRevision )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
|
||||
//
|
||||
// this block is enetered if the beacon was created as a side effect of
|
||||
// creating a connection and so we dont yet know the first beacon time
|
||||
// and sequence number
|
||||
//
|
||||
if ( this->timeStamp == epicsTime () ) {
|
||||
if ( CA_V410 ( protocolRevision ) ) {
|
||||
this->lastBeaconNumber = beaconNumber;
|
||||
}
|
||||
|
||||
this->beaconAnomalyNotify ( guard );
|
||||
|
||||
/*
|
||||
* this is the 1st beacon seen - the beacon time stamp
|
||||
* was not initialized during BHE create because
|
||||
* a TCP/IP connection created the beacon.
|
||||
* (nothing to do but set the beacon time stamp and return)
|
||||
*/
|
||||
this->timeStamp = currentTime;
|
||||
|
||||
logBeacon ( "fb", - DBL_MAX, currentTime );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1) detect beacon duplications due to redundant routes
|
||||
// 2) detect lost beacons due to input queue overrun or damage
|
||||
if ( CA_V410 ( protocolRevision ) ) {
|
||||
unsigned beaconSeqAdvance;
|
||||
if ( beaconNumber >= this->lastBeaconNumber ) {
|
||||
beaconSeqAdvance = beaconNumber - this->lastBeaconNumber;
|
||||
}
|
||||
else {
|
||||
beaconSeqAdvance = ( ca_uint32_max - this->lastBeaconNumber ) + beaconNumber;
|
||||
}
|
||||
this->lastBeaconNumber = beaconNumber;
|
||||
|
||||
// throw out sequence numbers just prior to, or the same as, the last one received
|
||||
// (this situation is probably caused by a temporary duplicate route )
|
||||
if ( beaconSeqAdvance == 0 || beaconSeqAdvance > ca_uint32_max - 256 ) {
|
||||
logBeaconDiscard ( beaconSeqAdvance, currentTime );
|
||||
return false;
|
||||
}
|
||||
|
||||
// throw out sequence numbers that jump forward by only a few numbers
|
||||
// (this situation is probably caused by a duplicate route
|
||||
// or a beacon due to input queue overun)
|
||||
if ( beaconSeqAdvance > 1 && beaconSeqAdvance < 4 ) {
|
||||
logBeaconDiscard ( beaconSeqAdvance, currentTime );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// compute the beacon period (if we have seen at least two beacons)
|
||||
bool netChange = false;
|
||||
double currentPeriod = currentTime - this->timeStamp;
|
||||
|
||||
if ( this->averagePeriod < 0.0 ) {
|
||||
double totalRunningTime;
|
||||
|
||||
this->beaconAnomalyNotify ( guard );
|
||||
|
||||
/*
|
||||
* this is the 2nd beacon seen. We cant tell about
|
||||
* the change in period at this point so we just
|
||||
* initialize the average period and return.
|
||||
*/
|
||||
this->averagePeriod = currentPeriod;
|
||||
|
||||
logBeacon ( "fp", currentPeriod, currentTime );
|
||||
|
||||
|
||||
/*
|
||||
* ignore beacons seen for the first time shortly after
|
||||
* init, but do not ignore beacons arriving with a short
|
||||
* period because the IOC was rebooted soon after the
|
||||
* client starts up.
|
||||
*/
|
||||
totalRunningTime = this->timeStamp - programBeginTime;
|
||||
if ( currentPeriod <= totalRunningTime ) {
|
||||
netChange = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
/*
|
||||
* Is this an IOC seen because of a restored
|
||||
* network segment?
|
||||
*
|
||||
* It may be possible to get false triggers here
|
||||
* if the client is busy, but this does not cause
|
||||
* problems because the echo response will tell us
|
||||
* that the server is available
|
||||
*/
|
||||
if ( currentPeriod >= this->averagePeriod * 1.25 ) {
|
||||
|
||||
/*
|
||||
* trigger on any missing beacon
|
||||
* if connected to this server
|
||||
*/
|
||||
this->beaconAnomalyNotify ( guard );
|
||||
|
||||
if ( currentPeriod >= this->averagePeriod * 3.25 ) {
|
||||
/*
|
||||
* trigger on any 3 contiguous missing beacons
|
||||
* if not connected to this server
|
||||
*/
|
||||
netChange = true;
|
||||
}
|
||||
logBeacon ( "bah", currentPeriod, currentTime );
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this an IOC seen because of an IOC reboot
|
||||
* (beacon come at a higher rate just after the
|
||||
* IOC reboots). Lower tolarance here because we
|
||||
* dont have to worry about lost beacons.
|
||||
*
|
||||
* It may be possible to get false triggers here
|
||||
* if the client is busy, but this does not cause
|
||||
* problems because the echo response will tell us
|
||||
* that the server is available
|
||||
*/
|
||||
else if ( currentPeriod <= this->averagePeriod * 0.80 ) {
|
||||
this->beaconAnomalyNotify ( guard );
|
||||
netChange = true;
|
||||
logBeacon ( "bal", currentPeriod, currentTime );
|
||||
}
|
||||
else if ( this->pIIU ) {
|
||||
// update state of health for active virtual circuits
|
||||
// if the beacon looks ok
|
||||
this->pIIU->beaconArrivalNotify ( guard );
|
||||
logBeacon ( "vb", currentPeriod, currentTime );
|
||||
}
|
||||
|
||||
// update a running average period
|
||||
this->averagePeriod = currentPeriod * 0.125 +
|
||||
this->averagePeriod * 0.875;
|
||||
}
|
||||
|
||||
this->timeStamp = currentTime;
|
||||
|
||||
return netChange;
|
||||
}
|
||||
|
||||
void bhe::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->show ( guard, level );
|
||||
}
|
||||
|
||||
void bhe::show ( epicsGuard < epicsMutex > &, unsigned level ) const
|
||||
{
|
||||
char host [64];
|
||||
this->name ( host, sizeof ( host ) );
|
||||
if ( this->averagePeriod == -DBL_MAX ) {
|
||||
::printf ( "CA beacon hash entry for %s <no period estimate>\n",
|
||||
host );
|
||||
}
|
||||
else {
|
||||
::printf ( "CA beacon hash entry for %s with period estimate %f\n",
|
||||
host, this->averagePeriod );
|
||||
}
|
||||
if ( level > 0u ) {
|
||||
char date[64];
|
||||
this->timeStamp.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
|
||||
::printf ( "\tbeacon number %u, on %s\n",
|
||||
this->lastBeaconNumber, date );
|
||||
}
|
||||
}
|
||||
|
||||
double bhe::period ( epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->averagePeriod;
|
||||
}
|
||||
|
||||
epicsTime bhe::updateTime ( epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->timeStamp;
|
||||
}
|
||||
|
||||
void bhe::registerIIU (
|
||||
epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->pIIU = & iiu;
|
||||
}
|
||||
|
||||
void bhe::unregisterIIU (
|
||||
epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->pIIU == & iiu ) {
|
||||
this->pIIU = 0;
|
||||
this->timeStamp = epicsTime();
|
||||
this->averagePeriod = - DBL_MAX;
|
||||
logBeacon ( "ui", this->averagePeriod, epicsTime::getCurrent () );
|
||||
}
|
||||
}
|
||||
|
||||
void bhe::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
void * bheFreeStore::allocate ( size_t size )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
void bheFreeStore::release ( void * pCadaver )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
|
||||
bheMemoryManager::~bheMemoryManager () {}
|
||||
|
||||
|
||||
122
src/client/bhe.h
Normal file
122
src/client/bhe.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#ifndef bheh
|
||||
#define bheh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define bhehEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "epicsTime.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef bhehEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
#include "inetAddrID.h"
|
||||
#include "caProto.h"
|
||||
|
||||
class tcpiiu;
|
||||
class bheMemoryManager;
|
||||
|
||||
// using a pure abstract wrapper class around the free list avoids
|
||||
// Tornado 2.0.1 GNU compiler bugs
|
||||
class epicsShareClass bheMemoryManager {
|
||||
public:
|
||||
virtual ~bheMemoryManager ();
|
||||
virtual void * allocate ( size_t ) = 0;
|
||||
virtual void release ( void * ) = 0;
|
||||
};
|
||||
|
||||
class bhe : public tsSLNode < bhe >, public inetAddrID {
|
||||
public:
|
||||
epicsShareFunc bhe (
|
||||
epicsMutex &, const epicsTime & initialTimeStamp,
|
||||
unsigned initialBeaconNumber, const inetAddrID & addr );
|
||||
epicsShareFunc ~bhe ();
|
||||
epicsShareFunc bool updatePeriod (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const epicsTime & programBeginTime,
|
||||
const epicsTime & currentTime, ca_uint32_t beaconNumber,
|
||||
unsigned protocolRevision );
|
||||
epicsShareFunc double period ( epicsGuard < epicsMutex > & ) const;
|
||||
epicsShareFunc epicsTime updateTime ( epicsGuard < epicsMutex > & ) const;
|
||||
epicsShareFunc void show ( unsigned level ) const;
|
||||
epicsShareFunc void show ( epicsGuard < epicsMutex > &, unsigned /* level */ ) const;
|
||||
epicsShareFunc void registerIIU ( epicsGuard < epicsMutex > &, tcpiiu & );
|
||||
epicsShareFunc void unregisterIIU ( epicsGuard < epicsMutex > &, tcpiiu & );
|
||||
epicsShareFunc void * operator new ( size_t size, bheMemoryManager & );
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
epicsShareFunc void operator delete ( void *, bheMemoryManager & );
|
||||
#endif
|
||||
private:
|
||||
epicsTime timeStamp;
|
||||
double averagePeriod;
|
||||
epicsMutex & mutex;
|
||||
tcpiiu * pIIU;
|
||||
ca_uint32_t lastBeaconNumber;
|
||||
void beaconAnomalyNotify ( epicsGuard < epicsMutex > & );
|
||||
void logBeacon ( const char * pDiagnostic,
|
||||
const double & currentPeriod,
|
||||
const epicsTime & currentTime );
|
||||
void logBeaconDiscard ( unsigned beaconAdvance,
|
||||
const epicsTime & currentTime );
|
||||
bhe ( const bhe & );
|
||||
bhe & operator = ( const bhe & );
|
||||
epicsShareFunc void operator delete ( void * );
|
||||
};
|
||||
|
||||
// using a wrapper class around the free list avoids
|
||||
// Tornado 2.0.1 GNU compiler bugs
|
||||
class bheFreeStore : public bheMemoryManager {
|
||||
public:
|
||||
bheFreeStore () {}
|
||||
void * allocate ( size_t );
|
||||
void release ( void * );
|
||||
private:
|
||||
tsFreeList < bhe, 0x100 > freeList;
|
||||
bheFreeStore ( const bheFreeStore & );
|
||||
bheFreeStore & operator = ( const bheFreeStore & );
|
||||
};
|
||||
|
||||
inline void * bhe::operator new ( size_t size,
|
||||
bheMemoryManager & mgr )
|
||||
{
|
||||
return mgr.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void bhe::operator delete ( void * pCadaver,
|
||||
bheMemoryManager & mgr )
|
||||
{
|
||||
mgr.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ifdef bheh
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ BEGIN
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "Comments","Soft Device Support Library for EPICS\0"
|
||||
VALUE "Comments","Channel Access Library for EPICS\0"
|
||||
VALUE "CompanyName", "The EPICS collaboration\0"
|
||||
VALUE "FileDescription", "Soft Device Support Library\0"
|
||||
VALUE "FileDescription", "Channel Access Library\0"
|
||||
VALUE "FileVersion", EPICS_VERSION_STRING "\0"
|
||||
VALUE "InternalName", "softDevIoc\0"
|
||||
VALUE "InternalName", "ca\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) Univ. of California, Univ. of Chicago\0"
|
||||
VALUE "OriginalFilename", "softDevIoc.dll\0"
|
||||
VALUE "OriginalFilename", "ca.dll\0"
|
||||
VALUE "ProductName", "Experimental Physics and Industrial Control System (EPICS)\0"
|
||||
VALUE "ProductVersion", EPICS_VERSION_STRING "\0"
|
||||
END
|
||||
109
src/client/caConnTest.cpp
Normal file
109
src/client/caConnTest.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "cadef.h"
|
||||
#include "epicsTime.h"
|
||||
|
||||
static unsigned channelCount = 0u;
|
||||
static unsigned connCount = 0u;
|
||||
static bool subsequentConnect = false;
|
||||
|
||||
epicsTime begin;
|
||||
|
||||
extern "C" void caConnTestConnHandler ( struct connection_handler_args args )
|
||||
{
|
||||
if ( args.op == CA_OP_CONN_UP ) {
|
||||
if ( connCount == 0u ) {
|
||||
if ( subsequentConnect ) {
|
||||
printf ("the first channel connected\n");
|
||||
begin = epicsTime::getCurrent ();
|
||||
}
|
||||
}
|
||||
connCount++;
|
||||
// printf ( "." );
|
||||
// fflush ( stdout );
|
||||
if ( connCount == channelCount ) {
|
||||
epicsTime current = epicsTime::getCurrent ();
|
||||
double delay = current - begin;
|
||||
printf ( "all channels connected after %f sec ( %f sec per channel)\n",
|
||||
delay, delay / channelCount );
|
||||
}
|
||||
}
|
||||
else if ( args.op == CA_OP_CONN_DOWN ) {
|
||||
if ( connCount == channelCount ) {
|
||||
printf ( "channels are disconnected\n" );
|
||||
subsequentConnect = true;
|
||||
}
|
||||
connCount--;
|
||||
if ( connCount == 0u ) {
|
||||
printf ( "all channels are disconnected\n" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert ( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void caConnTest ( const char *pNameIn, unsigned channelCountIn, double delayIn )
|
||||
{
|
||||
unsigned iteration = 0u;
|
||||
int status;
|
||||
unsigned i;
|
||||
chid *pChans;
|
||||
|
||||
channelCount = channelCountIn;
|
||||
|
||||
pChans = new chid [channelCount];
|
||||
|
||||
while ( 1 ) {
|
||||
connCount = 0u;
|
||||
subsequentConnect = false;
|
||||
begin = epicsTime::getCurrent ();
|
||||
|
||||
printf ( "initializing CA client library\n" );
|
||||
|
||||
status = ca_task_initialize();
|
||||
SEVCHK ( status, "CA init failed" );
|
||||
|
||||
printf ( "creating channels\n" );
|
||||
|
||||
for ( i = 0u; i < channelCount; i++ ) {
|
||||
status = ca_search_and_connect ( pNameIn,
|
||||
&pChans[i], caConnTestConnHandler, 0 );
|
||||
SEVCHK ( status, "CA search problems" );
|
||||
}
|
||||
|
||||
printf ( "all channels were created\n" );
|
||||
|
||||
ca_pend_event ( delayIn );
|
||||
|
||||
if ( iteration & 1 ) {
|
||||
for ( i = 0u; i < channelCount; i++ ) {
|
||||
status = ca_clear_channel ( pChans[i] );
|
||||
SEVCHK ( status, "ca_clear_channel() problems" );
|
||||
}
|
||||
printf ( "all channels were destroyed\n" );
|
||||
}
|
||||
|
||||
printf ( "shutting down CA client library\n" );
|
||||
|
||||
status = ca_task_exit ();
|
||||
SEVCHK ( status, "task exit problems" );
|
||||
|
||||
iteration++;
|
||||
}
|
||||
|
||||
//delete [] pChans;
|
||||
}
|
||||
45
src/client/caConnTestMain.cpp
Normal file
45
src/client/caConnTestMain.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <epicsStdlib.h>
|
||||
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
int main ( int argc, char **argv )
|
||||
{
|
||||
double delay = 60.0 * 5.0;
|
||||
unsigned count = 2000;
|
||||
|
||||
if ( argc < 2 || argc > 4 ) {
|
||||
printf ( "usage: %s < channel name > [ < count > ] [ < delay sec > ]\n", argv[0] );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( argc >= 3 ) {
|
||||
int nConverted = sscanf ( argv[2], "%u", &count );
|
||||
if ( nConverted != 1 ) {
|
||||
printf ( "conversion failed, changing channel count arg \"%s\" to %u\n",
|
||||
argv[1], count );
|
||||
}
|
||||
}
|
||||
|
||||
if ( argc >= 4 ) {
|
||||
int nConverted = epicsScanDouble( argv[3], &delay );
|
||||
if ( nConverted != 1 ) {
|
||||
printf ( "conversion failed, changing delay arg \"%s\" to %f\n",
|
||||
argv[2], delay );
|
||||
}
|
||||
}
|
||||
|
||||
caConnTest ( argv[1], count, delay );
|
||||
|
||||
return 0;
|
||||
}
|
||||
38
src/client/caDiagnostics.h
Normal file
38
src/client/caDiagnostics.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef caDiagnosticsh
|
||||
#define caDiagnosticsh
|
||||
|
||||
#include "cadef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum appendNumberFlag {appendNumber, dontAppendNumber};
|
||||
int catime ( const char *channelName, unsigned channelCount, enum appendNumberFlag appNF );
|
||||
|
||||
int acctst ( const char *pname, unsigned logggingInterestLevel,
|
||||
unsigned channelCount, unsigned repetitionCount,
|
||||
enum ca_preemptive_callback_select select );
|
||||
|
||||
#define CATIME_OK 0
|
||||
#define CATIME_ERROR -1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void caConnTest ( const char *pNameIn, unsigned channelCountIn, double delayIn );
|
||||
|
||||
#endif /* caDiagnosticsh */
|
||||
|
||||
|
||||
139
src/client/caEventRate.cpp
Normal file
139
src/client/caEventRate.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "cadef.h"
|
||||
#include "dbDefs.h"
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
|
||||
/*
|
||||
* event_handler()
|
||||
*/
|
||||
extern "C" void eventCallBack ( struct event_handler_args args )
|
||||
{
|
||||
unsigned *pCount = static_cast < unsigned * > ( args.usr );
|
||||
(*pCount)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* caEventRate ()
|
||||
*/
|
||||
void caEventRate ( const char *pName, unsigned count )
|
||||
{
|
||||
static const double initialSamplePeriod = 1.0;
|
||||
static const double maxSamplePeriod = 60.0 * 5.0;
|
||||
unsigned eventCount = 0u;
|
||||
|
||||
chid * pChidTable = new chid [ count ];
|
||||
|
||||
{
|
||||
printf ( "Connecting to CA Channel \"%s\" %u times.",
|
||||
pName, count );
|
||||
fflush ( stdout );
|
||||
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
for ( unsigned i = 0u; i < count; i++ ) {
|
||||
int status = ca_search ( pName, & pChidTable[i] );
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
|
||||
int status = ca_pend_io ( 10000.0 );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
fprintf ( stderr, " not found.\n" );
|
||||
return;
|
||||
}
|
||||
epicsTime end = epicsTime::getCurrent ();
|
||||
|
||||
printf ( " done(%f sec).\n", end - begin );
|
||||
}
|
||||
|
||||
{
|
||||
printf ( "Subscribing %u times.", count );
|
||||
fflush ( stdout );
|
||||
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
for ( unsigned i = 0u; i < count; i++ ) {
|
||||
int addEventStatus = ca_add_event ( DBR_FLOAT,
|
||||
pChidTable[i], eventCallBack, &eventCount, NULL);
|
||||
SEVCHK ( addEventStatus, __FILE__ );
|
||||
}
|
||||
|
||||
int status = ca_flush_io ();
|
||||
SEVCHK ( status, __FILE__ );
|
||||
|
||||
epicsTime end = epicsTime::getCurrent ();
|
||||
|
||||
printf ( " done(%f sec).\n", end - begin );
|
||||
}
|
||||
|
||||
{
|
||||
printf ( "Waiting for initial value events." );
|
||||
fflush ( stdout );
|
||||
|
||||
// let the first one go by
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
while ( eventCount < count ) {
|
||||
int status = ca_pend_event ( 0.01 );
|
||||
if ( status != ECA_TIMEOUT ) {
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
}
|
||||
epicsTime end = epicsTime::getCurrent ();
|
||||
|
||||
printf ( " done(%f sec).\n", end - begin );
|
||||
}
|
||||
|
||||
double samplePeriod = initialSamplePeriod;
|
||||
double X = 0.0;
|
||||
double XX = 0.0;
|
||||
unsigned N = 0u;
|
||||
while ( true ) {
|
||||
unsigned nEvents, lastEventCount, curEventCount;
|
||||
|
||||
epicsTime beginPend = epicsTime::getCurrent ();
|
||||
lastEventCount = eventCount;
|
||||
int status = ca_pend_event ( samplePeriod );
|
||||
curEventCount = eventCount;
|
||||
epicsTime endPend = epicsTime::getCurrent ();
|
||||
if ( status != ECA_TIMEOUT ) {
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
|
||||
if ( curEventCount >= lastEventCount ) {
|
||||
nEvents = curEventCount - lastEventCount;
|
||||
}
|
||||
else {
|
||||
nEvents = ( UINT_MAX - lastEventCount ) + curEventCount + 1u;
|
||||
}
|
||||
|
||||
N++;
|
||||
|
||||
double period = endPend - beginPend;
|
||||
double Hz = nEvents / period;
|
||||
|
||||
X += Hz;
|
||||
XX += Hz * Hz;
|
||||
|
||||
double mean = X / N;
|
||||
double stdDev = sqrt ( XX / N - mean * mean );
|
||||
|
||||
printf ( "CA Event Rate (Hz): current %g mean %g std dev %g\n",
|
||||
Hz, mean, stdDev );
|
||||
|
||||
if ( samplePeriod < maxSamplePeriod ) {
|
||||
samplePeriod += samplePeriod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
src/client/caEventRateMain.cpp
Normal file
38
src/client/caEventRateMain.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void caEventRate ( const char *pName, unsigned count );
|
||||
|
||||
int main ( int argc, char **argv )
|
||||
{
|
||||
if ( argc < 2 || argc > 3 ) {
|
||||
fprintf ( stderr, "usage: %s < PV name > [subscription count]\n", argv[0] );
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned count;
|
||||
if ( argc == 3 ) {
|
||||
int status = sscanf ( argv[2], " %u ", & count );
|
||||
if ( status != 1 ) {
|
||||
fprintf ( stderr, "expected unsigned integer 2nd argument\n" );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
count = 1;
|
||||
}
|
||||
|
||||
caEventRate ( argv[1], count );
|
||||
|
||||
return 0;
|
||||
}
|
||||
187
src/client/caProto.h
Normal file
187
src/client/caProto.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef __CAPROTO__
|
||||
#define __CAPROTO__
|
||||
|
||||
#define capStrOf(A) #A
|
||||
#define capStrOfX(A) capStrOf ( A )
|
||||
|
||||
/*
|
||||
* CA protocol revision
|
||||
* TCP/UDP port number (bumped each major protocol change)
|
||||
*/
|
||||
#define CA_MAJOR_PROTOCOL_REVISION 4
|
||||
#define CA_VERSION_STRING( MINOR_REVISION ) \
|
||||
( capStrOfX ( CA_MAJOR_PROTOCOL_REVISION ) "." capStrOfX ( MINOR_REVISION ) )
|
||||
#define CA_UKN_MINOR_VERSION 0u /* unknown minor version */
|
||||
#define CA_MINIMUM_SUPPORTED_VERSION 4u
|
||||
# define CA_VSUPPORTED(MINOR) ((MINOR)>=CA_MINIMUM_SUPPORTED_VERSION)
|
||||
# define CA_V41(MINOR) ((MINOR)>=1u)
|
||||
# define CA_V42(MINOR) ((MINOR)>=2u)
|
||||
# define CA_V43(MINOR) ((MINOR)>=3u)
|
||||
# define CA_V44(MINOR) ((MINOR)>=4u)
|
||||
# define CA_V45(MINOR) ((MINOR)>=5u)
|
||||
# define CA_V46(MINOR) ((MINOR)>=6u)
|
||||
# define CA_V47(MINOR) ((MINOR)>=7u)
|
||||
# define CA_V48(MINOR) ((MINOR)>=8u)
|
||||
# define CA_V49(MINOR) ((MINOR)>=9u) /* large arrays, dispatch priorities */
|
||||
# define CA_V410(MINOR) ((MINOR)>=10u) /* beacon counter */
|
||||
# define CA_V411(MINOR) ((MINOR)>=11u) /* sequence numbers in UDP version command */
|
||||
# define CA_V412(MINOR) ((MINOR)>=12u) /* TCP-based search requests */
|
||||
# define CA_V413(MINOR) ((MINOR)>=13u) /* Allow zero length in requests. */
|
||||
|
||||
/*
|
||||
* These port numbers are only used if the CA repeater and
|
||||
* CA server port numbers cant be obtained from the EPICS
|
||||
* environment variables "EPICS_CA_REPEATER_PORT" and
|
||||
* "EPICS_CA_SERVER_PORT"
|
||||
*/
|
||||
#define CA_PORT_BASE IPPORT_USERRESERVED + 56U
|
||||
#define CA_SERVER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*2u)
|
||||
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*2u+1u)
|
||||
|
||||
/*
|
||||
* 1500 (max of ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP)
|
||||
* (the MTU of Ethernet is currently independent of its speed varient)
|
||||
*/
|
||||
#define ETHERNET_MAX_UDP ( 1500u - 20u - 8u )
|
||||
#define MAX_UDP_RECV ( 0xffff + 16u ) /* allow large frames to be received in the future */
|
||||
#define MAX_UDP_SEND 1024u /* original MAX_UDP */
|
||||
#define MAX_TCP ( 1024 * 16u ) /* so waveforms fit */
|
||||
#define MAX_MSG_SIZE ( MAX_TCP ) /* the larger of tcp and udp max */
|
||||
|
||||
#define CA_PROTO_PRIORITY_MIN 0u
|
||||
#define CA_PROTO_PRIORITY_MAX 99u
|
||||
|
||||
/*
|
||||
* architecture independent types
|
||||
*
|
||||
* (so far this works on all archs we have ported to)
|
||||
*/
|
||||
typedef unsigned char ca_uint8_t;
|
||||
typedef unsigned short ca_uint16_t;
|
||||
typedef unsigned int ca_uint32_t;
|
||||
typedef float ca_float32_t;
|
||||
typedef ca_uint32_t caResId;
|
||||
|
||||
#define ca_uint32_max 0xffffffff
|
||||
|
||||
/* values for m_cmmd */
|
||||
#define CA_PROTO_VERSION 0u /* set minor version and priority (used to be NOOP cmd) */
|
||||
#define CA_PROTO_EVENT_ADD 1u /* add an event */
|
||||
#define CA_PROTO_EVENT_CANCEL 2u /* cancel an event */
|
||||
#define CA_PROTO_READ 3u /* read and return a channel value*/
|
||||
#define CA_PROTO_WRITE 4u /* write a channel value */
|
||||
#define CA_PROTO_SNAPSHOT 5u /* snapshot of the system */
|
||||
#define CA_PROTO_SEARCH 6u /* IOC channel search */
|
||||
#define CA_PROTO_BUILD 7u /* build - obsolete */
|
||||
#define CA_PROTO_EVENTS_OFF 8u /* flow control */
|
||||
#define CA_PROTO_EVENTS_ON 9u /* flow control */
|
||||
#define CA_PROTO_READ_SYNC 10u /* purge old reads */
|
||||
#define CA_PROTO_ERROR 11u /* an operation failed */
|
||||
#define CA_PROTO_CLEAR_CHANNEL 12u /* free chan resources */
|
||||
#define CA_PROTO_RSRV_IS_UP 13u /* CA server has joined the net */
|
||||
#define CA_PROTO_NOT_FOUND 14u /* channel not found */
|
||||
#define CA_PROTO_READ_NOTIFY 15u /* add a one shot event */
|
||||
#define CA_PROTO_READ_BUILD 16u /* read and build - obsolete */
|
||||
#define REPEATER_CONFIRM 17u /* registration confirmation */
|
||||
#define CA_PROTO_CREATE_CHAN 18u /* client creates channel in server */
|
||||
#define CA_PROTO_WRITE_NOTIFY 19u /* notify after write chan value */
|
||||
#define CA_PROTO_CLIENT_NAME 20u /* CA V4.1 identify client */
|
||||
#define CA_PROTO_HOST_NAME 21u /* CA V4.1 identify client */
|
||||
#define CA_PROTO_ACCESS_RIGHTS 22u /* CA V4.2 asynch access rights chg */
|
||||
#define CA_PROTO_ECHO 23u /* CA V4.3 connection verify */
|
||||
#define REPEATER_REGISTER 24u /* register for repeater fan out */
|
||||
#define CA_PROTO_SIGNAL 25u /* knock the server out of select */
|
||||
#define CA_PROTO_CREATE_CH_FAIL 26u /* unable to create chan resource in server */
|
||||
#define CA_PROTO_SERVER_DISCONN 27u /* server deletes PV (or channel) */
|
||||
|
||||
#define CA_PROTO_LAST_CMMD CA_PROTO_SERVER_DISCONN
|
||||
|
||||
/*
|
||||
* for use with search and not_found (if search fails and
|
||||
* its not a broadcast tell the client to look elesewhere)
|
||||
*/
|
||||
#define DOREPLY 10u
|
||||
#define DONTREPLY 5u
|
||||
|
||||
/*
|
||||
* for use with the m_dataType field in UDP messages emitted by servers
|
||||
*/
|
||||
#define sequenceNoIsValid 1
|
||||
|
||||
/* size of object in bytes rounded up to nearest oct word */
|
||||
#define OCT_ROUND(A) (((A)+7)/8)
|
||||
#define OCT_SIZEOF(A) (OCT_ROUND(sizeof(A)))
|
||||
|
||||
/* size of object in bytes rounded up to nearest long word */
|
||||
#define QUAD_ROUND(A) ((A)+3)/4)
|
||||
#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A)))
|
||||
|
||||
/* size of object in bytes rounded up to nearest short word */
|
||||
#define BI_ROUND(A) (((A)+1)/2)
|
||||
#define BI_SIZEOF(A) (BI_ROUND(sizeof(A)))
|
||||
|
||||
/*
|
||||
* For communicating access rights to the clients
|
||||
*
|
||||
* (placed in m_available hdr field of CA_PROTO_ACCESS_RIGHTS cmmd
|
||||
*/
|
||||
#define CA_PROTO_ACCESS_RIGHT_READ (1u<<0u)
|
||||
#define CA_PROTO_ACCESS_RIGHT_WRITE (1u<<1u)
|
||||
|
||||
/*
|
||||
* All structures passed in the protocol must have individual
|
||||
* fields aligned on natural boundaries.
|
||||
*
|
||||
* NOTE: all structures declared in this file must have a
|
||||
* byte count which is evenly divisible by 8 matching
|
||||
* the largest atomic data type in db_access.h.
|
||||
*/
|
||||
#define CA_MESSAGE_ALIGN(A) (OCT_ROUND(A)<<3u)
|
||||
|
||||
/*
|
||||
* the common part of each message sent/recv by the
|
||||
* CA server.
|
||||
*/
|
||||
typedef struct ca_hdr {
|
||||
ca_uint16_t m_cmmd; /* operation to be performed */
|
||||
ca_uint16_t m_postsize; /* size of payload */
|
||||
ca_uint16_t m_dataType; /* operation data type */
|
||||
ca_uint16_t m_count; /* operation data count */
|
||||
ca_uint32_t m_cid; /* channel identifier */
|
||||
ca_uint32_t m_available; /* protocol stub dependent */
|
||||
} caHdr;
|
||||
|
||||
/*
|
||||
* for monitor (event) message extension
|
||||
*/
|
||||
struct mon_info {
|
||||
ca_float32_t m_lval; /* low delta */
|
||||
ca_float32_t m_hval; /* high delta */
|
||||
ca_float32_t m_toval; /* period btween samples */
|
||||
ca_uint16_t m_mask; /* event select mask */
|
||||
ca_uint16_t m_pad; /* extend to 32 bits */
|
||||
};
|
||||
|
||||
/*
|
||||
* PV names greater than this length assumed to be invalid
|
||||
*/
|
||||
#define unreasonablePVNameSize 500u
|
||||
|
||||
#endif /* __CAPROTO__ */
|
||||
|
||||
42
src/client/caRepeater.cpp
Normal file
42
src/client/caRepeater.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* CA UDP repeater standalone executable
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
* Date: 3-27-90
|
||||
*
|
||||
* PURPOSE:
|
||||
* Broadcasts fan out over the LAN, but old IP kernels do not allow
|
||||
* two processes on the same machine to get the same broadcast
|
||||
* (and modern IP kernels do not allow two processes on the same machine
|
||||
* to receive the same unicast).
|
||||
*
|
||||
* This code fans out UDP messages sent to the CA repeater port
|
||||
* to all CA client processes that have subscribed.
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
* see repeater.c
|
||||
*
|
||||
*/
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "udpiiu.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
ca_repeater ();
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
25
src/client/caRepeater.service@
Normal file
25
src/client/caRepeater.service@
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# Linux systemd service file for the EPICS CA Repeater
|
||||
#
|
||||
# To install this file, as root:
|
||||
# cp caRepeater.service /etc/systemd/system
|
||||
# chmod 664 /etc/systemd/system/caRepeater.service
|
||||
# systemctl daemon-reload
|
||||
# systemctl enable caRepeater
|
||||
# systemctl start caRepeater
|
||||
#
|
||||
# To check the status:
|
||||
# systemctl status caRepeater
|
||||
|
||||
[Unit]
|
||||
Description=EPICS CA Repeater
|
||||
Requires=network.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@INSTALL_BIN@/caRepeater
|
||||
Restart=always
|
||||
User=daemon
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
88
src/client/caServerID.h
Normal file
88
src/client/caServerID.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#ifndef caServerIDh
|
||||
#define caServerIDh
|
||||
|
||||
#include "osiSock.h"
|
||||
#include "resourceLib.h"
|
||||
#include "caProto.h"
|
||||
|
||||
class caServerID {
|
||||
public:
|
||||
caServerID ( const struct sockaddr_in & addrIn, unsigned priority );
|
||||
bool operator == ( const caServerID & ) const;
|
||||
resTableIndex hash () const;
|
||||
osiSockAddr address () const;
|
||||
unsigned priority () const;
|
||||
private:
|
||||
struct sockaddr_in addr;
|
||||
ca_uint8_t pri;
|
||||
};
|
||||
|
||||
inline caServerID::caServerID (
|
||||
const struct sockaddr_in & addrIn, unsigned priorityIn ) :
|
||||
addr ( addrIn ), pri ( static_cast <ca_uint8_t> ( priorityIn ) )
|
||||
{
|
||||
assert ( priorityIn <= 0xff );
|
||||
}
|
||||
|
||||
inline bool caServerID::operator == ( const caServerID & rhs ) const
|
||||
{
|
||||
if ( this->addr.sin_addr.s_addr == rhs.addr.sin_addr.s_addr &&
|
||||
this->addr.sin_port == rhs.addr.sin_port &&
|
||||
this->pri == rhs.pri ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline resTableIndex caServerID::hash () const
|
||||
{
|
||||
// start with a very small server table to speed
|
||||
// up the flush traverse for the frequent case -
|
||||
// a small numbers of servers
|
||||
const unsigned caServerMinIndexBitWidth = 2u;
|
||||
const unsigned caServerMaxIndexBitWidth = 32u;
|
||||
|
||||
unsigned index;
|
||||
index = this->addr.sin_addr.s_addr;
|
||||
index ^= this->addr.sin_port;
|
||||
index ^= this->addr.sin_port >> 8u;
|
||||
index ^= this->pri;
|
||||
return integerHash ( caServerMinIndexBitWidth,
|
||||
caServerMaxIndexBitWidth, index );
|
||||
}
|
||||
|
||||
inline osiSockAddr caServerID::address () const
|
||||
{
|
||||
osiSockAddr tmp;
|
||||
tmp.ia = this->addr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline unsigned caServerID::priority () const
|
||||
{
|
||||
return this->pri;
|
||||
}
|
||||
|
||||
#endif // ifdef caServerID
|
||||
|
||||
|
||||
@@ -5,23 +5,24 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef DATABASEVERSION_H
|
||||
#define DATABASEVERSION_H
|
||||
#ifndef CAVERSION_H
|
||||
#define CAVERSION_H
|
||||
|
||||
#include <epicsVersion.h>
|
||||
#include <shareLib.h>
|
||||
|
||||
#ifndef VERSION_INT
|
||||
# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
|
||||
#endif
|
||||
|
||||
/* include generated headers with:
|
||||
* EPICS_DATABASE_MAJOR_VERSION
|
||||
* EPICS_DATABASE_MINOR_VERSION
|
||||
* EPICS_DATABASE_MAINTENANCE_VERSION
|
||||
* EPICS_DATABASE_DEVELOPMENT_FLAG
|
||||
* EPICS_CA_MAJOR_VERSION
|
||||
* EPICS_CA_MINOR_VERSION
|
||||
* EPICS_CA_MAINTENANCE_VERSION
|
||||
* EPICS_CA_DEVELOPMENT_FLAG
|
||||
*/
|
||||
#include "databaseVersionNum.h"
|
||||
#include "caVersionNum.h"
|
||||
|
||||
#define DATABASE_VERSION_INT VERSION_INT(EPICS_DATABASE_MAJOR_VERSION, EPICS_DATABASE_MINOR_VERSION, EPICS_DATABASE_MAINTENANCE_VERSION, 0)
|
||||
#define CA_VERSION_INT VERSION_INT(EPICS_CA_MAJOR_VERSION, EPICS_CA_MINOR_VERSION, EPICS_CA_MAINTENANCE_VERSION, 0)
|
||||
|
||||
#endif // DATABASEVERSION_H
|
||||
#endif // CAVERSION_H
|
||||
7
src/client/caVersionNum.h@
Normal file
7
src/client/caVersionNum.h@
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef CAVERSION_H
|
||||
# error include caVersion.h, not this header
|
||||
#endif
|
||||
#define EPICS_CA_MAJOR_VERSION @EPICS_CA_MAJOR_VERSION@
|
||||
#define EPICS_CA_MINOR_VERSION @EPICS_CA_MINOR_VERSION@
|
||||
#define EPICS_CA_MAINTENANCE_VERSION @EPICS_CA_MAINTENANCE_VERSION@
|
||||
#define EPICS_CA_DEVELOPMENT_FLAG @EPICS_CA_DEVELOPMENT_FLAG@
|
||||
811
src/client/ca_client_context.cpp
Normal file
811
src/client/ca_client_context.cpp
Normal file
@@ -0,0 +1,811 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable:4355)
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string> // vxWorks 6.0 requires this include
|
||||
#include <stdio.h>
|
||||
|
||||
#include "epicsExit.h"
|
||||
#include "errlog.h"
|
||||
#include "locationException.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "oldAccess.h"
|
||||
#include "cac.h"
|
||||
|
||||
epicsShareDef epicsThreadPrivateId caClientCallbackThreadId;
|
||||
|
||||
static epicsThreadOnceId cacOnce = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
const unsigned ca_client_context :: flushBlockThreshold = 0x58000;
|
||||
|
||||
extern "C" void cacExitHandler ( void *)
|
||||
{
|
||||
epicsThreadPrivateDelete ( caClientCallbackThreadId );
|
||||
caClientCallbackThreadId = 0;
|
||||
delete ca_client_context::pDefaultServiceInstallMutex;
|
||||
}
|
||||
|
||||
// runs once only for each process
|
||||
extern "C" void cacOnceFunc ( void * )
|
||||
{
|
||||
caClientCallbackThreadId = epicsThreadPrivateCreate ();
|
||||
assert ( caClientCallbackThreadId );
|
||||
ca_client_context::pDefaultServiceInstallMutex = newEpicsMutex;
|
||||
epicsAtExit ( cacExitHandler,0 );
|
||||
}
|
||||
|
||||
extern epicsThreadPrivateId caClientContextId;
|
||||
|
||||
cacService * ca_client_context::pDefaultService = 0;
|
||||
epicsMutex * ca_client_context::pDefaultServiceInstallMutex;
|
||||
|
||||
ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
|
||||
createdByThread ( epicsThreadGetIdSelf () ),
|
||||
ca_exception_func ( 0 ), ca_exception_arg ( 0 ),
|
||||
pVPrintfFunc ( errlogVprintf ), fdRegFunc ( 0 ), fdRegArg ( 0 ),
|
||||
pndRecvCnt ( 0u ), ioSeqNo ( 0u ), callbackThreadsPending ( 0u ),
|
||||
localPort ( 0 ), fdRegFuncNeedsToBeCalled ( false ),
|
||||
noWakeupSincePend ( true )
|
||||
{
|
||||
static const unsigned short PORT_ANY = 0u;
|
||||
|
||||
if ( ! osiSockAttach () ) {
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
|
||||
epicsThreadOnce ( & cacOnce, cacOnceFunc, 0 );
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( *ca_client_context::pDefaultServiceInstallMutex );
|
||||
if ( ca_client_context::pDefaultService ) {
|
||||
this->pServiceContext.reset (
|
||||
& ca_client_context::pDefaultService->contextCreate (
|
||||
this->mutex, this->cbMutex, *this ) );
|
||||
}
|
||||
else {
|
||||
this->pServiceContext.reset ( new cac ( this->mutex, this->cbMutex, *this ) );
|
||||
}
|
||||
}
|
||||
|
||||
this->sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
||||
if ( this->sock == INVALID_SOCKET ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
this->printFormated (
|
||||
"ca_client_context: unable to create "
|
||||
"datagram socket because = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
|
||||
{
|
||||
osiSockIoctl_t yes = true;
|
||||
int status = socket_ioctl ( this->sock,
|
||||
FIONBIO, & yes);
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( this->sock );
|
||||
this->printFormated (
|
||||
"%s: non blocking IO set fail because \"%s\"\n",
|
||||
__FILE__, sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
}
|
||||
|
||||
// force a bind to an unconstrained address so we can obtain
|
||||
// the local port number below
|
||||
{
|
||||
osiSockAddr addr;
|
||||
memset ( (char *)&addr, 0 , sizeof ( addr ) );
|
||||
addr.ia.sin_family = AF_INET;
|
||||
addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
|
||||
addr.ia.sin_port = htons ( PORT_ANY );
|
||||
int status = bind (this->sock, &addr.sa, sizeof (addr) );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy (this->sock);
|
||||
this->printFormated (
|
||||
"CAC: unable to bind to an unconstrained "
|
||||
"address because = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
osiSockAddr tmpAddr;
|
||||
osiSocklen_t saddr_length = sizeof ( tmpAddr );
|
||||
int status = getsockname ( this->sock, & tmpAddr.sa, & saddr_length );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( this->sock );
|
||||
this->printFormated ( "CAC: getsockname () error was \"%s\"\n", sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
if ( tmpAddr.sa.sa_family != AF_INET) {
|
||||
epicsSocketDestroy ( this->sock );
|
||||
this->printFormated ( "CAC: UDP socket was not inet addr family\n" );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
this->localPort = htons ( tmpAddr.ia.sin_port );
|
||||
}
|
||||
|
||||
std::auto_ptr < CallbackGuard > pCBGuard;
|
||||
if ( ! enablePreemptiveCallback ) {
|
||||
pCBGuard.reset ( new CallbackGuard ( this->cbMutex ) );
|
||||
}
|
||||
|
||||
// multiple steps ensure exception safety
|
||||
this->pCallbackGuard = pCBGuard;
|
||||
}
|
||||
|
||||
ca_client_context::~ca_client_context ()
|
||||
{
|
||||
if ( this->fdRegFunc ) {
|
||||
( *this->fdRegFunc )
|
||||
( this->fdRegArg, this->sock, false );
|
||||
}
|
||||
epicsSocketDestroy ( this->sock );
|
||||
|
||||
osiSockRelease ();
|
||||
|
||||
// force a logical shutdown order
|
||||
// so that the cac class does not hang its
|
||||
// receive threads during their shutdown sequence
|
||||
// and so that classes using this classes mutex
|
||||
// are destroyed before the mutex is destroyed
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
|
||||
this->pServiceContext.reset ( 0 );
|
||||
}
|
||||
else {
|
||||
this->pServiceContext.reset ( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::destroyGetCopy (
|
||||
epicsGuard < epicsMutex > & guard, getCopy & gc )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
gc.~getCopy ();
|
||||
this->getCopyFreeList.release ( & gc );
|
||||
}
|
||||
|
||||
void ca_client_context::destroyGetCallback (
|
||||
epicsGuard < epicsMutex > & guard, getCallback & gcb )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
gcb.~getCallback ();
|
||||
this->getCallbackFreeList.release ( & gcb );
|
||||
}
|
||||
|
||||
void ca_client_context::destroyPutCallback (
|
||||
epicsGuard < epicsMutex > & guard, putCallback & pcb )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
pcb.~putCallback ();
|
||||
this->putCallbackFreeList.release ( & pcb );
|
||||
}
|
||||
|
||||
void ca_client_context::destroySubscription (
|
||||
epicsGuard < epicsMutex > & guard, oldSubscription & os )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
os.~oldSubscription ();
|
||||
this->subscriptionFreeList.release ( & os );
|
||||
}
|
||||
|
||||
void ca_client_context::changeExceptionEvent (
|
||||
caExceptionHandler * pfunc, void * arg )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->ca_exception_func = pfunc;
|
||||
this->ca_exception_arg = arg;
|
||||
// should block here until releated callback in progress completes
|
||||
}
|
||||
|
||||
void ca_client_context::replaceErrLogHandler (
|
||||
caPrintfFunc * ca_printf_func )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( ca_printf_func ) {
|
||||
this->pVPrintfFunc = ca_printf_func;
|
||||
}
|
||||
else {
|
||||
this->pVPrintfFunc = epicsVprintf;
|
||||
}
|
||||
// should block here until releated callback in progress completes
|
||||
}
|
||||
|
||||
void ca_client_context::registerForFileDescriptorCallBack (
|
||||
CAFDHANDLER *pFunc, void *pArg )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->fdRegFunc = pFunc;
|
||||
this->fdRegArg = pArg;
|
||||
this->fdRegFuncNeedsToBeCalled = true;
|
||||
if ( pFunc ) {
|
||||
// the receive thread might already be blocking
|
||||
// w/o having sent the wakeup message
|
||||
this->_sendWakeupMsg ();
|
||||
}
|
||||
// should block here until releated callback in progress completes
|
||||
}
|
||||
|
||||
int ca_client_context :: printFormated (
|
||||
const char *pformat, ... ) const
|
||||
{
|
||||
va_list theArgs;
|
||||
int status;
|
||||
|
||||
va_start ( theArgs, pformat );
|
||||
|
||||
status = this->ca_client_context :: varArgsPrintFormated ( pformat, theArgs );
|
||||
|
||||
va_end ( theArgs );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int ca_client_context :: varArgsPrintFormated (
|
||||
const char *pformat, va_list args ) const
|
||||
{
|
||||
caPrintfFunc * pFunc;
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
pFunc = this->pVPrintfFunc;
|
||||
}
|
||||
if ( pFunc ) {
|
||||
return ( *pFunc ) ( pformat, args );
|
||||
}
|
||||
else {
|
||||
return :: vfprintf ( stderr, pformat, args );
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::exception (
|
||||
epicsGuard < epicsMutex > & guard, int stat, const char * pCtx,
|
||||
const char * pFile, unsigned lineNo )
|
||||
{
|
||||
struct exception_handler_args args;
|
||||
caExceptionHandler * pFunc = this->ca_exception_func;
|
||||
void * pArg = this->ca_exception_arg;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
// NOOP if they disable exceptions
|
||||
if ( pFunc ) {
|
||||
args.chid = NULL;
|
||||
args.type = TYPENOTCONN;
|
||||
args.count = 0;
|
||||
args.addr = NULL;
|
||||
args.stat = stat;
|
||||
args.op = CA_OP_OTHER;
|
||||
args.ctx = pCtx;
|
||||
args.pFile = pFile;
|
||||
args.lineNo = lineNo;
|
||||
args.usr = pArg;
|
||||
( *pFunc ) ( args );
|
||||
}
|
||||
else {
|
||||
this->signal ( stat, pFile, lineNo, pCtx );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::exception (
|
||||
epicsGuard < epicsMutex > & guard, int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo, oldChannelNotify & chan,
|
||||
unsigned type, arrayElementCount count, unsigned op )
|
||||
{
|
||||
struct exception_handler_args args;
|
||||
caExceptionHandler * pFunc = this->ca_exception_func;
|
||||
void * pArg = this->ca_exception_arg;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
// NOOP if they disable exceptions
|
||||
if ( pFunc ) {
|
||||
args.chid = &chan;
|
||||
args.type = type;
|
||||
args.count = count;
|
||||
args.addr = NULL;
|
||||
args.stat = status;
|
||||
args.op = op;
|
||||
args.ctx = pContext;
|
||||
args.pFile = pFileName;
|
||||
args.lineNo = lineNo;
|
||||
args.usr = pArg;
|
||||
( *pFunc ) ( args );
|
||||
}
|
||||
else {
|
||||
this->signal ( status, pFileName, lineNo,
|
||||
"op=%u, channel=%s, type=%s, count=%lu, ctx=\"%s\"",
|
||||
op, ca_name ( &chan ),
|
||||
dbr_type_to_text ( static_cast <int> ( type ) ),
|
||||
count, pContext );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::signal ( int ca_status, const char * pfilenm,
|
||||
int lineno, const char * pFormat, ... )
|
||||
{
|
||||
va_list theArgs;
|
||||
va_start ( theArgs, pFormat );
|
||||
this->vSignal ( ca_status, pfilenm, lineno, pFormat, theArgs);
|
||||
va_end ( theArgs );
|
||||
}
|
||||
|
||||
void ca_client_context :: vSignal (
|
||||
int ca_status, const char *pfilenm,
|
||||
int lineno, const char *pFormat, va_list args )
|
||||
{
|
||||
static const char *severity[] =
|
||||
{
|
||||
"Warning",
|
||||
"Success",
|
||||
"Error",
|
||||
"Info",
|
||||
"Fatal",
|
||||
"Fatal",
|
||||
"Fatal",
|
||||
"Fatal"
|
||||
};
|
||||
|
||||
this->printFormated ( "CA.Client.Exception...............................................\n" );
|
||||
|
||||
this->printFormated ( " %s: \"%s\"\n",
|
||||
severity[ CA_EXTRACT_SEVERITY ( ca_status ) ],
|
||||
ca_message ( ca_status ) );
|
||||
|
||||
if ( pFormat ) {
|
||||
this->printFormated ( " Context: \"" );
|
||||
this->varArgsPrintFormated ( pFormat, args );
|
||||
this->printFormated ( "\"\n" );
|
||||
}
|
||||
|
||||
if ( pfilenm ) {
|
||||
this->printFormated ( " Source File: %s line %d\n",
|
||||
pfilenm, lineno );
|
||||
}
|
||||
|
||||
epicsTime current = epicsTime::getCurrent ();
|
||||
char date[64];
|
||||
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
|
||||
this->printFormated ( " Current Time: %s\n", date );
|
||||
|
||||
/*
|
||||
* Terminate execution if unsuccessful
|
||||
*/
|
||||
if( ! ( ca_status & CA_M_SUCCESS ) &&
|
||||
CA_EXTRACT_SEVERITY ( ca_status ) != CA_K_WARNING ){
|
||||
errlogFlush ();
|
||||
abort ();
|
||||
}
|
||||
|
||||
this->printFormated ( "..................................................................\n" );
|
||||
}
|
||||
|
||||
void ca_client_context::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
::printf ( "ca_client_context at %p pndRecvCnt=%u ioSeqNo=%u\n",
|
||||
static_cast <const void *> ( this ),
|
||||
this->pndRecvCnt, this->ioSeqNo );
|
||||
|
||||
if ( level > 0u ) {
|
||||
this->pServiceContext->show ( guard, level - 1u );
|
||||
::printf ( "\tpreemptive callback is %s\n",
|
||||
this->pCallbackGuard.get() ? "disabled" : "enabled" );
|
||||
::printf ( "\tthere are %u unsatisfied IO operations blocking ca_pend_io()\n",
|
||||
this->pndRecvCnt );
|
||||
::printf ( "\tthe current io sequence number is %u\n",
|
||||
this->ioSeqNo );
|
||||
::printf ( "IO done event:\n");
|
||||
this->ioDone.show ( level - 1u );
|
||||
::printf ( "Synchronous group identifier hash table:\n" );
|
||||
this->sgTable.show ( level - 1u );
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::attachToClientCtx ()
|
||||
{
|
||||
assert ( ! epicsThreadPrivateGet ( caClientContextId ) );
|
||||
epicsThreadPrivateSet ( caClientContextId, this );
|
||||
}
|
||||
|
||||
void ca_client_context::incrementOutstandingIO (
|
||||
epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->ioSeqNo == ioSeqNoIn ) {
|
||||
assert ( this->pndRecvCnt < UINT_MAX );
|
||||
this->pndRecvCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::decrementOutstandingIO (
|
||||
epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->ioSeqNo == ioSeqNoIn ) {
|
||||
assert ( this->pndRecvCnt > 0u );
|
||||
this->pndRecvCnt--;
|
||||
if ( this->pndRecvCnt == 0u ) {
|
||||
this->ioDone.signal ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// !!!! This routine is only visible in the old interface - or in a new ST interface.
|
||||
// !!!! In the old interface we restrict thread attach so that calls from threads
|
||||
// !!!! other than the initializing thread are not allowed if preemptive callback
|
||||
// !!!! is disabled. This prevents the preemptive callback lock from being released
|
||||
// !!!! by other threads than the one that locked it.
|
||||
//
|
||||
int ca_client_context::pendIO ( const double & timeout )
|
||||
{
|
||||
// prevent recursion nightmares by disabling calls to
|
||||
// pendIO () from within a CA callback.
|
||||
if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) {
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
|
||||
int status = ECA_NORMAL;
|
||||
epicsTime beg_time = epicsTime::getCurrent ();
|
||||
double remaining = timeout;
|
||||
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
this->flush ( guard );
|
||||
|
||||
while ( this->pndRecvCnt > 0 ) {
|
||||
if ( remaining < CAC_SIGNIFICANT_DELAY ) {
|
||||
status = ECA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
this->blockForEventAndEnableCallbacks ( this->ioDone, remaining );
|
||||
}
|
||||
|
||||
double delay = epicsTime::getCurrent () - beg_time;
|
||||
if ( delay < timeout ) {
|
||||
remaining = timeout - delay;
|
||||
}
|
||||
else {
|
||||
remaining = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
this->ioSeqNo++;
|
||||
this->pndRecvCnt = 0u;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// !!!! This routine is only visible in the old interface - or in a new ST interface.
|
||||
// !!!! In the old interface we restrict thread attach so that calls from threads
|
||||
// !!!! other than the initializing thread are not allowed if preemptive callback
|
||||
// !!!! is disabled. This prevents the preemptive callback lock from being released
|
||||
// !!!! by other threads than the one that locked it.
|
||||
//
|
||||
int ca_client_context::pendEvent ( const double & timeout )
|
||||
{
|
||||
// prevent recursion nightmares by disabling calls to
|
||||
// pendIO () from within a CA callback.
|
||||
if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) {
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
|
||||
epicsTime current = epicsTime::getCurrent ();
|
||||
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->flush ( guard );
|
||||
}
|
||||
|
||||
// process at least once if preemptive callback is disabled
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
epicsGuardRelease < epicsMutex > cbUnguard ( *this->pCallbackGuard );
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
//
|
||||
// This is needed because in non-preemptive callback mode
|
||||
// legacy applications that use file descriptor managers
|
||||
// will register for ca receive thread activity and keep
|
||||
// calling ca_pend_event until all of the socket data has
|
||||
// been read. We must guarantee that other threads get a
|
||||
// chance to run if there is data in any of the sockets.
|
||||
//
|
||||
if ( this->fdRegFunc ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
|
||||
// remove short udp message sent to wake
|
||||
// up a file descriptor manager
|
||||
osiSockAddr tmpAddr;
|
||||
osiSocklen_t addrSize = sizeof ( tmpAddr.sa );
|
||||
char buf = 0;
|
||||
int status = 0;
|
||||
do {
|
||||
status = recvfrom ( this->sock, & buf, sizeof ( buf ),
|
||||
0, & tmpAddr.sa, & addrSize );
|
||||
} while ( status > 0 );
|
||||
}
|
||||
while ( this->callbackThreadsPending > 0 ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
this->callbackThreadActivityComplete.wait ( 30.0 );
|
||||
}
|
||||
this->noWakeupSincePend = true;
|
||||
}
|
||||
|
||||
double elapsed = epicsTime::getCurrent() - current;
|
||||
double delay;
|
||||
|
||||
if ( timeout > elapsed ) {
|
||||
delay = timeout - elapsed;
|
||||
}
|
||||
else {
|
||||
delay = 0.0;
|
||||
}
|
||||
|
||||
if ( delay >= CAC_SIGNIFICANT_DELAY ) {
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
|
||||
epicsThreadSleep ( delay );
|
||||
}
|
||||
else {
|
||||
epicsThreadSleep ( delay );
|
||||
}
|
||||
}
|
||||
|
||||
return ECA_TIMEOUT;
|
||||
}
|
||||
|
||||
void ca_client_context::blockForEventAndEnableCallbacks (
|
||||
epicsEvent & event, const double & timeout )
|
||||
{
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
|
||||
event.wait ( timeout );
|
||||
}
|
||||
else {
|
||||
event.wait ( timeout );
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::callbackProcessingInitiateNotify ()
|
||||
{
|
||||
// if preemptive callback is enabled then this is a noop
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
bool sendNeeded = false;
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->callbackThreadsPending++;
|
||||
if ( this->fdRegFunc && this->noWakeupSincePend ) {
|
||||
this->noWakeupSincePend = false;
|
||||
sendNeeded = true;
|
||||
}
|
||||
}
|
||||
if ( sendNeeded ) {
|
||||
_sendWakeupMsg ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context :: _sendWakeupMsg ()
|
||||
{
|
||||
// send short udp message to wake up a file descriptor manager
|
||||
// when a message arrives
|
||||
osiSockAddr tmpAddr;
|
||||
tmpAddr.ia.sin_family = AF_INET;
|
||||
tmpAddr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
|
||||
tmpAddr.ia.sin_port = htons ( this->localPort );
|
||||
char buf = 0;
|
||||
sendto ( this->sock, & buf, sizeof ( buf ),
|
||||
0, & tmpAddr.sa, sizeof ( tmpAddr.sa ) );
|
||||
}
|
||||
|
||||
void ca_client_context::callbackProcessingCompleteNotify ()
|
||||
{
|
||||
// if preemptive callback is enabled then this is a noop
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
bool signalNeeded = false;
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( this->callbackThreadsPending <= 1 ) {
|
||||
if ( this->callbackThreadsPending == 1 ) {
|
||||
this->callbackThreadsPending = 0;
|
||||
signalNeeded = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->callbackThreadsPending--;
|
||||
}
|
||||
}
|
||||
if ( signalNeeded ) {
|
||||
this->callbackThreadActivityComplete.signal ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cacChannel & ca_client_context::createChannel (
|
||||
epicsGuard < epicsMutex > & guard, const char * pChannelName,
|
||||
cacChannelNotify & chan, cacChannel::priLev pri )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->pServiceContext->createChannel (
|
||||
guard, pChannelName, chan, pri );
|
||||
}
|
||||
|
||||
void ca_client_context::flush ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->pServiceContext->flush ( guard );
|
||||
}
|
||||
|
||||
unsigned ca_client_context::circuitCount () const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
return this->pServiceContext->circuitCount ( guard );
|
||||
}
|
||||
|
||||
unsigned ca_client_context::beaconAnomaliesSinceProgramStart () const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
return this->pServiceContext->beaconAnomaliesSinceProgramStart ( guard );
|
||||
}
|
||||
|
||||
void ca_client_context::installCASG (
|
||||
epicsGuard < epicsMutex > & guard, CASG & sg )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->sgTable.idAssignAdd ( sg );
|
||||
}
|
||||
|
||||
void ca_client_context::uninstallCASG (
|
||||
epicsGuard < epicsMutex > & guard, CASG & sg )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->sgTable.remove ( sg );
|
||||
}
|
||||
|
||||
CASG * ca_client_context::lookupCASG (
|
||||
epicsGuard < epicsMutex > & guard, unsigned idIn )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
CASG * psg = this->sgTable.lookup ( idIn );
|
||||
if ( psg ) {
|
||||
if ( ! psg->verify ( guard ) ) {
|
||||
psg = 0;
|
||||
}
|
||||
}
|
||||
return psg;
|
||||
}
|
||||
|
||||
void ca_client_context::selfTest () const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->sgTable.verify ();
|
||||
this->pServiceContext->selfTest ( guard );
|
||||
}
|
||||
|
||||
epicsMutex & ca_client_context::mutexRef () const
|
||||
{
|
||||
return this->mutex;
|
||||
}
|
||||
|
||||
cacContext & ca_client_context::createNetworkContext (
|
||||
epicsMutex & mutexIn, epicsMutex & cbMutexIn )
|
||||
{
|
||||
return * new cac ( mutexIn, cbMutexIn, *this );
|
||||
}
|
||||
|
||||
void ca_client_context::installDefaultService ( cacService & service )
|
||||
{
|
||||
epicsThreadOnce ( & cacOnce, cacOnceFunc, 0 );
|
||||
|
||||
epicsGuard < epicsMutex > guard ( *ca_client_context::pDefaultServiceInstallMutex );
|
||||
if ( ca_client_context::pDefaultService ) {
|
||||
throw std::logic_error
|
||||
( "CA in-memory service already installed and can't be replaced");
|
||||
}
|
||||
ca_client_context::pDefaultService = & service;
|
||||
}
|
||||
|
||||
void epicsShareAPI caInstallDefaultService ( cacService & service )
|
||||
{
|
||||
ca_client_context::installDefaultService ( service );
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon )
|
||||
{
|
||||
oldChannelNotify & chan = pMon->channel ();
|
||||
ca_client_context & cac = chan.getClientCtx ();
|
||||
// !!!! the order in which we take the mutex here prevents deadlocks
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
try {
|
||||
// if this stalls out on a live circuit then an exception
|
||||
// can be forthcoming which we must ignore as the clear
|
||||
// request must always be successful
|
||||
chan.eliminateExcessiveSendBacklog ( guard );
|
||||
}
|
||||
catch ( cacChannel::notConnected & ) {
|
||||
// intentionally ignored
|
||||
}
|
||||
}
|
||||
if ( cac.pCallbackGuard.get() &&
|
||||
cac.createdByThread == epicsThreadGetIdSelf () ) {
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
pMon->cancel ( *cac.pCallbackGuard.get(), guard );
|
||||
}
|
||||
else {
|
||||
//
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( cac.cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
pMon->cancel ( cbGuard, guard );
|
||||
}
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
void ca_client_context :: eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > & guard, cacChannel & chan )
|
||||
{
|
||||
if ( chan.requestMessageBytesPending ( guard ) >
|
||||
ca_client_context :: flushBlockThreshold ) {
|
||||
if ( this->pCallbackGuard.get() &&
|
||||
this->createdByThread == epicsThreadGetIdSelf () ) {
|
||||
// we need to be very careful about lock hierarchy
|
||||
// inversion in this situation
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > cbunguard (
|
||||
* this->pCallbackGuard.get() );
|
||||
{
|
||||
epicsGuard < epicsMutex > nestedGuard ( this->mutex );
|
||||
chan.flush ( nestedGuard );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
chan.flush ( guard );
|
||||
}
|
||||
}
|
||||
}
|
||||
1336
src/client/cac.cpp
Normal file
1336
src/client/cac.cpp
Normal file
File diff suppressed because it is too large
Load Diff
435
src/client/cac.h
Normal file
435
src/client/cac.h
Normal file
@@ -0,0 +1,435 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef cach
|
||||
#define cach
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define cach_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "compilerDependencies.h"
|
||||
#include "ipAddrToAsciiAsynchronous.h"
|
||||
#include "msgForMultiplyDefinedPV.h"
|
||||
#include "epicsTimer.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "freeList.h"
|
||||
#include "localHostName.h"
|
||||
|
||||
#ifdef cach_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
#include "nciu.h"
|
||||
#include "comBuf.h"
|
||||
#include "bhe.h"
|
||||
#include "cacIO.h"
|
||||
#include "netIO.h"
|
||||
#include "localHostName.h"
|
||||
#include "virtualCircuit.h"
|
||||
|
||||
class netWriteNotifyIO;
|
||||
class netReadNotifyIO;
|
||||
class netSubscription;
|
||||
class tcpiiu;
|
||||
|
||||
// used to control access to cac's recycle routines which
|
||||
// should only be indirectly invoked by CAC when its lock
|
||||
// is applied
|
||||
class cacRecycle {
|
||||
public:
|
||||
virtual void recycleReadNotifyIO (
|
||||
epicsGuard < epicsMutex > &, netReadNotifyIO &io ) = 0;
|
||||
virtual void recycleWriteNotifyIO (
|
||||
epicsGuard < epicsMutex > &, netWriteNotifyIO &io ) = 0;
|
||||
virtual void recycleSubscription (
|
||||
epicsGuard < epicsMutex > &, netSubscription &io ) = 0;
|
||||
protected:
|
||||
virtual ~cacRecycle() {}
|
||||
};
|
||||
|
||||
struct CASG;
|
||||
class inetAddrID;
|
||||
class caServerID;
|
||||
struct caHdrLargeArray;
|
||||
|
||||
class cacComBufMemoryManager : public comBufMemoryManager
|
||||
{
|
||||
public:
|
||||
cacComBufMemoryManager () {}
|
||||
void * allocate ( size_t );
|
||||
void release ( void * );
|
||||
private:
|
||||
tsFreeList < comBuf, 0x20 > freeList;
|
||||
cacComBufMemoryManager ( const cacComBufMemoryManager & );
|
||||
cacComBufMemoryManager & operator = ( const cacComBufMemoryManager & );
|
||||
};
|
||||
|
||||
class notifyGuard {
|
||||
public:
|
||||
notifyGuard ( cacContextNotify & );
|
||||
~notifyGuard ();
|
||||
private:
|
||||
cacContextNotify & notify;
|
||||
notifyGuard ( const notifyGuard & );
|
||||
notifyGuard & operator = ( const notifyGuard & );
|
||||
};
|
||||
|
||||
class callbackManager : public notifyGuard {
|
||||
public:
|
||||
callbackManager (
|
||||
cacContextNotify &,
|
||||
epicsMutex & callbackControl );
|
||||
epicsGuard < epicsMutex > cbGuard;
|
||||
};
|
||||
|
||||
class cac :
|
||||
public cacContext,
|
||||
private cacRecycle,
|
||||
private callbackForMultiplyDefinedPV
|
||||
{
|
||||
public:
|
||||
cac (
|
||||
epicsMutex & mutualExclusion,
|
||||
epicsMutex & callbackControl,
|
||||
cacContextNotify & );
|
||||
virtual ~cac ();
|
||||
|
||||
// beacon management
|
||||
void beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime,
|
||||
ca_uint32_t beaconNumber, unsigned protocolRevision );
|
||||
unsigned beaconAnomaliesSinceProgramStart (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
|
||||
// IO management
|
||||
void flush ( epicsGuard < epicsMutex > & guard );
|
||||
bool executeResponse ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, caHdrLargeArray &, char *pMsgBody );
|
||||
|
||||
// channel routines
|
||||
void transferChanToVirtCircuit (
|
||||
unsigned cid, unsigned sid,
|
||||
ca_uint16_t typeCode, arrayElementCount count,
|
||||
unsigned minorVersionNumber, const osiSockAddr &,
|
||||
const epicsTime & currentTime );
|
||||
cacChannel & createChannel (
|
||||
epicsGuard < epicsMutex > & guard, const char * pChannelName,
|
||||
cacChannelNotify &, cacChannel::priLev );
|
||||
void destroyChannel (
|
||||
epicsGuard < epicsMutex > &, nciu & );
|
||||
void initiateConnect (
|
||||
epicsGuard < epicsMutex > &, nciu &, netiiu * & );
|
||||
nciu * lookupChannel (
|
||||
epicsGuard < epicsMutex > &, const cacChannel::ioid & );
|
||||
|
||||
// IO requests
|
||||
netWriteNotifyIO & writeNotifyRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
||||
unsigned type, arrayElementCount nElem, const void * pValue,
|
||||
cacWriteNotify & );
|
||||
netReadNotifyIO & readNotifyRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
||||
unsigned type, arrayElementCount nElem,
|
||||
cacReadNotify & );
|
||||
netSubscription & subscriptionRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
||||
unsigned type, arrayElementCount nElem, unsigned mask,
|
||||
cacStateNotify &, bool channelIsInstalled );
|
||||
bool destroyIO (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const cacChannel::ioid & idIn,
|
||||
nciu & chan );
|
||||
void disconnectAllIO (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
nciu &, tsDLList < baseNMIU > & ioList );
|
||||
|
||||
void ioShow (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid &id, unsigned level ) const;
|
||||
|
||||
// exception generation
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo );
|
||||
|
||||
// search destination management
|
||||
void registerSearchDest (
|
||||
epicsGuard < epicsMutex > &, SearchDest & req );
|
||||
bool findOrCreateVirtCircuit (
|
||||
epicsGuard < epicsMutex > &, const osiSockAddr &,
|
||||
unsigned, tcpiiu *&, unsigned, SearchDestTCP * pSearchDest = NULL );
|
||||
|
||||
// diagnostics
|
||||
unsigned circuitCount ( epicsGuard < epicsMutex > & ) const;
|
||||
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
|
||||
int printFormated (
|
||||
epicsGuard < epicsMutex > & callbackControl,
|
||||
const char *pformat, ... ) const;
|
||||
int varArgsPrintFormated (
|
||||
epicsGuard < epicsMutex > & callbackControl,
|
||||
const char *pformat, va_list args ) const;
|
||||
double connectionTimeout ( epicsGuard < epicsMutex > & );
|
||||
|
||||
unsigned maxContiguousFrames ( epicsGuard < epicsMutex > & ) const;
|
||||
|
||||
// misc
|
||||
const char * userNamePointer () const;
|
||||
unsigned getInitializingThreadsPriority () const;
|
||||
epicsMutex & mutexRef ();
|
||||
void attachToClientCtx ();
|
||||
void selfTest (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
double beaconPeriod (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const nciu & chan ) const;
|
||||
static unsigned lowestPriorityLevelAbove ( unsigned priority );
|
||||
static unsigned highestPriorityLevelBelow ( unsigned priority );
|
||||
void destroyIIU ( tcpiiu & iiu );
|
||||
|
||||
const char * pLocalHostName ();
|
||||
|
||||
private:
|
||||
epicsSingleton < localHostName > :: reference _refLocalHostName;
|
||||
chronIntIdResTable < nciu > chanTable;
|
||||
//
|
||||
// !!!! There is at this point no good reason
|
||||
// !!!! to maintain one IO table for all types of
|
||||
// !!!! IO. It would probably be better to maintain
|
||||
// !!!! an independent table for each IO type. The
|
||||
// !!!! new adaptive sized hash table will not
|
||||
// !!!! waste memory. Making this change will
|
||||
// !!!! avoid virtual function overhead when
|
||||
// !!!! accessing the different types of IO. This
|
||||
// !!!! approach would also probably be safer in
|
||||
// !!!! terms of detecting damaged protocol.
|
||||
//
|
||||
chronIntIdResTable < baseNMIU > ioTable;
|
||||
resTable < bhe, inetAddrID > beaconTable;
|
||||
resTable < tcpiiu, caServerID > serverTable;
|
||||
tsDLList < tcpiiu > circuitList;
|
||||
tsDLList < SearchDest > searchDestList;
|
||||
tsDLList < msgForMultiplyDefinedPV > msgMultiPVList;
|
||||
tsFreeList
|
||||
< class tcpiiu, 32, epicsMutexNOOP >
|
||||
freeListVirtualCircuit;
|
||||
tsFreeList
|
||||
< class netReadNotifyIO, 1024, epicsMutexNOOP >
|
||||
freeListReadNotifyIO;
|
||||
tsFreeList
|
||||
< class netWriteNotifyIO, 1024, epicsMutexNOOP >
|
||||
freeListWriteNotifyIO;
|
||||
tsFreeList
|
||||
< class netSubscription, 1024, epicsMutexNOOP >
|
||||
freeListSubscription;
|
||||
tsFreeList
|
||||
< class nciu, 1024, epicsMutexNOOP >
|
||||
channelFreeList;
|
||||
tsFreeList
|
||||
< class msgForMultiplyDefinedPV, 16 >
|
||||
mdpvFreeList;
|
||||
cacComBufMemoryManager comBufMemMgr;
|
||||
bheFreeStore bheFreeList;
|
||||
epicsTime programBeginTime;
|
||||
double connTMO;
|
||||
// **** lock hierarchy ****
|
||||
// 1) callback lock must always be acquired before
|
||||
// the primary mutex if both locks are needed
|
||||
epicsMutex & mutex;
|
||||
epicsMutex & cbMutex;
|
||||
epicsEvent iiuUninstall;
|
||||
ipAddrToAsciiEngine & ipToAEngine;
|
||||
epicsTimerQueueActive & timerQueue;
|
||||
char * pUserName;
|
||||
class udpiiu * pudpiiu;
|
||||
void * tcpSmallRecvBufFreeList;
|
||||
void * tcpLargeRecvBufFreeList;
|
||||
cacContextNotify & notify;
|
||||
epicsThreadId initializingThreadsId;
|
||||
unsigned initializingThreadsPriority;
|
||||
unsigned maxRecvBytesTCP;
|
||||
unsigned maxContigFrames;
|
||||
unsigned beaconAnomalyCount;
|
||||
unsigned short _serverPort;
|
||||
unsigned iiuExistenceCount;
|
||||
bool cacShutdownInProgress;
|
||||
|
||||
void recycleReadNotifyIO (
|
||||
epicsGuard < epicsMutex > &, netReadNotifyIO &io );
|
||||
void recycleWriteNotifyIO (
|
||||
epicsGuard < epicsMutex > &, netWriteNotifyIO &io );
|
||||
void recycleSubscription (
|
||||
epicsGuard < epicsMutex > &, netSubscription &io );
|
||||
|
||||
void disconnectChannel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan );
|
||||
|
||||
void ioExceptionNotify ( unsigned id, int status,
|
||||
const char * pContext, unsigned type, arrayElementCount count );
|
||||
void ioExceptionNotifyAndUninstall ( unsigned id, int status,
|
||||
const char * pContext, unsigned type, arrayElementCount count );
|
||||
|
||||
void pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
|
||||
const char * pChannelName, const char * pAcc, const char * pRej );
|
||||
|
||||
// recv protocol stubs
|
||||
bool versionAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool echoRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool writeNotifyRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool searchRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool readNotifyRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool eventRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool readRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool clearChannelRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool exceptionRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool accessRightsRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool createChannelRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool verifyAndDisconnectChan ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool badTCPRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
|
||||
typedef bool ( cac::*pProtoStubTCP ) (
|
||||
callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
static const pProtoStubTCP tcpJumpTableCAC [];
|
||||
|
||||
bool defaultExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool eventAddExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool readExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool writeExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool clearChanExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool readNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool writeNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
typedef bool ( cac::*pExcepProtoStubTCP ) (
|
||||
callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
static const pExcepProtoStubTCP tcpExcepJumpTableCAC [];
|
||||
|
||||
cac ( const cac & );
|
||||
cac & operator = ( const cac & );
|
||||
|
||||
friend class tcpiiu;
|
||||
};
|
||||
|
||||
inline const char * cac::userNamePointer () const
|
||||
{
|
||||
return this->pUserName;
|
||||
}
|
||||
|
||||
inline unsigned cac::getInitializingThreadsPriority () const
|
||||
{
|
||||
return this->initializingThreadsPriority;
|
||||
}
|
||||
|
||||
inline epicsMutex & cac::mutexRef ()
|
||||
{
|
||||
return this->mutex;
|
||||
}
|
||||
|
||||
inline int cac :: varArgsPrintFormated (
|
||||
epicsGuard < epicsMutex > & callbackControl,
|
||||
const char *pformat, va_list args ) const
|
||||
{
|
||||
callbackControl.assertIdenticalMutex ( this->cbMutex );
|
||||
return this->notify.varArgsPrintFormated ( pformat, args );
|
||||
}
|
||||
|
||||
inline void cac::attachToClientCtx ()
|
||||
{
|
||||
this->notify.attachToClientCtx ();
|
||||
}
|
||||
|
||||
inline unsigned cac::beaconAnomaliesSinceProgramStart (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->beaconAnomalyCount;
|
||||
}
|
||||
|
||||
inline notifyGuard::notifyGuard ( cacContextNotify & notifyIn ) :
|
||||
notify ( notifyIn )
|
||||
{
|
||||
this->notify.callbackProcessingInitiateNotify ();
|
||||
}
|
||||
|
||||
inline notifyGuard::~notifyGuard ()
|
||||
{
|
||||
this->notify.callbackProcessingCompleteNotify ();
|
||||
}
|
||||
|
||||
inline callbackManager::callbackManager (
|
||||
cacContextNotify & notify, epicsMutex & callbackControl ) :
|
||||
notifyGuard ( notify ), cbGuard ( callbackControl )
|
||||
{
|
||||
}
|
||||
|
||||
inline nciu * cac::lookupChannel (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid & idIn )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->chanTable.lookup ( idIn );
|
||||
}
|
||||
|
||||
inline const char * cac :: pLocalHostName ()
|
||||
{
|
||||
return _refLocalHostName->pointer ();
|
||||
}
|
||||
|
||||
inline unsigned cac ::
|
||||
maxContiguousFrames ( epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return maxContigFrames;
|
||||
}
|
||||
|
||||
inline double cac ::
|
||||
connectionTimeout ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->connTMO;
|
||||
}
|
||||
|
||||
#endif // ifdef cach
|
||||
145
src/client/cacChannel.cpp
Normal file
145
src/client/cacChannel.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
#include <float.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "localHostName.h"
|
||||
#include "cacIO.h"
|
||||
|
||||
class CACChannelPrivate {
|
||||
public:
|
||||
CACChannelPrivate ();
|
||||
unsigned getHostName ( char * pBuf, unsigned bufLength );
|
||||
const char * pHostName ();
|
||||
private:
|
||||
epicsSingleton < localHostName > :: reference
|
||||
_refLocalHostName;
|
||||
};
|
||||
|
||||
static epicsThreadOnceId cacChannelIdOnce = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
const cacChannel::priLev cacChannel::priorityMax = 99u;
|
||||
const cacChannel::priLev cacChannel::priorityMin = 0u;
|
||||
const cacChannel::priLev cacChannel::priorityDefault = priorityMin;
|
||||
const cacChannel::priLev cacChannel::priorityLinksDB = priorityMax;
|
||||
const cacChannel::priLev cacChannel::priorityArchive = ( priorityMax - priorityMin ) / 2;
|
||||
const cacChannel::priLev cacChannel::priorityOPI = priorityMin;
|
||||
|
||||
cacChannel::~cacChannel ()
|
||||
{
|
||||
}
|
||||
|
||||
caAccessRights cacChannel::accessRights (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
static caAccessRights ar ( true, true );
|
||||
return ar;
|
||||
}
|
||||
|
||||
unsigned cacChannel::searchAttempts (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
double cacChannel::beaconPeriod (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return - DBL_MAX;
|
||||
}
|
||||
|
||||
double cacChannel::receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return - DBL_MAX;
|
||||
}
|
||||
|
||||
bool cacChannel::ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cacChannel::connected (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CACChannelPrivate ::
|
||||
CACChannelPrivate() :
|
||||
_refLocalHostName ( localHostNameCache.getReference () )
|
||||
{
|
||||
}
|
||||
|
||||
inline unsigned CACChannelPrivate ::
|
||||
getHostName ( char * pBuf, unsigned bufLength )
|
||||
{
|
||||
return _refLocalHostName->getName ( pBuf, bufLength );
|
||||
}
|
||||
|
||||
inline const char * CACChannelPrivate ::
|
||||
pHostName ()
|
||||
{
|
||||
return _refLocalHostName->pointer ();
|
||||
}
|
||||
|
||||
static CACChannelPrivate * pCACChannelPrivate = 0;
|
||||
|
||||
// runs once only for each process
|
||||
extern "C" void cacChannelSetup ( void * )
|
||||
{
|
||||
pCACChannelPrivate = new CACChannelPrivate ();
|
||||
}
|
||||
|
||||
// the default is to assume that it is a locally hosted channel
|
||||
unsigned cacChannel::getHostName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLength ) const throw ()
|
||||
{
|
||||
if ( bufLength ) {
|
||||
epicsThreadOnce ( & cacChannelIdOnce, cacChannelSetup, 0);
|
||||
return pCACChannelPrivate->getHostName ( pBuf, bufLength );
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
|
||||
// the default is to assume that it is a locally hosted channel
|
||||
const char * cacChannel::pHostName (
|
||||
epicsGuard < epicsMutex > & ) const throw ()
|
||||
{
|
||||
epicsThreadOnce ( & cacChannelIdOnce, cacChannelSetup, 0);
|
||||
return pCACChannelPrivate->pHostName ();
|
||||
}
|
||||
|
||||
cacContext::~cacContext () {}
|
||||
|
||||
cacService::~cacService () {}
|
||||
|
||||
|
||||
34
src/client/cacChannelNotify.cpp
Normal file
34
src/client/cacChannelNotify.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cacIO.h"
|
||||
#undef epicsExportSharedSymbols
|
||||
|
||||
cacChannelNotify::~cacChannelNotify ()
|
||||
{
|
||||
}
|
||||
|
||||
43
src/client/cacContextNotify.cpp
Normal file
43
src/client/cacContextNotify.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cacIO.h"
|
||||
#undef epicsExportSharedSymbols
|
||||
|
||||
cacContextNotify::~cacContextNotify ()
|
||||
{
|
||||
}
|
||||
|
||||
void cacContextNotify::callbackProcessingInitiateNotify ()
|
||||
{
|
||||
}
|
||||
|
||||
void cacContextNotify::callbackProcessingCompleteNotify ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
392
src/client/cacIO.h
Normal file
392
src/client/cacIO.h
Normal file
@@ -0,0 +1,392 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef cacIOh
|
||||
#define cacIOh
|
||||
|
||||
//
|
||||
// Open Issues
|
||||
// -----------
|
||||
//
|
||||
// 1) A status code from the old client side interface is passed
|
||||
// to the exception notify callback. Should we just pass a string?
|
||||
// If so, then how do they detect the type of error and recover.
|
||||
// Perhaps we should call a different vf for each type of exception.
|
||||
//
|
||||
// 2) Some exception types are present here but there is no common
|
||||
// exception base class in use.
|
||||
//
|
||||
// 3) Should I be passing the channel reference in cacChannelNotify?
|
||||
//
|
||||
// 4) Should the code for caAccessRights not be inline so that this
|
||||
// interface is version independent.
|
||||
//
|
||||
//
|
||||
|
||||
#include <new>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define cacIOh_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsGuard.h"
|
||||
#include "epicsThread.h"
|
||||
|
||||
#ifdef cacIOh_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
|
||||
class cacChannel;
|
||||
|
||||
typedef unsigned long arrayElementCount;
|
||||
|
||||
// 1) this should not be passing caerr.h status to the exception callback
|
||||
// 2) needless-to-say the data should be passed here using the new data access API
|
||||
class epicsShareClass cacWriteNotify {
|
||||
public:
|
||||
virtual ~cacWriteNotify () = 0;
|
||||
virtual void completion ( epicsGuard < epicsMutex > & ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &,
|
||||
int status, const char * pContext,
|
||||
unsigned type, arrayElementCount count ) = 0;
|
||||
};
|
||||
|
||||
// 1) this should not be passing caerr.h status to the exception callback
|
||||
// 2) needless-to-say the data should be passed here using the new data access API
|
||||
class epicsShareClass cacReadNotify {
|
||||
public:
|
||||
virtual ~cacReadNotify () = 0;
|
||||
virtual void completion (
|
||||
epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, const void * pData ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, int status,
|
||||
const char * pContext, unsigned type,
|
||||
arrayElementCount count ) = 0;
|
||||
};
|
||||
|
||||
// 1) this should not be passing caerr.h status to the exception callback
|
||||
// 2) needless-to-say the data should be passed here using the new data access API
|
||||
class epicsShareClass cacStateNotify {
|
||||
public:
|
||||
virtual ~cacStateNotify () = 0;
|
||||
virtual void current (
|
||||
epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, const void * pData ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, int status,
|
||||
const char *pContext, unsigned type,
|
||||
arrayElementCount count ) = 0;
|
||||
};
|
||||
|
||||
class caAccessRights {
|
||||
public:
|
||||
caAccessRights (
|
||||
bool readPermit = false,
|
||||
bool writePermit = false,
|
||||
bool operatorConfirmationRequest = false);
|
||||
void setReadPermit ();
|
||||
void setWritePermit ();
|
||||
void setOperatorConfirmationRequest ();
|
||||
void clrReadPermit ();
|
||||
void clrWritePermit ();
|
||||
void clrOperatorConfirmationRequest ();
|
||||
bool readPermit () const;
|
||||
bool writePermit () const;
|
||||
bool operatorConfirmationRequest () const;
|
||||
private:
|
||||
bool f_readPermit:1;
|
||||
bool f_writePermit:1;
|
||||
bool f_operatorConfirmationRequest:1;
|
||||
};
|
||||
|
||||
class epicsShareClass cacChannelNotify {
|
||||
public:
|
||||
virtual ~cacChannelNotify () = 0;
|
||||
virtual void connectNotify ( epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual void disconnectNotify ( epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual void serviceShutdownNotify (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
virtual void accessRightsNotify (
|
||||
epicsGuard < epicsMutex > &, const caAccessRights & ) = 0;
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, int status, const char *pContext ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void readException (
|
||||
epicsGuard < epicsMutex > &, int status, const char *pContext,
|
||||
unsigned type, arrayElementCount count, void *pValue ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void writeException (
|
||||
epicsGuard < epicsMutex > &, int status, const char * pContext,
|
||||
unsigned type, arrayElementCount count ) = 0;
|
||||
};
|
||||
|
||||
class CallbackGuard :
|
||||
public epicsGuard < epicsMutex > {
|
||||
public:
|
||||
CallbackGuard ( epicsMutex & mutex ) :
|
||||
epicsGuard < epicsMutex > ( mutex ) {}
|
||||
private:
|
||||
CallbackGuard ( const CallbackGuard & );
|
||||
CallbackGuard & operator = ( const CallbackGuard & );
|
||||
};
|
||||
|
||||
//
|
||||
// Notes
|
||||
// 1) This interface assumes that when a channel is deleted then all
|
||||
// attached IO is deleted. This is left over from the old interface,
|
||||
// but perhaps is a bad practice that should be eliminated? If so,
|
||||
// then the IO should not store or use a pointer to the channel.
|
||||
//
|
||||
class epicsShareClass cacChannel {
|
||||
public:
|
||||
typedef unsigned priLev;
|
||||
static const priLev priorityMax;
|
||||
static const priLev priorityMin;
|
||||
static const priLev priorityDefault;
|
||||
static const priLev priorityLinksDB;
|
||||
static const priLev priorityArchive;
|
||||
static const priLev priorityOPI;
|
||||
|
||||
typedef unsigned ioid;
|
||||
enum ioStatus { iosSynch, iosAsynch };
|
||||
|
||||
cacChannel ( cacChannelNotify & );
|
||||
virtual void destroy (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
cacChannelNotify & notify () const; // required ?????
|
||||
virtual unsigned getName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLen ) const throw () = 0;
|
||||
// !! deprecated, avoid use !!
|
||||
virtual const char * pName (
|
||||
epicsGuard < epicsMutex > & guard ) const throw () = 0;
|
||||
virtual void show (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned level ) const = 0;
|
||||
virtual void initiateConnect (
|
||||
epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual unsigned requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
virtual void flush (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
virtual ioStatus read (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
cacReadNotify &, ioid * = 0 ) = 0;
|
||||
virtual void write (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void *pValue ) = 0;
|
||||
virtual ioStatus write (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void *pValue, cacWriteNotify &, ioid * = 0 ) = 0;
|
||||
virtual void subscribe (
|
||||
epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, unsigned mask, cacStateNotify &,
|
||||
ioid * = 0 ) = 0;
|
||||
// The primary mutex must be released when calling the user's
|
||||
// callback, and therefore a finite interval exists when we are
|
||||
// moving forward with the intent to call the users callback
|
||||
// but the users IO could be deleted during this interval.
|
||||
// To prevent the user's callback from being called after
|
||||
// destroying his IO we must past a guard for the callback
|
||||
// mutex here.
|
||||
virtual void ioCancel (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const ioid & ) = 0;
|
||||
virtual void ioShow (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const ioid &, unsigned level ) const = 0;
|
||||
virtual short nativeType (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual arrayElementCount nativeElementCount (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual caAccessRights accessRights (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
virtual unsigned searchAttempts (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
virtual double beaconPeriod (
|
||||
epicsGuard < epicsMutex > & ) const; // negative DBL_MAX if UKN
|
||||
virtual double receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & ) const; // negative DBL_MAX if UKN
|
||||
virtual bool ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
virtual bool connected (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
virtual unsigned getHostName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLength ) const throw ();
|
||||
// !! deprecated, avoid use !!
|
||||
virtual const char * pHostName (
|
||||
epicsGuard < epicsMutex > & guard ) const throw ();
|
||||
|
||||
// exceptions
|
||||
class badString {};
|
||||
class badType {};
|
||||
class badPriority {};
|
||||
class outOfBounds {};
|
||||
class badEventSelection {};
|
||||
class noWriteAccess {};
|
||||
class noReadAccess {};
|
||||
class notConnected {};
|
||||
class unsupportedByService {};
|
||||
class msgBodyCacheTooSmall {}; // hopefully this one goes away in the future
|
||||
class requestTimedOut {};
|
||||
|
||||
protected:
|
||||
virtual ~cacChannel () = 0;
|
||||
|
||||
private:
|
||||
cacChannelNotify & callback;
|
||||
cacChannel ( const cacChannel & );
|
||||
cacChannel & operator = ( const cacChannel & );
|
||||
};
|
||||
|
||||
class epicsShareClass cacContext {
|
||||
public:
|
||||
virtual ~cacContext ();
|
||||
virtual cacChannel & createChannel (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const char * pChannelName, cacChannelNotify &,
|
||||
cacChannel::priLev = cacChannel::priorityDefault ) = 0;
|
||||
virtual void flush (
|
||||
epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual unsigned circuitCount (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual void selfTest (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual unsigned beaconAnomaliesSinceProgramStart (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual void show (
|
||||
epicsGuard < epicsMutex > &, unsigned level ) const = 0;
|
||||
};
|
||||
|
||||
class epicsShareClass cacContextNotify {
|
||||
public:
|
||||
virtual ~cacContextNotify () = 0;
|
||||
virtual cacContext & createNetworkContext (
|
||||
epicsMutex & mutualExclusion, epicsMutex & callbackControl ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo ) = 0;
|
||||
// perhaps this should be phased out in deference to the exception mechanism
|
||||
virtual int varArgsPrintFormated ( const char * pformat, va_list args ) const = 0;
|
||||
// backwards compatibility (from here down)
|
||||
virtual void attachToClientCtx () = 0;
|
||||
virtual void callbackProcessingInitiateNotify () = 0;
|
||||
virtual void callbackProcessingCompleteNotify () = 0;
|
||||
};
|
||||
|
||||
// **** Lock Hierarchy ****
|
||||
// callbackControl must be taken before mutualExclusion if both are held at
|
||||
// the same time
|
||||
class epicsShareClass cacService {
|
||||
public:
|
||||
virtual ~cacService () = 0;
|
||||
virtual cacContext & contextCreate (
|
||||
epicsMutex & mutualExclusion,
|
||||
epicsMutex & callbackControl,
|
||||
cacContextNotify & ) = 0;
|
||||
};
|
||||
|
||||
epicsShareFunc void epicsShareAPI caInstallDefaultService ( cacService & service );
|
||||
|
||||
epicsShareExtern epicsThreadPrivateId caClientCallbackThreadId;
|
||||
|
||||
inline cacChannel::cacChannel ( cacChannelNotify & notify ) :
|
||||
callback ( notify )
|
||||
{
|
||||
}
|
||||
|
||||
inline cacChannelNotify & cacChannel::notify () const
|
||||
{
|
||||
return this->callback;
|
||||
}
|
||||
|
||||
inline caAccessRights::caAccessRights (
|
||||
bool readPermit, bool writePermit, bool operatorConfirmationRequest) :
|
||||
f_readPermit ( readPermit ), f_writePermit ( writePermit ),
|
||||
f_operatorConfirmationRequest ( operatorConfirmationRequest ) {}
|
||||
|
||||
inline void caAccessRights::setReadPermit ()
|
||||
{
|
||||
this->f_readPermit = true;
|
||||
}
|
||||
|
||||
inline void caAccessRights::setWritePermit ()
|
||||
{
|
||||
this->f_writePermit = true;
|
||||
}
|
||||
|
||||
inline void caAccessRights::setOperatorConfirmationRequest ()
|
||||
{
|
||||
this->f_operatorConfirmationRequest = true;
|
||||
}
|
||||
|
||||
inline void caAccessRights::clrReadPermit ()
|
||||
{
|
||||
this->f_readPermit = false;
|
||||
}
|
||||
|
||||
inline void caAccessRights::clrWritePermit ()
|
||||
{
|
||||
this->f_writePermit = false;
|
||||
}
|
||||
|
||||
inline void caAccessRights::clrOperatorConfirmationRequest ()
|
||||
{
|
||||
this->f_operatorConfirmationRequest = false;
|
||||
}
|
||||
|
||||
inline bool caAccessRights::readPermit () const
|
||||
{
|
||||
return this->f_readPermit;
|
||||
}
|
||||
|
||||
inline bool caAccessRights::writePermit () const
|
||||
{
|
||||
return this->f_writePermit;
|
||||
}
|
||||
|
||||
inline bool caAccessRights::operatorConfirmationRequest () const
|
||||
{
|
||||
return this->f_operatorConfirmationRequest;
|
||||
}
|
||||
|
||||
#endif // ifndef cacIOh
|
||||
30
src/client/cacReadNotify.cpp
Normal file
30
src/client/cacReadNotify.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cacIO.h"
|
||||
#undef epicsExportSharedSymbols
|
||||
|
||||
cacReadNotify::~cacReadNotify ()
|
||||
{
|
||||
}
|
||||
30
src/client/cacStateNotify.cpp
Normal file
30
src/client/cacStateNotify.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cacIO.h"
|
||||
#undef epicsExportSharedSymbols
|
||||
|
||||
cacStateNotify::~cacStateNotify ()
|
||||
{
|
||||
}
|
||||
30
src/client/cacWriteNotify.cpp
Normal file
30
src/client/cacWriteNotify.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cacIO.h"
|
||||
#undef epicsExportSharedSymbols
|
||||
|
||||
cacWriteNotify::~cacWriteNotify ()
|
||||
{
|
||||
}
|
||||
904
src/client/cadef.h
Normal file
904
src/client/cadef.h
Normal file
@@ -0,0 +1,904 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INCLcadefh
|
||||
#define INCLcadefh
|
||||
|
||||
/*
|
||||
* done in two ifdef steps so that we will remain compatible with
|
||||
* traditional C
|
||||
*/
|
||||
#ifndef CA_DONT_INCLUDE_STDARGH
|
||||
# include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define INCLcadefh_accessh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsThread.h"
|
||||
|
||||
#ifdef INCLcadefh_accessh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "caerr.h"
|
||||
#include "db_access.h"
|
||||
#include "caeventmask.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct oldChannelNotify *chid;
|
||||
typedef chid chanId; /* for when the structures field name is "chid" */
|
||||
typedef long chtype;
|
||||
typedef struct oldSubscription *evid;
|
||||
typedef double ca_real;
|
||||
|
||||
/* arguments passed to user connection handlers */
|
||||
struct connection_handler_args {
|
||||
chanId chid; /* channel id */
|
||||
long op; /* one of CA_OP_CONN_UP or CA_OP_CONN_DOWN */
|
||||
};
|
||||
|
||||
typedef void caCh (struct connection_handler_args args);
|
||||
|
||||
typedef struct ca_access_rights {
|
||||
unsigned read_access:1;
|
||||
unsigned write_access:1;
|
||||
} caar;
|
||||
|
||||
/* arguments passed to user access rights handlers */
|
||||
struct access_rights_handler_args {
|
||||
chanId chid; /* channel id */
|
||||
caar ar; /* new access rights state */
|
||||
};
|
||||
|
||||
typedef void caArh (struct access_rights_handler_args args);
|
||||
|
||||
/* The conversion routine to call for each type */
|
||||
#define VALID_TYPE(TYPE) (((unsigned short)TYPE)<=LAST_BUFFER_TYPE)
|
||||
|
||||
/*
|
||||
* Arguments passed to event handlers and get/put call back handlers.
|
||||
*
|
||||
* The status field below is the CA ECA_XXX status of the requested
|
||||
* operation which is saved from when the operation was attempted in the
|
||||
* server and copied back to the clients call back routine.
|
||||
* If the status is not ECA_NORMAL then the dbr pointer will be NULL
|
||||
* and the requested operation can not be assumed to be successful.
|
||||
*/
|
||||
typedef struct event_handler_args {
|
||||
void *usr; /* user argument supplied with request */
|
||||
chanId chid; /* channel id */
|
||||
long type; /* the type of the item returned */
|
||||
long count; /* the element count of the item returned */
|
||||
const void *dbr; /* a pointer to the item returned */
|
||||
int status; /* ECA_XXX status of the requested op from the server */
|
||||
} evargs;
|
||||
typedef void caEventCallBackFunc (struct event_handler_args);
|
||||
|
||||
epicsShareFunc void epicsShareAPI ca_test_event
|
||||
(
|
||||
struct event_handler_args
|
||||
);
|
||||
|
||||
/* arguments passed to user exception handlers */
|
||||
struct exception_handler_args {
|
||||
void *usr; /* user argument supplied when installed */
|
||||
chanId chid; /* channel id (may be nill) */
|
||||
long type; /* type requested */
|
||||
long count; /* count requested */
|
||||
void *addr; /* user's address to write results of CA_OP_GET */
|
||||
long stat; /* channel access ECA_XXXX status code */
|
||||
long op; /* CA_OP_GET, CA_OP_PUT, ..., CA_OP_OTHER */
|
||||
const char *ctx; /* a character string containing context info */
|
||||
const char *pFile; /* source file name (may be NULL) */
|
||||
unsigned lineNo; /* source file line number (may be zero) */
|
||||
};
|
||||
|
||||
typedef unsigned CA_SYNC_GID;
|
||||
|
||||
/*
|
||||
* External OP codes for CA operations
|
||||
*/
|
||||
#define CA_OP_GET 0
|
||||
#define CA_OP_PUT 1
|
||||
#define CA_OP_CREATE_CHANNEL 2
|
||||
#define CA_OP_ADD_EVENT 3
|
||||
#define CA_OP_CLEAR_EVENT 4
|
||||
#define CA_OP_OTHER 5
|
||||
|
||||
/*
|
||||
* used with connection_handler_args
|
||||
*/
|
||||
#define CA_OP_CONN_UP 6
|
||||
#define CA_OP_CONN_DOWN 7
|
||||
|
||||
/* depricated */
|
||||
#define CA_OP_SEARCH 2
|
||||
|
||||
/*
|
||||
* provides efficient test and display of channel access errors
|
||||
*/
|
||||
#define SEVCHK(CA_ERROR_CODE, MESSAGE_STRING) \
|
||||
{ \
|
||||
int ca_unique_status_name = (CA_ERROR_CODE); \
|
||||
if(!(ca_unique_status_name & CA_M_SUCCESS)) \
|
||||
ca_signal_with_file_and_lineno( \
|
||||
ca_unique_status_name, \
|
||||
(MESSAGE_STRING), \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
}
|
||||
|
||||
|
||||
#define TYPENOTCONN (-1) /* the channel's native type when disconnected */
|
||||
epicsShareFunc short epicsShareAPI ca_field_type (chid chan);
|
||||
epicsShareFunc unsigned long epicsShareAPI ca_element_count (chid chan);
|
||||
epicsShareFunc const char * epicsShareAPI ca_name (chid chan);
|
||||
epicsShareFunc void epicsShareAPI ca_set_puser (chid chan, void *puser);
|
||||
epicsShareFunc void * epicsShareAPI ca_puser (chid chan);
|
||||
epicsShareFunc unsigned epicsShareAPI ca_read_access (chid chan);
|
||||
epicsShareFunc unsigned epicsShareAPI ca_write_access (chid chan);
|
||||
|
||||
/*
|
||||
* cs_ - `channel state'
|
||||
*
|
||||
* cs_never_conn valid chid, IOC not found
|
||||
* cs_prev_conn valid chid, IOC was found, but unavailable
|
||||
* cs_conn valid chid, IOC was found, still available
|
||||
* cs_closed channel deleted by user
|
||||
*/
|
||||
enum channel_state {cs_never_conn, cs_prev_conn, cs_conn, cs_closed};
|
||||
epicsShareFunc enum channel_state epicsShareAPI ca_state (chid chan);
|
||||
|
||||
/************************************************************************/
|
||||
/* Perform Library Initialization */
|
||||
/* */
|
||||
/* Must be called once before calling any of the other routines */
|
||||
/************************************************************************/
|
||||
epicsShareFunc int epicsShareAPI ca_task_initialize (void);
|
||||
enum ca_preemptive_callback_select
|
||||
{ ca_disable_preemptive_callback, ca_enable_preemptive_callback };
|
||||
epicsShareFunc int epicsShareAPI
|
||||
ca_context_create (enum ca_preemptive_callback_select select);
|
||||
epicsShareFunc void epicsShareAPI ca_detach_context ();
|
||||
|
||||
/************************************************************************/
|
||||
/* Remove CA facility from your task */
|
||||
/* */
|
||||
/* Normally called automatically at task exit */
|
||||
/************************************************************************/
|
||||
epicsShareFunc int epicsShareAPI ca_task_exit (void);
|
||||
epicsShareFunc void epicsShareAPI ca_context_destroy (void);
|
||||
|
||||
typedef unsigned capri;
|
||||
#define CA_PRIORITY_MAX 99
|
||||
#define CA_PRIORITY_MIN 0
|
||||
#define CA_PRIORITY_DEFAULT CA_PRIORITY_MIN
|
||||
|
||||
#define CA_PRIORITY_DB_LINKS 80
|
||||
#define CA_PRIORITY_ARCHIVE 20
|
||||
#define CA_PRIORITY_OPI 0
|
||||
|
||||
/*
|
||||
* ca_create_channel ()
|
||||
*
|
||||
* pChanName R channel name string
|
||||
* pConnStateCallback R address of connection state change
|
||||
* callback function
|
||||
* pUserPrivate R placed in the channel's user private field
|
||||
* o can be fetched later by ca_puser(CHID)
|
||||
* o passed as void * arg to *pConnectCallback above
|
||||
* priority R priority level in the server 0 - 100
|
||||
* pChanID RW channel id written here
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_create_channel
|
||||
(
|
||||
const char *pChanName,
|
||||
caCh *pConnStateCallback,
|
||||
void *pUserPrivate,
|
||||
capri priority,
|
||||
chid *pChanID
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_change_connection_event()
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pfunc R address of connection call-back function
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_change_connection_event
|
||||
(
|
||||
chid chan,
|
||||
caCh * pfunc
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_replace_access_rights_event ()
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pfunc R address of access rights call-back function
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_replace_access_rights_event (
|
||||
chid chan,
|
||||
caArh *pfunc
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_add_exception_event ()
|
||||
*
|
||||
* replace the default exception handler
|
||||
*
|
||||
* pfunc R address of exception call-back function
|
||||
* pArg R copy of this pointer passed to exception
|
||||
* call-back function
|
||||
*/
|
||||
typedef void caExceptionHandler (struct exception_handler_args);
|
||||
epicsShareFunc int epicsShareAPI ca_add_exception_event
|
||||
(
|
||||
caExceptionHandler *pfunc,
|
||||
void *pArg
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_clear_channel()
|
||||
* - deallocate resources reserved for a channel
|
||||
*
|
||||
* chanId R channel ID
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_clear_channel
|
||||
(
|
||||
chid chanId
|
||||
);
|
||||
|
||||
/************************************************************************/
|
||||
/* Write a value to a channel */
|
||||
/************************************************************************/
|
||||
/*
|
||||
* ca_bput()
|
||||
*
|
||||
* WARNING: this copies the new value from a string (dbr_string_t)
|
||||
* (and not as an integer)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value string copied from this location
|
||||
*/
|
||||
#define ca_bput(chan, pValue) \
|
||||
ca_array_put(DBR_STRING, 1u, chan, (const dbr_string_t *) (pValue))
|
||||
|
||||
/*
|
||||
* ca_rput()
|
||||
*
|
||||
* WARNING: this copies the new value from a dbr_float_t
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
*/
|
||||
#define ca_rput(chan,pValue) \
|
||||
ca_array_put(DBR_FLOAT, 1u, chan, (const dbr_float_t *) pValue)
|
||||
|
||||
/*
|
||||
* ca_put()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
*/
|
||||
#define ca_put(type, chan, pValue) ca_array_put (type, 1u, chan, pValue)
|
||||
|
||||
/*
|
||||
* ca_array_put()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_array_put
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
const void * pValue
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_array_put_callback()
|
||||
*
|
||||
* This routine functions identically to the original ca put request
|
||||
* with the addition of a callback to the user supplied function
|
||||
* after recod processing completes in the IOC. The arguments
|
||||
* to the user supplied callback function are declared in
|
||||
* the structure event_handler_args and include the pointer
|
||||
* sized user argument supplied when ca_array_put_callback() is called.
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_array_put_callback
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
const void * pValue,
|
||||
caEventCallBackFunc * pFunc,
|
||||
void * pArg
|
||||
);
|
||||
|
||||
#define ca_put_callback(type, chan, pValue, pFunc, pArg) \
|
||||
ca_array_put_callback(type, 1u, chan, pValue, pFunc, pArg)
|
||||
|
||||
/************************************************************************/
|
||||
/* Read a value from a channel */
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* ca_bget()
|
||||
*
|
||||
* WARNING: this copies the new value into a string (dbr_string_t)
|
||||
* (and not into an integer)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
#define ca_bget(chan, pValue) \
|
||||
ca_array_get(DBR_STRING, 1u, chan, (dbr_string_t *)(pValue))
|
||||
|
||||
/*
|
||||
* ca_rget()
|
||||
*
|
||||
* WARNING: this copies the new value into a 32 bit float (dbr_float_t)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
#define ca_rget(chan, pValue) \
|
||||
ca_array_get(DBR_FLOAT, 1u, chan, (dbr_float_t *)(pValue))
|
||||
|
||||
/*
|
||||
* ca_rget()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
#define ca_get(type, chan, pValue) ca_array_get(type, 1u, chan, pValue)
|
||||
|
||||
/*
|
||||
* ca_array_get()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_array_get
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
void * pValue
|
||||
);
|
||||
|
||||
/************************************************************************/
|
||||
/* Read a value from a channel and run a callback when the value */
|
||||
/* returns */
|
||||
/* */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
/*
|
||||
* ca_bget_callback()
|
||||
*
|
||||
* WARNING: this returns the new value as a string (dbr_string_t)
|
||||
* (and not as an integer)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
#define ca_bget_callback(chan, pFunc, pArg)\
|
||||
ca_array_get_callback (DBR_STRING, 1u, chan, pFunc, pArg)
|
||||
|
||||
/*
|
||||
* ca_rget_callback()
|
||||
*
|
||||
* WARNING: this returns the new value as a float (dbr_float_t)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
#define ca_rget_callback(chan, pFunc, pArg)\
|
||||
ca_array_get_callback (DBR_FLOAT, 1u, chan, pFunc, pArg)
|
||||
|
||||
/*
|
||||
* ca_get_callback()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* chan R channel identifier
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
#define ca_get_callback(type, chan, pFunc, pArg)\
|
||||
ca_array_get_callback (type, 1u, chan, pFunc, pArg)
|
||||
|
||||
/*
|
||||
* ca_array_get_callback()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_array_get_callback
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
caEventCallBackFunc * pFunc,
|
||||
void * pArg
|
||||
);
|
||||
|
||||
/************************************************************************/
|
||||
/* Specify a function to be executed whenever significant changes */
|
||||
/* occur to a channel. */
|
||||
/* NOTES: */
|
||||
/* 1) Evid may be omited by passing a NULL pointer */
|
||||
/* */
|
||||
/* 2) An array count of zero specifies the native db count */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* ca_create_subscription ()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* mask R event mask - one of {DBE_VALUE, DBE_ALARM, DBE_LOG}
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
* pEventID W event id written at specified address
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_create_subscription
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
long mask,
|
||||
caEventCallBackFunc * pFunc,
|
||||
void * pArg,
|
||||
evid * pEventID
|
||||
);
|
||||
|
||||
/************************************************************************/
|
||||
/* Remove a function from a list of those specified to run */
|
||||
/* whenever significant changes occur to a channel */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
/*
|
||||
* ca_clear_subscription()
|
||||
*
|
||||
* eventID R event id
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_clear_subscription
|
||||
(
|
||||
evid eventID
|
||||
);
|
||||
|
||||
epicsShareFunc chid epicsShareAPI ca_evid_to_chid ( evid id );
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/* Requested data is not necessarily stable prior to */
|
||||
/* return from called subroutine. Call ca_pend_io() */
|
||||
/* to guarantee that requested data is stable. Call the routine */
|
||||
/* ca_flush_io() to force all outstanding requests to be */
|
||||
/* sent out over the network. Significant increases in */
|
||||
/* performance have been measured when batching several remote */
|
||||
/* requests together into one message. Additional */
|
||||
/* improvements can be obtained by performing local processing */
|
||||
/* in parallel with outstanding remote processing. */
|
||||
/* */
|
||||
/* FLOW OF TYPICAL APPLICATION */
|
||||
/* */
|
||||
/* search() ! Obtain Channel ids */
|
||||
/* . ! " */
|
||||
/* . ! " */
|
||||
/* pend_io ! wait for channels to connect */
|
||||
/* */
|
||||
/* get() ! several requests for remote info */
|
||||
/* get() ! " */
|
||||
/* add_event() ! " */
|
||||
/* get() ! " */
|
||||
/* . */
|
||||
/* . */
|
||||
/* . */
|
||||
/* flush_io() ! send get requests */
|
||||
/* ! optional parallel processing */
|
||||
/* . ! " */
|
||||
/* . ! " */
|
||||
/* pend_io() ! wait for replies from get requests */
|
||||
/* . ! access to requested data */
|
||||
/* . ! " */
|
||||
/* pend_event() ! wait for requested events */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
/************************************************************************/
|
||||
/* These routines wait for channel subscription events and call the */
|
||||
/* functions specified with add_event when events occur. If the */
|
||||
/* timeout is specified as 0 an infinite timeout is assumed. */
|
||||
/* ca_flush_io() is called by this routine. If ca_pend_io () */
|
||||
/* is called when no IO is outstanding then it will return immediately */
|
||||
/* without processing. */
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* ca_pend_event()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_pend_event (ca_real timeOut);
|
||||
#define ca_poll() ca_pend_event(1e-12)
|
||||
|
||||
/*
|
||||
* ca_pend_io()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds but return early
|
||||
* if all get requests (or search requests with null
|
||||
* connection handler pointer have completed)
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_pend_io (ca_real timeOut);
|
||||
|
||||
/* calls ca_pend_io() if early is true otherwise ca_pend_event() is called */
|
||||
epicsShareFunc int epicsShareAPI ca_pend (ca_real timeout, int early);
|
||||
|
||||
/*
|
||||
* ca_test_io()
|
||||
*
|
||||
* returns TRUE when get requests (or search requests with null
|
||||
* connection handler pointer) are outstanding
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_test_io (void);
|
||||
|
||||
/************************************************************************/
|
||||
/* Send out all outstanding messages in the send queue */
|
||||
/************************************************************************/
|
||||
/*
|
||||
* ca_flush_io()
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_flush_io (void);
|
||||
|
||||
|
||||
/*
|
||||
* ca_signal()
|
||||
*
|
||||
* errorCode R status returned from channel access function
|
||||
* pCtxStr R context string included with error print out
|
||||
*/
|
||||
epicsShareFunc void epicsShareAPI ca_signal
|
||||
(
|
||||
long errorCode,
|
||||
const char *pCtxStr
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_signal_with_file_and_lineno()
|
||||
* errorCode R status returned from channel access function
|
||||
* pCtxStr R context string included with error print out
|
||||
* pFileStr R file name string included with error print out
|
||||
* lineNo R line number included with error print out
|
||||
*
|
||||
*/
|
||||
epicsShareFunc void epicsShareAPI ca_signal_with_file_and_lineno
|
||||
(
|
||||
long errorCode,
|
||||
const char *pCtxStr,
|
||||
const char *pFileStr,
|
||||
int lineNo
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_signal_formated()
|
||||
* errorCode R status returned from channel access function
|
||||
* pFileStr R file name string included with error print out
|
||||
* lineNo R line number included with error print out
|
||||
* pFormat R printf dtyle format string (and optional arguments)
|
||||
*
|
||||
*/
|
||||
epicsShareFunc void epicsShareAPI ca_signal_formated (long ca_status, const char *pfilenm,
|
||||
int lineno, const char *pFormat, ...);
|
||||
|
||||
/*
|
||||
* ca_host_name_function()
|
||||
*
|
||||
* channel R channel identifier
|
||||
*
|
||||
* !!!! this function is _not_ thread safe !!!!
|
||||
*/
|
||||
epicsShareFunc const char * epicsShareAPI ca_host_name (chid channel);
|
||||
/* thread safe version */
|
||||
epicsShareFunc unsigned epicsShareAPI ca_get_host_name ( chid pChan,
|
||||
char *pBuf, unsigned bufLength );
|
||||
|
||||
/*
|
||||
* CA_ADD_FD_REGISTRATION
|
||||
*
|
||||
* call their function with their argument whenever
|
||||
* a new fd is added or removed
|
||||
* (for use with a manager of the select system call under UNIX)
|
||||
*
|
||||
* if (opened) then fd was created
|
||||
* if (!opened) then fd was deleted
|
||||
*
|
||||
*/
|
||||
typedef void CAFDHANDLER (void *parg, int fd, int opened);
|
||||
|
||||
/*
|
||||
* ca_add_fd_registration()
|
||||
*
|
||||
* pHandler R pointer to function which is to be called
|
||||
* when an fd is created or deleted
|
||||
* pArg R argument passed to above function
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_add_fd_registration
|
||||
(
|
||||
CAFDHANDLER *pHandler,
|
||||
void *pArg
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* CA synch groups
|
||||
*
|
||||
* This facility will allow the programmer to create
|
||||
* any number of synchronization groups. The programmer might then
|
||||
* interleave IO requests within any of the groups. Once The
|
||||
* IO operations are initiated then the programmer is free to
|
||||
* block for IO completion within any one of the groups as needed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ca_sg_create()
|
||||
*
|
||||
* create a sync group
|
||||
*
|
||||
* pgid W pointer to sync group id that will be written
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_create (CA_SYNC_GID * pgid);
|
||||
|
||||
/*
|
||||
* ca_sg_delete()
|
||||
*
|
||||
* delete a sync group
|
||||
*
|
||||
* gid R sync group id
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_delete (const CA_SYNC_GID gid);
|
||||
|
||||
/*
|
||||
* ca_sg_block()
|
||||
*
|
||||
* block for IO performed within a sync group to complete
|
||||
*
|
||||
* gid R sync group id
|
||||
* timeout R wait for this duration prior to timing out
|
||||
* and returning ECA_TIMEOUT
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_block (const CA_SYNC_GID gid, ca_real timeout);
|
||||
|
||||
/*
|
||||
* ca_sg_test()
|
||||
*
|
||||
* test for sync group IO operations in progress
|
||||
*
|
||||
* gid R sync group id
|
||||
*
|
||||
* returns one of ECA_BADSYNCGRP, ECA_IOINPROGRESS, ECA_IODONE
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_test (const CA_SYNC_GID gid);
|
||||
|
||||
/*
|
||||
* ca_sg_reset
|
||||
*
|
||||
* gid R sync group id
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_reset(const CA_SYNC_GID gid);
|
||||
|
||||
/*
|
||||
* ca_sg_array_get()
|
||||
*
|
||||
* initiate a get within a sync group
|
||||
* (essentially a ca_array_get() with a sync group specified)
|
||||
*
|
||||
* gid R sync group id
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_array_get
|
||||
(
|
||||
const CA_SYNC_GID gid,
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chan,
|
||||
void *pValue
|
||||
);
|
||||
|
||||
#define ca_sg_get(gid, type, chan, pValue) \
|
||||
ca_sg_array_get (gid, type, 1u, chan, pValue)
|
||||
|
||||
/*
|
||||
* ca_sg_array_put()
|
||||
*
|
||||
* initiate a put within a sync group
|
||||
* (essentially a ca_array_put() with a sync group specified)
|
||||
*
|
||||
* gid R sync group id
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_array_put
|
||||
(
|
||||
const CA_SYNC_GID gid,
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chan,
|
||||
const void *pValue
|
||||
);
|
||||
|
||||
#define ca_sg_put(gid, type, chan, pValue) \
|
||||
ca_sg_array_put (gid, type, 1u, chan, pValue)
|
||||
|
||||
/*
|
||||
* ca_sg_stat()
|
||||
*
|
||||
* print status of a sync group
|
||||
*
|
||||
* gid R sync group id
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_stat (CA_SYNC_GID gid);
|
||||
|
||||
epicsShareFunc void epicsShareAPI ca_dump_dbr (chtype type, unsigned count, const void * pbuffer);
|
||||
|
||||
|
||||
/*
|
||||
* ca_v42_ok()
|
||||
*
|
||||
* Put call back is available if the CA server is on version is 4.2
|
||||
* or higher.
|
||||
*
|
||||
* chan R channel identifier
|
||||
*
|
||||
* (returns true or false)
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_v42_ok (chid chan);
|
||||
|
||||
/*
|
||||
* ca_version()
|
||||
*
|
||||
* returns the CA version string
|
||||
*/
|
||||
epicsShareFunc const char * epicsShareAPI ca_version (void);
|
||||
|
||||
/*
|
||||
* ca_replace_printf_handler ()
|
||||
*
|
||||
* for apps that want to change where ca formatted
|
||||
* text output goes
|
||||
*
|
||||
* use two ifdef's for trad C compatibility
|
||||
*
|
||||
* ca_printf_func R pointer to new function called when
|
||||
* CA prints an error message
|
||||
*/
|
||||
#ifndef CA_DONT_INCLUDE_STDARGH
|
||||
typedef int caPrintfFunc (const char *pformat, va_list args);
|
||||
epicsShareFunc int epicsShareAPI ca_replace_printf_handler (
|
||||
caPrintfFunc *ca_printf_func
|
||||
);
|
||||
#endif /*CA_DONT_INCLUDE_STDARGH*/
|
||||
|
||||
/*
|
||||
* (for testing purposes only)
|
||||
*/
|
||||
epicsShareFunc unsigned epicsShareAPI ca_get_ioc_connection_count (void);
|
||||
epicsShareFunc int epicsShareAPI ca_preemtive_callback_is_enabled (void);
|
||||
epicsShareFunc void epicsShareAPI ca_self_test (void);
|
||||
epicsShareFunc unsigned epicsShareAPI ca_beacon_anomaly_count (void);
|
||||
epicsShareFunc unsigned epicsShareAPI ca_search_attempts (chid chan);
|
||||
epicsShareFunc double epicsShareAPI ca_beacon_period (chid chan);
|
||||
epicsShareFunc double epicsShareAPI ca_receive_watchdog_delay (chid chan);
|
||||
|
||||
/*
|
||||
* used when an auxillary thread needs to join a CA client context started
|
||||
* by another thread
|
||||
*/
|
||||
epicsShareFunc struct ca_client_context * epicsShareAPI ca_current_context ();
|
||||
epicsShareFunc int epicsShareAPI ca_attach_context ( struct ca_client_context * context );
|
||||
|
||||
|
||||
epicsShareFunc int epicsShareAPI ca_client_status ( unsigned level );
|
||||
epicsShareFunc int epicsShareAPI ca_context_status ( struct ca_client_context *, unsigned level );
|
||||
|
||||
/*
|
||||
* deprecated
|
||||
*/
|
||||
#define ca_build_channel(NAME,XXXXX,CHIDPTR,YYYYY)\
|
||||
ca_build_and_connect(NAME, XXXXX, 1, CHIDPTR, YYYYY, 0, 0)
|
||||
#define ca_array_build(NAME,XXXXX, ZZZZZZ, CHIDPTR,YYYYY)\
|
||||
ca_build_and_connect(NAME, XXXXX, ZZZZZZ, CHIDPTR, YYYYY, 0, 0)
|
||||
epicsShareFunc int epicsShareAPI ca_build_and_connect
|
||||
( const char *pChanName, chtype, unsigned long,
|
||||
chid * pChanID, void *, caCh * pFunc, void * pArg );
|
||||
#define ca_search(pChanName, pChanID)\
|
||||
ca_search_and_connect (pChanName, pChanID, 0, 0)
|
||||
epicsShareFunc int epicsShareAPI ca_search_and_connect
|
||||
( const char * pChanName, chid * pChanID,
|
||||
caCh *pFunc, void * pArg );
|
||||
epicsShareFunc int epicsShareAPI ca_channel_status (epicsThreadId tid);
|
||||
epicsShareFunc int epicsShareAPI ca_clear_event ( evid eventID );
|
||||
#define ca_add_event(type,chan,pFunc,pArg,pEventID)\
|
||||
ca_add_array_event(type,1u,chan,pFunc,pArg,0.0,0.0,0.0,pEventID)
|
||||
#define ca_add_delta_event(TYPE,CHID,ENTRY,ARG,DELTA,EVID)\
|
||||
ca_add_array_event(TYPE,1,CHID,ENTRY,ARG,DELTA,DELTA,0.0,EVID)
|
||||
#define ca_add_general_event(TYPE,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)\
|
||||
ca_add_array_event(TYPE,1,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)
|
||||
#define ca_add_array_event(TYPE,COUNT,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)\
|
||||
ca_add_masked_array_event(TYPE,COUNT,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID, DBE_VALUE | DBE_ALARM)
|
||||
epicsShareFunc int epicsShareAPI ca_add_masked_array_event
|
||||
( chtype type, unsigned long count, chid chanId, caEventCallBackFunc * pFunc,
|
||||
void * pArg, ca_real p_delta, ca_real n_delta, ca_real timeout,
|
||||
evid * pEventID, long mask );
|
||||
|
||||
/*
|
||||
* defunct
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_modify_user_name ( const char *pUserName );
|
||||
epicsShareFunc int epicsShareAPI ca_modify_host_name ( const char *pHostName );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* no additions below this endif
|
||||
*/
|
||||
#endif /* ifndef INCLcadefh */
|
||||
|
||||
160
src/client/caerr.h
Normal file
160
src/client/caerr.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeffrey O. Hill
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLcaerrh
|
||||
#define INCLcaerrh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define INCLcaerrh_accessh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
# include "epicsTypes.h"
|
||||
|
||||
#ifdef INCLcaerrh_accessh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
/* CA Status Code Definitions */
|
||||
|
||||
#define CA_K_INFO 3 /* successful */
|
||||
#define CA_K_ERROR 2 /* failed- continue */
|
||||
#define CA_K_SUCCESS 1 /* successful */
|
||||
#define CA_K_WARNING 0 /* unsuccessful */
|
||||
#define CA_K_SEVERE 4 /* failed- quit */
|
||||
#define CA_K_FATAL CA_K_ERROR | CA_K_SEVERE
|
||||
|
||||
#define CA_M_MSG_NO 0x0000FFF8
|
||||
#define CA_M_SEVERITY 0x00000007
|
||||
#define CA_M_LEVEL 0x00000003
|
||||
#define CA_M_SUCCESS 0x00000001
|
||||
#define CA_M_ERROR 0x00000002
|
||||
#define CA_M_SEVERE 0x00000004
|
||||
|
||||
#define CA_S_MSG_NO 0x0D
|
||||
#define CA_S_SEVERITY 0x03
|
||||
|
||||
#define CA_V_MSG_NO 0x03
|
||||
#define CA_V_SEVERITY 0x00
|
||||
#define CA_V_SUCCESS 0x00
|
||||
|
||||
/* Define MACROS to extract/insert individual fields from a status value */
|
||||
|
||||
#define CA_EXTRACT_MSG_NO(code)\
|
||||
( ( (code) & CA_M_MSG_NO ) >> CA_V_MSG_NO )
|
||||
#define CA_EXTRACT_SEVERITY(code)\
|
||||
( ( (code) & CA_M_SEVERITY ) >> CA_V_SEVERITY )
|
||||
#define CA_EXTRACT_SUCCESS(code)\
|
||||
( ( (code) & CA_M_SUCCESS ) >> CA_V_SUCCESS )
|
||||
|
||||
#define CA_INSERT_MSG_NO(code)\
|
||||
( ((code)<< CA_V_MSG_NO) & CA_M_MSG_NO )
|
||||
#define CA_INSERT_SEVERITY(code)\
|
||||
( ((code)<< CA_V_SEVERITY)& CA_M_SEVERITY )
|
||||
#define CA_INSERT_SUCCESS(code)\
|
||||
( ((code)<< CA_V_SUCCESS) & CA_M_SUCCESS )
|
||||
|
||||
#define DEFMSG(SEVERITY,NUMBER)\
|
||||
(CA_INSERT_MSG_NO(NUMBER) | CA_INSERT_SEVERITY(SEVERITY))
|
||||
|
||||
/*
|
||||
* In the lines below "defunct" indicates that current release
|
||||
* servers and client library will not return this error code, but
|
||||
* servers on earlier releases that communicate with current clients
|
||||
* might still generate exceptions with these error constants
|
||||
*/
|
||||
#define ECA_NORMAL DEFMSG(CA_K_SUCCESS, 0) /* success */
|
||||
#define ECA_MAXIOC DEFMSG(CA_K_ERROR, 1) /* defunct */
|
||||
#define ECA_UKNHOST DEFMSG(CA_K_ERROR, 2) /* defunct */
|
||||
#define ECA_UKNSERV DEFMSG(CA_K_ERROR, 3) /* defunct */
|
||||
#define ECA_SOCK DEFMSG(CA_K_ERROR, 4) /* defunct */
|
||||
#define ECA_CONN DEFMSG(CA_K_WARNING, 5) /* defunct */
|
||||
#define ECA_ALLOCMEM DEFMSG(CA_K_WARNING, 6)
|
||||
#define ECA_UKNCHAN DEFMSG(CA_K_WARNING, 7) /* defunct */
|
||||
#define ECA_UKNFIELD DEFMSG(CA_K_WARNING, 8) /* defunct */
|
||||
#define ECA_TOLARGE DEFMSG(CA_K_WARNING, 9)
|
||||
#define ECA_TIMEOUT DEFMSG(CA_K_WARNING, 10)
|
||||
#define ECA_NOSUPPORT DEFMSG(CA_K_WARNING, 11) /* defunct */
|
||||
#define ECA_STRTOBIG DEFMSG(CA_K_WARNING, 12) /* defunct */
|
||||
#define ECA_DISCONNCHID DEFMSG(CA_K_ERROR, 13) /* defunct */
|
||||
#define ECA_BADTYPE DEFMSG(CA_K_ERROR, 14)
|
||||
#define ECA_CHIDNOTFND DEFMSG(CA_K_INFO, 15) /* defunct */
|
||||
#define ECA_CHIDRETRY DEFMSG(CA_K_INFO, 16) /* defunct */
|
||||
#define ECA_INTERNAL DEFMSG(CA_K_FATAL, 17)
|
||||
#define ECA_DBLCLFAIL DEFMSG(CA_K_WARNING, 18) /* defunct */
|
||||
#define ECA_GETFAIL DEFMSG(CA_K_WARNING, 19)
|
||||
#define ECA_PUTFAIL DEFMSG(CA_K_WARNING, 20)
|
||||
#define ECA_ADDFAIL DEFMSG(CA_K_WARNING, 21) /* defunct */
|
||||
#define ECA_BADCOUNT DEFMSG(CA_K_WARNING, 22)
|
||||
#define ECA_BADSTR DEFMSG(CA_K_ERROR, 23)
|
||||
#define ECA_DISCONN DEFMSG(CA_K_WARNING, 24)
|
||||
#define ECA_DBLCHNL DEFMSG(CA_K_WARNING, 25)
|
||||
#define ECA_EVDISALLOW DEFMSG(CA_K_ERROR, 26)
|
||||
#define ECA_BUILDGET DEFMSG(CA_K_WARNING, 27) /* defunct */
|
||||
#define ECA_NEEDSFP DEFMSG(CA_K_WARNING, 28) /* defunct */
|
||||
#define ECA_OVEVFAIL DEFMSG(CA_K_WARNING, 29) /* defunct */
|
||||
#define ECA_BADMONID DEFMSG(CA_K_ERROR, 30)
|
||||
#define ECA_NEWADDR DEFMSG(CA_K_WARNING, 31) /* defunct */
|
||||
#define ECA_NEWCONN DEFMSG(CA_K_INFO, 32) /* defunct */
|
||||
#define ECA_NOCACTX DEFMSG(CA_K_WARNING, 33) /* defunct */
|
||||
#define ECA_DEFUNCT DEFMSG(CA_K_FATAL, 34) /* defunct */
|
||||
#define ECA_EMPTYSTR DEFMSG(CA_K_WARNING, 35) /* defunct */
|
||||
#define ECA_NOREPEATER DEFMSG(CA_K_WARNING, 36) /* defunct */
|
||||
#define ECA_NOCHANMSG DEFMSG(CA_K_WARNING, 37) /* defunct */
|
||||
#define ECA_DLCKREST DEFMSG(CA_K_WARNING, 38) /* defunct */
|
||||
#define ECA_SERVBEHIND DEFMSG(CA_K_WARNING, 39) /* defunct */
|
||||
#define ECA_NOCAST DEFMSG(CA_K_WARNING, 40) /* defunct */
|
||||
#define ECA_BADMASK DEFMSG(CA_K_ERROR, 41)
|
||||
#define ECA_IODONE DEFMSG(CA_K_INFO, 42)
|
||||
#define ECA_IOINPROGRESS DEFMSG(CA_K_INFO, 43)
|
||||
#define ECA_BADSYNCGRP DEFMSG(CA_K_ERROR, 44)
|
||||
#define ECA_PUTCBINPROG DEFMSG(CA_K_ERROR, 45)
|
||||
#define ECA_NORDACCESS DEFMSG(CA_K_WARNING, 46)
|
||||
#define ECA_NOWTACCESS DEFMSG(CA_K_WARNING, 47)
|
||||
#define ECA_ANACHRONISM DEFMSG(CA_K_ERROR, 48)
|
||||
#define ECA_NOSEARCHADDR DEFMSG(CA_K_WARNING, 49)
|
||||
#define ECA_NOCONVERT DEFMSG(CA_K_WARNING, 50)
|
||||
#define ECA_BADCHID DEFMSG(CA_K_ERROR, 51)
|
||||
#define ECA_BADFUNCPTR DEFMSG(CA_K_ERROR, 52)
|
||||
#define ECA_ISATTACHED DEFMSG(CA_K_WARNING, 53)
|
||||
#define ECA_UNAVAILINSERV DEFMSG(CA_K_WARNING, 54)
|
||||
#define ECA_CHANDESTROY DEFMSG(CA_K_WARNING, 55)
|
||||
#define ECA_BADPRIORITY DEFMSG(CA_K_ERROR, 56)
|
||||
#define ECA_NOTTHREADED DEFMSG(CA_K_ERROR, 57)
|
||||
#define ECA_16KARRAYCLIENT DEFMSG(CA_K_WARNING, 58)
|
||||
#define ECA_CONNSEQTMO DEFMSG(CA_K_WARNING, 59)
|
||||
#define ECA_UNRESPTMO DEFMSG(CA_K_WARNING, 60)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareFunc const char * epicsShareAPI ca_message(long ca_status);
|
||||
|
||||
epicsShareExtern const char * ca_message_text [];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
44
src/client/caeventmask.h
Normal file
44
src/client/caeventmask.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef INCLcaeventmaskh
|
||||
#define INCLcaeventmaskh
|
||||
|
||||
/*
|
||||
event selections
|
||||
(If any more than 8 of these are needed then update the
|
||||
select field in the event_block struct in db_event.c from
|
||||
unsigned char to unsigned short)
|
||||
|
||||
|
||||
DBE_VALUE
|
||||
Trigger an event when a significant change in the channel's value
|
||||
occurs. Relies on the monitor deadband field under DCT.
|
||||
|
||||
DBE_ARCHIVE (DBE_LOG)
|
||||
Trigger an event when an archive significant change in the channel's
|
||||
value occurs. Relies on the archiver monitor deadband field under DCT.
|
||||
|
||||
DBE_ALARM
|
||||
Trigger an event when the alarm state changes
|
||||
|
||||
DBE_PROPERTY
|
||||
Trigger an event when a property change (control limit, graphical
|
||||
limit, status string, enum string ...) occurs.
|
||||
|
||||
*/
|
||||
|
||||
#define DBE_VALUE (1<<0)
|
||||
#define DBE_ARCHIVE (1<<1)
|
||||
#define DBE_LOG DBE_ARCHIVE
|
||||
#define DBE_ALARM (1<<2)
|
||||
#define DBE_PROPERTY (1<<3)
|
||||
|
||||
#endif
|
||||
306
src/client/casw.cpp
Normal file
306
src/client/casw.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "envDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "osiWireFormat.h"
|
||||
|
||||
#include "bhe.h"
|
||||
#include "udpiiu.h"
|
||||
#include "inetAddrID.h"
|
||||
|
||||
// using a wrapper class around the free list avoids
|
||||
// Tornado 2.0.1 GNU compiler bugs
|
||||
class bheFreeStoreMgr : public bheMemoryManager {
|
||||
public:
|
||||
bheFreeStoreMgr () {}
|
||||
void * allocate ( size_t );
|
||||
void release ( void * );
|
||||
private:
|
||||
tsFreeList < class bhe, 0x100 > freeList;
|
||||
bheFreeStoreMgr ( const bheFreeStoreMgr & );
|
||||
bheFreeStoreMgr & operator = ( const bheFreeStoreMgr & );
|
||||
};
|
||||
|
||||
void * bheFreeStoreMgr::allocate ( size_t size )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
void bheFreeStoreMgr::release ( void * pCadaver )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
|
||||
int main ( int argc, char ** argv )
|
||||
{
|
||||
epicsMutex mutex;
|
||||
epicsGuard < epicsMutex > guard ( mutex );
|
||||
bheFreeStoreMgr bheFreeList;
|
||||
epicsTime programBeginTime = epicsTime::getCurrent ();
|
||||
bool validCommandLine = false;
|
||||
unsigned interest = 0u;
|
||||
SOCKET sock;
|
||||
osiSockAddr addr;
|
||||
osiSocklen_t addrSize;
|
||||
char buf [0x4000];
|
||||
const char *pCurBuf;
|
||||
const caHdr *pCurMsg;
|
||||
ca_uint16_t serverPort;
|
||||
ca_uint16_t repeaterPort;
|
||||
int status;
|
||||
|
||||
if ( argc == 1 ) {
|
||||
validCommandLine = true;
|
||||
}
|
||||
else if ( argc == 2 ) {
|
||||
status = sscanf ( argv[1], " -i%u ", & interest );
|
||||
if ( status == 1 ) {
|
||||
validCommandLine = true;
|
||||
}
|
||||
}
|
||||
else if ( argc == 3 ) {
|
||||
if ( strcmp ( argv[1], "-i" ) == 0 ) {
|
||||
status = sscanf ( argv[2], " %u ", & interest );
|
||||
if ( status == 1 ) {
|
||||
validCommandLine = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! validCommandLine ) {
|
||||
printf ( "usage: casw <-i interestLevel>\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
serverPort =
|
||||
envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT,
|
||||
static_cast <unsigned short> (CA_SERVER_PORT) );
|
||||
|
||||
repeaterPort =
|
||||
envGetInetPortConfigParam ( &EPICS_CA_REPEATER_PORT,
|
||||
static_cast <unsigned short> (CA_REPEATER_PORT) );
|
||||
|
||||
caStartRepeaterIfNotInstalled ( repeaterPort );
|
||||
|
||||
sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
||||
if ( sock == INVALID_SOCKET ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("casw: unable to create datagram socket because = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset ( (char *) &addr, 0 , sizeof (addr) );
|
||||
addr.ia.sin_family = AF_INET;
|
||||
addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
|
||||
addr.ia.sin_port = htons ( 0 ); // any port
|
||||
status = bind ( sock, &addr.sa, sizeof (addr) );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ( "casw: unable to bind to an unconstrained address because = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
osiSockIoctl_t yes = true;
|
||||
status = socket_ioctl ( sock, FIONBIO, &yes );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ( "casw: unable to set socket to nonblocking state because \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned attemptNumber = 0u;
|
||||
while ( true ) {
|
||||
caRepeaterRegistrationMessage ( sock, repeaterPort, attemptNumber );
|
||||
epicsThreadSleep ( 0.1 );
|
||||
addrSize = ( osiSocklen_t ) sizeof ( addr );
|
||||
status = recvfrom ( sock, buf, sizeof ( buf ), 0,
|
||||
&addr.sa, &addrSize );
|
||||
if ( status >= static_cast <int> ( sizeof ( *pCurMsg ) ) ) {
|
||||
pCurMsg = reinterpret_cast < caHdr * > ( buf );
|
||||
epicsUInt16 cmmd = AlignedWireRef < const epicsUInt16 > ( pCurMsg->m_cmmd );
|
||||
if ( cmmd == REPEATER_CONFIRM ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
attemptNumber++;
|
||||
if ( attemptNumber > 100 ) {
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ( "casw: unable to register with the CA repeater\n" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
osiSockIoctl_t no = false;
|
||||
status = socket_ioctl ( sock, FIONBIO, &no );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ( "casw: unable to set socket to blocking state because \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
resTable < bhe, inetAddrID > beaconTable;
|
||||
while ( true ) {
|
||||
|
||||
addrSize = ( osiSocklen_t ) sizeof ( addr );
|
||||
status = recvfrom ( sock, buf, sizeof ( buf ), 0,
|
||||
&addr.sa, &addrSize );
|
||||
if ( status <= 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ("casw: error from recv was = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( addr.sa.sa_family != AF_INET ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned byteCount = static_cast <unsigned> ( status );
|
||||
pCurMsg = reinterpret_cast < const caHdr * > ( ( pCurBuf = buf ) );
|
||||
while ( byteCount ) {
|
||||
AlignedWireRef < const epicsUInt16 > pstSize ( pCurMsg->m_postsize );
|
||||
size_t msgSize = pstSize + sizeof ( *pCurMsg ) ;
|
||||
if ( msgSize > byteCount ) {
|
||||
errlogPrintf ( "CASW: udp input protocol violation\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
epicsUInt16 cmmd = AlignedWireRef < const epicsUInt16 > ( pCurMsg->m_cmmd );
|
||||
if ( cmmd == CA_PROTO_RSRV_IS_UP ) {
|
||||
bool anomaly = false;
|
||||
epicsTime previousTime;
|
||||
struct sockaddr_in ina;
|
||||
|
||||
/*
|
||||
* this allows a fan-out server to potentially
|
||||
* insert the true address of the CA server
|
||||
*
|
||||
* old servers:
|
||||
* 1) set this field to one of the ip addresses of the host _or_
|
||||
* 2) set this field to INADDR_ANY
|
||||
* new servers:
|
||||
* always set this field to INADDR_ANY
|
||||
*
|
||||
* clients always assume that if this
|
||||
* field is set to something that isnt INADDR_ANY
|
||||
* then it is the overriding IP address of the server.
|
||||
*/
|
||||
ina.sin_family = AF_INET;
|
||||
ina.sin_addr.s_addr = pCurMsg->m_available;
|
||||
|
||||
if ( pCurMsg->m_count != 0 ) {
|
||||
ina.sin_port = pCurMsg->m_count;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* old servers dont supply this and the
|
||||
* default port must be assumed
|
||||
*/
|
||||
ina.sin_port = htons ( serverPort );
|
||||
}
|
||||
|
||||
ca_uint32_t beaconNumber = ntohl ( pCurMsg->m_cid );
|
||||
unsigned protocolRevision = ntohs ( pCurMsg->m_dataType );
|
||||
|
||||
epicsTime currentTime = epicsTime::getCurrent();
|
||||
|
||||
/*
|
||||
* look for it in the hash table
|
||||
*/
|
||||
bhe *pBHE = beaconTable.lookup ( ina );
|
||||
if ( pBHE ) {
|
||||
previousTime = pBHE->updateTime ( guard );
|
||||
anomaly = pBHE->updatePeriod (
|
||||
guard, programBeginTime,
|
||||
currentTime, beaconNumber, protocolRevision );
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* This is the first beacon seen from this server.
|
||||
* Wait until 2nd beacon is seen before deciding
|
||||
* if it is a new server (or just the first
|
||||
* time that we have seen a server's beacon
|
||||
* shortly after the program started up)
|
||||
*/
|
||||
pBHE = new ( bheFreeList )
|
||||
bhe ( mutex, currentTime, beaconNumber, ina );
|
||||
if ( pBHE ) {
|
||||
if ( beaconTable.add ( *pBHE ) < 0 ) {
|
||||
pBHE->~bhe ();
|
||||
bheFreeList.release ( pBHE );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( anomaly || interest > 1 ) {
|
||||
char date[64];
|
||||
currentTime.strftime ( date, sizeof ( date ),
|
||||
"%Y-%m-%d %H:%M:%S.%09f");
|
||||
char host[64];
|
||||
ipAddrToA ( &ina, host, sizeof ( host ) );
|
||||
const char * pPrefix = "";
|
||||
if ( interest > 1 ) {
|
||||
if ( anomaly ) {
|
||||
pPrefix = "* ";
|
||||
}
|
||||
else {
|
||||
pPrefix = " ";
|
||||
}
|
||||
}
|
||||
printf ( "%s%-40s %s\n",
|
||||
pPrefix, host, date );
|
||||
if ( anomaly && interest > 0 ) {
|
||||
printf ( "\testimate=%f current=%f\n",
|
||||
pBHE->period ( guard ),
|
||||
currentTime - previousTime );
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
pCurBuf += msgSize;
|
||||
pCurMsg = reinterpret_cast < const caHdr * > ( pCurBuf );
|
||||
byteCount -= msgSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
685
src/client/catime.c
Normal file
685
src/client/catime.c
Normal file
@@ -0,0 +1,685 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* CA performance test
|
||||
*
|
||||
* History
|
||||
* joh 09-12-89 Initial release
|
||||
* joh 12-20-94 portability
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsTime.h"
|
||||
#include "cadef.h"
|
||||
#include "caProto.h"
|
||||
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#define WAIT_FOR_ACK
|
||||
|
||||
typedef struct testItem {
|
||||
chid chix;
|
||||
char name[128];
|
||||
int type;
|
||||
int count;
|
||||
void * pValue;
|
||||
} ti;
|
||||
|
||||
typedef void tf ( ti *pItems, unsigned iterations, unsigned *pInlineIter );
|
||||
|
||||
/*
|
||||
* test_pend()
|
||||
*/
|
||||
static void test_pend(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
unsigned i;
|
||||
int status;
|
||||
|
||||
for (i=0; i<iterations; i++) {
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
}
|
||||
*pInlineIter = 5;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_search ()
|
||||
*/
|
||||
static void test_search (
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
unsigned i;
|
||||
int status;
|
||||
|
||||
for ( i = 0u; i < iterations; i++ ) {
|
||||
status = ca_search ( pItems[i].name, &pItems[i].chix );
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
status = ca_pend_io ( 0.0 );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
*pInlineIter = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_sync_search()
|
||||
*/
|
||||
#if 0
|
||||
static void test_sync_search(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
unsigned i;
|
||||
int status;
|
||||
|
||||
for (i=0u; i<iterations; i++) {
|
||||
status = ca_search (pItems[i].name, &pItems[i].chix);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_pend_io(0.0);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
|
||||
*pInlineIter = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* test_free ()
|
||||
*/
|
||||
static void test_free(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
int status;
|
||||
unsigned i;
|
||||
|
||||
for (i=0u; i<iterations; i++) {
|
||||
status = ca_clear_channel (pItems[i].chix);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
status = ca_flush_io();
|
||||
SEVCHK (status, NULL);
|
||||
*pInlineIter = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_put ()
|
||||
*/
|
||||
static void test_put(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
ti *pi;
|
||||
int status;
|
||||
dbr_int_t val;
|
||||
|
||||
for (pi=pItems; pi < &pItems[iterations]; pi++) {
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
#ifdef WAIT_FOR_ACK
|
||||
status = ca_array_get (DBR_INT, 1, pItems[0].chix, &val);
|
||||
SEVCHK (status, NULL);
|
||||
ca_pend_io(100.0);
|
||||
#endif
|
||||
status = ca_array_put(
|
||||
pItems[0].type,
|
||||
pItems[0].count,
|
||||
pItems[0].chix,
|
||||
pItems[0].pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_flush_io();
|
||||
SEVCHK (status, NULL);
|
||||
|
||||
*pInlineIter = 10;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_get ()
|
||||
*/
|
||||
static void test_get(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
ti *pi;
|
||||
int status;
|
||||
|
||||
for (pi=pItems; pi<&pItems[iterations]; pi++) {
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
status = ca_pend_io(1e20);
|
||||
SEVCHK (status, NULL);
|
||||
|
||||
*pInlineIter = 10;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_wait ()
|
||||
*/
|
||||
static void test_wait (
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
ti *pi;
|
||||
int status;
|
||||
|
||||
for (pi=pItems; pi<&pItems[iterations]; pi++) {
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_pend_io(100.0);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
|
||||
*pInlineIter = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* measure_get_latency
|
||||
*/
|
||||
static void measure_get_latency (ti *pItems, unsigned iterations)
|
||||
{
|
||||
epicsTimeStamp end_time;
|
||||
epicsTimeStamp start_time;
|
||||
double delay;
|
||||
double X = 0u;
|
||||
double XX = 0u;
|
||||
double max = DBL_MIN;
|
||||
double min = DBL_MAX;
|
||||
double mean;
|
||||
double stdDev;
|
||||
ti *pi;
|
||||
int status;
|
||||
|
||||
for ( pi = pItems; pi < &pItems[iterations]; pi++ ) {
|
||||
epicsTimeGetCurrent ( &start_time );
|
||||
status = ca_array_get ( pi->type, pi->count,
|
||||
pi->chix, pi->pValue );
|
||||
SEVCHK ( status, NULL );
|
||||
status = ca_pend_io ( 100.0 );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
epicsTimeGetCurrent ( &end_time );
|
||||
|
||||
delay = epicsTimeDiffInSeconds ( &end_time,&start_time );
|
||||
|
||||
X += delay;
|
||||
XX += delay*delay;
|
||||
|
||||
if ( delay > max ) {
|
||||
max = delay;
|
||||
}
|
||||
|
||||
if ( delay < min ) {
|
||||
min = delay;
|
||||
}
|
||||
}
|
||||
|
||||
mean = X/iterations;
|
||||
stdDev = sqrt ( XX/iterations - mean*mean );
|
||||
printf (
|
||||
"Get Latency - "
|
||||
"mean = %3.1f uS, "
|
||||
"std dev = %3.1f uS, "
|
||||
"min = %3.1f uS "
|
||||
"max = %3.1f uS\n",
|
||||
mean * 1e6, stdDev * 1e6,
|
||||
min * 1e6, max * 1e6 );
|
||||
}
|
||||
|
||||
/*
|
||||
* printSearchStat()
|
||||
*/
|
||||
static void printSearchStat ( const ti * pi, unsigned iterations )
|
||||
{
|
||||
unsigned i;
|
||||
double X = 0u;
|
||||
double XX = 0u;
|
||||
double max = DBL_MIN;
|
||||
double min = DBL_MAX;
|
||||
double mean;
|
||||
double stdDev;
|
||||
|
||||
for ( i = 0; i < iterations; i++ ) {
|
||||
double retry = ca_search_attempts ( pi[i].chix );
|
||||
X += retry;
|
||||
XX += retry * retry;
|
||||
if ( retry > max ) {
|
||||
max = retry;
|
||||
}
|
||||
if ( retry < min ) {
|
||||
min = retry;
|
||||
}
|
||||
}
|
||||
|
||||
mean = X / iterations;
|
||||
stdDev = sqrt( XX / iterations - mean * mean );
|
||||
printf (
|
||||
"Search tries per chan - "
|
||||
"mean = %3.1f "
|
||||
"std dev = %3.1f "
|
||||
"min = %3.1f "
|
||||
"max = %3.1f\n",
|
||||
mean, stdDev, min, max);
|
||||
}
|
||||
|
||||
/*
|
||||
* timeIt ()
|
||||
*/
|
||||
void timeIt ( tf *pfunc, ti *pItems, unsigned iterations,
|
||||
unsigned nBytesSent, unsigned nBytesRecv )
|
||||
{
|
||||
epicsTimeStamp end_time;
|
||||
epicsTimeStamp start_time;
|
||||
double delay;
|
||||
unsigned inlineIter;
|
||||
|
||||
epicsTimeGetCurrent ( &start_time );
|
||||
(*pfunc) ( pItems, iterations, &inlineIter );
|
||||
epicsTimeGetCurrent ( &end_time );
|
||||
delay = epicsTimeDiffInSeconds ( &end_time, &start_time );
|
||||
if ( delay > 0.0 ) {
|
||||
double freq = ( iterations * inlineIter ) / delay;
|
||||
printf ( "Per Op, %8.4f uS ( %8.4f MHz )",
|
||||
1e6 / freq, freq / 1e6 );
|
||||
if ( pItems != NULL ) {
|
||||
printf(", %8.4f snd Mbps, %8.4f rcv Mbps\n",
|
||||
(inlineIter*nBytesSent*CHAR_BIT)/(delay*1e6),
|
||||
(inlineIter*nBytesRecv*CHAR_BIT)/(delay*1e6) );
|
||||
}
|
||||
else {
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* test ()
|
||||
*/
|
||||
static void test ( ti *pItems, unsigned iterations )
|
||||
{
|
||||
unsigned payloadSize, dblPayloadSize;
|
||||
unsigned nBytesSent, nBytesRecv;
|
||||
|
||||
payloadSize =
|
||||
dbr_size_n ( pItems[0].type, pItems[0].count );
|
||||
payloadSize = CA_MESSAGE_ALIGN ( payloadSize );
|
||||
|
||||
dblPayloadSize = dbr_size [ DBR_DOUBLE ];
|
||||
dblPayloadSize = CA_MESSAGE_ALIGN ( dblPayloadSize );
|
||||
|
||||
if ( payloadSize > dblPayloadSize ) {
|
||||
unsigned factor = payloadSize / dblPayloadSize;
|
||||
while ( factor ) {
|
||||
if ( iterations > 10 * factor ) {
|
||||
iterations /= factor;
|
||||
break;
|
||||
}
|
||||
factor /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
printf ( "\t### async put test ###\n");
|
||||
nBytesSent = sizeof ( caHdr ) + CA_MESSAGE_ALIGN( payloadSize );
|
||||
nBytesRecv = 0u;
|
||||
timeIt ( test_put, pItems, iterations,
|
||||
nBytesSent * iterations,
|
||||
nBytesRecv * iterations );
|
||||
|
||||
printf ( "\t### async get test ###\n");
|
||||
nBytesSent = sizeof ( caHdr );
|
||||
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
|
||||
timeIt ( test_get, pItems, iterations,
|
||||
nBytesSent * ( iterations ),
|
||||
nBytesRecv * ( iterations ) );
|
||||
|
||||
printf ("\t### synch get test ###\n");
|
||||
nBytesSent = sizeof ( caHdr );
|
||||
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
|
||||
if ( iterations > 100 ) {
|
||||
iterations /= 100;
|
||||
}
|
||||
else if ( iterations > 10 ) {
|
||||
iterations /= 10;
|
||||
}
|
||||
timeIt ( test_wait, pItems, iterations,
|
||||
nBytesSent * iterations,
|
||||
nBytesRecv * iterations );
|
||||
}
|
||||
|
||||
/*
|
||||
* catime ()
|
||||
*/
|
||||
int catime ( const char * channelName,
|
||||
unsigned channelCount, enum appendNumberFlag appNF )
|
||||
{
|
||||
unsigned i;
|
||||
int j;
|
||||
unsigned strsize;
|
||||
unsigned nBytesSent, nBytesRecv;
|
||||
ti *pItemList;
|
||||
|
||||
if ( channelCount == 0 ) {
|
||||
printf ( "channel count was zero\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
pItemList = calloc ( channelCount, sizeof (ti) );
|
||||
if ( ! pItemList ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SEVCHK ( ca_context_create ( ca_disable_preemptive_callback ),
|
||||
"Unable to initialize" );
|
||||
|
||||
if ( appNF == appendNumber ) {
|
||||
printf ( "Testing with %u channels named %snnn\n",
|
||||
channelCount, channelName );
|
||||
}
|
||||
else {
|
||||
printf ( "Testing with %u channels named %s\n",
|
||||
channelCount, channelName );
|
||||
}
|
||||
|
||||
strsize = sizeof ( pItemList[0].name ) - 1;
|
||||
nBytesSent = 0;
|
||||
nBytesRecv = 0;
|
||||
for ( i=0; i < channelCount; i++ ) {
|
||||
if ( appNF == appendNumber ) {
|
||||
sprintf ( pItemList[i].name,"%.*s%.6u",
|
||||
(int) (strsize - 15u), channelName, i );
|
||||
}
|
||||
else {
|
||||
strncpy ( pItemList[i].name, channelName, strsize);
|
||||
}
|
||||
pItemList[i].name[strsize]= '\0';
|
||||
pItemList[i].count = 0;
|
||||
pItemList[i].pValue = 0;
|
||||
nBytesSent += 2 * ( CA_MESSAGE_ALIGN ( strlen ( pItemList[i].name ) )
|
||||
+ sizeof (caHdr) );
|
||||
nBytesRecv += 2 * sizeof (caHdr);
|
||||
}
|
||||
|
||||
printf ( "Channel Connect Test\n" );
|
||||
printf ( "--------------------\n" );
|
||||
timeIt ( test_search, pItemList, channelCount, nBytesSent, nBytesRecv );
|
||||
printSearchStat ( pItemList, channelCount );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
size_t count = ca_element_count ( pItemList[i].chix );
|
||||
size_t size = sizeof ( dbr_string_t ) * count;
|
||||
pItemList[i].count = count;
|
||||
pItemList[i].pValue = malloc ( size );
|
||||
assert ( pItemList[i].pValue );
|
||||
}
|
||||
|
||||
printf (
|
||||
"channel name=%s, native type=%d, native count=%u\n",
|
||||
ca_name (pItemList[0].chix),
|
||||
ca_field_type (pItemList[0].chix),
|
||||
pItemList[0].count );
|
||||
|
||||
printf ("Pend Event Test\n");
|
||||
printf ( "----------------\n" );
|
||||
timeIt ( test_pend, NULL, 100, 0, 0 );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_float_t * pFltVal = ( dbr_float_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pFltVal[j] = (dbr_float_t) val;
|
||||
}
|
||||
pItemList[i].type = DBR_FLOAT;
|
||||
}
|
||||
printf ( "DBR_FLOAT Test\n" );
|
||||
printf ( "--------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pDblVal[j] = (dbr_double_t) val;
|
||||
}
|
||||
pItemList[i].type = DBR_DOUBLE;
|
||||
}
|
||||
printf ( "DBR_DOUBLE Test\n" );
|
||||
printf ( "---------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_string_t * pStrVal = ( dbr_string_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
sprintf ( pStrVal[j], "%f", val );
|
||||
}
|
||||
pItemList[i].type = DBR_STRING;
|
||||
}
|
||||
printf ( "DBR_STRING Test\n" );
|
||||
printf ( "---------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_int_t * pIntVal = ( dbr_int_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pIntVal[j] = (dbr_int_t) val;
|
||||
}
|
||||
pItemList[i].type = DBR_INT;
|
||||
}
|
||||
printf ( "DBR_INT Test\n" );
|
||||
printf ( "------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
printf ( "Get Latency Test\n" );
|
||||
printf ( "----------------\n" );
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pDblVal[j] = 0;
|
||||
}
|
||||
pItemList[i].type = DBR_DOUBLE;
|
||||
}
|
||||
measure_get_latency ( pItemList, channelCount );
|
||||
|
||||
printf ( "Free Channel Test\n" );
|
||||
printf ( "-----------------\n" );
|
||||
timeIt ( test_free, pItemList, channelCount, 0, 0 );
|
||||
|
||||
SEVCHK ( ca_task_exit (), "Unable to free resources at exit" );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
free ( pItemList[i].pValue );
|
||||
}
|
||||
|
||||
free ( pItemList );
|
||||
|
||||
return CATIME_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
53
src/client/catimeMain.c
Normal file
53
src/client/catimeMain.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
static const unsigned defaultIterations = 10000u;
|
||||
|
||||
int main ( int argc, char **argv )
|
||||
{
|
||||
const char *pUsage = "<PV name> [<channel count> [<append number to pv name if true>]]";
|
||||
|
||||
if ( argc > 1 ) {
|
||||
char *pname = argv[1];
|
||||
if ( argc > 2 ) {
|
||||
int iterations = atoi (argv[2]);
|
||||
if ( iterations > 0) {
|
||||
if ( argc > 3 ) {
|
||||
if ( argc == 4 ) {
|
||||
int status;
|
||||
unsigned appendNumberBool;
|
||||
status = sscanf ( argv[3], " %u ", &appendNumberBool );
|
||||
if ( status == 1 ) {
|
||||
if ( appendNumberBool ) {
|
||||
return catime ( pname, (unsigned) iterations, appendNumber );
|
||||
}
|
||||
else {
|
||||
return catime ( pname, (unsigned) iterations, dontAppendNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return catime ( pname, (unsigned) iterations, dontAppendNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return catime ( pname, defaultIterations, dontAppendNumber );
|
||||
}
|
||||
}
|
||||
printf ( "usage: %s %s\n", argv[0], pUsage);
|
||||
return -1;
|
||||
}
|
||||
66
src/client/comBuf.cpp
Normal file
66
src/client/comBuf.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "comBuf.h"
|
||||
#include "errlog.h"
|
||||
|
||||
bool comBuf::flushToWire ( wireSendAdapter & wire, const epicsTime & currentTime )
|
||||
{
|
||||
unsigned index = this->nextReadIndex;
|
||||
unsigned finalIndex = this->commitIndex;
|
||||
while ( index < finalIndex ) {
|
||||
unsigned nBytes = wire.sendBytes (
|
||||
&this->buf[index], finalIndex - index, currentTime );
|
||||
if ( nBytes == 0u ) {
|
||||
this->nextReadIndex = index;
|
||||
return false;
|
||||
}
|
||||
index += nBytes;
|
||||
}
|
||||
this->nextReadIndex = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
// throwing the exception from a function that isnt inline
|
||||
// shrinks the GNU compiled object code
|
||||
void comBuf::throwInsufficentBytesException ()
|
||||
{
|
||||
throw comBuf::insufficentBytesAvailable ();
|
||||
}
|
||||
|
||||
void comBuf::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
comBufMemoryManager::~comBufMemoryManager () {}
|
||||
335
src/client/comBuf.h
Normal file
335
src/client/comBuf.h
Normal file
@@ -0,0 +1,335 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
#ifndef comBufh
|
||||
#define comBufh
|
||||
|
||||
#include <new>
|
||||
#include <cstring>
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "tsDLList.h"
|
||||
#include "osiWireFormat.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
static const unsigned comBufSize = 0x4000;
|
||||
|
||||
// this wrapper avoids Tornado 2.0.1 compiler bugs
|
||||
class comBufMemoryManager {
|
||||
public:
|
||||
virtual ~comBufMemoryManager ();
|
||||
virtual void * allocate ( size_t ) = 0;
|
||||
virtual void release ( void * ) = 0;
|
||||
};
|
||||
|
||||
class wireSendAdapter {
|
||||
public:
|
||||
virtual unsigned sendBytes ( const void * pBuf,
|
||||
unsigned nBytesInBuf,
|
||||
const class epicsTime & currentTime ) = 0;
|
||||
protected:
|
||||
virtual ~wireSendAdapter() {}
|
||||
};
|
||||
|
||||
enum swioCircuitState {
|
||||
swioConnected,
|
||||
swioPeerHangup,
|
||||
swioPeerAbort,
|
||||
swioLinkFailure,
|
||||
swioLocalAbort
|
||||
};
|
||||
struct statusWireIO {
|
||||
unsigned bytesCopied;
|
||||
swioCircuitState circuitState;
|
||||
};
|
||||
|
||||
class wireRecvAdapter {
|
||||
public:
|
||||
virtual void recvBytes ( void * pBuf,
|
||||
unsigned nBytesInBuf, statusWireIO & ) = 0;
|
||||
protected:
|
||||
virtual ~wireRecvAdapter() {}
|
||||
};
|
||||
|
||||
class comBuf : public tsDLNode < comBuf > {
|
||||
public:
|
||||
class insufficentBytesAvailable {};
|
||||
comBuf ();
|
||||
unsigned unoccupiedBytes () const;
|
||||
unsigned occupiedBytes () const;
|
||||
unsigned uncommittedBytes () const;
|
||||
static unsigned capacityBytes ();
|
||||
void clear ();
|
||||
unsigned copyInBytes ( const void *pBuf, unsigned nBytes );
|
||||
unsigned push ( comBuf & );
|
||||
template < class T >
|
||||
bool push ( const T & value );
|
||||
template < class T >
|
||||
unsigned push ( const T * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsInt8 * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsUInt8 * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsOldString * pValue, unsigned nElem );
|
||||
void commitIncomming ();
|
||||
void clearUncommittedIncomming ();
|
||||
bool copyInAllBytes ( const void *pBuf, unsigned nBytes );
|
||||
unsigned copyOutBytes ( void *pBuf, unsigned nBytes );
|
||||
bool copyOutAllBytes ( void *pBuf, unsigned nBytes );
|
||||
unsigned removeBytes ( unsigned nBytes );
|
||||
bool flushToWire ( wireSendAdapter &, const epicsTime & currentTime );
|
||||
void fillFromWire ( wireRecvAdapter &, statusWireIO & );
|
||||
struct popStatus {
|
||||
bool success;
|
||||
bool nowEmpty;
|
||||
};
|
||||
template < class T >
|
||||
popStatus pop ( T & );
|
||||
static void throwInsufficentBytesException ();
|
||||
void * operator new ( size_t size,
|
||||
comBufMemoryManager & );
|
||||
epicsPlacementDeleteOperator (( void *, comBufMemoryManager & ))
|
||||
private:
|
||||
unsigned commitIndex;
|
||||
unsigned nextWriteIndex;
|
||||
unsigned nextReadIndex;
|
||||
epicsUInt8 buf [ comBufSize ];
|
||||
void operator delete ( void * );
|
||||
template < class T >
|
||||
bool push ( const T * ); // disabled
|
||||
};
|
||||
|
||||
inline void * comBuf::operator new ( size_t size,
|
||||
comBufMemoryManager & mgr )
|
||||
{
|
||||
return mgr.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void comBuf::operator delete ( void * pCadaver,
|
||||
comBufMemoryManager & mgr )
|
||||
{
|
||||
mgr.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline comBuf::comBuf () : commitIndex ( 0u ),
|
||||
nextWriteIndex ( 0u ), nextReadIndex ( 0u )
|
||||
{
|
||||
}
|
||||
|
||||
inline void comBuf :: clear ()
|
||||
{
|
||||
this->commitIndex = 0u;
|
||||
this->nextWriteIndex = 0u;
|
||||
this->nextReadIndex = 0u;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: unoccupiedBytes () const
|
||||
{
|
||||
return sizeof ( this->buf ) - this->nextWriteIndex;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: occupiedBytes () const
|
||||
{
|
||||
return this->commitIndex - this->nextReadIndex;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: uncommittedBytes () const
|
||||
{
|
||||
return this->nextWriteIndex - this->commitIndex;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( comBuf & bufIn )
|
||||
{
|
||||
unsigned nBytes = this->copyInBytes (
|
||||
& bufIn.buf[ bufIn.nextReadIndex ],
|
||||
bufIn.commitIndex - bufIn.nextReadIndex );
|
||||
bufIn.nextReadIndex += nBytes;
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: capacityBytes ()
|
||||
{
|
||||
return comBufSize;
|
||||
}
|
||||
|
||||
inline void comBuf :: fillFromWire (
|
||||
wireRecvAdapter & wire, statusWireIO & stat )
|
||||
{
|
||||
wire.recvBytes (
|
||||
& this->buf[this->nextWriteIndex],
|
||||
sizeof ( this->buf ) - this->nextWriteIndex, stat );
|
||||
if ( stat.circuitState == swioConnected ) {
|
||||
this->nextWriteIndex += stat.bytesCopied;
|
||||
}
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline bool comBuf :: push ( const T & value )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
if ( sizeof ( value ) > available ) {
|
||||
return false;
|
||||
}
|
||||
WireSet ( value, & this->buf[index] );
|
||||
this->nextWriteIndex = index + sizeof ( value );
|
||||
return true;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const epicsInt8 *pValue, unsigned nElem )
|
||||
{
|
||||
return copyInBytes ( pValue, nElem );
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const epicsUInt8 *pValue, unsigned nElem )
|
||||
{
|
||||
return copyInBytes ( pValue, nElem );
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const epicsOldString * pValue, unsigned nElem )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
unsigned nBytes = sizeof ( *pValue ) * nElem;
|
||||
if ( nBytes > available ) {
|
||||
nElem = available / sizeof ( *pValue );
|
||||
nBytes = nElem * sizeof ( *pValue );
|
||||
}
|
||||
memcpy ( &this->buf[ index ], pValue, nBytes );
|
||||
this->nextWriteIndex = index + nBytes;
|
||||
return nElem;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
unsigned comBuf :: push ( const T * pValue, unsigned nElem )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
unsigned nBytes = sizeof ( *pValue ) * nElem;
|
||||
if ( nBytes > available ) {
|
||||
nElem = available / sizeof ( *pValue );
|
||||
}
|
||||
for ( unsigned i = 0u; i < nElem; i++ ) {
|
||||
// allow native floating point formats to be converted to IEEE
|
||||
WireSet( pValue[i], &this->buf[index] );
|
||||
index += sizeof ( *pValue );
|
||||
}
|
||||
this->nextWriteIndex = index;
|
||||
return nElem;
|
||||
}
|
||||
|
||||
inline void comBuf :: commitIncomming ()
|
||||
{
|
||||
this->commitIndex = this->nextWriteIndex;
|
||||
}
|
||||
|
||||
inline void comBuf :: clearUncommittedIncomming ()
|
||||
{
|
||||
this->nextWriteIndex = this->commitIndex;
|
||||
}
|
||||
|
||||
inline bool comBuf :: copyInAllBytes ( const void *pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
if ( nBytes <= available ) {
|
||||
memcpy ( & this->buf[index], pBuf, nBytes );
|
||||
this->nextWriteIndex = index + nBytes;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: copyInBytes ( const void * pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
if ( nBytes > available ) {
|
||||
nBytes = available;
|
||||
}
|
||||
memcpy ( & this->buf[index], pBuf, nBytes );
|
||||
this->nextWriteIndex = index + nBytes;
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
inline bool comBuf :: copyOutAllBytes ( void * pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextReadIndex;
|
||||
unsigned occupied = this->commitIndex - index;
|
||||
if ( nBytes <= occupied ) {
|
||||
memcpy ( pBuf, &this->buf[index], nBytes);
|
||||
this->nextReadIndex = index + nBytes;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: copyOutBytes ( void *pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextReadIndex;
|
||||
unsigned occupied = this->commitIndex - index;
|
||||
if ( nBytes > occupied ) {
|
||||
nBytes = occupied;
|
||||
}
|
||||
memcpy ( pBuf, &this->buf[index], nBytes);
|
||||
this->nextReadIndex = index + nBytes;
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: removeBytes ( unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextReadIndex;
|
||||
unsigned occupied = this->commitIndex - index;
|
||||
if ( nBytes > occupied ) {
|
||||
nBytes = occupied;
|
||||
}
|
||||
this->nextReadIndex = index + nBytes;
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
comBuf :: popStatus comBuf :: pop ( T & returnVal )
|
||||
{
|
||||
unsigned nrIndex = this->nextReadIndex;
|
||||
unsigned popIndex = nrIndex + sizeof ( returnVal );
|
||||
unsigned cIndex = this->commitIndex;
|
||||
popStatus status;
|
||||
status.success = true;
|
||||
status.nowEmpty = false;
|
||||
if ( popIndex >= cIndex ) {
|
||||
if ( popIndex == cIndex ) {
|
||||
status.nowEmpty = true;
|
||||
}
|
||||
else {
|
||||
status.success = false;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
WireGet ( & this->buf[ nrIndex ], returnVal );
|
||||
this->nextReadIndex = popIndex;
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif // ifndef comBufh
|
||||
269
src/client/comQueRecv.cpp
Normal file
269
src/client/comQueRecv.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "iocinf.h"
|
||||
#include "virtualCircuit.h"
|
||||
|
||||
comQueRecv::comQueRecv ( comBufMemoryManager & comBufMemoryManagerIn ):
|
||||
comBufMemMgr ( comBufMemoryManagerIn ), nBytesPending ( 0u )
|
||||
{
|
||||
}
|
||||
|
||||
comQueRecv::~comQueRecv ()
|
||||
{
|
||||
this->clear ();
|
||||
}
|
||||
|
||||
void comQueRecv::clear ()
|
||||
{
|
||||
comBuf *pBuf;
|
||||
while ( ( pBuf = this->bufs.get () ) ) {
|
||||
pBuf->~comBuf ();
|
||||
this->comBufMemMgr.release ( pBuf );
|
||||
}
|
||||
this->nBytesPending = 0u;
|
||||
}
|
||||
|
||||
unsigned comQueRecv::copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned totalBytes = 0u;
|
||||
do {
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
this->nBytesPending -= totalBytes;
|
||||
return totalBytes;
|
||||
}
|
||||
totalBytes += pComBuf->copyOutBytes ( &pBuf[totalBytes], nBytes - totalBytes );
|
||||
if ( pComBuf->occupiedBytes () == 0u ) {
|
||||
this->bufs.remove ( *pComBuf );
|
||||
pComBuf->~comBuf ();
|
||||
this->comBufMemMgr.release ( pComBuf );
|
||||
}
|
||||
}
|
||||
while ( totalBytes < nBytes );
|
||||
this->nBytesPending -= totalBytes;
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
unsigned comQueRecv::removeBytes ( unsigned nBytes )
|
||||
{
|
||||
unsigned totalBytes = 0u;
|
||||
unsigned bytesLeft = nBytes;
|
||||
while ( bytesLeft ) {
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
this->nBytesPending -= totalBytes;
|
||||
return totalBytes;
|
||||
}
|
||||
unsigned nBytesThisTime = pComBuf->removeBytes ( bytesLeft );
|
||||
if ( pComBuf->occupiedBytes () == 0u ) {
|
||||
this->bufs.remove ( *pComBuf );
|
||||
pComBuf->~comBuf ();
|
||||
this->comBufMemMgr.release ( pComBuf );
|
||||
}
|
||||
if ( nBytesThisTime == 0u) {
|
||||
break;
|
||||
}
|
||||
totalBytes += nBytesThisTime;
|
||||
bytesLeft = nBytes - totalBytes;
|
||||
}
|
||||
this->nBytesPending -= totalBytes;
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
void comQueRecv::popString ( epicsOldString *pStr )
|
||||
{
|
||||
for ( unsigned i = 0u; i < sizeof ( *pStr ); i++ ) {
|
||||
pStr[0][i] = this->popInt8 ();
|
||||
}
|
||||
}
|
||||
|
||||
void comQueRecv::pushLastComBufReceived ( comBuf & bufIn )
|
||||
|
||||
{
|
||||
bufIn.commitIncomming ();
|
||||
comBuf * pComBuf = this->bufs.last ();
|
||||
if ( pComBuf ) {
|
||||
if ( pComBuf->unoccupiedBytes() ) {
|
||||
this->nBytesPending += pComBuf->push ( bufIn );
|
||||
pComBuf->commitIncomming ();
|
||||
}
|
||||
}
|
||||
unsigned bufBytes = bufIn.occupiedBytes();
|
||||
if ( bufBytes ) {
|
||||
this->nBytesPending += bufBytes;
|
||||
this->bufs.add ( bufIn );
|
||||
}
|
||||
else {
|
||||
bufIn.~comBuf ();
|
||||
this->comBufMemMgr.release ( & bufIn );
|
||||
}
|
||||
}
|
||||
|
||||
// 1) split between buffers expected to run slower
|
||||
// 2) using canonical unsigned tmp avoids ANSI C conversions to int
|
||||
// 3) cast required because sizeof(unsigned) >= sizeof(epicsUInt32)
|
||||
epicsUInt16 comQueRecv::multiBufferPopUInt16 ()
|
||||
{
|
||||
epicsUInt16 tmp;
|
||||
if ( this->occupiedBytes() >= sizeof (tmp) ) {
|
||||
unsigned byte1 = this->popUInt8 ();
|
||||
unsigned byte2 = this->popUInt8 ();
|
||||
tmp = static_cast <epicsUInt16> ( ( byte1 << 8u ) | byte2 );
|
||||
}
|
||||
else {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
tmp = 0u;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// 1) split between buffers expected to run slower
|
||||
// 2) using canonical unsigned temporary avoids ANSI C conversions to int
|
||||
// 3) cast required because sizeof(unsigned) >= sizeof(epicsUInt32)
|
||||
epicsUInt32 comQueRecv::multiBufferPopUInt32 ()
|
||||
{
|
||||
epicsUInt32 tmp;
|
||||
if ( this->occupiedBytes() >= sizeof (tmp) ) {
|
||||
// 1) split between buffers expected to run slower
|
||||
// 2) using canonical unsigned temporary avoids ANSI C conversions to int
|
||||
// 3) cast required because sizeof(unsigned) >= sizeof(epicsUInt32)
|
||||
unsigned byte1 = this->popUInt8();
|
||||
unsigned byte2 = this->popUInt8();
|
||||
unsigned byte3 = this->popUInt8();
|
||||
unsigned byte4 = this->popUInt8();
|
||||
tmp = static_cast <epicsUInt32>
|
||||
( ( byte1 << 24u ) | ( byte2 << 16u ) |
|
||||
( byte3 << 8u ) | byte4 );
|
||||
}
|
||||
else {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
tmp = 0u; // avoid compiler warnings
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void comQueRecv::removeAndDestroyBuf ( comBuf & buf )
|
||||
{
|
||||
this->bufs.remove ( buf );
|
||||
buf.~comBuf ();
|
||||
this->comBufMemMgr.release ( & buf );
|
||||
}
|
||||
|
||||
epicsUInt8 comQueRecv::popUInt8 ()
|
||||
{
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
epicsUInt8 tmp = '\0';
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( ! status.success ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
if ( status.nowEmpty ) {
|
||||
this->removeAndDestroyBuf ( *pComBuf );
|
||||
}
|
||||
this->nBytesPending--;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
epicsUInt16 comQueRecv::popUInt16 ()
|
||||
{
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
// try first for all in one buffer efficent version
|
||||
epicsUInt16 tmp = 0;
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( status.success ) {
|
||||
this->nBytesPending -= sizeof ( epicsUInt16 );
|
||||
if ( status.nowEmpty ) {
|
||||
this->removeAndDestroyBuf ( *pComBuf );
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
return this->multiBufferPopUInt16 ();
|
||||
}
|
||||
|
||||
epicsUInt32 comQueRecv::popUInt32 ()
|
||||
{
|
||||
comBuf *pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
// try first for all in one buffer efficent version
|
||||
epicsUInt32 tmp = 0;
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( status.success ) {
|
||||
this->nBytesPending -= sizeof ( epicsUInt32 );
|
||||
if ( status.nowEmpty ) {
|
||||
this->removeAndDestroyBuf ( *pComBuf );
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
return this->multiBufferPopUInt32 ();
|
||||
}
|
||||
|
||||
bool comQueRecv::popOldMsgHeader ( caHdrLargeArray & msg )
|
||||
{
|
||||
// try first for all in one buffer efficent version
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
return false;
|
||||
}
|
||||
unsigned avail = pComBuf->occupiedBytes ();
|
||||
if ( avail >= sizeof ( caHdr ) ) {
|
||||
pComBuf->pop ( msg.m_cmmd );
|
||||
ca_uint16_t smallPostsize = 0;
|
||||
pComBuf->pop ( smallPostsize );
|
||||
msg.m_postsize = smallPostsize;
|
||||
pComBuf->pop ( msg.m_dataType );
|
||||
ca_uint16_t smallCount = 0;
|
||||
pComBuf->pop ( smallCount );
|
||||
msg.m_count = smallCount;
|
||||
pComBuf->pop ( msg.m_cid );
|
||||
pComBuf->pop ( msg.m_available );
|
||||
this->nBytesPending -= sizeof ( caHdr );
|
||||
if ( avail == sizeof ( caHdr ) ) {
|
||||
this->removeAndDestroyBuf ( *pComBuf );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if ( this->occupiedBytes () >= sizeof ( caHdr ) ) {
|
||||
msg.m_cmmd = this->popUInt16 ();
|
||||
msg.m_postsize = this->popUInt16 ();
|
||||
msg.m_dataType = this->popUInt16 ();
|
||||
msg.m_count = this->popUInt16 ();
|
||||
msg.m_cid = this->popUInt32 ();
|
||||
msg.m_available = this->popUInt32 ();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
111
src/client/comQueRecv.h
Normal file
111
src/client/comQueRecv.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef comQueRecvh
|
||||
#define comQueRecvh
|
||||
|
||||
#include "comBuf.h"
|
||||
|
||||
class comQueRecv {
|
||||
public:
|
||||
comQueRecv ( comBufMemoryManager & );
|
||||
~comQueRecv ();
|
||||
unsigned occupiedBytes () const;
|
||||
unsigned copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes );
|
||||
unsigned removeBytes ( unsigned nBytes );
|
||||
void pushLastComBufReceived ( comBuf & );
|
||||
void clear ();
|
||||
bool popOldMsgHeader ( struct caHdrLargeArray & );
|
||||
epicsInt8 popInt8 ();
|
||||
epicsUInt8 popUInt8 ();
|
||||
epicsInt16 popInt16 ();
|
||||
epicsUInt16 popUInt16 ();
|
||||
epicsInt32 popInt32 ();
|
||||
epicsUInt32 popUInt32 ();
|
||||
epicsFloat32 popFloat32 ();
|
||||
epicsFloat64 popFloat64 ();
|
||||
void popString ( epicsOldString * );
|
||||
private:
|
||||
tsDLList < comBuf > bufs;
|
||||
comBufMemoryManager & comBufMemMgr;
|
||||
unsigned nBytesPending;
|
||||
epicsUInt16 multiBufferPopUInt16 ();
|
||||
epicsUInt32 multiBufferPopUInt32 ();
|
||||
void removeAndDestroyBuf ( comBuf & );
|
||||
comQueRecv ( const comQueRecv & );
|
||||
comQueRecv & operator = ( const comQueRecv & );
|
||||
};
|
||||
|
||||
inline unsigned comQueRecv::occupiedBytes () const
|
||||
{
|
||||
return this->nBytesPending;
|
||||
}
|
||||
|
||||
inline epicsInt8 comQueRecv::popInt8 ()
|
||||
{
|
||||
return static_cast < epicsInt8 > ( this->popUInt8() );
|
||||
}
|
||||
|
||||
inline epicsInt16 comQueRecv::popInt16 ()
|
||||
{
|
||||
return static_cast < epicsInt16 > ( this->popUInt16() );
|
||||
}
|
||||
|
||||
inline epicsInt32 comQueRecv::popInt32 ()
|
||||
{
|
||||
return static_cast < epicsInt32 > ( this->popUInt32() );
|
||||
}
|
||||
|
||||
// this has been optimized to aligned convert, maybe more could be done,
|
||||
// but since it is currently not used ...
|
||||
inline epicsFloat32 comQueRecv::popFloat32 ()
|
||||
{
|
||||
union {
|
||||
epicsUInt8 _wire[ sizeof ( epicsFloat32 ) ];
|
||||
epicsFloat32 _fp;
|
||||
} tmp;
|
||||
// optimizer will unroll this loop
|
||||
for ( unsigned i = 0u; i < sizeof ( tmp._wire ); i++ ) {
|
||||
tmp._wire[i] = this->popUInt8 ();
|
||||
}
|
||||
return AlignedWireRef < epicsFloat32 > ( tmp._fp );
|
||||
}
|
||||
|
||||
// this has been optimized to aligned convert, maybe more could be done,
|
||||
// but since it is currently not used ...
|
||||
inline epicsFloat64 comQueRecv::popFloat64 ()
|
||||
{
|
||||
union {
|
||||
epicsUInt8 _wire[ sizeof ( epicsFloat64 ) ];
|
||||
epicsFloat64 _fp;
|
||||
} tmp;
|
||||
// optimizer will unroll this loop
|
||||
for ( unsigned i = 0u; i < sizeof ( tmp._wire ); i++ ) {
|
||||
tmp._wire[i] = this->popUInt8 ();
|
||||
}
|
||||
return AlignedWireRef < epicsFloat64 > ( tmp._fp );
|
||||
}
|
||||
|
||||
#endif // ifndef comQueRecvh
|
||||
411
src/client/comQueSend.cpp
Normal file
411
src/client/comQueSend.cpp
Normal file
@@ -0,0 +1,411 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
//
|
||||
// Requirements:
|
||||
// 1) Allow sufficent headroom so that users will be able to perform
|
||||
// a reasonable amount of IO within CA callbacks without experiencing
|
||||
// a push/pull deadlock. If a potential push/pull deadlock situation
|
||||
// occurs then detect and avoid it and provide diagnotic to the user
|
||||
// via special status.
|
||||
// 2) Return status to the user when there is insufficent memory to
|
||||
// queue a complete message.
|
||||
// 3) return status to the user when a message cant be flushed because
|
||||
// a connection dropped.
|
||||
// 4) Do not allocate too much memory in exception situatons (such as
|
||||
// after a circuit disconnect).
|
||||
// 5) Avoid allocating more memory than is absolutely necessary to meet
|
||||
// the above requirements.
|
||||
// 6) Message fragments must never be sent to the IOC when there isnt
|
||||
// enough memory to queue part of a message (we also must not force
|
||||
// a disconnect because the client is starved for memory).
|
||||
// 7) avoid the need to check status for each byte pushed into the
|
||||
// protocol stream.
|
||||
//
|
||||
// Implementation:
|
||||
// 1) When queuing a complete message, first test to see if a flush is
|
||||
// required. If it is a receive thread scheduals the flush with the
|
||||
// send thread, and otherwise directly execute the system call. The
|
||||
// send thread must run at a higher priority than the receive thread
|
||||
// if we are to minimize memory consumption.
|
||||
// 2) Preallocate space for the entire message prior to copying in the
|
||||
// message so that message fragments are not flushed out just prior
|
||||
// to detecting that memory is unavailable.
|
||||
// 3) Return a special error constant when the following situations
|
||||
// are detected when the user is attempting to queue a request
|
||||
// from within a user callback executed by a receive thread:
|
||||
// a) A user is queuing more requests that demand a response from a
|
||||
// callback than are removed by the response that initiated the
|
||||
// callback, and this situation persists for many callbacks until
|
||||
// all buffering in the system is exausted.
|
||||
// b) A user is queuing many requests that demand a response from one
|
||||
// callback until all buffering in the system is exausted.
|
||||
// c) Some combination of both (a) nad (b).
|
||||
//
|
||||
//
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "virtualCircuit.h"
|
||||
#include "db_access.h" // for dbr_short_t etc
|
||||
|
||||
// nill message alignment pad bytes
|
||||
const char cacNillBytes [] =
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
comQueSend::comQueSend ( wireSendAdapter & wireIn,
|
||||
comBufMemoryManager & comBufMemMgrIn ):
|
||||
comBufMemMgr ( comBufMemMgrIn ), wire ( wireIn ),
|
||||
nBytesPending ( 0u )
|
||||
{
|
||||
}
|
||||
|
||||
comQueSend::~comQueSend ()
|
||||
{
|
||||
this->clear ();
|
||||
}
|
||||
|
||||
void comQueSend::clear ()
|
||||
{
|
||||
comBuf *pBuf;
|
||||
|
||||
while ( ( pBuf = this->bufs.get () ) ) {
|
||||
this->nBytesPending -= pBuf->occupiedBytes ();
|
||||
pBuf->~comBuf ();
|
||||
this->comBufMemMgr.release ( pBuf );
|
||||
}
|
||||
this->pFirstUncommited = tsDLIter < comBuf > ();
|
||||
assert ( this->nBytesPending == 0 );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_string ( const void * pValue )
|
||||
{
|
||||
this->push ( static_cast < const char * > ( pValue ), MAX_STRING_SIZE );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_short ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_short_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_float ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_float_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_char ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_char_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_long ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_long_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_double ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_double_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_invalid ( const void * )
|
||||
{
|
||||
throw cacChannel::badType ();
|
||||
}
|
||||
|
||||
const comQueSend::copyScalarFunc_t comQueSend::dbrCopyScalar [39] = {
|
||||
&comQueSend::copy_dbr_string,
|
||||
&comQueSend::copy_dbr_short,
|
||||
&comQueSend::copy_dbr_float,
|
||||
&comQueSend::copy_dbr_short, // DBR_ENUM
|
||||
&comQueSend::copy_dbr_char,
|
||||
&comQueSend::copy_dbr_long,
|
||||
&comQueSend::copy_dbr_double,
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_INT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_DOUBLE
|
||||
&comQueSend::copy_dbr_short, // DBR_PUT_ACKT
|
||||
&comQueSend::copy_dbr_short, // DBR_PUT_ACKS
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STSACK_STRING
|
||||
&comQueSend::copy_dbr_invalid // DBR_CLASS_NAME
|
||||
};
|
||||
|
||||
void comQueSend::copy_dbr_string ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast < const char * > ( pValue ), nElem * MAX_STRING_SIZE );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_short ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_short_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_float ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_float_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_char ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_char_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_long ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_long_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_double ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_double_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_invalid ( const void *, unsigned )
|
||||
{
|
||||
throw cacChannel::badType ();
|
||||
}
|
||||
|
||||
const comQueSend::copyVectorFunc_t comQueSend::dbrCopyVector [39] = {
|
||||
&comQueSend::copy_dbr_string,
|
||||
&comQueSend::copy_dbr_short,
|
||||
&comQueSend::copy_dbr_float,
|
||||
&comQueSend::copy_dbr_short, // DBR_ENUM
|
||||
&comQueSend::copy_dbr_char,
|
||||
&comQueSend::copy_dbr_long,
|
||||
&comQueSend::copy_dbr_double,
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_INT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_DOUBLE
|
||||
&comQueSend::copy_dbr_short, // DBR_PUT_ACKT
|
||||
&comQueSend::copy_dbr_short, // DBR_PUT_ACKS
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STSACK_STRING
|
||||
&comQueSend::copy_dbr_invalid // DBR_CLASS_NAME
|
||||
};
|
||||
|
||||
comBuf * comQueSend::popNextComBufToSend ()
|
||||
{
|
||||
comBuf *pBuf = this->bufs.get ();
|
||||
if ( pBuf ) {
|
||||
unsigned nBytesThisBuf = pBuf->occupiedBytes ();
|
||||
if ( nBytesThisBuf ) {
|
||||
assert ( this->nBytesPending >= nBytesThisBuf );
|
||||
this->nBytesPending -= nBytesThisBuf;
|
||||
}
|
||||
else {
|
||||
this->bufs.push ( *pBuf );
|
||||
pBuf = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert ( this->nBytesPending == 0u );
|
||||
}
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
void comQueSend::insertRequestHeader (
|
||||
ca_uint16_t request, ca_uint32_t payloadSize,
|
||||
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
|
||||
ca_uint32_t requestDependent, bool v49Ok )
|
||||
{
|
||||
if ( payloadSize < 0xffff && nElem < 0xffff ) {
|
||||
comBuf * pComBuf = this->bufs.last ();
|
||||
if ( ! pComBuf || pComBuf->unoccupiedBytes() < 16u ) {
|
||||
pComBuf = newComBuf ();
|
||||
this->pushComBuf ( *pComBuf );
|
||||
}
|
||||
pComBuf->push ( request );
|
||||
pComBuf->push ( static_cast < ca_uint16_t > ( payloadSize ) );
|
||||
pComBuf->push ( dataType );
|
||||
pComBuf->push ( static_cast < ca_uint16_t > ( nElem ) );
|
||||
pComBuf->push ( cid );
|
||||
pComBuf->push ( requestDependent );
|
||||
}
|
||||
else if ( v49Ok ) {
|
||||
comBuf * pComBuf = this->bufs.last ();
|
||||
if ( ! pComBuf || pComBuf->unoccupiedBytes() < 24u ) {
|
||||
pComBuf = newComBuf ();
|
||||
this->pushComBuf ( *pComBuf );
|
||||
}
|
||||
pComBuf->push ( request );
|
||||
pComBuf->push ( static_cast < ca_uint16_t > ( 0xffff ) );
|
||||
pComBuf->push ( dataType );
|
||||
pComBuf->push ( static_cast < ca_uint16_t > ( 0u ) );
|
||||
pComBuf->push ( cid );
|
||||
pComBuf->push ( requestDependent );
|
||||
pComBuf->push ( payloadSize );
|
||||
pComBuf->push ( nElem );
|
||||
}
|
||||
else {
|
||||
throw cacChannel::outOfBounds ();
|
||||
}
|
||||
}
|
||||
|
||||
void comQueSend::insertRequestWithPayLoad (
|
||||
ca_uint16_t request, unsigned dataType, arrayElementCount nElem,
|
||||
ca_uint32_t cid, ca_uint32_t requestDependent,
|
||||
const void * pPayload, bool v49Ok )
|
||||
{
|
||||
if ( INVALID_DB_REQ ( dataType ) ) {
|
||||
throw cacChannel::badType ();
|
||||
}
|
||||
if ( dataType >= comQueSendCopyDispatchSize ) {
|
||||
throw cacChannel::badType();
|
||||
}
|
||||
ca_uint32_t size = 0u;
|
||||
ca_uint32_t payloadSize = 0u;
|
||||
if ( nElem == 1 ) {
|
||||
if ( dataType == DBR_STRING ) {
|
||||
const char * pStr = static_cast < const char * > ( pPayload );
|
||||
size = strlen ( pStr ) + 1u;
|
||||
if ( size > MAX_STRING_SIZE ) {
|
||||
throw cacChannel::outOfBounds();
|
||||
}
|
||||
payloadSize = CA_MESSAGE_ALIGN ( size );
|
||||
this->insertRequestHeader ( request, payloadSize,
|
||||
static_cast <ca_uint16_t> ( dataType ),
|
||||
nElem, cid, requestDependent, v49Ok );
|
||||
this->pushString ( pStr, size );
|
||||
}
|
||||
else {
|
||||
size = dbr_size[dataType];
|
||||
payloadSize = CA_MESSAGE_ALIGN ( size );
|
||||
this->insertRequestHeader ( request, payloadSize,
|
||||
static_cast <ca_uint16_t> ( dataType ),
|
||||
nElem, cid, requestDependent, v49Ok );
|
||||
( this->*dbrCopyScalar [dataType] ) ( pPayload );
|
||||
}
|
||||
}
|
||||
else {
|
||||
arrayElementCount maxBytes;
|
||||
if ( v49Ok ) {
|
||||
maxBytes = 0xffffffff;
|
||||
}
|
||||
else {
|
||||
maxBytes = MAX_TCP - sizeof ( caHdr );
|
||||
}
|
||||
arrayElementCount maxElem =
|
||||
( maxBytes - sizeof (dbr_double_t) - dbr_size[dataType] ) /
|
||||
dbr_value_size[dataType];
|
||||
if ( nElem >= maxElem ) {
|
||||
throw cacChannel::outOfBounds();
|
||||
}
|
||||
// the above checks verify that the total size
|
||||
// is lest that 0xffffffff
|
||||
size = static_cast < ca_uint32_t >
|
||||
( dbr_size_n ( dataType, nElem ) );
|
||||
payloadSize = CA_MESSAGE_ALIGN ( size );
|
||||
this->insertRequestHeader ( request, payloadSize,
|
||||
static_cast <ca_uint16_t> ( dataType ),
|
||||
static_cast < ca_uint32_t > ( nElem ),
|
||||
cid, requestDependent, v49Ok );
|
||||
( this->*dbrCopyVector [dataType] ) ( pPayload, nElem );
|
||||
}
|
||||
// set pad bytes to nill
|
||||
unsigned padSize = payloadSize - size;
|
||||
if ( padSize ) {
|
||||
this->pushString ( cacNillBytes, payloadSize - size );
|
||||
}
|
||||
}
|
||||
|
||||
void comQueSend::commitMsg ()
|
||||
{
|
||||
while ( this->pFirstUncommited.valid() ) {
|
||||
this->nBytesPending += this->pFirstUncommited->uncommittedBytes ();
|
||||
this->pFirstUncommited->commitIncomming ();
|
||||
this->pFirstUncommited++;
|
||||
}
|
||||
// printf ( "NBP: %u\n", this->nBytesPending );
|
||||
}
|
||||
|
||||
|
||||
void comQueSend::clearUncommitedMsg ()
|
||||
{
|
||||
while ( this->pFirstUncommited.valid() ) {
|
||||
tsDLIter < comBuf > next = this->pFirstUncommited;
|
||||
next++;
|
||||
this->pFirstUncommited->clearUncommittedIncomming ();
|
||||
if ( this->pFirstUncommited->occupiedBytes() == 0u ) {
|
||||
this->bufs.remove ( *this->pFirstUncommited );
|
||||
this->pFirstUncommited->~comBuf ();
|
||||
this->comBufMemMgr.release ( this->pFirstUncommited.pointer() );
|
||||
}
|
||||
this->pFirstUncommited = next;
|
||||
}
|
||||
}
|
||||
|
||||
238
src/client/comQueSend.h
Normal file
238
src/client/comQueSend.h
Normal file
@@ -0,0 +1,238 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef comQueSendh
|
||||
#define comQueSendh
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include "comBuf.h"
|
||||
|
||||
#define comQueSendCopyDispatchSize 39
|
||||
|
||||
class epicsMutex;
|
||||
template < class T > class epicsGuard;
|
||||
|
||||
class comQueSendMsgMinder {
|
||||
public:
|
||||
comQueSendMsgMinder (
|
||||
class comQueSend &, epicsGuard < epicsMutex > & );
|
||||
~comQueSendMsgMinder ();
|
||||
void commit ();
|
||||
private:
|
||||
class comQueSend * pSendQue;
|
||||
};
|
||||
|
||||
//
|
||||
// Notes.
|
||||
// o calling popNextComBufToSend() will clear any uncommitted bytes
|
||||
//
|
||||
class comQueSend {
|
||||
public:
|
||||
comQueSend ( wireSendAdapter &, comBufMemoryManager & );
|
||||
~comQueSend ();
|
||||
void clear ();
|
||||
unsigned occupiedBytes () const;
|
||||
bool flushEarlyThreshold ( unsigned nBytesThisMsg ) const;
|
||||
bool flushBlockThreshold () const;
|
||||
void pushUInt16 ( const ca_uint16_t value );
|
||||
void pushUInt32 ( const ca_uint32_t value );
|
||||
void pushFloat32 ( const ca_float32_t value );
|
||||
void pushString ( const char *pVal, unsigned nChar );
|
||||
void insertRequestHeader (
|
||||
ca_uint16_t request, ca_uint32_t payloadSize,
|
||||
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
|
||||
ca_uint32_t requestDependent, bool v49Ok );
|
||||
void insertRequestWithPayLoad (
|
||||
ca_uint16_t request, unsigned dataType, arrayElementCount nElem,
|
||||
ca_uint32_t cid, ca_uint32_t requestDependent,
|
||||
const void * pPayload, bool v49Ok );
|
||||
comBuf * popNextComBufToSend ();
|
||||
private:
|
||||
comBufMemoryManager & comBufMemMgr;
|
||||
tsDLList < comBuf > bufs;
|
||||
tsDLIter < comBuf > pFirstUncommited;
|
||||
wireSendAdapter & wire;
|
||||
unsigned nBytesPending;
|
||||
|
||||
typedef void ( comQueSend::*copyScalarFunc_t ) (
|
||||
const void * pValue );
|
||||
static const copyScalarFunc_t dbrCopyScalar [comQueSendCopyDispatchSize];
|
||||
void copy_dbr_string ( const void * pValue );
|
||||
void copy_dbr_short ( const void * pValue );
|
||||
void copy_dbr_float ( const void * pValue );
|
||||
void copy_dbr_char ( const void * pValue );
|
||||
void copy_dbr_long ( const void * pValue );
|
||||
void copy_dbr_double ( const void * pValue );
|
||||
void copy_dbr_invalid ( const void * pValue );
|
||||
|
||||
typedef void ( comQueSend::*copyVectorFunc_t ) (
|
||||
const void * pValue, unsigned nElem );
|
||||
static const copyVectorFunc_t dbrCopyVector [comQueSendCopyDispatchSize];
|
||||
void copy_dbr_string ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_short ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_float ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_char ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_long ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_double ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_invalid ( const void * pValue, unsigned nElem );
|
||||
|
||||
void pushComBuf ( comBuf & );
|
||||
comBuf * newComBuf ();
|
||||
|
||||
void beginMsg ();
|
||||
void commitMsg ();
|
||||
void clearUncommitedMsg ();
|
||||
|
||||
friend class comQueSendMsgMinder;
|
||||
|
||||
//
|
||||
// visual C++ versions 6 & 7 do not allow out of
|
||||
// class member template function definition
|
||||
//
|
||||
template < class T >
|
||||
inline void push ( const T *pVal, const unsigned nElem )
|
||||
{
|
||||
comBuf * pLastBuf = this->bufs.last ();
|
||||
unsigned nCopied;
|
||||
if ( pLastBuf ) {
|
||||
nCopied = pLastBuf->push ( pVal, nElem );
|
||||
}
|
||||
else {
|
||||
nCopied = 0u;
|
||||
}
|
||||
while ( nElem > nCopied ) {
|
||||
comBuf * pComBuf = newComBuf ();
|
||||
nCopied += pComBuf->push
|
||||
( &pVal[nCopied], nElem - nCopied );
|
||||
this->pushComBuf ( *pComBuf );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// visual C++ versions 6 and 7 do not allow out of
|
||||
// class member template function definition
|
||||
//
|
||||
template < class T >
|
||||
inline void push ( const T & val )
|
||||
{
|
||||
comBuf * pComBuf = this->bufs.last ();
|
||||
if ( pComBuf && pComBuf->push ( val ) ) {
|
||||
return;
|
||||
}
|
||||
pComBuf = newComBuf ();
|
||||
bool success = pComBuf->push ( val );
|
||||
assert ( success );
|
||||
this->pushComBuf ( *pComBuf );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline void push ( const T * ); // disabled
|
||||
|
||||
comQueSend ( const comQueSend & );
|
||||
comQueSend & operator = ( const comQueSend & );
|
||||
};
|
||||
|
||||
extern const char cacNillBytes[];
|
||||
|
||||
inline comQueSendMsgMinder::comQueSendMsgMinder (
|
||||
class comQueSend & sendQueIn, epicsGuard < epicsMutex > & ) :
|
||||
pSendQue ( & sendQueIn )
|
||||
{
|
||||
sendQueIn.beginMsg ();
|
||||
}
|
||||
|
||||
inline comQueSendMsgMinder::~comQueSendMsgMinder ()
|
||||
{
|
||||
if ( this->pSendQue ) {
|
||||
this->pSendQue->clearUncommitedMsg ();
|
||||
}
|
||||
}
|
||||
|
||||
inline void comQueSendMsgMinder::commit ()
|
||||
{
|
||||
if ( this->pSendQue ) {
|
||||
this->pSendQue->commitMsg ();
|
||||
this->pSendQue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void comQueSend::beginMsg ()
|
||||
{
|
||||
this->pFirstUncommited = this->bufs.lastIter ();
|
||||
}
|
||||
|
||||
inline void comQueSend::pushUInt16 ( const ca_uint16_t value )
|
||||
{
|
||||
this->push ( value );
|
||||
}
|
||||
|
||||
inline void comQueSend::pushUInt32 ( const ca_uint32_t value )
|
||||
{
|
||||
this->push ( value );
|
||||
}
|
||||
|
||||
inline void comQueSend::pushFloat32 ( const ca_float32_t value )
|
||||
{
|
||||
this->push ( value );
|
||||
}
|
||||
|
||||
inline void comQueSend::pushString ( const char *pVal, unsigned nChar )
|
||||
{
|
||||
this->push ( pVal, nChar );
|
||||
}
|
||||
|
||||
inline void comQueSend::pushComBuf ( comBuf & cb )
|
||||
{
|
||||
this->bufs.add ( cb );
|
||||
if ( ! this->pFirstUncommited.valid() ) {
|
||||
this->pFirstUncommited = this->bufs.lastIter ();
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned comQueSend::occupiedBytes () const
|
||||
{
|
||||
return this->nBytesPending;
|
||||
}
|
||||
|
||||
inline bool comQueSend::flushBlockThreshold () const
|
||||
{
|
||||
return ( this->nBytesPending > 16 * comBuf::capacityBytes () );
|
||||
}
|
||||
|
||||
inline bool comQueSend::flushEarlyThreshold ( unsigned nBytesThisMsg ) const
|
||||
{
|
||||
return ( this->nBytesPending + nBytesThisMsg > 4 * comBuf::capacityBytes () );
|
||||
}
|
||||
|
||||
// wrapping this with a function avoids WRS T2.2 Cygnus GNU compiler bugs
|
||||
inline comBuf * comQueSend::newComBuf ()
|
||||
{
|
||||
return new ( this->comBufMemMgr ) comBuf;
|
||||
}
|
||||
|
||||
#endif // ifndef comQueSendh
|
||||
1440
src/client/convert.cpp
Normal file
1440
src/client/convert.cpp
Normal file
File diff suppressed because it is too large
Load Diff
740
src/client/db_access.h
Normal file
740
src/client/db_access.h
Normal file
@@ -0,0 +1,740 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/* base/include/db_access.h */
|
||||
/* Author: Bob Dalesio
|
||||
* Date: 4-4-88
|
||||
*/
|
||||
|
||||
#ifndef INCLdb_accessh
|
||||
#define INCLdb_accessh
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define INCLdb_accessh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsTypes.h"
|
||||
#include "epicsTime.h"
|
||||
|
||||
#ifdef INCLdb_accessh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_UNITS_SIZE 8
|
||||
#define MAX_ENUM_STRING_SIZE 26
|
||||
#define MAX_ENUM_STATES 16
|
||||
|
||||
/*
|
||||
* architecture independent types
|
||||
*
|
||||
* (so far this is sufficient for all archs we have ported to)
|
||||
*/
|
||||
typedef epicsOldString dbr_string_t;
|
||||
typedef epicsUInt8 dbr_char_t;
|
||||
typedef epicsInt16 dbr_short_t;
|
||||
typedef epicsUInt16 dbr_ushort_t;
|
||||
typedef epicsInt16 dbr_int_t;
|
||||
typedef epicsUInt16 dbr_enum_t;
|
||||
typedef epicsInt32 dbr_long_t;
|
||||
typedef epicsUInt32 dbr_ulong_t;
|
||||
typedef epicsFloat32 dbr_float_t;
|
||||
typedef epicsFloat64 dbr_double_t;
|
||||
typedef epicsUInt16 dbr_put_ackt_t;
|
||||
typedef epicsUInt16 dbr_put_acks_t;
|
||||
typedef epicsOldString dbr_stsack_string_t;
|
||||
typedef epicsOldString dbr_class_name_t;
|
||||
|
||||
#ifndef db_accessHFORdb_accessC
|
||||
/* database field types */
|
||||
#define DBF_STRING 0
|
||||
#define DBF_INT 1
|
||||
#define DBF_SHORT 1
|
||||
#define DBF_FLOAT 2
|
||||
#define DBF_ENUM 3
|
||||
#define DBF_CHAR 4
|
||||
#define DBF_LONG 5
|
||||
#define DBF_DOUBLE 6
|
||||
#define DBF_NO_ACCESS 7
|
||||
#define LAST_TYPE DBF_DOUBLE
|
||||
#define VALID_DB_FIELD(x) ((x >= 0) && (x <= LAST_TYPE))
|
||||
#define INVALID_DB_FIELD(x) ((x < 0) || (x > LAST_TYPE))
|
||||
|
||||
/* data request buffer types */
|
||||
#define DBR_STRING DBF_STRING
|
||||
#define DBR_INT DBF_INT
|
||||
#define DBR_SHORT DBF_INT
|
||||
#define DBR_FLOAT DBF_FLOAT
|
||||
#define DBR_ENUM DBF_ENUM
|
||||
#define DBR_CHAR DBF_CHAR
|
||||
#define DBR_LONG DBF_LONG
|
||||
#define DBR_DOUBLE DBF_DOUBLE
|
||||
#define DBR_STS_STRING 7
|
||||
#define DBR_STS_SHORT 8
|
||||
#define DBR_STS_INT DBR_STS_SHORT
|
||||
#define DBR_STS_FLOAT 9
|
||||
#define DBR_STS_ENUM 10
|
||||
#define DBR_STS_CHAR 11
|
||||
#define DBR_STS_LONG 12
|
||||
#define DBR_STS_DOUBLE 13
|
||||
#define DBR_TIME_STRING 14
|
||||
#define DBR_TIME_INT 15
|
||||
#define DBR_TIME_SHORT 15
|
||||
#define DBR_TIME_FLOAT 16
|
||||
#define DBR_TIME_ENUM 17
|
||||
#define DBR_TIME_CHAR 18
|
||||
#define DBR_TIME_LONG 19
|
||||
#define DBR_TIME_DOUBLE 20
|
||||
#define DBR_GR_STRING 21
|
||||
#define DBR_GR_SHORT 22
|
||||
#define DBR_GR_INT DBR_GR_SHORT
|
||||
#define DBR_GR_FLOAT 23
|
||||
#define DBR_GR_ENUM 24
|
||||
#define DBR_GR_CHAR 25
|
||||
#define DBR_GR_LONG 26
|
||||
#define DBR_GR_DOUBLE 27
|
||||
#define DBR_CTRL_STRING 28
|
||||
#define DBR_CTRL_SHORT 29
|
||||
#define DBR_CTRL_INT DBR_CTRL_SHORT
|
||||
#define DBR_CTRL_FLOAT 30
|
||||
#define DBR_CTRL_ENUM 31
|
||||
#define DBR_CTRL_CHAR 32
|
||||
#define DBR_CTRL_LONG 33
|
||||
#define DBR_CTRL_DOUBLE 34
|
||||
#define DBR_PUT_ACKT DBR_CTRL_DOUBLE + 1
|
||||
#define DBR_PUT_ACKS DBR_PUT_ACKT + 1
|
||||
#define DBR_STSACK_STRING DBR_PUT_ACKS + 1
|
||||
#define DBR_CLASS_NAME DBR_STSACK_STRING + 1
|
||||
#define LAST_BUFFER_TYPE DBR_CLASS_NAME
|
||||
#define VALID_DB_REQ(x) ((x >= 0) && (x <= LAST_BUFFER_TYPE))
|
||||
#define INVALID_DB_REQ(x) ((x < 0) || (x > LAST_BUFFER_TYPE))
|
||||
|
||||
/*
|
||||
* The enumeration "epicsType" is an index to this array
|
||||
* of type DBR types. In some cases we select the a
|
||||
* larger type to avoid loss of information
|
||||
*/
|
||||
epicsShareExtern const int epicsTypeToDBR_XXXX [lastEpicsType+1];
|
||||
|
||||
/*
|
||||
* The DBR_XXXX types are indicies into this array
|
||||
*/
|
||||
epicsShareExtern const epicsType DBR_XXXXToEpicsType [LAST_BUFFER_TYPE+1];
|
||||
|
||||
/* values returned for each field type
|
||||
* DBR_STRING returns a NULL terminated string
|
||||
* DBR_SHORT returns an unsigned short
|
||||
* DBR_INT returns an unsigned short
|
||||
* DBR_FLOAT returns an IEEE floating point value
|
||||
* DBR_ENUM returns an unsigned short which is the enum item
|
||||
* DBR_CHAR returns an unsigned char
|
||||
* DBR_LONG returns an unsigned long
|
||||
* DBR_DOUBLE returns a double precision floating point number
|
||||
* DBR_STS_STRING returns a string status structure (dbr_sts_string)
|
||||
* DBR_STS_SHORT returns a short status structure (dbr_sts_short)
|
||||
* DBR_STS_INT returns a short status structure (dbr_sts_int)
|
||||
* DBR_STS_FLOAT returns a float status structure (dbr_sts_float)
|
||||
* DBR_STS_ENUM returns an enum status structure (dbr_sts_enum)
|
||||
* DBR_STS_CHAR returns a char status structure (dbr_sts_char)
|
||||
* DBR_STS_LONG returns a long status structure (dbr_sts_long)
|
||||
* DBR_STS_DOUBLE returns a double status structure (dbr_sts_double)
|
||||
* DBR_TIME_STRING returns a string time structure (dbr_time_string)
|
||||
* DBR_TIME_SHORT returns a short time structure (dbr_time_short)
|
||||
* DBR_TIME_INT returns a short time structure (dbr_time_short)
|
||||
* DBR_TIME_FLOAT returns a float time structure (dbr_time_float)
|
||||
* DBR_TIME_ENUM returns an enum time structure (dbr_time_enum)
|
||||
* DBR_TIME_CHAR returns a char time structure (dbr_time_char)
|
||||
* DBR_TIME_LONG returns a long time structure (dbr_time_long)
|
||||
* DBR_TIME_DOUBLE returns a double time structure (dbr_time_double)
|
||||
* DBR_GR_STRING returns a graphic string structure (dbr_gr_string)
|
||||
* DBR_GR_SHORT returns a graphic short structure (dbr_gr_short)
|
||||
* DBR_GR_INT returns a graphic short structure (dbr_gr_int)
|
||||
* DBR_GR_FLOAT returns a graphic float structure (dbr_gr_float)
|
||||
* DBR_GR_ENUM returns a graphic enum structure (dbr_gr_enum)
|
||||
* DBR_GR_CHAR returns a graphic char structure (dbr_gr_char)
|
||||
* DBR_GR_LONG returns a graphic long structure (dbr_gr_long)
|
||||
* DBR_GR_DOUBLE returns a graphic double structure (dbr_gr_double)
|
||||
* DBR_CTRL_STRING returns a control string structure (dbr_ctrl_int)
|
||||
* DBR_CTRL_SHORT returns a control short structure (dbr_ctrl_short)
|
||||
* DBR_CTRL_INT returns a control short structure (dbr_ctrl_int)
|
||||
* DBR_CTRL_FLOAT returns a control float structure (dbr_ctrl_float)
|
||||
* DBR_CTRL_ENUM returns a control enum structure (dbr_ctrl_enum)
|
||||
* DBR_CTRL_CHAR returns a control char structure (dbr_ctrl_char)
|
||||
* DBR_CTRL_LONG returns a control long structure (dbr_ctrl_long)
|
||||
* DBR_CTRL_DOUBLE returns a control double structure (dbr_ctrl_double)
|
||||
*/
|
||||
#endif /*db_accessHFORdb_accessC*/
|
||||
|
||||
/* VALUES WITH STATUS STRUCTURES */
|
||||
|
||||
/* structure for a string status field */
|
||||
struct dbr_sts_string {
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_string_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a string status and ack field */
|
||||
struct dbr_stsack_string{
|
||||
dbr_ushort_t status; /* status of value */
|
||||
dbr_ushort_t severity; /* severity of alarm */
|
||||
dbr_ushort_t ackt; /* ack transient? */
|
||||
dbr_ushort_t acks; /* ack severity */
|
||||
dbr_string_t value; /* current value */
|
||||
};
|
||||
/* structure for an short status field */
|
||||
struct dbr_sts_int{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
struct dbr_sts_short{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a float status field */
|
||||
struct dbr_sts_float{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_float_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a enum status field */
|
||||
struct dbr_sts_enum{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_enum_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a char status field */
|
||||
struct dbr_sts_char{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_char_t RISC_pad; /* RISC alignment */
|
||||
dbr_char_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a long status field */
|
||||
struct dbr_sts_long{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_long_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a double status field */
|
||||
struct dbr_sts_double{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_long_t RISC_pad; /* RISC alignment */
|
||||
dbr_double_t value; /* current value */
|
||||
};
|
||||
|
||||
/* VALUES WITH STATUS AND TIME STRUCTURES */
|
||||
|
||||
/* structure for a string time field */
|
||||
struct dbr_time_string{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_string_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for an short time field */
|
||||
struct dbr_time_short{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_short_t RISC_pad; /* RISC alignment */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a float time field */
|
||||
struct dbr_time_float{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_float_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a enum time field */
|
||||
struct dbr_time_enum{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_short_t RISC_pad; /* RISC alignment */
|
||||
dbr_enum_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a char time field */
|
||||
struct dbr_time_char{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_short_t RISC_pad0; /* RISC alignment */
|
||||
dbr_char_t RISC_pad1; /* RISC alignment */
|
||||
dbr_char_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a long time field */
|
||||
struct dbr_time_long{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_long_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a double time field */
|
||||
struct dbr_time_double{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_long_t RISC_pad; /* RISC alignment */
|
||||
dbr_double_t value; /* current value */
|
||||
};
|
||||
|
||||
/* VALUES WITH STATUS AND GRAPHIC STRUCTURES */
|
||||
|
||||
/* structure for a graphic string */
|
||||
/* not implemented; use struct_dbr_sts_string */
|
||||
|
||||
/* structure for a graphic short field */
|
||||
struct dbr_gr_int{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_short_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_short_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_short_t upper_alarm_limit;
|
||||
dbr_short_t upper_warning_limit;
|
||||
dbr_short_t lower_warning_limit;
|
||||
dbr_short_t lower_alarm_limit;
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
struct dbr_gr_short{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_short_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_short_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_short_t upper_alarm_limit;
|
||||
dbr_short_t upper_warning_limit;
|
||||
dbr_short_t lower_warning_limit;
|
||||
dbr_short_t lower_alarm_limit;
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic floating point field */
|
||||
struct dbr_gr_float{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t precision; /* number of decimal places */
|
||||
dbr_short_t RISC_pad0; /* RISC alignment */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_float_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_float_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_float_t upper_alarm_limit;
|
||||
dbr_float_t upper_warning_limit;
|
||||
dbr_float_t lower_warning_limit;
|
||||
dbr_float_t lower_alarm_limit;
|
||||
dbr_float_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic enumeration field */
|
||||
struct dbr_gr_enum{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t no_str; /* number of strings */
|
||||
char strs[MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];
|
||||
/* state strings */
|
||||
dbr_enum_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic char field */
|
||||
struct dbr_gr_char{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_char_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_char_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_char_t upper_alarm_limit;
|
||||
dbr_char_t upper_warning_limit;
|
||||
dbr_char_t lower_warning_limit;
|
||||
dbr_char_t lower_alarm_limit;
|
||||
dbr_char_t RISC_pad; /* RISC alignment */
|
||||
dbr_char_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic long field */
|
||||
struct dbr_gr_long{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_long_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_long_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_long_t upper_alarm_limit;
|
||||
dbr_long_t upper_warning_limit;
|
||||
dbr_long_t lower_warning_limit;
|
||||
dbr_long_t lower_alarm_limit;
|
||||
dbr_long_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic double field */
|
||||
struct dbr_gr_double{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t precision; /* number of decimal places */
|
||||
dbr_short_t RISC_pad0; /* RISC alignment */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_double_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_double_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_double_t upper_alarm_limit;
|
||||
dbr_double_t upper_warning_limit;
|
||||
dbr_double_t lower_warning_limit;
|
||||
dbr_double_t lower_alarm_limit;
|
||||
dbr_double_t value; /* current value */
|
||||
};
|
||||
|
||||
/* VALUES WITH STATUS, GRAPHIC and CONTROL STRUCTURES */
|
||||
|
||||
/* structure for a control string */
|
||||
/* not implemented; use struct_dbr_sts_string */
|
||||
|
||||
/* structure for a control integer */
|
||||
struct dbr_ctrl_int{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_short_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_short_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_short_t upper_alarm_limit;
|
||||
dbr_short_t upper_warning_limit;
|
||||
dbr_short_t lower_warning_limit;
|
||||
dbr_short_t lower_alarm_limit;
|
||||
dbr_short_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_short_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
struct dbr_ctrl_short{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_short_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_short_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_short_t upper_alarm_limit;
|
||||
dbr_short_t upper_warning_limit;
|
||||
dbr_short_t lower_warning_limit;
|
||||
dbr_short_t lower_alarm_limit;
|
||||
dbr_short_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_short_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control floating point field */
|
||||
struct dbr_ctrl_float{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t precision; /* number of decimal places */
|
||||
dbr_short_t RISC_pad; /* RISC alignment */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_float_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_float_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_float_t upper_alarm_limit;
|
||||
dbr_float_t upper_warning_limit;
|
||||
dbr_float_t lower_warning_limit;
|
||||
dbr_float_t lower_alarm_limit;
|
||||
dbr_float_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_float_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_float_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control enumeration field */
|
||||
struct dbr_ctrl_enum{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t no_str; /* number of strings */
|
||||
char strs[MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];
|
||||
/* state strings */
|
||||
dbr_enum_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control char field */
|
||||
struct dbr_ctrl_char{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_char_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_char_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_char_t upper_alarm_limit;
|
||||
dbr_char_t upper_warning_limit;
|
||||
dbr_char_t lower_warning_limit;
|
||||
dbr_char_t lower_alarm_limit;
|
||||
dbr_char_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_char_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_char_t RISC_pad; /* RISC alignment */
|
||||
dbr_char_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control long field */
|
||||
struct dbr_ctrl_long{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_long_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_long_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_long_t upper_alarm_limit;
|
||||
dbr_long_t upper_warning_limit;
|
||||
dbr_long_t lower_warning_limit;
|
||||
dbr_long_t lower_alarm_limit;
|
||||
dbr_long_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_long_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_long_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control double field */
|
||||
struct dbr_ctrl_double{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t precision; /* number of decimal places */
|
||||
dbr_short_t RISC_pad0; /* RISC alignment */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_double_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_double_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_double_t upper_alarm_limit;
|
||||
dbr_double_t upper_warning_limit;
|
||||
dbr_double_t lower_warning_limit;
|
||||
dbr_double_t lower_alarm_limit;
|
||||
dbr_double_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_double_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_double_t value; /* current value */
|
||||
};
|
||||
|
||||
#define dbr_size_n(TYPE,COUNT)\
|
||||
((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
|
||||
|
||||
/* size for each type - array indexed by the DBR_ type code */
|
||||
epicsShareExtern const unsigned short dbr_size[];
|
||||
|
||||
/* size for each type's value - array indexed by the DBR_ type code */
|
||||
epicsShareExtern const unsigned short dbr_value_size[];
|
||||
|
||||
#ifndef db_accessHFORdb_accessC
|
||||
/* class for each type's value */
|
||||
enum dbr_value_class {
|
||||
dbr_class_int,
|
||||
dbr_class_float,
|
||||
dbr_class_string,
|
||||
dbr_class_max};
|
||||
|
||||
epicsShareExtern const enum dbr_value_class dbr_value_class[LAST_BUFFER_TYPE+1];
|
||||
|
||||
/*
|
||||
* ptr to value given a pointer to the structure and the DBR type
|
||||
*/
|
||||
#define dbr_value_ptr(PDBR, DBR_TYPE) \
|
||||
((void *)(((char *)PDBR)+dbr_value_offset[DBR_TYPE]))
|
||||
|
||||
/*
|
||||
* ptr to value given a pointer to the structure and the structure declaration
|
||||
*/
|
||||
#define dbr_value_ptr_from_structure(PDBR, STRUCTURE)\
|
||||
((void *)(((char *)PDBR)+BYTE_OS(STRUCTURE, value)))
|
||||
|
||||
epicsShareExtern const unsigned short dbr_value_offset[LAST_BUFFER_TYPE+1];
|
||||
|
||||
|
||||
/* union for each fetch buffers */
|
||||
union db_access_val{
|
||||
dbr_string_t strval; /* string max size */
|
||||
dbr_short_t shrtval; /* short */
|
||||
dbr_short_t intval; /* short */
|
||||
dbr_float_t fltval; /* IEEE Float */
|
||||
dbr_enum_t enmval; /* item number */
|
||||
dbr_char_t charval; /* character */
|
||||
dbr_long_t longval; /* long */
|
||||
dbr_double_t doubleval; /* double */
|
||||
struct dbr_sts_string sstrval; /* string field with status */
|
||||
struct dbr_sts_short sshrtval; /* short field with status */
|
||||
struct dbr_sts_float sfltval; /* float field with status */
|
||||
struct dbr_sts_enum senmval; /* item number with status */
|
||||
struct dbr_sts_char schrval; /* char field with status */
|
||||
struct dbr_sts_long slngval; /* long field with status */
|
||||
struct dbr_sts_double sdblval; /* double field with time */
|
||||
struct dbr_time_string tstrval; /* string field with time */
|
||||
struct dbr_time_short tshrtval; /* short field with time */
|
||||
struct dbr_time_float tfltval; /* float field with time */
|
||||
struct dbr_time_enum tenmval; /* item number with time */
|
||||
struct dbr_time_char tchrval; /* char field with time */
|
||||
struct dbr_time_long tlngval; /* long field with time */
|
||||
struct dbr_time_double tdblval; /* double field with time */
|
||||
struct dbr_sts_string gstrval; /* graphic string info */
|
||||
struct dbr_gr_short gshrtval; /* graphic short info */
|
||||
struct dbr_gr_float gfltval; /* graphic float info */
|
||||
struct dbr_gr_enum genmval; /* graphic item info */
|
||||
struct dbr_gr_char gchrval; /* graphic char info */
|
||||
struct dbr_gr_long glngval; /* graphic long info */
|
||||
struct dbr_gr_double gdblval; /* graphic double info */
|
||||
struct dbr_sts_string cstrval; /* control string info */
|
||||
struct dbr_ctrl_short cshrtval; /* control short info */
|
||||
struct dbr_ctrl_float cfltval; /* control float info */
|
||||
struct dbr_ctrl_enum cenmval; /* control item info */
|
||||
struct dbr_ctrl_char cchrval; /* control char info */
|
||||
struct dbr_ctrl_long clngval; /* control long info */
|
||||
struct dbr_ctrl_double cdblval; /* control double info */
|
||||
dbr_put_ackt_t putackt; /* item number */
|
||||
dbr_put_acks_t putacks; /* item number */
|
||||
struct dbr_sts_string sastrval; /* string field with status */
|
||||
dbr_string_t classname; /* string max size */
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* repository for some useful PV database constants and utilities
|
||||
*
|
||||
* item dimensions
|
||||
* db_strval_dim dimension for string values
|
||||
* db_units_dim dimension for record units text
|
||||
* db_desc_dim dimension for record description text
|
||||
* db_name_dim dimension for channel names (record.field\0)
|
||||
* db_state_dim number of states possible in a state table
|
||||
* db_state_text_dim dimension for a state text string
|
||||
* usage: char state_table[db_state_dim][db_state_text_dim]
|
||||
*
|
||||
* type checking macros -- return non-zero if condition is true, zero otherwise
|
||||
*
|
||||
* int dbf_type_is_valid(type) type is a valid DBF_xxx
|
||||
* int dbr_type_is_valid(type) type is a valid DBR_xxx
|
||||
* int dbr_type_is_plain(type) type is a valid plain DBR_xxx
|
||||
* int dbr_type_is_STS(type) type is a valid DBR_STS_xxx
|
||||
* int dbr_type_is_TIME(type) type is a valid DBR_TIME_xxx
|
||||
* int dbr_type_is_GR(type) type is a valid DBR_GR_xxx
|
||||
* int dbr_type_is_CTRL(type) type is a valid DBR_CTRL_xxx
|
||||
* int dbr_type_is_STRING(type) type is a valid DBR_STRING_xxx
|
||||
* int dbr_type_is_SHORT(type) type is a valid DBR_SHORT_xxx
|
||||
* int dbr_type_is_FLOAT(type) type is a valid DBR_FLOAT_xxx
|
||||
* int dbr_type_is_ENUM(type) type is a valid DBR_ENUM_xxx
|
||||
* int dbr_type_is_CHAR(type) type is a valid DBR_CHAR_xxx
|
||||
* int dbr_type_is_LONG(type) type is a valid DBR_LONG_xxx
|
||||
* int dbr_type_is_DOUBLE(type) type is a valid DBR_DOUBLE_xxx
|
||||
*
|
||||
* type conversion macros
|
||||
*
|
||||
* char *dbf_type_to_text(type) returns text matching DBF_xxx
|
||||
* void dbf_text_to_type(text, type) finds DBF_xxx matching text
|
||||
* int dbf_type_to_DBR(type) returns DBR_xxx matching DBF_xxx
|
||||
* int dbf_type_to_DBR_TIME(type) returns DBR_TIME_xxx matching DBF_xxx
|
||||
* int dbf_type_to_DBR_GR(type) returns DBR_GR_xxx matching DBF_xxx
|
||||
* int dbf_type_to_DBR_CTRL(type) returns DBR_CTRL_xxx matching DBF_xxx
|
||||
* char *dbr_type_to_text(type) returns text matching DBR_xxx
|
||||
* void dbr_text_to_type(text, type) finds DBR_xxx matching text
|
||||
*---------------------------------------------------------------------------*/
|
||||
#define db_strval_dim MAX_STRING_SIZE
|
||||
#define db_units_dim MAX_UNITS_SIZE
|
||||
#define db_desc_dim 24
|
||||
#define db_name_dim 36
|
||||
#define db_state_dim MAX_ENUM_STATES
|
||||
#define db_state_text_dim MAX_ENUM_STRING_SIZE
|
||||
|
||||
#define dbf_type_is_valid(type) ((type) >= 0 && (type) <= LAST_TYPE)
|
||||
#define dbr_type_is_valid(type) ((type) >= 0 && (type) <= LAST_BUFFER_TYPE)
|
||||
#define dbr_type_is_plain(type) \
|
||||
((type) >= DBR_STRING && (type) <= DBR_DOUBLE)
|
||||
#define dbr_type_is_STS(type) \
|
||||
((type) >= DBR_STS_STRING && (type) <= DBR_STS_DOUBLE)
|
||||
#define dbr_type_is_TIME(type) \
|
||||
((type) >= DBR_TIME_STRING && (type) <= DBR_TIME_DOUBLE)
|
||||
#define dbr_type_is_GR(type) \
|
||||
((type) >= DBR_GR_STRING && (type) <= DBR_GR_DOUBLE)
|
||||
#define dbr_type_is_CTRL(type) \
|
||||
((type) >= DBR_CTRL_STRING && (type) <= DBR_CTRL_DOUBLE)
|
||||
#define dbr_type_is_STRING(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_STRING)
|
||||
#define dbr_type_is_SHORT(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_SHORT)
|
||||
#define dbr_type_is_FLOAT(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_FLOAT)
|
||||
#define dbr_type_is_ENUM(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_ENUM)
|
||||
#define dbr_type_is_CHAR(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_CHAR)
|
||||
#define dbr_type_is_LONG(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_LONG)
|
||||
#define dbr_type_is_DOUBLE(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_DOUBLE)
|
||||
|
||||
#define dbf_type_to_text(type) \
|
||||
( ((type) >= -1 && (type) < dbf_text_dim-2) ? \
|
||||
dbf_text[type+1] : dbf_text_invalid )
|
||||
|
||||
#define dbf_text_to_type(text, type) \
|
||||
for (type=dbf_text_dim-3; type>=0; type--) { \
|
||||
if (strcmp(text, dbf_text[type+1]) == 0) \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define dbr_type_to_text(type) \
|
||||
( ((type) >= 0 && (type) < dbr_text_dim) ? \
|
||||
dbr_text[(type)] : dbr_text_invalid )
|
||||
|
||||
#define dbr_text_to_type(text, type) \
|
||||
for (type=dbr_text_dim-2; type>=0; type--) { \
|
||||
if (strcmp(text, dbr_text[type]) == 0) \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define dbf_type_to_DBR(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) : -1 )
|
||||
|
||||
#define dbf_type_to_DBR_STS(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) + (dbf_text_dim-2) : -1 )
|
||||
|
||||
#define dbf_type_to_DBR_TIME(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) + 2*(dbf_text_dim-2) : -1 )
|
||||
|
||||
#define dbf_type_to_DBR_GR(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) + 3*(dbf_text_dim-2) : -1 )
|
||||
|
||||
#define dbf_type_to_DBR_CTRL(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) + 4*(dbf_text_dim-2) : -1 )
|
||||
|
||||
|
||||
epicsShareExtern const char *dbf_text[LAST_TYPE+3];
|
||||
epicsShareExtern const short dbf_text_dim;
|
||||
epicsShareExtern const char *dbf_text_invalid;
|
||||
|
||||
epicsShareExtern const char *dbr_text[LAST_BUFFER_TYPE+1];
|
||||
epicsShareExtern const short dbr_text_dim;
|
||||
epicsShareExtern const char *dbr_text_invalid;
|
||||
#endif /*db_accessHFORdb_accessC*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INCLdb_accessh */
|
||||
110
src/client/disconnectGovernorTimer.cpp
Normal file
110
src/client/disconnectGovernorTimer.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
//
|
||||
//
|
||||
// L O S A L A M O S
|
||||
// Los Alamos National Laboratory
|
||||
// Los Alamos, New Mexico 87545
|
||||
//
|
||||
// Copyright, 1986, The Regents of the University of California.
|
||||
//
|
||||
// Author: Jeff Hill
|
||||
//
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "disconnectGovernorTimer.h"
|
||||
#include "udpiiu.h"
|
||||
#include "nciu.h"
|
||||
|
||||
static const double disconnectGovernorPeriod = 10.0; // sec
|
||||
|
||||
disconnectGovernorTimer::disconnectGovernorTimer (
|
||||
disconnectGovernorNotify & iiuIn,
|
||||
epicsTimerQueue & queueIn,
|
||||
epicsMutex & mutexIn ) :
|
||||
mutex ( mutexIn ), timer ( queueIn.createTimer () ),
|
||||
iiu ( iiuIn )
|
||||
{
|
||||
}
|
||||
|
||||
disconnectGovernorTimer::~disconnectGovernorTimer ()
|
||||
{
|
||||
this->timer.destroy ();
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer:: start ()
|
||||
{
|
||||
this->timer.start ( *this, disconnectGovernorPeriod );
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer::shutdown (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > cbUnguard ( cbGuard );
|
||||
this->timer.cancel ();
|
||||
}
|
||||
}
|
||||
while ( nciu * pChan = this->chanList.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
pChan->serviceShutdownNotify ( cbGuard, guard );
|
||||
}
|
||||
}
|
||||
|
||||
epicsTimerNotify::expireStatus disconnectGovernorTimer::expire (
|
||||
const epicsTime & /* currentTime */ )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
while ( nciu * pChan = chanList.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
this->iiu.govExpireNotify ( guard, *pChan );
|
||||
}
|
||||
return expireStatus ( restart, disconnectGovernorPeriod );
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
::printf ( "disconnect governor timer: with %u channels pending\n",
|
||||
this->chanList.count () );
|
||||
if ( level > 0u ) {
|
||||
tsDLIterConst < nciu > pChan = this->chanList.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 1u );
|
||||
pChan++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer::installChan (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->chanList.add ( chan );
|
||||
chan.channelNode::listMember = channelNode::cs_disconnGov;
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer::uninstallChan (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->chanList.remove ( chan );
|
||||
chan.channelNode::listMember = channelNode::cs_none;
|
||||
}
|
||||
|
||||
disconnectGovernorNotify::~disconnectGovernorNotify () {}
|
||||
|
||||
77
src/client/disconnectGovernorTimer.h
Normal file
77
src/client/disconnectGovernorTimer.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// L O S A L A M O S
|
||||
// Los Alamos National Laboratory
|
||||
// Los Alamos, New Mexico 87545
|
||||
//
|
||||
// Copyright, 1986, The Regents of the University of California.
|
||||
//
|
||||
//
|
||||
// Author Jeffrey O. Hill
|
||||
// johill@lanl.gov
|
||||
// 505 665 1831
|
||||
//
|
||||
|
||||
#ifndef disconnectGovernorTimerh
|
||||
#define disconnectGovernorTimerh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define searchTimerh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsGuard.h"
|
||||
#include "epicsTimer.h"
|
||||
|
||||
#ifdef searchTimerh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
#include "caProto.h"
|
||||
#include "netiiu.h"
|
||||
|
||||
class disconnectGovernorNotify {
|
||||
public:
|
||||
virtual ~disconnectGovernorNotify () = 0;
|
||||
virtual void govExpireNotify (
|
||||
epicsGuard < epicsMutex > &, nciu & ) = 0;
|
||||
};
|
||||
|
||||
class disconnectGovernorTimer : private epicsTimerNotify {
|
||||
public:
|
||||
disconnectGovernorTimer (
|
||||
class disconnectGovernorNotify &, epicsTimerQueue &, epicsMutex & );
|
||||
virtual ~disconnectGovernorTimer ();
|
||||
void start ();
|
||||
void shutdown (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void installChan (
|
||||
epicsGuard < epicsMutex > &, nciu & );
|
||||
void uninstallChan (
|
||||
epicsGuard < epicsMutex > &, nciu & );
|
||||
void show ( unsigned level ) const;
|
||||
private:
|
||||
tsDLList < nciu > chanList;
|
||||
epicsMutex & mutex;
|
||||
epicsTimer & timer;
|
||||
class disconnectGovernorNotify & iiu;
|
||||
epicsTimerNotify::expireStatus expire ( const epicsTime & currentTime );
|
||||
disconnectGovernorTimer ( const disconnectGovernorTimer & );
|
||||
disconnectGovernorTimer & operator = ( const disconnectGovernorTimer & );
|
||||
};
|
||||
|
||||
#endif // ifdef disconnectGovernorTimerh
|
||||
95
src/client/evtime.c
Normal file
95
src/client/evtime.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "epicsTime.h"
|
||||
#include "cadef.h"
|
||||
|
||||
void event_handler (struct event_handler_args args);
|
||||
int evtime (char *pname);
|
||||
|
||||
static unsigned iteration_count;
|
||||
static epicsUInt32 last_time;
|
||||
|
||||
#ifndef iocCore
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *pname;
|
||||
|
||||
if(argc == 2){
|
||||
pname = argv[1];
|
||||
evtime(pname);
|
||||
}
|
||||
else{
|
||||
printf("usage: %s <channel name>", argv[0]);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* evtime()
|
||||
*/
|
||||
int evtime(char *pname)
|
||||
{
|
||||
chid chan;
|
||||
int status;
|
||||
|
||||
status = ca_search(pname, &chan);
|
||||
SEVCHK(status, NULL);
|
||||
|
||||
status = ca_pend_io(10.0);
|
||||
if(status != ECA_NORMAL){
|
||||
printf("%s not found\n", pname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = ca_add_event(
|
||||
DBR_FLOAT,
|
||||
chan,
|
||||
event_handler,
|
||||
NULL,
|
||||
NULL);
|
||||
SEVCHK(status, __FILE__);
|
||||
|
||||
status = ca_pend_event(0.0);
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* event_handler()
|
||||
*
|
||||
*/
|
||||
void event_handler(struct event_handler_args args)
|
||||
{
|
||||
epicsUInt32 current_time;
|
||||
# define COUNT 0x8000
|
||||
double interval;
|
||||
double delay;
|
||||
epicsTimeStamp ts;
|
||||
|
||||
if(iteration_count%COUNT == 0){
|
||||
epicsTimeGetCurrent(&ts);
|
||||
current_time = ts.secPastEpoch;
|
||||
if(last_time != 0){
|
||||
interval = current_time - last_time;
|
||||
delay = interval/COUNT;
|
||||
printf("Delay = %f sec per event\n",
|
||||
delay);
|
||||
}
|
||||
last_time = current_time;
|
||||
}
|
||||
|
||||
iteration_count++;
|
||||
}
|
||||
|
||||
38
src/client/future_work.txt
Normal file
38
src/client/future_work.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
Potential upgrades to Channel Access
|
||||
|
||||
o generalized access to abstract data
|
||||
o use multicast for broadcasting and ax the repeater
|
||||
o improve client API
|
||||
o improve security
|
||||
o name service (wildcard queries)
|
||||
o PV name prefix (for all PVs)
|
||||
o client access to process passive and for maximize severity
|
||||
o detect name conflicts at boot time
|
||||
o multi priority connections (quality of service)
|
||||
o reduce protocol overhead
|
||||
o compressed protocol
|
||||
|
||||
|
||||
o If there is a beacon anomaly then this indicates that
|
||||
the server is _not_ available. Perhaps we should only
|
||||
reset the search timer interval when we see a beacon
|
||||
anomaly transition into a sure steady beacon.
|
||||
|
||||
o make certain that a monitor callback canceling itself
|
||||
does not deadlock.
|
||||
|
||||
o the free list library does not now cause exceptions to
|
||||
occur (it uses new ( nothrow )), and therefore we should
|
||||
change the new handlers to be nothrow also if this is
|
||||
the design goal.
|
||||
|
||||
o test the library when an IOC is running low on memory.
|
||||
|
||||
o The new CA interface should be multi-threaded by default.
|
||||
We should continue to support a single-threaded interface,
|
||||
but this would should be restricted so that it always
|
||||
runs with preemptive callback disable and no threads
|
||||
may join in. Alternatively, the new CA interface could
|
||||
be 100% preemptive multi-threaded and the old interface
|
||||
could be layered on this.
|
||||
104
src/client/getCallback.cpp
Normal file
104
src/client/getCallback.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "oldAccess.h"
|
||||
|
||||
getCallback::getCallback ( oldChannelNotify & chanIn,
|
||||
caEventCallBackFunc *pFuncIn, void *pPrivateIn ) :
|
||||
chan ( chanIn ), pFunc ( pFuncIn ), pPrivate ( pPrivateIn )
|
||||
{
|
||||
}
|
||||
|
||||
getCallback::~getCallback ()
|
||||
{
|
||||
}
|
||||
|
||||
void getCallback::completion (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
unsigned type, arrayElementCount count, const void *pData )
|
||||
{
|
||||
struct event_handler_args args;
|
||||
args.usr = this->pPrivate;
|
||||
args.chid = & this->chan;
|
||||
args.type = type;
|
||||
args.count = count;
|
||||
args.status = ECA_NORMAL;
|
||||
args.dbr = pData;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
|
||||
if ( pFuncTmp ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
pFuncTmp ( args );
|
||||
}
|
||||
}
|
||||
|
||||
void getCallback::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * /* pContext */,
|
||||
unsigned type, arrayElementCount count )
|
||||
{
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
struct event_handler_args args;
|
||||
args.usr = this->pPrivate;
|
||||
args.chid = & this->chan;
|
||||
args.type = type;
|
||||
args.count = count;
|
||||
args.status = status;
|
||||
args.dbr = 0;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFuncTmp ) ( args );
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
|
||||
}
|
||||
}
|
||||
|
||||
void getCallback::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
118
src/client/getCopy.cpp
Normal file
118
src/client/getCopy.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "oldAccess.h"
|
||||
#include "cac.h"
|
||||
|
||||
getCopy::getCopy (
|
||||
epicsGuard < epicsMutex > & guard, ca_client_context & cacCtxIn,
|
||||
oldChannelNotify & chanIn, unsigned typeIn,
|
||||
arrayElementCount countIn, void * pValueIn ) :
|
||||
count ( countIn ), cacCtx ( cacCtxIn ), chan ( chanIn ), pValue ( pValueIn ),
|
||||
ioSeqNo ( 0 ), type ( typeIn )
|
||||
{
|
||||
this->ioSeqNo = cacCtxIn.sequenceNumberOfOutstandingIO ( guard );
|
||||
cacCtxIn.incrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
}
|
||||
|
||||
getCopy::~getCopy ()
|
||||
{
|
||||
}
|
||||
|
||||
void getCopy::cancel ()
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef () );
|
||||
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
}
|
||||
|
||||
void getCopy::completion (
|
||||
epicsGuard < epicsMutex > & guard, unsigned typeIn,
|
||||
arrayElementCount countIn, const void *pDataIn )
|
||||
{
|
||||
if ( this->type == typeIn ) {
|
||||
unsigned size = dbr_size_n ( typeIn, countIn );
|
||||
memcpy ( this->pValue, pDataIn, size );
|
||||
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
// this object destroyed by preceding function call
|
||||
}
|
||||
else {
|
||||
this->exception ( guard, ECA_INTERNAL,
|
||||
"bad data type match in get copy back response",
|
||||
typeIn, countIn);
|
||||
// this object destroyed by preceding function call
|
||||
}
|
||||
}
|
||||
|
||||
void getCopy::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char *pContext,
|
||||
unsigned /* typeIn */, arrayElementCount /* countIn */ )
|
||||
{
|
||||
oldChannelNotify & chanTmp ( this->chan );
|
||||
unsigned typeTmp ( this->type );
|
||||
arrayElementCount countTmp ( this->count );
|
||||
ca_client_context & caClientCtx ( this->cacCtx );
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
caClientCtx.exception ( guard, status, pContext,
|
||||
__FILE__, __LINE__, chanTmp, typeTmp,
|
||||
countTmp, CA_OP_GET );
|
||||
}
|
||||
}
|
||||
|
||||
void getCopy::show ( unsigned level ) const
|
||||
{
|
||||
int tmpType = static_cast <int> ( this->type );
|
||||
::printf ( "read copy IO at %p, type %s, element count %lu\n",
|
||||
static_cast <const void *> ( this ), dbf_type_to_text ( tmpType ), this->count );
|
||||
if ( level > 0u ) {
|
||||
::printf ( "\tIO sequence number %u, user's storage %p\n",
|
||||
this->ioSeqNo, static_cast <const void *> ( this->pValue ) );
|
||||
}
|
||||
}
|
||||
|
||||
void getCopy::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
92
src/client/hostNameCache.cpp
Normal file
92
src/client/hostNameCache.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
#include "hostNameCache.h"
|
||||
#include "epicsGuard.h"
|
||||
|
||||
hostNameCache::hostNameCache (
|
||||
const osiSockAddr & addr, ipAddrToAsciiEngine & engine ) :
|
||||
dnsTransaction ( engine.createTransaction() ), nameLength ( 0 )
|
||||
{
|
||||
sockAddrToDottedIP ( &addr.sa, hostNameBuf, sizeof ( hostNameBuf ) );
|
||||
hostNameBuf[ sizeof ( hostNameBuf ) - 1 ] = '\0';
|
||||
nameLength = strlen ( hostNameBuf );
|
||||
this->dnsTransaction.ipAddrToAscii ( addr, *this );
|
||||
}
|
||||
|
||||
void hostNameCache::destroy ()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
hostNameCache::~hostNameCache ()
|
||||
{
|
||||
this->dnsTransaction.release ();
|
||||
}
|
||||
|
||||
void hostNameCache::transactionComplete ( const char * pHostNameIn )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
// a few legacy clients have a direct pointer to this buffer so we
|
||||
// set the entrire string to nill terminators before we start copying
|
||||
// in the name (this reduces the chance that another thread will see
|
||||
// garbage characters).
|
||||
size_t newNameLen = strlen ( pHostNameIn );
|
||||
if ( newNameLen > sizeof ( this->hostNameBuf ) - 1u ) {
|
||||
newNameLen = sizeof ( this->hostNameBuf ) - 1u;
|
||||
}
|
||||
strncpy ( this->hostNameBuf, "", sizeof ( this->hostNameBuf ) );
|
||||
strncpy ( this->hostNameBuf, pHostNameIn, sizeof ( this->hostNameBuf ) - 1 );
|
||||
this->nameLength = newNameLen;
|
||||
}
|
||||
|
||||
unsigned hostNameCache::getName (
|
||||
char * pBuf, unsigned bufSize ) const
|
||||
{
|
||||
if ( bufSize == 0u ) {
|
||||
return 0u;
|
||||
}
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( this->nameLength > 0u ) {
|
||||
if ( this->nameLength < bufSize ) {
|
||||
strcpy ( pBuf, this->hostNameBuf );
|
||||
return this->nameLength;
|
||||
}
|
||||
else {
|
||||
unsigned reducedSize = bufSize - 1u;
|
||||
strncpy ( pBuf, this->hostNameBuf, reducedSize );
|
||||
pBuf [ reducedSize ] = '\0';
|
||||
return reducedSize;
|
||||
}
|
||||
}
|
||||
else {
|
||||
osiSockAddr tmpAddr = this->dnsTransaction.address ();
|
||||
return sockAddrToDottedIP ( &tmpAddr.sa, pBuf, bufSize );
|
||||
}
|
||||
}
|
||||
|
||||
61
src/client/hostNameCache.h
Normal file
61
src/client/hostNameCache.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef hostNameCacheh
|
||||
#define hostNameCacheh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define hostNameCache_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "ipAddrToAsciiAsynchronous.h"
|
||||
#include "epicsMutex.h"
|
||||
|
||||
#ifdef hostNameCache_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
class hostNameCache : public ipAddrToAsciiCallBack {
|
||||
public:
|
||||
hostNameCache ( const osiSockAddr & addr, ipAddrToAsciiEngine & engine );
|
||||
~hostNameCache ();
|
||||
void destroy ();
|
||||
void transactionComplete ( const char * pHostName );
|
||||
unsigned getName ( char *pBuf, unsigned bufLength ) const;
|
||||
const char * pointer () const;
|
||||
private:
|
||||
char hostNameBuf [128];
|
||||
mutable epicsMutex mutex;
|
||||
ipAddrToAsciiTransaction & dnsTransaction;
|
||||
unsigned nameLength;
|
||||
};
|
||||
|
||||
inline const char * hostNameCache::pointer () const
|
||||
{
|
||||
return this->hostNameBuf;
|
||||
}
|
||||
|
||||
#endif // #ifndef hostNameCacheh
|
||||
72
src/client/inetAddrID.h
Normal file
72
src/client/inetAddrID.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#ifndef inetAddrIDh
|
||||
#define inetAddrIDh
|
||||
|
||||
#include "osiSock.h"
|
||||
#include "resourceLib.h"
|
||||
|
||||
class inetAddrID {
|
||||
public:
|
||||
inetAddrID ( const struct sockaddr_in & addrIn );
|
||||
bool operator == ( const inetAddrID & ) const;
|
||||
resTableIndex hash () const;
|
||||
void name ( char *pBuf, unsigned bufSize ) const;
|
||||
private:
|
||||
struct sockaddr_in addr;
|
||||
};
|
||||
|
||||
inline inetAddrID::inetAddrID ( const struct sockaddr_in & addrIn ) :
|
||||
addr ( addrIn )
|
||||
{
|
||||
}
|
||||
|
||||
inline bool inetAddrID::operator == ( const inetAddrID &rhs ) const
|
||||
{
|
||||
if ( this->addr.sin_addr.s_addr == rhs.addr.sin_addr.s_addr ) {
|
||||
if ( this->addr.sin_port == rhs.addr.sin_port ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline resTableIndex inetAddrID::hash () const
|
||||
{
|
||||
const unsigned inetAddrMinIndexBitWidth = 8u;
|
||||
const unsigned inetAddrMaxIndexBitWidth = 32u;
|
||||
unsigned index;
|
||||
index = this->addr.sin_addr.s_addr;
|
||||
index ^= this->addr.sin_port;
|
||||
index ^= this->addr.sin_port >> 8u;
|
||||
return integerHash ( inetAddrMinIndexBitWidth,
|
||||
inetAddrMaxIndexBitWidth, index );
|
||||
}
|
||||
|
||||
inline void inetAddrID::name ( char *pBuf, unsigned bufSize ) const
|
||||
{
|
||||
ipAddrToDottedIP ( &this->addr, pBuf, bufSize );
|
||||
}
|
||||
|
||||
#endif // ifdef inetAddrID
|
||||
|
||||
|
||||
265
src/client/iocinf.cpp
Normal file
265
src/client/iocinf.cpp
Normal file
@@ -0,0 +1,265 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "envDefs.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsStdioRedirect.h"
|
||||
#include "errlog.h"
|
||||
#include "osiWireFormat.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "addrList.h"
|
||||
#undef epicsExportSharedSymbols
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
/*
|
||||
* getToken()
|
||||
*/
|
||||
static char *getToken ( const char **ppString, char *pBuf, unsigned bufSIze )
|
||||
{
|
||||
bool tokenFound = false;
|
||||
const char *pToken;
|
||||
unsigned i;
|
||||
|
||||
pToken = *ppString;
|
||||
while ( isspace (*pToken) && *pToken ){
|
||||
pToken++;
|
||||
}
|
||||
|
||||
for ( i=0u; i<bufSIze; i++ ) {
|
||||
if ( isspace (pToken[i]) || pToken[i]=='\0' ) {
|
||||
pBuf[i] = '\0';
|
||||
*ppString = &pToken[i];
|
||||
if ( i != 0 ) {
|
||||
tokenFound = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pBuf[i] = pToken[i];
|
||||
}
|
||||
|
||||
if ( tokenFound ) {
|
||||
pBuf[bufSIze-1] = '\0';
|
||||
return pBuf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* addAddrToChannelAccessAddressList ()
|
||||
*/
|
||||
extern "C" int epicsShareAPI addAddrToChannelAccessAddressList
|
||||
( ELLLIST *pList, const ENV_PARAM *pEnv,
|
||||
unsigned short port, int ignoreNonDefaultPort )
|
||||
{
|
||||
osiSockAddrNode *pNewNode;
|
||||
const char *pStr;
|
||||
const char *pToken;
|
||||
struct sockaddr_in addr;
|
||||
char buf[32u]; /* large enough to hold an IP address */
|
||||
int status, ret = -1;
|
||||
|
||||
pStr = envGetConfigParamPtr (pEnv);
|
||||
if (!pStr) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ( ( pToken = getToken (&pStr, buf, sizeof (buf) ) ) ) {
|
||||
status = aToIPAddr ( pToken, port, &addr );
|
||||
if (status<0) {
|
||||
fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name);
|
||||
fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
|
||||
if (pNewNode==NULL) {
|
||||
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
|
||||
break;
|
||||
}
|
||||
|
||||
pNewNode->addr.ia = addr;
|
||||
|
||||
/*
|
||||
* LOCK applied externally
|
||||
*/
|
||||
ellAdd (pList, &pNewNode->node);
|
||||
ret = 0; /* success if anything is added to the list */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* removeDuplicateAddresses ()
|
||||
*/
|
||||
extern "C" void epicsShareAPI removeDuplicateAddresses
|
||||
( ELLLIST *pDestList, ELLLIST *pSrcList, int silent )
|
||||
{
|
||||
ELLNODE *pRawNode;
|
||||
|
||||
while ( (pRawNode = ellGet ( pSrcList ) ) ) {
|
||||
STATIC_ASSERT ( offsetof (osiSockAddrNode, node) == 0 );
|
||||
osiSockAddrNode *pNode = reinterpret_cast <osiSockAddrNode *> ( pRawNode );
|
||||
osiSockAddrNode *pTmpNode;
|
||||
|
||||
if ( pNode->addr.sa.sa_family == AF_INET ) {
|
||||
|
||||
pTmpNode = (osiSockAddrNode *) ellFirst (pDestList);
|
||||
while ( pTmpNode ) {
|
||||
if (pTmpNode->addr.sa.sa_family == AF_INET) {
|
||||
if ( pNode->addr.ia.sin_addr.s_addr == pTmpNode->addr.ia.sin_addr.s_addr &&
|
||||
pNode->addr.ia.sin_port == pTmpNode->addr.ia.sin_port ) {
|
||||
if ( ! silent ) {
|
||||
char buf[64];
|
||||
ipAddrToDottedIP ( &pNode->addr.ia, buf, sizeof (buf) );
|
||||
fprintf ( stderr,
|
||||
"Warning: Duplicate EPICS CA Address list entry \"%s\" discarded\n", buf );
|
||||
}
|
||||
free (pNode);
|
||||
pNode = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pTmpNode = (osiSockAddrNode *) ellNext (&pTmpNode->node);
|
||||
}
|
||||
if (pNode) {
|
||||
ellAdd (pDestList, &pNode->node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ellAdd (pDestList, &pNode->node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* forcePort ()
|
||||
*/
|
||||
static void forcePort ( ELLLIST *pList, unsigned short port )
|
||||
{
|
||||
osiSockAddrNode *pNode;
|
||||
|
||||
pNode = ( osiSockAddrNode * ) ellFirst ( pList );
|
||||
while ( pNode ) {
|
||||
if ( pNode->addr.sa.sa_family == AF_INET ) {
|
||||
pNode->addr.ia.sin_port = htons ( port );
|
||||
}
|
||||
pNode = ( osiSockAddrNode * ) ellNext ( &pNode->node );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* configureChannelAccessAddressList ()
|
||||
*/
|
||||
extern "C" void epicsShareAPI configureChannelAccessAddressList
|
||||
( ELLLIST *pList, SOCKET sock, unsigned short port )
|
||||
{
|
||||
ELLLIST tmpList;
|
||||
char *pstr;
|
||||
char yesno[32u];
|
||||
int yes;
|
||||
|
||||
/*
|
||||
* dont load the list twice
|
||||
*/
|
||||
assert ( ellCount (pList) == 0 );
|
||||
|
||||
ellInit ( &tmpList );
|
||||
|
||||
/*
|
||||
* Check to see if the user has disabled
|
||||
* initializing the search b-cast list
|
||||
* from the interfaces found.
|
||||
*/
|
||||
yes = true;
|
||||
pstr = envGetConfigParam ( &EPICS_CA_AUTO_ADDR_LIST,
|
||||
sizeof (yesno), yesno );
|
||||
if ( pstr ) {
|
||||
if ( strstr ( pstr, "no" ) || strstr ( pstr, "NO" ) ) {
|
||||
yes = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* LOCK is for piiu->destAddr list
|
||||
* (lock outside because this is used by the server also)
|
||||
*/
|
||||
if (yes) {
|
||||
ELLLIST bcastList;
|
||||
osiSockAddr addr;
|
||||
ellInit ( &bcastList );
|
||||
addr.ia.sin_family = AF_UNSPEC;
|
||||
osiSockDiscoverBroadcastAddresses ( &bcastList, sock, &addr );
|
||||
forcePort ( &bcastList, port );
|
||||
removeDuplicateAddresses ( &tmpList, &bcastList, 1 );
|
||||
if ( ellCount ( &tmpList ) == 0 ) {
|
||||
osiSockAddrNode *pNewNode;
|
||||
pNewNode = (osiSockAddrNode *) calloc ( 1, sizeof (*pNewNode) );
|
||||
if ( pNewNode ) {
|
||||
/*
|
||||
* if no interfaces found then look for local channels
|
||||
* with the loop back interface
|
||||
*/
|
||||
pNewNode->addr.ia.sin_family = AF_INET;
|
||||
pNewNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
|
||||
pNewNode->addr.ia.sin_port = htons ( port );
|
||||
ellAdd ( &tmpList, &pNewNode->node );
|
||||
}
|
||||
else {
|
||||
errlogPrintf ( "configureChannelAccessAddressList(): no memory available for configuration\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
addAddrToChannelAccessAddressList ( &tmpList, &EPICS_CA_ADDR_LIST, port, false );
|
||||
|
||||
removeDuplicateAddresses ( pList, &tmpList, 0 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* printChannelAccessAddressList ()
|
||||
*/
|
||||
extern "C" void epicsShareAPI printChannelAccessAddressList ( const ELLLIST *pList )
|
||||
{
|
||||
osiSockAddrNode *pNode;
|
||||
|
||||
::printf ( "Channel Access Address List\n" );
|
||||
pNode = (osiSockAddrNode *) ellFirst ( pList );
|
||||
while (pNode) {
|
||||
char buf[64];
|
||||
ipAddrToA ( &pNode->addr.ia, buf, sizeof ( buf ) );
|
||||
::printf ( "%s\n", buf );
|
||||
pNode = (osiSockAddrNode *) ellNext ( &pNode->node );
|
||||
}
|
||||
}
|
||||
70
src/client/iocinf.h
Normal file
70
src/client/iocinf.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef INCiocinfh
|
||||
#define INCiocinfh
|
||||
|
||||
#ifdef DEBUG
|
||||
# define debugPrintf(argsInParen) ::printf argsInParen
|
||||
#else
|
||||
# define debugPrintf(argsInParen)
|
||||
#endif
|
||||
|
||||
#if defined ( CLOCKS_PER_SEC )
|
||||
# define CAC_SIGNIFICANT_DELAY ( 1.0 / CLOCKS_PER_SEC )
|
||||
#else
|
||||
# define CAC_SIGNIFICANT_DELAY (1.0 / 1000000u)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* these two control the period of connection verifies
|
||||
* (echo requests) - CA_CONN_VERIFY_PERIOD - and how
|
||||
* long we will wait for an echo reply before we
|
||||
* give up and flag the connection for disconnect
|
||||
* - CA_ECHO_TIMEOUT.
|
||||
*
|
||||
* CA_CONN_VERIFY_PERIOD is normally obtained from an
|
||||
* EPICS environment variable.
|
||||
*/
|
||||
static const double CA_ECHO_TIMEOUT = 5.0; /* (sec) disconn no echo reply tmo */
|
||||
static const double CA_CONN_VERIFY_PERIOD = 30.0; /* (sec) how often to request echo */
|
||||
|
||||
/*
|
||||
* this determines the number of messages received
|
||||
* without a delay in between before we go into
|
||||
* monitor flow control
|
||||
*
|
||||
* turning this down effects maximum throughput
|
||||
* because we dont get an optimal number of bytes
|
||||
* per network frame
|
||||
*/
|
||||
static const unsigned contiguousMsgCountWhichTriggersFlowControl = 10u;
|
||||
|
||||
/*
|
||||
* CA internal functions
|
||||
*/
|
||||
#define genLocalExcep( CBGUARD, GUARD, CAC, STAT, PCTX ) \
|
||||
(CAC).exception ( CBGUARD, GUARD, STAT, PCTX, __FILE__, __LINE__ )
|
||||
|
||||
#endif // ifdef INCiocinfh
|
||||
66
src/client/localHostName.cpp
Normal file
66
src/client/localHostName.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include "osiSock.h"
|
||||
|
||||
#include "localHostName.h"
|
||||
|
||||
epicsSingleton < localHostName > localHostNameCache;
|
||||
|
||||
localHostName::localHostName () :
|
||||
attachedToSockLib ( osiSockAttach () != 0 ), length ( 0u )
|
||||
{
|
||||
const char * pErrStr = "<unknown host>";
|
||||
int status = -1;
|
||||
if ( this->attachedToSockLib ) {
|
||||
status = gethostname (
|
||||
this->cache, sizeof ( this->cache ) );
|
||||
}
|
||||
if ( status ) {
|
||||
strncpy ( this->cache, pErrStr, sizeof ( this->cache ) );
|
||||
}
|
||||
this->cache [ sizeof ( this->cache ) - 1u ] = '\0';
|
||||
this->length = strlen ( this->cache );
|
||||
}
|
||||
|
||||
localHostName::~localHostName ()
|
||||
{
|
||||
if ( this->attachedToSockLib ) {
|
||||
osiSockRelease ();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned localHostName::getName (
|
||||
char * pBuf, unsigned bufLength ) const
|
||||
{
|
||||
if ( bufLength ) {
|
||||
strncpy ( pBuf, this->cache, bufLength );
|
||||
if ( this->length < bufLength ) {
|
||||
return this->length;
|
||||
}
|
||||
else {
|
||||
unsigned reducedSize = bufLength - 1;
|
||||
pBuf [ reducedSize ] = '\0';
|
||||
return reducedSize;
|
||||
}
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
65
src/client/localHostName.h
Normal file
65
src/client/localHostName.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#ifndef localHostNameh
|
||||
#define localHostNameh
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define localHostNameh_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsSingleton.h"
|
||||
|
||||
#ifdef localHostNameh_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
class localHostName {
|
||||
public:
|
||||
localHostName ();
|
||||
~localHostName ();
|
||||
const char * pointer () const;
|
||||
unsigned getName ( char * pBuf, unsigned bufLength ) const;
|
||||
unsigned nameLength () const;
|
||||
private:
|
||||
bool attachedToSockLib;
|
||||
unsigned length;
|
||||
char cache [128];
|
||||
};
|
||||
|
||||
extern epicsSingleton < localHostName > localHostNameCache;
|
||||
|
||||
inline unsigned localHostName::nameLength () const
|
||||
{
|
||||
return this->length;
|
||||
}
|
||||
|
||||
inline const char * localHostName::pointer () const
|
||||
{
|
||||
return this->cache;
|
||||
}
|
||||
|
||||
#endif // ifndef localHostNameh
|
||||
|
||||
|
||||
93
src/client/msgForMultiplyDefinedPV.cpp
Normal file
93
src/client/msgForMultiplyDefinedPV.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "msgForMultiplyDefinedPV.h"
|
||||
#include "cac.h"
|
||||
#include "caerr.h" // for ECA_DBLCHNL
|
||||
|
||||
msgForMultiplyDefinedPV::msgForMultiplyDefinedPV (
|
||||
ipAddrToAsciiEngine & engine,
|
||||
callbackForMultiplyDefinedPV & cbIn,
|
||||
const char * pChannelName, const char * pAcc ) :
|
||||
dnsTransaction ( engine.createTransaction () ), cb ( cbIn )
|
||||
{
|
||||
strncpy ( this->acc, pAcc, sizeof ( this->acc ) );
|
||||
this->acc[ sizeof ( this->acc ) - 1 ] = '\0';
|
||||
strncpy ( this->channel, pChannelName, sizeof ( this->channel ) );
|
||||
this->channel[ sizeof ( this->channel ) - 1 ] = '\0';
|
||||
}
|
||||
|
||||
msgForMultiplyDefinedPV::~msgForMultiplyDefinedPV ()
|
||||
{
|
||||
this->dnsTransaction.release ();
|
||||
}
|
||||
|
||||
void msgForMultiplyDefinedPV::transactionComplete ( const char * pHostNameRej )
|
||||
{
|
||||
// calls into cac for the notification
|
||||
// the msg object (= this) is being deleted as part of the notification
|
||||
this->cb.pvMultiplyDefinedNotify ( *this, this->channel, this->acc, pHostNameRej );
|
||||
// !! dont touch 'this' pointer after this point because object has been deleted !!
|
||||
}
|
||||
|
||||
void * msgForMultiplyDefinedPV::operator new ( size_t size,
|
||||
tsFreeList < class msgForMultiplyDefinedPV, 16 > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
void msgForMultiplyDefinedPV::operator delete ( void *pCadaver,
|
||||
tsFreeList < class msgForMultiplyDefinedPV, 16 > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver, sizeof ( msgForMultiplyDefinedPV ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
void msgForMultiplyDefinedPV::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
callbackForMultiplyDefinedPV::~callbackForMultiplyDefinedPV ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
79
src/client/msgForMultiplyDefinedPV.h
Normal file
79
src/client/msgForMultiplyDefinedPV.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef msgForMultiplyDefinedPVh
|
||||
#define msgForMultiplyDefinedPVh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define msgForMultiplyDefinedPVh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "ipAddrToAsciiAsynchronous.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "tsDLList.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef msgForMultiplyDefinedPVh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
class callbackForMultiplyDefinedPV {
|
||||
public:
|
||||
virtual ~callbackForMultiplyDefinedPV () = 0;
|
||||
virtual void pvMultiplyDefinedNotify (
|
||||
class msgForMultiplyDefinedPV &, const char * pChannelName,
|
||||
const char * pAcc, const char * pRej ) = 0;
|
||||
};
|
||||
|
||||
class msgForMultiplyDefinedPV :
|
||||
public ipAddrToAsciiCallBack,
|
||||
public tsDLNode < msgForMultiplyDefinedPV > {
|
||||
public:
|
||||
msgForMultiplyDefinedPV ( ipAddrToAsciiEngine & engine,
|
||||
callbackForMultiplyDefinedPV &, const char * pChannelName,
|
||||
const char * pAcc );
|
||||
virtual ~msgForMultiplyDefinedPV ();
|
||||
void ioInitiate ( const osiSockAddr & rej );
|
||||
void * operator new ( size_t size, tsFreeList < class msgForMultiplyDefinedPV, 16 > & );
|
||||
epicsPlacementDeleteOperator (( void *, tsFreeList < class msgForMultiplyDefinedPV, 16 > & ))
|
||||
private:
|
||||
char acc[64];
|
||||
char channel[64];
|
||||
ipAddrToAsciiTransaction & dnsTransaction;
|
||||
callbackForMultiplyDefinedPV & cb;
|
||||
void transactionComplete ( const char * pHostName );
|
||||
msgForMultiplyDefinedPV ( const msgForMultiplyDefinedPV & );
|
||||
msgForMultiplyDefinedPV & operator = ( const msgForMultiplyDefinedPV & );
|
||||
void operator delete ( void * );
|
||||
};
|
||||
|
||||
inline void msgForMultiplyDefinedPV::ioInitiate ( const osiSockAddr & rej )
|
||||
{
|
||||
this->dnsTransaction.ipAddrToAscii ( rej, *this );
|
||||
}
|
||||
|
||||
#endif // ifdef msgForMultiplyDefinedPVh
|
||||
|
||||
626
src/client/nciu.cpp
Normal file
626
src/client/nciu.cpp
Normal file
@@ -0,0 +1,626 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*
|
||||
*/
|
||||
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "epicsAlgorithm.h"
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "cac.h"
|
||||
#include "osiWireFormat.h"
|
||||
#include "udpiiu.h"
|
||||
#include "virtualCircuit.h"
|
||||
#include "cadef.h"
|
||||
#include "db_access.h" // for INVALID_DB_REQ
|
||||
#include "noopiiu.h"
|
||||
|
||||
nciu::nciu ( cac & cacIn, netiiu & iiuIn, cacChannelNotify & chanIn,
|
||||
const char *pNameIn, cacChannel::priLev pri ) :
|
||||
cacChannel ( chanIn ),
|
||||
cacCtx ( cacIn ),
|
||||
piiu ( & iiuIn ),
|
||||
sid ( UINT_MAX ),
|
||||
count ( 0 ),
|
||||
retry ( 0u ),
|
||||
nameLength ( 0u ),
|
||||
typeCode ( USHRT_MAX ),
|
||||
priority ( static_cast <ca_uint8_t> ( pri ) )
|
||||
{
|
||||
size_t nameLengthTmp = strlen ( pNameIn ) + 1;
|
||||
|
||||
// second constraint is imposed by size field in protocol header
|
||||
if ( nameLengthTmp > MAX_UDP_SEND - sizeof ( caHdr ) || nameLengthTmp > USHRT_MAX ) {
|
||||
throw cacChannel::badString ();
|
||||
}
|
||||
|
||||
if ( pri > 0xff ) {
|
||||
throw cacChannel::badPriority ();
|
||||
}
|
||||
|
||||
this->nameLength = static_cast <unsigned short> ( nameLengthTmp );
|
||||
|
||||
this->pNameStr = new char [ this->nameLength ];
|
||||
strcpy ( this->pNameStr, pNameIn );
|
||||
}
|
||||
|
||||
nciu::~nciu ()
|
||||
{
|
||||
delete [] this->pNameStr;
|
||||
}
|
||||
|
||||
// channels are created by the user, and only destroyed by the user
|
||||
// using this routine
|
||||
void nciu::destroy (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExcusionGuard )
|
||||
{
|
||||
while ( baseNMIU * pNetIO = this->eventq.first () ) {
|
||||
bool success = this->cacCtx.destroyIO ( callbackGuard, mutualExcusionGuard,
|
||||
pNetIO->getId (), *this );
|
||||
assert ( success );
|
||||
}
|
||||
|
||||
// if the claim reply has not returned yet then we will issue
|
||||
// the clear channel request to the server when the claim reply
|
||||
// arrives and there is no matching nciu in the client
|
||||
if ( this->channelNode::isInstalledInServer ( mutualExcusionGuard ) ) {
|
||||
this->getPIIU(mutualExcusionGuard)->clearChannelRequest (
|
||||
mutualExcusionGuard, this->sid, this->id );
|
||||
}
|
||||
this->piiu->uninstallChan ( mutualExcusionGuard, *this );
|
||||
this->cacCtx.destroyChannel ( mutualExcusionGuard, *this );
|
||||
}
|
||||
|
||||
void nciu::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
void nciu::initiateConnect (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->cacCtx.initiateConnect ( guard, *this, this->piiu );
|
||||
}
|
||||
|
||||
void nciu::connect ( unsigned nativeType,
|
||||
unsigned nativeCount, unsigned sidIn,
|
||||
epicsGuard < epicsMutex > & /* cbGuard */,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
if ( ! dbf_type_is_valid ( nativeType ) ) {
|
||||
throw std::logic_error ( "Ignored conn resp with bad native data type" );
|
||||
}
|
||||
|
||||
this->typeCode = static_cast < unsigned short > ( nativeType );
|
||||
this->count = nativeCount;
|
||||
this->sid = sidIn;
|
||||
|
||||
/*
|
||||
* if less than v4.1 then the server will never
|
||||
* send access rights and there will always be access
|
||||
*/
|
||||
bool v41Ok = this->piiu->ca_v41_ok ( guard );
|
||||
if ( ! v41Ok ) {
|
||||
this->accessRightState.setReadPermit();
|
||||
this->accessRightState.setWritePermit();
|
||||
}
|
||||
|
||||
/*
|
||||
* if less than v4.1 then the server will never
|
||||
* send access rights and we know that there
|
||||
* will always be access and also need to call
|
||||
* their call back here
|
||||
*/
|
||||
if ( ! v41Ok ) {
|
||||
this->notify().accessRightsNotify (
|
||||
guard, this->accessRightState );
|
||||
}
|
||||
|
||||
// channel uninstal routine grabs the callback lock so
|
||||
// a channel will not be deleted while a call back is
|
||||
// in progress
|
||||
//
|
||||
// the callback lock is also taken when a channel
|
||||
// disconnects to prevent a race condition with the
|
||||
// code below - ie we hold the callback lock here
|
||||
// so a chanel cant be destroyed out from under us.
|
||||
this->notify().connectNotify ( guard );
|
||||
}
|
||||
|
||||
void nciu::unresponsiveCircuitNotify (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
ioid tmpId = this->getId ();
|
||||
cac & caRefTmp = this->cacCtx;
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
this->cacCtx.disconnectAllIO ( cbGuard, guard,
|
||||
*this, this->eventq );
|
||||
this->notify().disconnectNotify ( guard );
|
||||
// if they destroy the channel in their disconnect
|
||||
// handler then we have to be very careful to not
|
||||
// touch this object if it has been destroyed
|
||||
nciu * pChan = caRefTmp.lookupChannel ( guard, tmpId );
|
||||
if ( pChan ) {
|
||||
caAccessRights noRights;
|
||||
pChan->notify().accessRightsNotify ( guard, noRights );
|
||||
// likewise, they might destroy the channel in their access rights
|
||||
// handler so we have to be very careful to not touch this
|
||||
// object from here on down
|
||||
}
|
||||
}
|
||||
|
||||
void nciu::setServerAddressUnknown ( netiiu & newiiu,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
this->piiu = & newiiu;
|
||||
this->retry = 0;
|
||||
this->typeCode = USHRT_MAX;
|
||||
this->count = 0u;
|
||||
this->sid = UINT_MAX;
|
||||
this->accessRightState.clrReadPermit();
|
||||
this->accessRightState.clrWritePermit();
|
||||
}
|
||||
|
||||
void nciu::accessRightsStateChange (
|
||||
const caAccessRights & arIn, epicsGuard < epicsMutex > & /* cbGuard */,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
this->accessRightState = arIn;
|
||||
|
||||
//
|
||||
// the channel delete routine takes the call back lock so
|
||||
// that this will not be called when the channel is being
|
||||
// deleted.
|
||||
//
|
||||
this->notify().accessRightsNotify ( guard, this->accessRightState );
|
||||
}
|
||||
|
||||
/*
|
||||
* nciu::searchMsg ()
|
||||
*/
|
||||
bool nciu::searchMsg ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
bool success = this->piiu->searchMsg (
|
||||
guard, this->getId (), this->pNameStr, this->nameLength );
|
||||
if ( success ) {
|
||||
if ( this->retry < UINT_MAX ) {
|
||||
this->retry++;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
const char *nciu::pName (
|
||||
epicsGuard < epicsMutex > & guard ) const throw ()
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
return this->pNameStr;
|
||||
}
|
||||
|
||||
unsigned nciu::getName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLen ) const throw ()
|
||||
{
|
||||
if ( bufLen == 0u ) {
|
||||
return 0u;
|
||||
}
|
||||
if ( this->nameLength < bufLen ) {
|
||||
strcpy ( pBuf, this->pNameStr );
|
||||
return this->nameLength;
|
||||
}
|
||||
else {
|
||||
unsigned reducedSize = bufLen - 1u;
|
||||
strncpy ( pBuf, this->pNameStr, bufLen );
|
||||
pBuf[reducedSize] = '\0';
|
||||
return reducedSize;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned nciu::nameLen (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
return this->nameLength;
|
||||
}
|
||||
|
||||
unsigned nciu::requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
return piiu->requestMessageBytesPending ( guard );
|
||||
}
|
||||
|
||||
void nciu::flush (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
piiu->flush ( guard );
|
||||
}
|
||||
|
||||
cacChannel::ioStatus nciu::read (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
unsigned type, arrayElementCount countIn,
|
||||
cacReadNotify ¬ify, ioid *pId )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
|
||||
if ( ! this->connected ( guard ) ) {
|
||||
throw cacChannel::notConnected ();
|
||||
}
|
||||
if ( ! this->accessRightState.readPermit () ) {
|
||||
throw cacChannel::noReadAccess ();
|
||||
}
|
||||
if ( countIn > this->count ) {
|
||||
throw cacChannel::outOfBounds ();
|
||||
}
|
||||
|
||||
//
|
||||
// fail out if their arguments are invalid
|
||||
//
|
||||
if ( INVALID_DB_REQ ( type ) ) {
|
||||
throw cacChannel::badType ();
|
||||
}
|
||||
|
||||
netReadNotifyIO & io = this->cacCtx.readNotifyRequest (
|
||||
guard, *this, *this, type, countIn, notify );
|
||||
if ( pId ) {
|
||||
*pId = io.getId ();
|
||||
}
|
||||
this->eventq.add ( io );
|
||||
return cacChannel::iosAsynch;
|
||||
}
|
||||
|
||||
void nciu::stringVerify ( const char *pStr, const unsigned count )
|
||||
{
|
||||
for ( unsigned i = 0; i < count; i++ ) {
|
||||
unsigned int strsize = 0;
|
||||
while ( pStr[strsize++] != '\0' ) {
|
||||
if ( strsize >= MAX_STRING_SIZE ) {
|
||||
throw badString();
|
||||
}
|
||||
}
|
||||
pStr += MAX_STRING_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void nciu::write (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
unsigned type, arrayElementCount countIn, const void * pValue )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
|
||||
// make sure that they get this and not "no write access"
|
||||
// if disconnected
|
||||
if ( ! this->connected ( guard ) ) {
|
||||
throw cacChannel::notConnected();
|
||||
}
|
||||
if ( ! this->accessRightState.writePermit() ) {
|
||||
throw cacChannel::noWriteAccess();
|
||||
}
|
||||
if ( countIn > this->count || countIn == 0 ) {
|
||||
throw cacChannel::outOfBounds();
|
||||
}
|
||||
if ( type == DBR_STRING ) {
|
||||
nciu::stringVerify ( (char *) pValue, countIn );
|
||||
}
|
||||
this->piiu->writeRequest ( guard, *this, type, countIn, pValue );
|
||||
}
|
||||
|
||||
cacChannel::ioStatus nciu::write (
|
||||
epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount countIn,
|
||||
const void * pValue, cacWriteNotify & notify, ioid * pId )
|
||||
{
|
||||
// make sure that they get this and not "no write access"
|
||||
// if disconnected
|
||||
if ( ! this->connected ( guard ) ) {
|
||||
throw cacChannel::notConnected();
|
||||
}
|
||||
if ( ! this->accessRightState.writePermit() ) {
|
||||
throw cacChannel::noWriteAccess();
|
||||
}
|
||||
if ( countIn > this->count || countIn == 0 ) {
|
||||
throw cacChannel::outOfBounds();
|
||||
}
|
||||
if ( type == DBR_STRING ) {
|
||||
nciu::stringVerify ( (char *) pValue, countIn );
|
||||
}
|
||||
|
||||
netWriteNotifyIO & io = this->cacCtx.writeNotifyRequest (
|
||||
guard, *this, *this, type, countIn, pValue, notify );
|
||||
if ( pId ) {
|
||||
*pId = io.getId ();
|
||||
}
|
||||
this->eventq.add ( io );
|
||||
return cacChannel::iosAsynch;
|
||||
}
|
||||
|
||||
void nciu::subscribe (
|
||||
epicsGuard < epicsMutex > & guard, unsigned type,
|
||||
arrayElementCount nElem, unsigned mask,
|
||||
cacStateNotify & notify, ioid *pId )
|
||||
{
|
||||
netSubscription & io = this->cacCtx.subscriptionRequest (
|
||||
guard, *this, *this, type, nElem, mask, notify,
|
||||
this->channelNode::isInstalledInServer ( guard ) );
|
||||
this->eventq.add ( io );
|
||||
if ( pId ) {
|
||||
*pId = io.getId ();
|
||||
}
|
||||
}
|
||||
|
||||
void nciu::ioCancel (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const ioid & idIn )
|
||||
{
|
||||
this->cacCtx.destroyIO ( callbackGuard,
|
||||
mutualExclusionGuard, idIn, *this );
|
||||
}
|
||||
|
||||
void nciu::ioShow (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const ioid &idIn, unsigned level ) const
|
||||
{
|
||||
this->cacCtx.ioShow ( guard, idIn, level );
|
||||
}
|
||||
|
||||
unsigned nciu::getHostName (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
char *pBuf, unsigned bufLength ) const throw ()
|
||||
{
|
||||
return this->piiu->getHostName (
|
||||
guard, pBuf, bufLength );
|
||||
}
|
||||
|
||||
const char * nciu::pHostName (
|
||||
epicsGuard < epicsMutex > & guard ) const throw ()
|
||||
{
|
||||
return this->piiu->pHostName ( guard );
|
||||
}
|
||||
|
||||
bool nciu::ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
return this->piiu->ca_v42_ok ( guard );
|
||||
}
|
||||
|
||||
short nciu::nativeType (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
short type = TYPENOTCONN;
|
||||
if ( this->connected ( guard ) ) {
|
||||
if ( this->typeCode < SHRT_MAX ) {
|
||||
type = static_cast <short> ( this->typeCode );
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
arrayElementCount nciu::nativeElementCount (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
arrayElementCount countOut = 0ul;
|
||||
if ( this->connected ( guard ) ) {
|
||||
countOut = this->count;
|
||||
}
|
||||
return countOut;
|
||||
}
|
||||
|
||||
caAccessRights nciu::accessRights (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
return this->accessRightState;
|
||||
}
|
||||
|
||||
unsigned nciu::searchAttempts (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
return this->retry;
|
||||
}
|
||||
|
||||
double nciu::beaconPeriod (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
return this->cacCtx.beaconPeriod ( guard, *this );
|
||||
}
|
||||
|
||||
double nciu::receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
return this->piiu->receiveWatchdogDelay ( guard );
|
||||
}
|
||||
|
||||
bool nciu::connected ( epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
return this->channelNode::isConnected ( guard );
|
||||
}
|
||||
|
||||
void nciu::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef() );
|
||||
this->show ( guard, level );
|
||||
}
|
||||
|
||||
void nciu::show (
|
||||
epicsGuard < epicsMutex > & guard, unsigned level ) const
|
||||
{
|
||||
if ( this->connected ( guard ) ) {
|
||||
char hostNameTmp [256];
|
||||
this->getHostName ( guard, hostNameTmp, sizeof ( hostNameTmp ) );
|
||||
::printf ( "Channel \"%s\", connected to server %s",
|
||||
this->pNameStr, hostNameTmp );
|
||||
if ( level > 1u ) {
|
||||
int tmpTypeCode = static_cast < int > ( this->typeCode );
|
||||
::printf ( ", native type %s, native element count %u",
|
||||
dbf_type_to_text ( tmpTypeCode ), this->count );
|
||||
::printf ( ", %sread access, %swrite access",
|
||||
this->accessRightState.readPermit() ? "" : "no ",
|
||||
this->accessRightState.writePermit() ? "" : "no ");
|
||||
}
|
||||
::printf ( "\n" );
|
||||
}
|
||||
else {
|
||||
::printf ( "Channel \"%s\" is disconnected\n", this->pNameStr );
|
||||
}
|
||||
|
||||
if ( level > 2u ) {
|
||||
::printf ( "\tnetwork IO pointer = %p\n",
|
||||
static_cast <void *> ( this->piiu ) );
|
||||
::printf ( "\tserver identifier %u\n", this->sid );
|
||||
::printf ( "\tsearch retry number=%u\n", this->retry );
|
||||
::printf ( "\tname length=%u\n", this->nameLength );
|
||||
}
|
||||
}
|
||||
|
||||
void nciu::ioCompletionNotify (
|
||||
epicsGuard < epicsMutex > &, class baseNMIU & io )
|
||||
{
|
||||
this->eventq.remove ( io );
|
||||
}
|
||||
|
||||
void nciu::resubscribe ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
tsDLIter < baseNMIU > pNetIO = this->eventq.firstIter ();
|
||||
while ( pNetIO.valid () ) {
|
||||
tsDLIter < baseNMIU > next = pNetIO;
|
||||
next++;
|
||||
class netSubscription * pSubscr = pNetIO->isSubscription ();
|
||||
// Its normal for other types of IO to exist after the channel connects,
|
||||
// but before all of the resubscription requests go out. We must ignore
|
||||
// them here.
|
||||
if ( pSubscr ) {
|
||||
try {
|
||||
pSubscr->subscribeIfRequired ( guard, *this );
|
||||
}
|
||||
catch ( ... ) {
|
||||
errlogPrintf ( "CAC: failed to send subscription request "
|
||||
"during channel connect\n" );
|
||||
}
|
||||
}
|
||||
pNetIO = next;
|
||||
}
|
||||
}
|
||||
|
||||
void nciu::sendSubscriptionUpdateRequests ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
tsDLIter < baseNMIU > pNetIO = this->eventq.firstIter ();
|
||||
while ( pNetIO.valid () ) {
|
||||
tsDLIter < baseNMIU > next = pNetIO;
|
||||
next++;
|
||||
try {
|
||||
pNetIO->forceSubscriptionUpdate ( guard, *this );
|
||||
}
|
||||
catch ( ... ) {
|
||||
errlogPrintf (
|
||||
"CAC: failed to send subscription update request "
|
||||
"during channel connect\n" );
|
||||
}
|
||||
pNetIO = next;
|
||||
}
|
||||
}
|
||||
|
||||
void nciu::disconnectAllIO (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->cacCtx.disconnectAllIO ( cbGuard, guard,
|
||||
*this, this->eventq );
|
||||
}
|
||||
|
||||
void nciu::serviceShutdownNotify (
|
||||
epicsGuard < epicsMutex > & callbackControlGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard )
|
||||
{
|
||||
this->setServerAddressUnknown ( noopIIU, mutualExclusionGuard );
|
||||
this->notify().serviceShutdownNotify ( mutualExclusionGuard );
|
||||
}
|
||||
|
||||
void channelNode::setRespPendingState (
|
||||
epicsGuard < epicsMutex > &, unsigned index )
|
||||
{
|
||||
this->listMember =
|
||||
static_cast < channelNode::channelState >
|
||||
( channelNode::cs_searchRespPending0 + index );
|
||||
if ( this->listMember > cs_searchRespPending17 ) {
|
||||
throw std::runtime_error (
|
||||
"resp search timer index out of bounds" );
|
||||
}
|
||||
}
|
||||
|
||||
void channelNode::setReqPendingState (
|
||||
epicsGuard < epicsMutex > &, unsigned index )
|
||||
{
|
||||
this->listMember =
|
||||
static_cast < channelNode::channelState >
|
||||
( channelNode::cs_searchReqPending0 + index );
|
||||
if ( this->listMember > cs_searchReqPending17 ) {
|
||||
throw std::runtime_error (
|
||||
"req search timer index out of bounds" );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned channelNode::getMaxSearchTimerCount ()
|
||||
{
|
||||
return epicsMin (
|
||||
cs_searchReqPending17 - cs_searchReqPending0,
|
||||
cs_searchRespPending17 - cs_searchRespPending0 ) + 1u;
|
||||
}
|
||||
|
||||
unsigned channelNode::getSearchTimerIndex (
|
||||
epicsGuard < epicsMutex > & )
|
||||
{
|
||||
channelNode::channelState chanState = this->listMember;
|
||||
unsigned index = 0u;
|
||||
if ( chanState >= cs_searchReqPending0 &&
|
||||
chanState <= cs_searchReqPending17 ) {
|
||||
index = chanState - cs_searchReqPending0;
|
||||
}
|
||||
else if ( chanState >= cs_searchRespPending0 &&
|
||||
chanState <= cs_searchRespPending17 ) {
|
||||
index = chanState - cs_searchRespPending0;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error (
|
||||
"channel was expected to be in a search timer, but wasnt" );;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
385
src/client/nciu.h
Normal file
385
src/client/nciu.h
Normal file
@@ -0,0 +1,385 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef nciuh
|
||||
#define nciuh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define nciuh_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "resourceLib.h"
|
||||
#include "tsDLList.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef nciuh_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
#define CA_MINOR_PROTOCOL_REVISION 13
|
||||
#include "caProto.h"
|
||||
|
||||
#include "cacIO.h"
|
||||
|
||||
class cac;
|
||||
class netiiu;
|
||||
|
||||
// The node and the state which tracks the list membership
|
||||
// are in the channel, but belong to the circuit.
|
||||
// Protected by the callback mutex
|
||||
class channelNode : public tsDLNode < class nciu >
|
||||
{
|
||||
protected:
|
||||
channelNode ();
|
||||
bool isInstalledInServer ( epicsGuard < epicsMutex > & ) const;
|
||||
bool isConnected ( epicsGuard < epicsMutex > & ) const;
|
||||
public:
|
||||
static unsigned getMaxSearchTimerCount ();
|
||||
private:
|
||||
enum channelState {
|
||||
cs_none,
|
||||
cs_disconnGov,
|
||||
// note: indexing is used here
|
||||
// so these must be contiguous
|
||||
cs_searchReqPending0,
|
||||
cs_searchReqPending1,
|
||||
cs_searchReqPending2,
|
||||
cs_searchReqPending3,
|
||||
cs_searchReqPending4,
|
||||
cs_searchReqPending5,
|
||||
cs_searchReqPending6,
|
||||
cs_searchReqPending7,
|
||||
cs_searchReqPending8,
|
||||
cs_searchReqPending9,
|
||||
cs_searchReqPending10,
|
||||
cs_searchReqPending11,
|
||||
cs_searchReqPending12,
|
||||
cs_searchReqPending13,
|
||||
cs_searchReqPending14,
|
||||
cs_searchReqPending15,
|
||||
cs_searchReqPending16,
|
||||
cs_searchReqPending17,
|
||||
// note: indexing is used here
|
||||
// so these must be contiguous
|
||||
cs_searchRespPending0,
|
||||
cs_searchRespPending1,
|
||||
cs_searchRespPending2,
|
||||
cs_searchRespPending3,
|
||||
cs_searchRespPending4,
|
||||
cs_searchRespPending5,
|
||||
cs_searchRespPending6,
|
||||
cs_searchRespPending7,
|
||||
cs_searchRespPending8,
|
||||
cs_searchRespPending9,
|
||||
cs_searchRespPending10,
|
||||
cs_searchRespPending11,
|
||||
cs_searchRespPending12,
|
||||
cs_searchRespPending13,
|
||||
cs_searchRespPending14,
|
||||
cs_searchRespPending15,
|
||||
cs_searchRespPending16,
|
||||
cs_searchRespPending17,
|
||||
cs_createReqPend,
|
||||
cs_createRespPend,
|
||||
cs_v42ConnCallbackPend,
|
||||
cs_subscripReqPend,
|
||||
cs_connected,
|
||||
cs_unrespCircuit,
|
||||
cs_subscripUpdateReqPend
|
||||
} listMember;
|
||||
void setRespPendingState ( epicsGuard < epicsMutex > &, unsigned index );
|
||||
void setReqPendingState ( epicsGuard < epicsMutex > &, unsigned index );
|
||||
unsigned getSearchTimerIndex ( epicsGuard < epicsMutex > & );
|
||||
friend class tcpiiu;
|
||||
friend class udpiiu;
|
||||
friend class tcpSendThread;
|
||||
friend class searchTimer;
|
||||
friend class disconnectGovernorTimer;
|
||||
};
|
||||
|
||||
class privateInterfaceForIO {
|
||||
public:
|
||||
virtual void ioCompletionNotify (
|
||||
epicsGuard < epicsMutex > &, class baseNMIU & ) = 0;
|
||||
virtual arrayElementCount nativeElementCount (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual bool connected ( epicsGuard < epicsMutex > & ) const = 0;
|
||||
protected:
|
||||
virtual ~privateInterfaceForIO() {}
|
||||
};
|
||||
|
||||
class nciu :
|
||||
public cacChannel,
|
||||
public chronIntIdRes < nciu >,
|
||||
public channelNode,
|
||||
private privateInterfaceForIO {
|
||||
public:
|
||||
nciu ( cac &, netiiu &, cacChannelNotify &,
|
||||
const char * pNameIn, cacChannel::priLev );
|
||||
~nciu ();
|
||||
void connect ( unsigned nativeType,
|
||||
unsigned nativeCount, unsigned sid,
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void connect ( epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void unresponsiveCircuitNotify (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void circuitHangupNotify ( class udpiiu &,
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void setServerAddressUnknown (
|
||||
netiiu & newiiu, epicsGuard < epicsMutex > & guard );
|
||||
bool searchMsg (
|
||||
epicsGuard < epicsMutex > & );
|
||||
void serviceShutdownNotify (
|
||||
epicsGuard < epicsMutex > & callbackControlGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
void accessRightsStateChange ( const caAccessRights &,
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
ca_uint32_t getSID (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
ca_uint32_t getCID (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
netiiu * getPIIU (
|
||||
epicsGuard < epicsMutex > & );
|
||||
const netiiu * getConstPIIU (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
cac & getClient ();
|
||||
void searchReplySetUp ( netiiu &iiu, unsigned sidIn,
|
||||
ca_uint16_t typeIn, arrayElementCount countIn,
|
||||
epicsGuard < epicsMutex > & );
|
||||
void show (
|
||||
unsigned level ) const;
|
||||
void show (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned level ) const;
|
||||
unsigned getName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLen ) const throw ();
|
||||
const char * pName (
|
||||
epicsGuard < epicsMutex > & ) const throw ();
|
||||
unsigned nameLen (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
unsigned getHostName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLen ) const throw ();
|
||||
void writeException (
|
||||
epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > &,
|
||||
int status, const char *pContext, unsigned type, arrayElementCount count );
|
||||
cacChannel::priLev getPriority (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
void * operator new (
|
||||
size_t size, tsFreeList < class nciu, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (
|
||||
( void *, tsFreeList < class nciu, 1024, epicsMutexNOOP > & ))
|
||||
//arrayElementCount nativeElementCount ( epicsGuard < epicsMutex > & ) const;
|
||||
void resubscribe ( epicsGuard < epicsMutex > & );
|
||||
void sendSubscriptionUpdateRequests ( epicsGuard < epicsMutex > & );
|
||||
void disconnectAllIO (
|
||||
epicsGuard < epicsMutex > &, epicsGuard < epicsMutex > & );
|
||||
bool connected ( epicsGuard < epicsMutex > & ) const;
|
||||
unsigned getcount() const { return count; }
|
||||
|
||||
private:
|
||||
tsDLList < class baseNMIU > eventq;
|
||||
caAccessRights accessRightState;
|
||||
cac & cacCtx;
|
||||
char * pNameStr;
|
||||
netiiu * piiu;
|
||||
ca_uint32_t sid; // server id
|
||||
unsigned count;
|
||||
unsigned retry; // search retry number
|
||||
unsigned short nameLength; // channel name length
|
||||
ca_uint16_t typeCode;
|
||||
ca_uint8_t priority;
|
||||
virtual void destroy (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
void initiateConnect (
|
||||
epicsGuard < epicsMutex > & );
|
||||
unsigned requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
void flush (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
ioStatus read (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
cacReadNotify &, ioid * );
|
||||
void write (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void *pValue );
|
||||
ioStatus write (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void *pValue, cacWriteNotify &, ioid * );
|
||||
void subscribe (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
unsigned type, arrayElementCount nElem,
|
||||
unsigned mask, cacStateNotify ¬ify, ioid * );
|
||||
// The primary mutex must be released when calling the user's
|
||||
// callback, and therefore a finite interval exists when we are
|
||||
// moving forward with the intent to call the users callback
|
||||
// but the users IO could be deleted during this interval.
|
||||
// To prevent the user's callback from being called after
|
||||
// destroying his IO we must past a guard for the callback
|
||||
// mutex here.
|
||||
virtual void ioCancel (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const ioid & );
|
||||
void ioShow (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const ioid &, unsigned level ) const;
|
||||
short nativeType (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
caAccessRights accessRights (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
unsigned searchAttempts (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
double beaconPeriod (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
double receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
bool ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
arrayElementCount nativeElementCount (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
static void stringVerify ( const char *pStr, const unsigned count );
|
||||
void ioCompletionNotify (
|
||||
epicsGuard < epicsMutex > &, class baseNMIU & );
|
||||
const char * pHostName (
|
||||
epicsGuard < epicsMutex > & guard ) const throw ();
|
||||
nciu ( const nciu & );
|
||||
nciu & operator = ( const nciu & );
|
||||
void operator delete ( void * );
|
||||
};
|
||||
|
||||
inline void * nciu::operator new ( size_t size,
|
||||
tsFreeList < class nciu, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void nciu::operator delete ( void * pCadaver,
|
||||
tsFreeList < class nciu, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver, sizeof ( nciu ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline ca_uint32_t nciu::getSID (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return this->sid;
|
||||
}
|
||||
|
||||
inline ca_uint32_t nciu::getCID (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return this->id;
|
||||
}
|
||||
|
||||
// this is to only be used by early protocol revisions
|
||||
inline void nciu::connect ( epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->connect ( this->typeCode, this->count,
|
||||
this->sid, cbGuard, guard );
|
||||
}
|
||||
|
||||
inline void nciu::searchReplySetUp ( netiiu &iiu, unsigned sidIn,
|
||||
ca_uint16_t typeIn, arrayElementCount countIn,
|
||||
epicsGuard < epicsMutex > & )
|
||||
{
|
||||
this->piiu = & iiu;
|
||||
this->typeCode = typeIn;
|
||||
this->count = countIn;
|
||||
this->sid = sidIn;
|
||||
}
|
||||
|
||||
inline netiiu * nciu::getPIIU (
|
||||
epicsGuard < epicsMutex > & )
|
||||
{
|
||||
return this->piiu;
|
||||
}
|
||||
|
||||
inline void nciu::writeException (
|
||||
epicsGuard < epicsMutex > & /* cbGuard */,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * pContext,
|
||||
unsigned typeIn, arrayElementCount countIn )
|
||||
{
|
||||
this->notify().writeException ( guard,
|
||||
status, pContext, typeIn, countIn );
|
||||
}
|
||||
|
||||
inline const netiiu * nciu::getConstPIIU (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return this->piiu;
|
||||
}
|
||||
|
||||
inline cac & nciu::getClient ()
|
||||
{
|
||||
return this->cacCtx;
|
||||
}
|
||||
|
||||
inline cacChannel::priLev nciu::getPriority (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return this->priority;
|
||||
}
|
||||
|
||||
inline channelNode::channelNode () :
|
||||
listMember ( cs_none )
|
||||
{
|
||||
}
|
||||
|
||||
inline bool channelNode::isConnected ( epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return
|
||||
this->listMember == cs_connected ||
|
||||
this->listMember == cs_subscripReqPend ||
|
||||
this->listMember == cs_subscripUpdateReqPend;
|
||||
}
|
||||
|
||||
inline bool channelNode::isInstalledInServer ( epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return
|
||||
this->listMember == cs_connected ||
|
||||
this->listMember == cs_subscripReqPend ||
|
||||
this->listMember == cs_unrespCircuit ||
|
||||
this->listMember == cs_subscripUpdateReqPend;
|
||||
}
|
||||
|
||||
#endif // ifdef nciuh
|
||||
306
src/client/netIO.h
Normal file
306
src/client/netIO.h
Normal file
@@ -0,0 +1,306 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef netIOh
|
||||
#define netIOh
|
||||
|
||||
#include "nciu.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
// SUN PRO generates multiply defined symbols if the baseNMIU
|
||||
// destructor is virtual (therefore it is protected).
|
||||
// I assume that SUNPRO will fix this in future versions.
|
||||
// With other compilers we get warnings (and
|
||||
// potential problems) if we dont make the baseNMIU
|
||||
// destructor virtual.
|
||||
#if defined ( __SUNPRO_CC ) && ( __SUNPRO_CC <= 0x540 )
|
||||
# define NETIO_VIRTUAL_DESTRUCTOR
|
||||
#else
|
||||
# define NETIO_VIRTUAL_DESTRUCTOR virtual
|
||||
#endif
|
||||
|
||||
class privateInterfaceForIO;
|
||||
|
||||
class baseNMIU : public tsDLNode < baseNMIU >,
|
||||
public chronIntIdRes < baseNMIU > {
|
||||
public:
|
||||
virtual void destroy (
|
||||
epicsGuard < epicsMutex > &, class cacRecycle & ) = 0; // only called by cac
|
||||
virtual void completion (
|
||||
epicsGuard < epicsMutex > &, cacRecycle & ) = 0;
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
int status, const char * pContext ) = 0;
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
int status, const char * pContext, unsigned type,
|
||||
arrayElementCount count ) = 0;
|
||||
virtual void completion (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void * pData ) = 0;
|
||||
virtual void forceSubscriptionUpdate (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan ) = 0;
|
||||
virtual class netSubscription * isSubscription () = 0;
|
||||
virtual void show (
|
||||
unsigned level ) const = 0;
|
||||
virtual void show (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned level ) const = 0;
|
||||
protected:
|
||||
NETIO_VIRTUAL_DESTRUCTOR ~baseNMIU ();
|
||||
};
|
||||
|
||||
class netSubscription : public baseNMIU {
|
||||
public:
|
||||
static netSubscription * factory (
|
||||
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > &,
|
||||
class privateInterfaceForIO &, unsigned type, arrayElementCount count,
|
||||
unsigned mask, cacStateNotify & );
|
||||
void show (
|
||||
unsigned level ) const;
|
||||
void show (
|
||||
epicsGuard < epicsMutex > &, unsigned level ) const;
|
||||
arrayElementCount getCount (
|
||||
epicsGuard < epicsMutex > &, bool allow_zero ) const;
|
||||
unsigned getType (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
unsigned getMask (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
void subscribeIfRequired (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan );
|
||||
void unsubscribeIfRequired (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan );
|
||||
protected:
|
||||
netSubscription (
|
||||
class privateInterfaceForIO &, unsigned type,
|
||||
arrayElementCount count,
|
||||
unsigned mask, cacStateNotify & );
|
||||
~netSubscription ();
|
||||
private:
|
||||
const arrayElementCount count;
|
||||
class privateInterfaceForIO & privateChanForIO;
|
||||
cacStateNotify & notify;
|
||||
const unsigned type;
|
||||
const unsigned mask;
|
||||
bool subscribed;
|
||||
class netSubscription * isSubscription ();
|
||||
void operator delete ( void * );
|
||||
void * operator new ( size_t,
|
||||
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (( void *,
|
||||
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > & ))
|
||||
void destroy (
|
||||
epicsGuard < epicsMutex > &, class cacRecycle & );
|
||||
void completion (
|
||||
epicsGuard < epicsMutex > &, cacRecycle & );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
int status, const char * pContext );
|
||||
void completion (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
unsigned type, arrayElementCount count, const void * pData );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
int status, const char * pContext, unsigned type,
|
||||
arrayElementCount count );
|
||||
void forceSubscriptionUpdate (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan );
|
||||
netSubscription ( const netSubscription & );
|
||||
netSubscription & operator = ( const netSubscription & );
|
||||
};
|
||||
|
||||
class netReadNotifyIO : public baseNMIU {
|
||||
public:
|
||||
static netReadNotifyIO * factory (
|
||||
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > &,
|
||||
privateInterfaceForIO &, cacReadNotify & );
|
||||
void show (
|
||||
unsigned level ) const;
|
||||
void show (
|
||||
epicsGuard < epicsMutex > &, unsigned level ) const;
|
||||
protected:
|
||||
netReadNotifyIO ( privateInterfaceForIO &, cacReadNotify & );
|
||||
~netReadNotifyIO ();
|
||||
private:
|
||||
cacReadNotify & notify;
|
||||
class privateInterfaceForIO & privateChanForIO;
|
||||
void operator delete ( void * );
|
||||
void * operator new ( size_t,
|
||||
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (( void *,
|
||||
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & ))
|
||||
void destroy (
|
||||
epicsGuard < epicsMutex > &, class cacRecycle & );
|
||||
void completion (
|
||||
epicsGuard < epicsMutex > &, cacRecycle & );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
int status, const char * pContext );
|
||||
void completion (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void * pData );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
int status, const char * pContext,
|
||||
unsigned type, arrayElementCount count );
|
||||
class netSubscription * isSubscription ();
|
||||
void forceSubscriptionUpdate (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan );
|
||||
netReadNotifyIO ( const netReadNotifyIO & );
|
||||
netReadNotifyIO & operator = ( const netReadNotifyIO & );
|
||||
};
|
||||
|
||||
class netWriteNotifyIO : public baseNMIU {
|
||||
public:
|
||||
static netWriteNotifyIO * factory (
|
||||
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > &,
|
||||
privateInterfaceForIO &, cacWriteNotify & );
|
||||
void show (
|
||||
unsigned level ) const;
|
||||
void show (
|
||||
epicsGuard < epicsMutex > &, unsigned level ) const;
|
||||
protected:
|
||||
netWriteNotifyIO ( privateInterfaceForIO &, cacWriteNotify & );
|
||||
~netWriteNotifyIO ();
|
||||
private:
|
||||
cacWriteNotify & notify;
|
||||
privateInterfaceForIO & privateChanForIO;
|
||||
void operator delete ( void * );
|
||||
void * operator new ( size_t,
|
||||
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (( void *,
|
||||
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & ))
|
||||
class netSubscription * isSubscription ();
|
||||
void destroy (
|
||||
epicsGuard < epicsMutex > &, class cacRecycle & );
|
||||
void completion (
|
||||
epicsGuard < epicsMutex > &, cacRecycle & );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
int status, const char * pContext );
|
||||
void completion (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void * pData );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, cacRecycle &,
|
||||
int status, const char * pContext, unsigned type,
|
||||
arrayElementCount count );
|
||||
void forceSubscriptionUpdate (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan );
|
||||
netWriteNotifyIO ( const netWriteNotifyIO & );
|
||||
netWriteNotifyIO & operator = ( const netWriteNotifyIO & );
|
||||
};
|
||||
|
||||
inline void * netSubscription::operator new ( size_t size,
|
||||
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > &freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#if defined ( CXX_PLACEMENT_DELETE )
|
||||
inline void netSubscription::operator delete ( void *pCadaver,
|
||||
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > &freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline netSubscription * netSubscription::factory (
|
||||
tsFreeList < class netSubscription, 1024, epicsMutexNOOP > & freeList,
|
||||
class privateInterfaceForIO & chan, unsigned type, arrayElementCount count,
|
||||
unsigned mask, cacStateNotify ¬ify )
|
||||
{
|
||||
return new ( freeList ) netSubscription ( chan, type,
|
||||
count, mask, notify );
|
||||
}
|
||||
|
||||
inline arrayElementCount netSubscription::getCount (
|
||||
epicsGuard < epicsMutex > & guard, bool allow_zero ) const
|
||||
{
|
||||
//guard.assertIdenticalMutex ( this->mutex );
|
||||
arrayElementCount nativeCount = this->privateChanForIO.nativeElementCount ( guard );
|
||||
if ( (this->count == 0u && !allow_zero) || this->count > nativeCount ) {
|
||||
return nativeCount;
|
||||
}
|
||||
else {
|
||||
return this->count;
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned netSubscription::getType ( epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return this->type;
|
||||
}
|
||||
|
||||
inline unsigned netSubscription::getMask ( epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return this->mask;
|
||||
}
|
||||
|
||||
inline netReadNotifyIO * netReadNotifyIO::factory (
|
||||
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & freeList,
|
||||
privateInterfaceForIO & ioComplNotifIntf, cacReadNotify & notify )
|
||||
{
|
||||
return new ( freeList ) netReadNotifyIO ( ioComplNotifIntf, notify );
|
||||
}
|
||||
|
||||
inline void * netReadNotifyIO::operator new ( size_t size,
|
||||
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#if defined ( CXX_PLACEMENT_DELETE )
|
||||
inline void netReadNotifyIO::operator delete ( void *pCadaver,
|
||||
tsFreeList < class netReadNotifyIO, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline netWriteNotifyIO * netWriteNotifyIO::factory (
|
||||
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & freeList,
|
||||
privateInterfaceForIO & ioComplNotifyIntf, cacWriteNotify & notify )
|
||||
{
|
||||
return new ( freeList ) netWriteNotifyIO ( ioComplNotifyIntf, notify );
|
||||
}
|
||||
|
||||
inline void * netWriteNotifyIO::operator new ( size_t size,
|
||||
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#if defined ( CXX_PLACEMENT_DELETE )
|
||||
inline void netWriteNotifyIO::operator delete ( void *pCadaver,
|
||||
tsFreeList < class netWriteNotifyIO, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ifdef netIOh
|
||||
134
src/client/netReadNotifyIO.cpp
Normal file
134
src/client/netReadNotifyIO.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "iocinf.h"
|
||||
#include "nciu.h"
|
||||
#include "cac.h"
|
||||
|
||||
netReadNotifyIO::netReadNotifyIO (
|
||||
privateInterfaceForIO & ioComplIntfIn,
|
||||
cacReadNotify & notify ) :
|
||||
notify ( notify ), privateChanForIO ( ioComplIntfIn )
|
||||
{
|
||||
}
|
||||
|
||||
netReadNotifyIO::~netReadNotifyIO ()
|
||||
{
|
||||
}
|
||||
|
||||
void netReadNotifyIO::show ( unsigned /* level */ ) const
|
||||
{
|
||||
::printf ( "netReadNotifyIO at %p\n",
|
||||
static_cast < const void * > ( this ) );
|
||||
}
|
||||
|
||||
void netReadNotifyIO::show (
|
||||
epicsGuard < epicsMutex > &, unsigned level ) const
|
||||
{
|
||||
this->show ( level );
|
||||
}
|
||||
|
||||
void netReadNotifyIO::destroy (
|
||||
epicsGuard < epicsMutex > & guard, cacRecycle & recycle )
|
||||
{
|
||||
this->~netReadNotifyIO ();
|
||||
recycle.recycleReadNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
void netReadNotifyIO::completion (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle, unsigned type,
|
||||
arrayElementCount count, const void * pData )
|
||||
{
|
||||
//guard.assertIdenticalMutex ( this->mutex );
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->notify.completion ( guard, type, count, pData );
|
||||
this->~netReadNotifyIO ();
|
||||
recycle.recycleReadNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
void netReadNotifyIO::completion (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle )
|
||||
{
|
||||
//guard.assertIdenticalMutex ( this->mutex );
|
||||
//this->chan.getClient().printf ( "Read response w/o data ?\n" );
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->~netReadNotifyIO ();
|
||||
recycle.recycleReadNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
void netReadNotifyIO::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle,
|
||||
int status, const char *pContext )
|
||||
{
|
||||
//guard.assertIdenticalMutex ( this->mutex );
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->notify.exception (
|
||||
guard, status, pContext, UINT_MAX, 0u );
|
||||
this->~netReadNotifyIO ();
|
||||
recycle.recycleReadNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
void netReadNotifyIO::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle,
|
||||
int status, const char *pContext,
|
||||
unsigned type, arrayElementCount count )
|
||||
{
|
||||
//guard.assertIdenticalMutex ( this->mutex )
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->notify.exception (
|
||||
guard, status, pContext, type, count );
|
||||
this->~netReadNotifyIO ();
|
||||
recycle.recycleReadNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
class netSubscription * netReadNotifyIO::isSubscription ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void netReadNotifyIO::forceSubscriptionUpdate (
|
||||
epicsGuard < epicsMutex > &, nciu & )
|
||||
{
|
||||
}
|
||||
|
||||
void netReadNotifyIO::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
|
||||
189
src/client/netSubscription.cpp
Normal file
189
src/client/netSubscription.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "nciu.h"
|
||||
#include "cac.h"
|
||||
#include "db_access.h" // for dbf_type_to_text
|
||||
#include "caerr.h"
|
||||
|
||||
netSubscription::netSubscription (
|
||||
privateInterfaceForIO & chanIn,
|
||||
unsigned typeIn, arrayElementCount countIn,
|
||||
unsigned maskIn, cacStateNotify & notifyIn ) :
|
||||
count ( countIn ), privateChanForIO ( chanIn ),
|
||||
notify ( notifyIn ), type ( typeIn ), mask ( maskIn ),
|
||||
subscribed ( false )
|
||||
{
|
||||
if ( ! dbr_type_is_valid ( typeIn ) ) {
|
||||
throw cacChannel::badType ();
|
||||
}
|
||||
if ( this->mask == 0u ) {
|
||||
throw cacChannel::badEventSelection ();
|
||||
}
|
||||
}
|
||||
|
||||
netSubscription::~netSubscription ()
|
||||
{
|
||||
}
|
||||
|
||||
void netSubscription::destroy (
|
||||
epicsGuard < epicsMutex > & guard, cacRecycle & recycle )
|
||||
{
|
||||
this->~netSubscription ();
|
||||
recycle.recycleSubscription ( guard, *this );
|
||||
}
|
||||
|
||||
class netSubscription * netSubscription::isSubscription ()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void netSubscription::show ( unsigned /* level */ ) const
|
||||
{
|
||||
::printf ( "event subscription IO at %p, type %s, element count %lu, mask %u\n",
|
||||
static_cast < const void * > ( this ),
|
||||
dbf_type_to_text ( static_cast < int > ( this->type ) ),
|
||||
this->count, this->mask );
|
||||
}
|
||||
|
||||
void netSubscription::show (
|
||||
epicsGuard < epicsMutex > &, unsigned level ) const
|
||||
{
|
||||
this->show ( level );
|
||||
}
|
||||
|
||||
void netSubscription::completion (
|
||||
epicsGuard < epicsMutex > &, cacRecycle & )
|
||||
{
|
||||
errlogPrintf ( "subscription update w/o data ?\n" );
|
||||
}
|
||||
|
||||
void netSubscription::exception (
|
||||
epicsGuard < epicsMutex > & guard, cacRecycle & recycle,
|
||||
int status, const char * pContext )
|
||||
{
|
||||
if ( status == ECA_DISCONN ) {
|
||||
this->subscribed = false;
|
||||
}
|
||||
if ( status == ECA_CHANDESTROY ) {
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->notify.exception (
|
||||
guard, status, pContext, UINT_MAX, 0 );
|
||||
this->~netSubscription ();
|
||||
recycle.recycleSubscription ( guard, *this );
|
||||
}
|
||||
else {
|
||||
// guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->privateChanForIO.connected ( guard ) ) {
|
||||
this->notify.exception (
|
||||
guard, status, pContext, UINT_MAX, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void netSubscription::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle, int status, const char * pContext,
|
||||
unsigned typeIn, arrayElementCount countIn )
|
||||
{
|
||||
if ( status == ECA_DISCONN ) {
|
||||
this->subscribed = false;
|
||||
}
|
||||
if ( status == ECA_CHANDESTROY ) {
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->notify.exception (
|
||||
guard, status, pContext, UINT_MAX, 0 );
|
||||
this->~netSubscription ();
|
||||
recycle.recycleSubscription ( guard, *this );
|
||||
}
|
||||
else {
|
||||
//guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->privateChanForIO.connected ( guard ) ) {
|
||||
this->notify.exception (
|
||||
guard, status, pContext, typeIn, countIn );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void netSubscription::completion (
|
||||
epicsGuard < epicsMutex > & guard, cacRecycle &,
|
||||
unsigned typeIn, arrayElementCount countIn,
|
||||
const void * pDataIn )
|
||||
{
|
||||
// guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->privateChanForIO.connected ( guard ) ) {
|
||||
this->notify.current (
|
||||
guard, typeIn, countIn, pDataIn );
|
||||
}
|
||||
}
|
||||
|
||||
void netSubscription::subscribeIfRequired (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan )
|
||||
{
|
||||
if ( ! this->subscribed ) {
|
||||
chan.getPIIU(guard)->subscriptionRequest (
|
||||
guard, chan, *this );
|
||||
this->subscribed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void netSubscription::unsubscribeIfRequired (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan )
|
||||
{
|
||||
if ( this->subscribed ) {
|
||||
chan.getPIIU(guard)->subscriptionCancelRequest (
|
||||
guard, chan, *this );
|
||||
this->subscribed = false;
|
||||
}
|
||||
}
|
||||
|
||||
void netSubscription::forceSubscriptionUpdate (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan )
|
||||
{
|
||||
chan.getPIIU(guard)->subscriptionUpdateRequest (
|
||||
guard, chan, *this );
|
||||
}
|
||||
|
||||
void netSubscription::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
130
src/client/netWriteNotifyIO.cpp
Normal file
130
src/client/netWriteNotifyIO.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "iocinf.h"
|
||||
#include "nciu.h"
|
||||
#include "cac.h"
|
||||
|
||||
netWriteNotifyIO::netWriteNotifyIO (
|
||||
privateInterfaceForIO & ioComplIntf, cacWriteNotify & notifyIn ) :
|
||||
notify ( notifyIn ), privateChanForIO ( ioComplIntf )
|
||||
{
|
||||
}
|
||||
|
||||
netWriteNotifyIO::~netWriteNotifyIO ()
|
||||
{
|
||||
}
|
||||
|
||||
void netWriteNotifyIO::show ( unsigned /* level */ ) const
|
||||
{
|
||||
::printf ( "read write notify IO at %p\n",
|
||||
static_cast < const void * > ( this ) );
|
||||
}
|
||||
|
||||
void netWriteNotifyIO::show (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned level ) const
|
||||
{
|
||||
this->show ( level );
|
||||
}
|
||||
|
||||
void netWriteNotifyIO::destroy (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle )
|
||||
{
|
||||
this->~netWriteNotifyIO ();
|
||||
recycle.recycleWriteNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
void netWriteNotifyIO::completion (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle )
|
||||
{
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->notify.completion ( guard );
|
||||
this->~netWriteNotifyIO ();
|
||||
recycle.recycleWriteNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
void netWriteNotifyIO::completion (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle,
|
||||
unsigned /* type */, arrayElementCount /* count */,
|
||||
const void * /* pData */ )
|
||||
{
|
||||
//this->chan.getClient().printf ( "Write response with data ?\n" );
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->~netWriteNotifyIO ();
|
||||
recycle.recycleWriteNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
void netWriteNotifyIO::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle,
|
||||
int status, const char * pContext )
|
||||
{
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->notify.exception (
|
||||
guard, status, pContext, UINT_MAX, 0u );
|
||||
this->~netWriteNotifyIO ();
|
||||
recycle.recycleWriteNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
void netWriteNotifyIO::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
cacRecycle & recycle,
|
||||
int status, const char *pContext,
|
||||
unsigned type, arrayElementCount count )
|
||||
{
|
||||
this->privateChanForIO.ioCompletionNotify ( guard, *this );
|
||||
this->notify.exception (
|
||||
guard, status, pContext, type, count );
|
||||
this->~netWriteNotifyIO ();
|
||||
recycle.recycleWriteNotifyIO ( guard, *this );
|
||||
}
|
||||
|
||||
class netSubscription * netWriteNotifyIO::isSubscription ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void netWriteNotifyIO::forceSubscriptionUpdate (
|
||||
epicsGuard < epicsMutex > &, nciu & )
|
||||
{
|
||||
}
|
||||
|
||||
void netWriteNotifyIO::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
@@ -7,23 +7,30 @@
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* dbConvertFast.h */
|
||||
/*
|
||||
*
|
||||
* Author: J. Hill
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INCdbConvertFasth
|
||||
#define INCdbConvertFasth
|
||||
#ifndef _NET_CONVERT_H
|
||||
#define _NET_CONVERT_H
|
||||
|
||||
#include "dbFldTypes.h"
|
||||
#include "db_access.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareExtern long (*dbFastGetConvertRoutine[DBF_DEVICE+1][DBR_ENUM+1])();
|
||||
epicsShareExtern long (*dbFastPutConvertRoutine[DBR_ENUM+1][DBF_DEVICE+1])();
|
||||
typedef unsigned long arrayElementCount;
|
||||
|
||||
epicsShareFunc int caNetConvert (
|
||||
unsigned type, const void *pSrc, void *pDest,
|
||||
int hton, arrayElementCount count );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*INCdbConvertFasth*/
|
||||
#endif /* define _NET_CONVERT_H */
|
||||
174
src/client/netiiu.cpp
Normal file
174
src/client/netiiu.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string> // vxWorks 6.0 requires this include
|
||||
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "iocinf.h"
|
||||
#include "cac.h"
|
||||
#include "netiiu.h"
|
||||
|
||||
netiiu::~netiiu ()
|
||||
{
|
||||
}
|
||||
|
||||
bool netiiu::ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool netiiu::ca_v41_ok (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void netiiu::writeRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &,
|
||||
unsigned, arrayElementCount, const void * )
|
||||
{
|
||||
throw cacChannel::notConnected();
|
||||
}
|
||||
|
||||
void netiiu::writeNotifyRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu &, netWriteNotifyIO &, unsigned,
|
||||
arrayElementCount, const void * )
|
||||
{
|
||||
throw cacChannel::notConnected();
|
||||
}
|
||||
|
||||
void netiiu::readNotifyRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu &, netReadNotifyIO &, unsigned, arrayElementCount )
|
||||
{
|
||||
throw cacChannel::notConnected();
|
||||
}
|
||||
|
||||
void netiiu::clearChannelRequest (
|
||||
epicsGuard < epicsMutex > &, ca_uint32_t, ca_uint32_t )
|
||||
{
|
||||
}
|
||||
|
||||
void netiiu::subscriptionRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &, netSubscription & )
|
||||
{
|
||||
}
|
||||
|
||||
void netiiu::subscriptionCancelRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &, netSubscription & )
|
||||
{
|
||||
}
|
||||
|
||||
void netiiu::subscriptionUpdateRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &, netSubscription & )
|
||||
{
|
||||
}
|
||||
|
||||
static const char * const pHostNameNetIIU = "<disconnected>";
|
||||
|
||||
unsigned netiiu::getHostName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLen ) const throw ()
|
||||
{
|
||||
if ( bufLen ) {
|
||||
unsigned len = strlen ( pHostNameNetIIU );
|
||||
strncpy ( pBuf, pHostNameNetIIU, bufLen );
|
||||
if ( len < bufLen ) {
|
||||
return len;
|
||||
}
|
||||
else {
|
||||
unsigned reducedSize = bufLen - 1u;
|
||||
pBuf[reducedSize] = '\0';
|
||||
return reducedSize;
|
||||
}
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
|
||||
const char * netiiu::pHostName (
|
||||
epicsGuard < epicsMutex > & ) const throw ()
|
||||
{
|
||||
return pHostNameNetIIU;
|
||||
}
|
||||
|
||||
osiSockAddr netiiu::getNetworkAddress (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
osiSockAddr addr;
|
||||
addr.sa.sa_family = AF_UNSPEC;
|
||||
return addr;
|
||||
}
|
||||
|
||||
void netiiu::flushRequest (
|
||||
epicsGuard < epicsMutex > & )
|
||||
{
|
||||
}
|
||||
|
||||
unsigned netiiu::requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & )
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void netiiu::flush (
|
||||
epicsGuard < epicsMutex > & )
|
||||
{
|
||||
}
|
||||
|
||||
void netiiu::requestRecvProcessPostponedFlush (
|
||||
epicsGuard < epicsMutex > & )
|
||||
{
|
||||
}
|
||||
|
||||
void netiiu::uninstallChan (
|
||||
epicsGuard < epicsMutex > &, nciu & )
|
||||
{
|
||||
throw cacChannel::notConnected();
|
||||
}
|
||||
|
||||
double netiiu::receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return - DBL_MAX;
|
||||
}
|
||||
|
||||
void netiiu::uninstallChanDueToSuccessfulSearchResponse (
|
||||
epicsGuard < epicsMutex > &, nciu &, const epicsTime & )
|
||||
{
|
||||
throw std::runtime_error (
|
||||
"search response occured when not attached to udpiiu?" );
|
||||
}
|
||||
|
||||
bool netiiu::searchMsg (
|
||||
epicsGuard < epicsMutex > &, ca_uint32_t /* id */,
|
||||
const char * /* pName */, unsigned /* nameLength */ )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
97
src/client/netiiu.h
Normal file
97
src/client/netiiu.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef netiiuh
|
||||
#define netiiuh
|
||||
|
||||
#include "cacIO.h"
|
||||
#include "caProto.h"
|
||||
|
||||
class netWriteNotifyIO;
|
||||
class netReadNotifyIO;
|
||||
class netSubscription;
|
||||
union osiSockAddr;
|
||||
class cac;
|
||||
class nciu;
|
||||
|
||||
class netiiu {
|
||||
public:
|
||||
virtual ~netiiu () = 0;
|
||||
virtual unsigned getHostName (
|
||||
epicsGuard < epicsMutex > &, char * pBuf,
|
||||
unsigned bufLength ) const throw () = 0;
|
||||
virtual const char * pHostName (
|
||||
epicsGuard < epicsMutex > & ) const throw () = 0;
|
||||
virtual bool ca_v41_ok (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual bool ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual unsigned requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
virtual void flush (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
virtual void writeRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &,
|
||||
unsigned type, arrayElementCount nElem,
|
||||
const void *pValue ) = 0;
|
||||
virtual void writeNotifyRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu &, netWriteNotifyIO &,
|
||||
unsigned type, arrayElementCount nElem,
|
||||
const void *pValue ) = 0;
|
||||
virtual void readNotifyRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &,
|
||||
netReadNotifyIO &, unsigned type,
|
||||
arrayElementCount nElem ) = 0;
|
||||
virtual void clearChannelRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
ca_uint32_t sid, ca_uint32_t cid ) = 0;
|
||||
virtual void subscriptionRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu &, netSubscription & ) = 0;
|
||||
virtual void subscriptionUpdateRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu &, netSubscription & ) = 0;
|
||||
virtual void subscriptionCancelRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu & chan, netSubscription & subscr ) = 0;
|
||||
virtual void flushRequest (
|
||||
epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual void requestRecvProcessPostponedFlush (
|
||||
epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual osiSockAddr getNetworkAddress (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual void uninstallChan (
|
||||
epicsGuard < epicsMutex > &, nciu & ) = 0;
|
||||
virtual void uninstallChanDueToSuccessfulSearchResponse (
|
||||
epicsGuard < epicsMutex > &, nciu &,
|
||||
const class epicsTime & currentTime ) = 0;
|
||||
virtual double receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual bool searchMsg (
|
||||
epicsGuard < epicsMutex > &, ca_uint32_t id,
|
||||
const char * pName, unsigned nameLength ) = 0;
|
||||
};
|
||||
|
||||
#endif // netiiuh
|
||||
170
src/client/noopiiu.cpp
Normal file
170
src/client/noopiiu.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include "osiSock.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "noopiiu.h"
|
||||
|
||||
noopiiu noopIIU;
|
||||
|
||||
noopiiu::~noopiiu ()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned noopiiu::getHostName (
|
||||
epicsGuard < epicsMutex > & cacGuard,
|
||||
char * pBuf, unsigned bufLength ) const throw ()
|
||||
{
|
||||
return netiiu::getHostName ( cacGuard, pBuf, bufLength );
|
||||
}
|
||||
|
||||
const char * noopiiu::pHostName (
|
||||
epicsGuard < epicsMutex > & cacGuard ) const throw ()
|
||||
{
|
||||
return netiiu::pHostName ( cacGuard );
|
||||
}
|
||||
|
||||
bool noopiiu::ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & cacGuard ) const
|
||||
{
|
||||
return netiiu::ca_v42_ok ( cacGuard );
|
||||
}
|
||||
|
||||
bool noopiiu::ca_v41_ok (
|
||||
epicsGuard < epicsMutex > & cacGuard ) const
|
||||
{
|
||||
return netiiu::ca_v41_ok ( cacGuard );
|
||||
}
|
||||
|
||||
void noopiiu::writeRequest (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
nciu & chan, unsigned type,
|
||||
arrayElementCount nElem, const void * pValue )
|
||||
{
|
||||
netiiu::writeRequest ( guard, chan, type, nElem, pValue );
|
||||
}
|
||||
|
||||
void noopiiu::writeNotifyRequest (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan,
|
||||
netWriteNotifyIO & io, unsigned type,
|
||||
arrayElementCount nElem, const void *pValue )
|
||||
{
|
||||
netiiu::writeNotifyRequest ( guard, chan, io, type, nElem, pValue );
|
||||
}
|
||||
|
||||
void noopiiu::readNotifyRequest (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan,
|
||||
netReadNotifyIO & io, unsigned type, arrayElementCount nElem )
|
||||
{
|
||||
netiiu::readNotifyRequest ( guard, chan, io, type, nElem );
|
||||
}
|
||||
|
||||
void noopiiu::clearChannelRequest (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
ca_uint32_t sid, ca_uint32_t cid )
|
||||
{
|
||||
netiiu::clearChannelRequest ( guard, sid, cid );
|
||||
}
|
||||
|
||||
void noopiiu::subscriptionRequest (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan,
|
||||
netSubscription & subscr )
|
||||
{
|
||||
netiiu::subscriptionRequest ( guard, chan, subscr );
|
||||
}
|
||||
|
||||
void noopiiu::subscriptionUpdateRequest (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan,
|
||||
netSubscription & subscr )
|
||||
{
|
||||
netiiu::subscriptionUpdateRequest (
|
||||
guard, chan, subscr );
|
||||
}
|
||||
|
||||
void noopiiu::subscriptionCancelRequest (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
nciu & chan, netSubscription & subscr )
|
||||
{
|
||||
netiiu::subscriptionCancelRequest ( guard, chan, subscr );
|
||||
}
|
||||
|
||||
void noopiiu::flushRequest (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
netiiu::flushRequest ( guard );
|
||||
}
|
||||
|
||||
unsigned noopiiu::requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
return netiiu::requestMessageBytesPending ( guard );
|
||||
}
|
||||
|
||||
void noopiiu::flush (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
netiiu::flush ( guard );
|
||||
}
|
||||
|
||||
void noopiiu::requestRecvProcessPostponedFlush (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
netiiu::requestRecvProcessPostponedFlush ( guard );
|
||||
}
|
||||
|
||||
osiSockAddr noopiiu::getNetworkAddress (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
return netiiu::getNetworkAddress ( guard );
|
||||
}
|
||||
|
||||
double noopiiu::receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
return netiiu::receiveWatchdogDelay ( guard );
|
||||
}
|
||||
|
||||
void noopiiu::uninstallChan (
|
||||
epicsGuard < epicsMutex > &, nciu & )
|
||||
{
|
||||
// intentionally does not call default in netiiu
|
||||
}
|
||||
|
||||
void noopiiu::uninstallChanDueToSuccessfulSearchResponse (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan,
|
||||
const class epicsTime & currentTime )
|
||||
{
|
||||
netiiu::uninstallChanDueToSuccessfulSearchResponse (
|
||||
guard, chan, currentTime );
|
||||
}
|
||||
|
||||
bool noopiiu::searchMsg (
|
||||
epicsGuard < epicsMutex > & guard, ca_uint32_t id,
|
||||
const char * pName, unsigned nameLength )
|
||||
{
|
||||
return netiiu::searchMsg (
|
||||
guard, id, pName, nameLength );
|
||||
}
|
||||
|
||||
92
src/client/noopiiu.h
Normal file
92
src/client/noopiiu.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef noopiiuh
|
||||
#define noopiiuh
|
||||
|
||||
#include "netiiu.h"
|
||||
|
||||
class noopiiu : public netiiu {
|
||||
public:
|
||||
~noopiiu ();
|
||||
unsigned getHostName (
|
||||
epicsGuard < epicsMutex > &, char * pBuf,
|
||||
unsigned bufLength ) const throw ();
|
||||
const char * pHostName (
|
||||
epicsGuard < epicsMutex > & ) const throw ();
|
||||
bool ca_v41_ok (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
bool ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
unsigned requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
void flush (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
void writeRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &,
|
||||
unsigned type, arrayElementCount nElem,
|
||||
const void *pValue );
|
||||
void writeNotifyRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu &, netWriteNotifyIO &,
|
||||
unsigned type, arrayElementCount nElem,
|
||||
const void *pValue );
|
||||
void readNotifyRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &,
|
||||
netReadNotifyIO &, unsigned type,
|
||||
arrayElementCount nElem );
|
||||
void clearChannelRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
ca_uint32_t sid, ca_uint32_t cid );
|
||||
void subscriptionRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu &, netSubscription & );
|
||||
void subscriptionUpdateRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu &, netSubscription & );
|
||||
void subscriptionCancelRequest (
|
||||
epicsGuard < epicsMutex > &,
|
||||
nciu & chan, netSubscription & subscr );
|
||||
void flushRequest (
|
||||
epicsGuard < epicsMutex > & );
|
||||
void requestRecvProcessPostponedFlush (
|
||||
epicsGuard < epicsMutex > & );
|
||||
osiSockAddr getNetworkAddress (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
void uninstallChan (
|
||||
epicsGuard < epicsMutex > & mutex,
|
||||
nciu & );
|
||||
void uninstallChanDueToSuccessfulSearchResponse (
|
||||
epicsGuard < epicsMutex > &, nciu &,
|
||||
const class epicsTime & currentTime );
|
||||
double receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
bool searchMsg (
|
||||
epicsGuard < epicsMutex > &, ca_uint32_t id,
|
||||
const char * pName, unsigned nameLength );
|
||||
};
|
||||
|
||||
extern noopiiu noopIIU;
|
||||
|
||||
#endif // ifndef noopiiuh
|
||||
612
src/client/oldAccess.h
Normal file
612
src/client/oldAccess.h
Normal file
@@ -0,0 +1,612 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef oldAccessh
|
||||
#define oldAccessh
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define oldAccessh_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "tsFreeList.h"
|
||||
#include "compilerDependencies.h"
|
||||
#include "osiSock.h"
|
||||
|
||||
#ifdef oldAccessh_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
#include "caProto.h"
|
||||
#include "cacIO.h"
|
||||
#include "cadef.h"
|
||||
#include "syncGroup.h"
|
||||
|
||||
struct oldChannelNotify : private cacChannelNotify {
|
||||
public:
|
||||
oldChannelNotify (
|
||||
epicsGuard < epicsMutex > &, struct ca_client_context &,
|
||||
const char * pName, caCh * pConnCallBackIn,
|
||||
void * pPrivateIn, capri priority );
|
||||
void destructor (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & mutexGuard );
|
||||
|
||||
// legacy C API
|
||||
friend unsigned epicsShareAPI ca_get_host_name (
|
||||
chid pChan, char * pBuf, unsigned bufLength );
|
||||
friend const char * epicsShareAPI ca_host_name (
|
||||
chid pChan );
|
||||
friend const char * epicsShareAPI ca_name (
|
||||
chid pChan );
|
||||
friend void epicsShareAPI ca_set_puser (
|
||||
chid pChan, void * puser );
|
||||
friend void * epicsShareAPI ca_puser (
|
||||
chid pChan );
|
||||
friend int epicsShareAPI ca_change_connection_event (
|
||||
chid pChan, caCh * pfunc );
|
||||
friend int epicsShareAPI ca_replace_access_rights_event (
|
||||
chid pChan, caArh *pfunc );
|
||||
friend int epicsShareAPI ca_array_get ( chtype type,
|
||||
arrayElementCount count, chid pChan, void * pValue );
|
||||
friend int epicsShareAPI ca_array_get_callback ( chtype type,
|
||||
arrayElementCount count, chid pChan,
|
||||
caEventCallBackFunc *pfunc, void *arg );
|
||||
friend int epicsShareAPI ca_array_put (
|
||||
chtype type, arrayElementCount count,
|
||||
chid pChan, const void * pValue );
|
||||
friend int epicsShareAPI ca_array_put_callback (
|
||||
chtype type, arrayElementCount count,
|
||||
chid pChan, const void *pValue,
|
||||
caEventCallBackFunc *pfunc, void *usrarg );
|
||||
friend double epicsShareAPI ca_beacon_period (
|
||||
chid pChan );
|
||||
friend unsigned epicsShareAPI ca_search_attempts (
|
||||
chid pChan );
|
||||
friend unsigned epicsShareAPI ca_write_access (
|
||||
chid pChan );
|
||||
friend unsigned epicsShareAPI ca_read_access (
|
||||
chid pChan );
|
||||
friend short epicsShareAPI ca_field_type (
|
||||
chid pChan );
|
||||
friend arrayElementCount epicsShareAPI ca_element_count (
|
||||
chid pChan );
|
||||
friend int epicsShareAPI ca_v42_ok (
|
||||
chid pChan );
|
||||
friend int epicsShareAPI ca_create_subscription (
|
||||
chtype type, arrayElementCount count, chid pChan,
|
||||
long mask, caEventCallBackFunc * pCallBack,
|
||||
void * pCallBackArg, evid * monixptr );
|
||||
friend enum channel_state epicsShareAPI ca_state (
|
||||
chid pChan );
|
||||
friend double epicsShareAPI ca_receive_watchdog_delay (
|
||||
chid pChan );
|
||||
|
||||
unsigned getName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLen ) const throw ();
|
||||
void show (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned level ) const;
|
||||
void initiateConnect (
|
||||
epicsGuard < epicsMutex > & );
|
||||
void read (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
cacReadNotify ¬ify, cacChannel::ioid *pId = 0 );
|
||||
void write (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count, const void *pValue,
|
||||
cacWriteNotify &, cacChannel::ioid *pId = 0 );
|
||||
void ioCancel (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const cacChannel::ioid & );
|
||||
void ioShow (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid &, unsigned level ) const;
|
||||
ca_client_context & getClientCtx ();
|
||||
void eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > & );
|
||||
|
||||
void * operator new ( size_t size,
|
||||
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (( void * ,
|
||||
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & ))
|
||||
protected:
|
||||
~oldChannelNotify ();
|
||||
private:
|
||||
ca_client_context & cacCtx;
|
||||
cacChannel & io;
|
||||
caCh * pConnCallBack;
|
||||
void * pPrivate;
|
||||
caArh * pAccessRightsFunc;
|
||||
unsigned ioSeqNo;
|
||||
bool currentlyConnected;
|
||||
bool prevConnected;
|
||||
void connectNotify ( epicsGuard < epicsMutex > & );
|
||||
void disconnectNotify ( epicsGuard < epicsMutex > & );
|
||||
void serviceShutdownNotify (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
void accessRightsNotify (
|
||||
epicsGuard < epicsMutex > &, const caAccessRights & );
|
||||
void exception ( epicsGuard < epicsMutex > &,
|
||||
int status, const char * pContext );
|
||||
void readException ( epicsGuard < epicsMutex > &,
|
||||
int status, const char * pContext,
|
||||
unsigned type, arrayElementCount count, void *pValue );
|
||||
void writeException ( epicsGuard < epicsMutex > &,
|
||||
int status, const char * pContext,
|
||||
unsigned type, arrayElementCount count );
|
||||
oldChannelNotify ( const oldChannelNotify & );
|
||||
oldChannelNotify & operator = ( const oldChannelNotify & );
|
||||
void operator delete ( void * );
|
||||
};
|
||||
|
||||
class getCopy : public cacReadNotify {
|
||||
public:
|
||||
getCopy (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
ca_client_context & cacCtx,
|
||||
oldChannelNotify &, unsigned type,
|
||||
arrayElementCount count, void *pValue );
|
||||
~getCopy ();
|
||||
void show ( unsigned level ) const;
|
||||
void cancel ();
|
||||
void * operator new ( size_t size,
|
||||
tsFreeList < class getCopy, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (( void *,
|
||||
tsFreeList < class getCopy, 1024, epicsMutexNOOP > & ))
|
||||
private:
|
||||
arrayElementCount count;
|
||||
ca_client_context & cacCtx;
|
||||
oldChannelNotify & chan;
|
||||
void * pValue;
|
||||
unsigned ioSeqNo;
|
||||
unsigned type;
|
||||
void completion (
|
||||
epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, const void *pData );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, int status,
|
||||
const char *pContext, unsigned type, arrayElementCount count );
|
||||
getCopy ( const getCopy & );
|
||||
getCopy & operator = ( const getCopy & );
|
||||
void operator delete ( void * );
|
||||
};
|
||||
|
||||
class getCallback : public cacReadNotify {
|
||||
public:
|
||||
getCallback (
|
||||
oldChannelNotify & chanIn,
|
||||
caEventCallBackFunc *pFunc, void *pPrivate );
|
||||
~getCallback ();
|
||||
void * operator new ( size_t size,
|
||||
tsFreeList < class getCallback, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (( void *,
|
||||
tsFreeList < class getCallback, 1024, epicsMutexNOOP > & ))
|
||||
private:
|
||||
oldChannelNotify & chan;
|
||||
caEventCallBackFunc * pFunc;
|
||||
void * pPrivate;
|
||||
void completion (
|
||||
epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, const void *pData);
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, int status,
|
||||
const char * pContext, unsigned type, arrayElementCount count );
|
||||
getCallback ( const getCallback & );
|
||||
getCallback & operator = ( const getCallback & );
|
||||
void operator delete ( void * );
|
||||
};
|
||||
|
||||
class putCallback : public cacWriteNotify {
|
||||
public:
|
||||
putCallback (
|
||||
oldChannelNotify &,
|
||||
caEventCallBackFunc *pFunc, void *pPrivate );
|
||||
~putCallback ();
|
||||
void * operator new ( size_t size,
|
||||
tsFreeList < class putCallback, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (( void *,
|
||||
tsFreeList < class putCallback, 1024, epicsMutexNOOP > & ))
|
||||
private:
|
||||
oldChannelNotify & chan;
|
||||
caEventCallBackFunc * pFunc;
|
||||
void *pPrivate;
|
||||
void completion ( epicsGuard < epicsMutex > & );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, int status, const char *pContext,
|
||||
unsigned type, arrayElementCount count );
|
||||
putCallback ( const putCallback & );
|
||||
putCallback & operator = ( const putCallback & );
|
||||
void operator delete ( void * );
|
||||
};
|
||||
|
||||
struct oldSubscription : private cacStateNotify {
|
||||
public:
|
||||
oldSubscription (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
oldChannelNotify & chanIn, cacChannel & io,
|
||||
unsigned type, arrayElementCount nElem, unsigned mask,
|
||||
caEventCallBackFunc * pFuncIn, void * pPrivateIn,
|
||||
evid * );
|
||||
~oldSubscription ();
|
||||
oldChannelNotify & channel () const;
|
||||
// The primary mutex must be released when calling the user's
|
||||
// callback, and therefore a finite interval exists when we are
|
||||
// moving forward with the intent to call the users callback
|
||||
// but the users IO could be deleted during this interval.
|
||||
// To prevent the user's callback from being called after
|
||||
// destroying his IO we must past a guard for the callback
|
||||
// mutex here.
|
||||
void cancel (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard );
|
||||
void * operator new ( size_t size,
|
||||
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & );
|
||||
epicsPlacementDeleteOperator (( void *,
|
||||
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & ))
|
||||
private:
|
||||
oldChannelNotify & chan;
|
||||
cacChannel::ioid id;
|
||||
caEventCallBackFunc * pFunc;
|
||||
void * pPrivate;
|
||||
void current (
|
||||
epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, const void *pData );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, int status,
|
||||
const char *pContext, unsigned type, arrayElementCount count );
|
||||
oldSubscription ( const oldSubscription & );
|
||||
oldSubscription & operator = ( const oldSubscription & );
|
||||
void operator delete ( void * );
|
||||
};
|
||||
|
||||
extern "C" void cacOnceFunc ( void * );
|
||||
extern "C" void cacExitHandler ( void *);
|
||||
|
||||
struct ca_client_context : public cacContextNotify
|
||||
{
|
||||
public:
|
||||
ca_client_context ( bool enablePreemptiveCallback = false );
|
||||
virtual ~ca_client_context ();
|
||||
void changeExceptionEvent (
|
||||
caExceptionHandler * pfunc, void * arg );
|
||||
void registerForFileDescriptorCallBack (
|
||||
CAFDHANDLER * pFunc, void * pArg );
|
||||
void replaceErrLogHandler ( caPrintfFunc * ca_printf_func );
|
||||
cacChannel & createChannel (
|
||||
epicsGuard < epicsMutex > &, const char * pChannelName,
|
||||
cacChannelNotify &, cacChannel::priLev pri );
|
||||
void flush ( epicsGuard < epicsMutex > & );
|
||||
void eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > &, cacChannel & );
|
||||
int pendIO ( const double & timeout );
|
||||
int pendEvent ( const double & timeout );
|
||||
bool ioComplete () const;
|
||||
void show ( unsigned level ) const;
|
||||
unsigned circuitCount () const;
|
||||
unsigned sequenceNumberOfOutstandingIO (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
unsigned beaconAnomaliesSinceProgramStart () const;
|
||||
void incrementOutstandingIO (
|
||||
epicsGuard < epicsMutex > &, unsigned ioSeqNo );
|
||||
void decrementOutstandingIO (
|
||||
epicsGuard < epicsMutex > &, unsigned ioSeqNo );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo );
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > &, int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo, oldChannelNotify & chan,
|
||||
unsigned type, arrayElementCount count, unsigned op );
|
||||
void blockForEventAndEnableCallbacks (
|
||||
epicsEvent & event, const double & timeout );
|
||||
CASG * lookupCASG ( epicsGuard < epicsMutex > &, unsigned id );
|
||||
static void installDefaultService ( cacService & );
|
||||
void installCASG ( epicsGuard < epicsMutex > &, CASG & );
|
||||
void uninstallCASG ( epicsGuard < epicsMutex > &, CASG & );
|
||||
void selfTest () const;
|
||||
// perhaps these should be eliminated in deference to the exception mechanism
|
||||
int printFormated ( const char * pformat, ... ) const;
|
||||
int varArgsPrintFormated ( const char * pformat, va_list args ) const;
|
||||
void signal ( int ca_status, const char * pfilenm,
|
||||
int lineno, const char * pFormat, ... );
|
||||
void vSignal ( int ca_status, const char * pfilenm,
|
||||
int lineno, const char *pFormat, va_list args );
|
||||
bool preemptiveCallbakIsEnabled () const;
|
||||
void destroyGetCopy ( epicsGuard < epicsMutex > &, getCopy & );
|
||||
void destroyGetCallback ( epicsGuard < epicsMutex > &, getCallback & );
|
||||
void destroyPutCallback ( epicsGuard < epicsMutex > &, putCallback & );
|
||||
void destroySubscription ( epicsGuard < epicsMutex > &, oldSubscription & );
|
||||
epicsMutex & mutexRef () const;
|
||||
|
||||
template < class T >
|
||||
void whenThereIsAnExceptionDestroySyncGroupIO ( epicsGuard < epicsMutex > &, T & );
|
||||
|
||||
// legacy C API
|
||||
friend int epicsShareAPI ca_create_channel (
|
||||
const char * name_str, caCh * conn_func, void * puser,
|
||||
capri priority, chid * chanptr );
|
||||
friend int epicsShareAPI ca_clear_channel ( chid pChan );
|
||||
friend int epicsShareAPI ca_array_get ( chtype type,
|
||||
arrayElementCount count, chid pChan, void * pValue );
|
||||
friend int epicsShareAPI ca_array_get_callback ( chtype type,
|
||||
arrayElementCount count, chid pChan,
|
||||
caEventCallBackFunc *pfunc, void *arg );
|
||||
friend int epicsShareAPI ca_array_put ( chtype type,
|
||||
arrayElementCount count, chid pChan, const void * pValue );
|
||||
friend int epicsShareAPI ca_array_put_callback ( chtype type,
|
||||
arrayElementCount count, chid pChan, const void * pValue,
|
||||
caEventCallBackFunc *pfunc, void *usrarg );
|
||||
friend int epicsShareAPI ca_create_subscription (
|
||||
chtype type, arrayElementCount count, chid pChan,
|
||||
long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg,
|
||||
evid *monixptr );
|
||||
friend int epicsShareAPI ca_flush_io ();
|
||||
friend int epicsShareAPI ca_clear_subscription ( evid pMon );
|
||||
friend int epicsShareAPI ca_sg_create ( CA_SYNC_GID * pgid );
|
||||
friend int epicsShareAPI ca_sg_delete ( const CA_SYNC_GID gid );
|
||||
friend int epicsShareAPI ca_sg_block ( const CA_SYNC_GID gid, ca_real timeout );
|
||||
friend int epicsShareAPI ca_sg_reset ( const CA_SYNC_GID gid );
|
||||
friend int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid );
|
||||
friend int epicsShareAPI ca_sg_array_get ( const CA_SYNC_GID gid,
|
||||
chtype type, arrayElementCount count,
|
||||
chid pChan, void *pValue );
|
||||
friend int epicsShareAPI ca_sg_array_put ( const CA_SYNC_GID gid,
|
||||
chtype type, arrayElementCount count,
|
||||
chid pChan, const void *pValue );
|
||||
friend int ca_sync_group_destroy ( CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
ca_client_context & cac, const CA_SYNC_GID gid );
|
||||
friend void sync_group_reset ( ca_client_context & client,
|
||||
CASG & sg );
|
||||
|
||||
// exceptions
|
||||
class noSocket {};
|
||||
private:
|
||||
chronIntIdResTable < CASG > sgTable;
|
||||
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > oldChannelNotifyFreeList;
|
||||
tsFreeList < class getCopy, 1024, epicsMutexNOOP > getCopyFreeList;
|
||||
tsFreeList < class getCallback, 1024, epicsMutexNOOP > getCallbackFreeList;
|
||||
tsFreeList < class putCallback, 1024, epicsMutexNOOP > putCallbackFreeList;
|
||||
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > subscriptionFreeList;
|
||||
tsFreeList < struct CASG, 128, epicsMutexNOOP > casgFreeList;
|
||||
mutable epicsMutex mutex;
|
||||
mutable epicsMutex cbMutex;
|
||||
epicsEvent ioDone;
|
||||
epicsEvent callbackThreadActivityComplete;
|
||||
epicsThreadId createdByThread;
|
||||
std::auto_ptr < CallbackGuard > pCallbackGuard;
|
||||
std::auto_ptr < cacContext > pServiceContext;
|
||||
caExceptionHandler * ca_exception_func;
|
||||
void * ca_exception_arg;
|
||||
caPrintfFunc * pVPrintfFunc;
|
||||
CAFDHANDLER * fdRegFunc;
|
||||
void * fdRegArg;
|
||||
SOCKET sock;
|
||||
unsigned pndRecvCnt;
|
||||
unsigned ioSeqNo;
|
||||
unsigned callbackThreadsPending;
|
||||
ca_uint16_t localPort;
|
||||
bool fdRegFuncNeedsToBeCalled;
|
||||
bool noWakeupSincePend;
|
||||
|
||||
void attachToClientCtx ();
|
||||
void callbackProcessingInitiateNotify ();
|
||||
void callbackProcessingCompleteNotify ();
|
||||
cacContext & createNetworkContext (
|
||||
epicsMutex & mutualExclusion, epicsMutex & callbackControl );
|
||||
void _sendWakeupMsg ();
|
||||
|
||||
ca_client_context ( const ca_client_context & );
|
||||
ca_client_context & operator = ( const ca_client_context & );
|
||||
|
||||
friend void cacOnceFunc ( void * );
|
||||
friend void cacExitHandler ( void *);
|
||||
static cacService * pDefaultService;
|
||||
static epicsMutex * pDefaultServiceInstallMutex;
|
||||
static const unsigned flushBlockThreshold;
|
||||
};
|
||||
|
||||
int fetchClientContext ( ca_client_context * * ppcac );
|
||||
|
||||
inline ca_client_context & oldChannelNotify::getClientCtx ()
|
||||
{
|
||||
return this->cacCtx;
|
||||
}
|
||||
|
||||
inline unsigned oldChannelNotify::getName (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
char * pBuf, unsigned bufLen ) const throw ()
|
||||
{
|
||||
return this->io.getName ( guard, pBuf, bufLen );
|
||||
}
|
||||
|
||||
inline void oldChannelNotify::show (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
unsigned level ) const
|
||||
{
|
||||
this->io.show ( guard, level );
|
||||
}
|
||||
|
||||
inline void oldChannelNotify::initiateConnect (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->io.initiateConnect ( guard );
|
||||
}
|
||||
|
||||
inline void oldChannelNotify::ioCancel (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const cacChannel::ioid & id )
|
||||
{
|
||||
this->io.ioCancel ( callbackGuard, mutualExclusionGuard, id );
|
||||
}
|
||||
|
||||
inline void oldChannelNotify::ioShow (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid & id, unsigned level ) const
|
||||
{
|
||||
this->io.ioShow ( guard, id, level );
|
||||
}
|
||||
|
||||
inline void oldChannelNotify::eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->cacCtx.eliminateExcessiveSendBacklog ( guard, this->io );
|
||||
}
|
||||
|
||||
inline void * oldChannelNotify::operator new ( size_t size,
|
||||
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void oldChannelNotify::operator delete ( void *pCadaver,
|
||||
tsFreeList < struct oldChannelNotify, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void * oldSubscription::operator new ( size_t size,
|
||||
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void oldSubscription::operator delete ( void *pCadaver,
|
||||
tsFreeList < struct oldSubscription, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void oldSubscription::cancel (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard )
|
||||
{
|
||||
this->chan.ioCancel ( callbackGuard, mutualExclusionGuard, this->id );
|
||||
}
|
||||
|
||||
inline oldChannelNotify & oldSubscription::channel () const
|
||||
{
|
||||
return this->chan;
|
||||
}
|
||||
|
||||
inline void * getCopy::operator new ( size_t size,
|
||||
tsFreeList < class getCopy, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void getCopy::operator delete ( void *pCadaver,
|
||||
tsFreeList < class getCopy, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void * putCallback::operator new ( size_t size,
|
||||
tsFreeList < class putCallback, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void putCallback::operator delete ( void * pCadaver,
|
||||
tsFreeList < class putCallback, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void * getCallback::operator new ( size_t size,
|
||||
tsFreeList < class getCallback, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void getCallback::operator delete ( void * pCadaver,
|
||||
tsFreeList < class getCallback, 1024, epicsMutexNOOP > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool ca_client_context::preemptiveCallbakIsEnabled () const
|
||||
{
|
||||
return this->pCallbackGuard.get () == 0;
|
||||
}
|
||||
|
||||
inline bool ca_client_context::ioComplete () const
|
||||
{
|
||||
return ( this->pndRecvCnt == 0u );
|
||||
}
|
||||
|
||||
inline unsigned ca_client_context::sequenceNumberOfOutstandingIO (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
// perhaps on SMP systems THERE should be lock/unlock around this
|
||||
return this->ioSeqNo;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
void ca_client_context :: whenThereIsAnExceptionDestroySyncGroupIO (
|
||||
epicsGuard < epicsMutex > & guard, T & io )
|
||||
{
|
||||
if ( this->pCallbackGuard.get() &&
|
||||
this->createdByThread == epicsThreadGetIdSelf () ) {
|
||||
io.destroy ( *this->pCallbackGuard.get(), guard );
|
||||
}
|
||||
else {
|
||||
// dont reverse the lock hierarchy
|
||||
epicsGuardRelease < epicsMutex > guardRelease ( guard );
|
||||
{
|
||||
//
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( this->cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
io.destroy ( cbGuard, guard );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ifndef oldAccessh
|
||||
709
src/client/oldChannelNotify.cpp
Normal file
709
src/client/oldChannelNotify.cpp
Normal file
@@ -0,0 +1,709 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable:4355)
|
||||
#endif
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "oldAccess.h"
|
||||
#include "cac.h"
|
||||
#include "autoPtrFreeList.h"
|
||||
|
||||
extern "C" void cacNoopAccesRightsHandler ( struct access_rights_handler_args )
|
||||
{
|
||||
}
|
||||
|
||||
oldChannelNotify::oldChannelNotify (
|
||||
epicsGuard < epicsMutex > & guard, ca_client_context & cacIn,
|
||||
const char *pName, caCh * pConnCallBackIn,
|
||||
void * pPrivateIn, capri priority ) :
|
||||
cacCtx ( cacIn ),
|
||||
io ( cacIn.createChannel ( guard, pName, *this, priority ) ),
|
||||
pConnCallBack ( pConnCallBackIn ),
|
||||
pPrivate ( pPrivateIn ), pAccessRightsFunc ( cacNoopAccesRightsHandler ),
|
||||
ioSeqNo ( 0 ), currentlyConnected ( false ), prevConnected ( false )
|
||||
{
|
||||
guard.assertIdenticalMutex ( cacIn.mutexRef () );
|
||||
this->ioSeqNo = cacIn.sequenceNumberOfOutstandingIO ( guard );
|
||||
if ( pConnCallBackIn == 0 ) {
|
||||
cacIn.incrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
}
|
||||
}
|
||||
|
||||
oldChannelNotify::~oldChannelNotify ()
|
||||
{
|
||||
}
|
||||
|
||||
void oldChannelNotify::destructor (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & mutexGuard )
|
||||
{
|
||||
mutexGuard.assertIdenticalMutex ( this->cacCtx.mutexRef () );
|
||||
this->io.destroy ( cbGuard, mutexGuard );
|
||||
// no need to worry about a connect preempting here because
|
||||
// the io (the nciu) has been destroyed above
|
||||
if ( this->pConnCallBack == 0 && ! this->currentlyConnected ) {
|
||||
this->cacCtx.decrementOutstandingIO ( mutexGuard, this->ioSeqNo );
|
||||
}
|
||||
this->~oldChannelNotify ();
|
||||
}
|
||||
|
||||
void oldChannelNotify::connectNotify (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->currentlyConnected = true;
|
||||
this->prevConnected = true;
|
||||
if ( this->pConnCallBack ) {
|
||||
struct connection_handler_args args;
|
||||
args.chid = this;
|
||||
args.op = CA_OP_CONN_UP;
|
||||
caCh * pFunc = this->pConnCallBack;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFunc ) ( args );
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
}
|
||||
}
|
||||
|
||||
void oldChannelNotify::disconnectNotify (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->currentlyConnected = false;
|
||||
if ( this->pConnCallBack ) {
|
||||
struct connection_handler_args args;
|
||||
args.chid = this;
|
||||
args.op = CA_OP_CONN_DOWN;
|
||||
caCh * pFunc = this->pConnCallBack;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFunc ) ( args );
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->cacCtx.incrementOutstandingIO (
|
||||
guard, this->ioSeqNo );
|
||||
}
|
||||
}
|
||||
|
||||
void oldChannelNotify::serviceShutdownNotify (
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->disconnectNotify ( guard );
|
||||
}
|
||||
|
||||
void oldChannelNotify::accessRightsNotify (
|
||||
epicsGuard < epicsMutex > & guard, const caAccessRights & ar )
|
||||
{
|
||||
struct access_rights_handler_args args;
|
||||
args.chid = this;
|
||||
args.ar.read_access = ar.readPermit();
|
||||
args.ar.write_access = ar.writePermit();
|
||||
caArh * pFunc = this->pAccessRightsFunc;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFunc ) ( args );
|
||||
}
|
||||
}
|
||||
|
||||
void oldChannelNotify::exception (
|
||||
epicsGuard < epicsMutex > & guard, int status, const char * pContext )
|
||||
{
|
||||
this->cacCtx.exception ( guard, status, pContext, __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
void oldChannelNotify::readException (
|
||||
epicsGuard < epicsMutex > & guard, int status, const char *pContext,
|
||||
unsigned type, arrayElementCount count, void * /* pValue */ )
|
||||
{
|
||||
this->cacCtx.exception ( guard, status, pContext,
|
||||
__FILE__, __LINE__, *this, type, count, CA_OP_GET );
|
||||
}
|
||||
|
||||
void oldChannelNotify::writeException (
|
||||
epicsGuard < epicsMutex > & guard, int status, const char *pContext,
|
||||
unsigned type, arrayElementCount count )
|
||||
{
|
||||
this->cacCtx.exception ( guard, status, pContext,
|
||||
__FILE__, __LINE__, *this, type, count, CA_OP_PUT );
|
||||
}
|
||||
|
||||
void oldChannelNotify::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_get_host_name ()
|
||||
*/
|
||||
unsigned epicsShareAPI ca_get_host_name (
|
||||
chid pChan, char * pBuf, unsigned bufLength )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef() );
|
||||
return pChan->io.getHostName ( guard, pBuf, bufLength );
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_host_name ()
|
||||
*
|
||||
* !!!! not thread safe !!!!
|
||||
*
|
||||
*/
|
||||
const char * epicsShareAPI ca_host_name (
|
||||
chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.pHostName ( guard );
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_set_puser ()
|
||||
*/
|
||||
void epicsShareAPI ca_set_puser (
|
||||
chid pChan, void * puser )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
pChan->pPrivate = puser;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_get_puser ()
|
||||
*/
|
||||
void * epicsShareAPI ca_puser (
|
||||
chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->pPrivate;
|
||||
}
|
||||
|
||||
/*
|
||||
* Specify an event subroutine to be run for connection events
|
||||
*/
|
||||
int epicsShareAPI ca_change_connection_event ( chid pChan, caCh * pfunc )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
if ( ! pChan->currentlyConnected ) {
|
||||
if ( pfunc ) {
|
||||
if ( ! pChan->pConnCallBack ) {
|
||||
pChan->cacCtx.decrementOutstandingIO ( guard, pChan->ioSeqNo );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( pChan->pConnCallBack ) {
|
||||
pChan->cacCtx.incrementOutstandingIO ( guard, pChan->ioSeqNo );
|
||||
}
|
||||
}
|
||||
}
|
||||
pChan->pConnCallBack = pfunc;
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_replace_access_rights_event
|
||||
*/
|
||||
int epicsShareAPI ca_replace_access_rights_event (
|
||||
chid pChan, caArh *pfunc )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
|
||||
// The order of the following is significant to guarantee that the
|
||||
// access rights handler is always gets called even if the channel connects
|
||||
// while this is running. There is some very small chance that the
|
||||
// handler could be called twice here with the same access rights state, but
|
||||
// that will not upset the application.
|
||||
pChan->pAccessRightsFunc = pfunc ? pfunc : cacNoopAccesRightsHandler;
|
||||
caAccessRights tmp = pChan->io.accessRights ( guard );
|
||||
|
||||
if ( pChan->currentlyConnected ) {
|
||||
struct access_rights_handler_args args;
|
||||
args.chid = pChan;
|
||||
args.ar.read_access = tmp.readPermit ();
|
||||
args.ar.write_access = tmp.writePermit ();
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pChan->pAccessRightsFunc ) ( args );
|
||||
}
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_array_get ()
|
||||
*/
|
||||
int epicsShareAPI ca_array_get ( chtype type,
|
||||
arrayElementCount count, chid pChan, void *pValue )
|
||||
{
|
||||
int caStatus;
|
||||
try {
|
||||
if ( type < 0 ) {
|
||||
return ECA_BADTYPE;
|
||||
}
|
||||
if ( count == 0 )
|
||||
return ECA_BADCOUNT;
|
||||
|
||||
unsigned tmpType = static_cast < unsigned > ( type );
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
autoPtrFreeList < getCopy, 0x400, epicsMutexNOOP > pNotify
|
||||
( pChan->getClientCtx().getCopyFreeList,
|
||||
new ( pChan->getClientCtx().getCopyFreeList )
|
||||
getCopy ( guard, pChan->getClientCtx(), *pChan,
|
||||
tmpType, count, pValue ) );
|
||||
pChan->io.read ( guard, type, count, *pNotify, 0 );
|
||||
pNotify.release ();
|
||||
caStatus = ECA_NORMAL;
|
||||
}
|
||||
catch ( cacChannel::badString & )
|
||||
{
|
||||
caStatus = ECA_BADSTR;
|
||||
}
|
||||
catch ( cacChannel::badType & )
|
||||
{
|
||||
caStatus = ECA_BADTYPE;
|
||||
}
|
||||
catch ( cacChannel::outOfBounds & )
|
||||
{
|
||||
caStatus = ECA_BADCOUNT;
|
||||
}
|
||||
catch ( cacChannel::noReadAccess & )
|
||||
{
|
||||
caStatus = ECA_NORDACCESS;
|
||||
}
|
||||
catch ( cacChannel::notConnected & )
|
||||
{
|
||||
caStatus = ECA_DISCONN;
|
||||
}
|
||||
catch ( cacChannel::unsupportedByService & )
|
||||
{
|
||||
caStatus = ECA_UNAVAILINSERV;
|
||||
}
|
||||
catch ( cacChannel::requestTimedOut & )
|
||||
{
|
||||
caStatus = ECA_TIMEOUT;
|
||||
}
|
||||
catch ( std::bad_alloc & )
|
||||
{
|
||||
caStatus = ECA_ALLOCMEM;
|
||||
}
|
||||
catch ( cacChannel::msgBodyCacheTooSmall & ) {
|
||||
caStatus = ECA_TOLARGE;
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
caStatus = ECA_GETFAIL;
|
||||
}
|
||||
return caStatus;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_array_get_callback ()
|
||||
*/
|
||||
int epicsShareAPI ca_array_get_callback ( chtype type,
|
||||
arrayElementCount count, chid pChan,
|
||||
caEventCallBackFunc *pfunc, void *arg )
|
||||
{
|
||||
int caStatus;
|
||||
try {
|
||||
if ( type < 0 ) {
|
||||
return ECA_BADTYPE;
|
||||
}
|
||||
if ( pfunc == NULL ) {
|
||||
return ECA_BADFUNCPTR;
|
||||
}
|
||||
unsigned tmpType = static_cast < unsigned > ( type );
|
||||
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
autoPtrFreeList < getCallback, 0x400, epicsMutexNOOP > pNotify
|
||||
( pChan->getClientCtx().getCallbackFreeList,
|
||||
new ( pChan->getClientCtx().getCallbackFreeList )
|
||||
getCallback ( *pChan, pfunc, arg ) );
|
||||
pChan->io.read ( guard, tmpType, count, *pNotify, 0 );
|
||||
pNotify.release ();
|
||||
caStatus = ECA_NORMAL;
|
||||
}
|
||||
catch ( cacChannel::badString & )
|
||||
{
|
||||
caStatus = ECA_BADSTR;
|
||||
}
|
||||
catch ( cacChannel::badType & )
|
||||
{
|
||||
caStatus = ECA_BADTYPE;
|
||||
}
|
||||
catch ( cacChannel::outOfBounds & )
|
||||
{
|
||||
caStatus = ECA_BADCOUNT;
|
||||
}
|
||||
catch ( cacChannel::noReadAccess & )
|
||||
{
|
||||
caStatus = ECA_NORDACCESS;
|
||||
}
|
||||
catch ( cacChannel::notConnected & )
|
||||
{
|
||||
caStatus = ECA_DISCONN;
|
||||
}
|
||||
catch ( cacChannel::unsupportedByService & )
|
||||
{
|
||||
caStatus = ECA_UNAVAILINSERV;
|
||||
}
|
||||
catch ( cacChannel::requestTimedOut & )
|
||||
{
|
||||
caStatus = ECA_TIMEOUT;
|
||||
}
|
||||
catch ( std::bad_alloc & )
|
||||
{
|
||||
caStatus = ECA_ALLOCMEM;
|
||||
}
|
||||
catch ( cacChannel::msgBodyCacheTooSmall ) {
|
||||
caStatus = ECA_TOLARGE;
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
caStatus = ECA_GETFAIL;
|
||||
}
|
||||
return caStatus;
|
||||
}
|
||||
|
||||
void oldChannelNotify::read (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
unsigned type, arrayElementCount count,
|
||||
cacReadNotify & notify, cacChannel::ioid * pId )
|
||||
{
|
||||
this->io.read ( guard, type, count, notify, pId );
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_array_put_callback ()
|
||||
*/
|
||||
int epicsShareAPI ca_array_put_callback ( chtype type, arrayElementCount count,
|
||||
chid pChan, const void *pValue, caEventCallBackFunc *pfunc, void *usrarg )
|
||||
{
|
||||
int caStatus;
|
||||
try {
|
||||
if ( type < 0 ) {
|
||||
return ECA_BADTYPE;
|
||||
}
|
||||
if ( pfunc == NULL ) {
|
||||
return ECA_BADFUNCPTR;
|
||||
}
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
unsigned tmpType = static_cast < unsigned > ( type );
|
||||
autoPtrFreeList < putCallback, 0x400, epicsMutexNOOP > pNotify
|
||||
( pChan->getClientCtx().putCallbackFreeList,
|
||||
new ( pChan->getClientCtx().putCallbackFreeList )
|
||||
putCallback ( *pChan, pfunc, usrarg ) );
|
||||
pChan->io.write ( guard, tmpType, count, pValue, *pNotify, 0 );
|
||||
pNotify.release ();
|
||||
caStatus = ECA_NORMAL;
|
||||
}
|
||||
catch ( cacChannel::badString & )
|
||||
{
|
||||
caStatus = ECA_BADSTR;
|
||||
}
|
||||
catch ( cacChannel::badType & )
|
||||
{
|
||||
caStatus = ECA_BADTYPE;
|
||||
}
|
||||
catch ( cacChannel::outOfBounds & )
|
||||
{
|
||||
caStatus = ECA_BADCOUNT;
|
||||
}
|
||||
catch ( cacChannel::noWriteAccess & )
|
||||
{
|
||||
caStatus = ECA_NOWTACCESS;
|
||||
}
|
||||
catch ( cacChannel::notConnected & )
|
||||
{
|
||||
caStatus = ECA_DISCONN;
|
||||
}
|
||||
catch ( cacChannel::unsupportedByService & )
|
||||
{
|
||||
caStatus = ECA_UNAVAILINSERV;
|
||||
}
|
||||
catch ( cacChannel::requestTimedOut & )
|
||||
{
|
||||
caStatus = ECA_TIMEOUT;
|
||||
}
|
||||
catch ( std::bad_alloc & )
|
||||
{
|
||||
caStatus = ECA_ALLOCMEM;
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
caStatus = ECA_PUTFAIL;
|
||||
}
|
||||
return caStatus;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_array_put ()
|
||||
*/
|
||||
int epicsShareAPI ca_array_put ( chtype type, arrayElementCount count,
|
||||
chid pChan, const void * pValue )
|
||||
{
|
||||
if ( type < 0 ) {
|
||||
return ECA_BADTYPE;
|
||||
}
|
||||
unsigned tmpType = static_cast < unsigned > ( type );
|
||||
|
||||
int caStatus;
|
||||
try {
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
pChan->io.write ( guard, tmpType, count, pValue );
|
||||
caStatus = ECA_NORMAL;
|
||||
}
|
||||
catch ( cacChannel::badString & )
|
||||
{
|
||||
caStatus = ECA_BADSTR;
|
||||
}
|
||||
catch ( cacChannel::badType & )
|
||||
{
|
||||
caStatus = ECA_BADTYPE;
|
||||
}
|
||||
catch ( cacChannel::outOfBounds & )
|
||||
{
|
||||
caStatus = ECA_BADCOUNT;
|
||||
}
|
||||
catch ( cacChannel::noWriteAccess & )
|
||||
{
|
||||
caStatus = ECA_NOWTACCESS;
|
||||
}
|
||||
catch ( cacChannel::notConnected & )
|
||||
{
|
||||
caStatus = ECA_DISCONN;
|
||||
}
|
||||
catch ( cacChannel::unsupportedByService & )
|
||||
{
|
||||
caStatus = ECA_UNAVAILINSERV;
|
||||
}
|
||||
catch ( cacChannel::requestTimedOut & )
|
||||
{
|
||||
caStatus = ECA_TIMEOUT;
|
||||
}
|
||||
catch ( std::bad_alloc & )
|
||||
{
|
||||
caStatus = ECA_ALLOCMEM;
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
caStatus = ECA_PUTFAIL;
|
||||
}
|
||||
return caStatus;
|
||||
}
|
||||
|
||||
int epicsShareAPI ca_create_subscription (
|
||||
chtype type, arrayElementCount count, chid pChan,
|
||||
long mask, caEventCallBackFunc * pCallBack, void * pCallBackArg,
|
||||
evid * monixptr )
|
||||
{
|
||||
if ( type < 0 ) {
|
||||
return ECA_BADTYPE;
|
||||
}
|
||||
unsigned tmpType = static_cast < unsigned > ( type );
|
||||
|
||||
if ( INVALID_DB_REQ (type) ) {
|
||||
return ECA_BADTYPE;
|
||||
}
|
||||
|
||||
if ( pCallBack == NULL ) {
|
||||
return ECA_BADFUNCPTR;
|
||||
}
|
||||
|
||||
static const long maskMask = 0xffff;
|
||||
if ( ( mask & maskMask ) == 0) {
|
||||
return ECA_BADMASK;
|
||||
}
|
||||
|
||||
if ( mask & ~maskMask ) {
|
||||
return ECA_BADMASK;
|
||||
}
|
||||
|
||||
try {
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
try {
|
||||
// if this stalls out on a live circuit then an exception
|
||||
// can be forthcoming which we must ignore (this is a
|
||||
// special case preserving legacy ca_create_subscription
|
||||
// behavior)
|
||||
pChan->eliminateExcessiveSendBacklog ( guard );
|
||||
}
|
||||
catch ( cacChannel::notConnected & ) {
|
||||
// intentionally ignored (its ok to subscribe when not connected)
|
||||
}
|
||||
new ( pChan->getClientCtx().subscriptionFreeList )
|
||||
oldSubscription (
|
||||
guard, *pChan, pChan->io, tmpType, count, mask,
|
||||
pCallBack, pCallBackArg, monixptr );
|
||||
// dont touch object created after above new because
|
||||
// the first callback might have canceled, and therefore
|
||||
// destroyed, it
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
catch ( cacChannel::badType & )
|
||||
{
|
||||
return ECA_BADTYPE;
|
||||
}
|
||||
catch ( cacChannel::outOfBounds & )
|
||||
{
|
||||
return ECA_BADCOUNT;
|
||||
}
|
||||
catch ( cacChannel::badEventSelection & )
|
||||
{
|
||||
return ECA_BADMASK;
|
||||
}
|
||||
catch ( cacChannel::noReadAccess & )
|
||||
{
|
||||
return ECA_NORDACCESS;
|
||||
}
|
||||
catch ( cacChannel::unsupportedByService & )
|
||||
{
|
||||
return ECA_UNAVAILINSERV;
|
||||
}
|
||||
catch ( std::bad_alloc & )
|
||||
{
|
||||
return ECA_ALLOCMEM;
|
||||
}
|
||||
catch ( cacChannel::msgBodyCacheTooSmall & ) {
|
||||
return ECA_TOLARGE;
|
||||
}
|
||||
catch ( ... )
|
||||
{
|
||||
return ECA_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
void oldChannelNotify::write (
|
||||
epicsGuard < epicsMutex > & guard, unsigned type, arrayElementCount count,
|
||||
const void * pValue, cacWriteNotify & notify, cacChannel::ioid * pId )
|
||||
{
|
||||
this->io.write ( guard, type, count, pValue, notify, pId );
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_field_type()
|
||||
*/
|
||||
short epicsShareAPI ca_field_type ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.nativeType ( guard );
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_element_count ()
|
||||
*/
|
||||
arrayElementCount epicsShareAPI ca_element_count ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.nativeElementCount ( guard );
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_state ()
|
||||
*/
|
||||
enum channel_state epicsShareAPI ca_state ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
if ( pChan->io.connected ( guard ) ) {
|
||||
return cs_conn;
|
||||
}
|
||||
else if ( pChan->prevConnected ){
|
||||
return cs_prev_conn;
|
||||
}
|
||||
else {
|
||||
return cs_never_conn;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_read_access ()
|
||||
*/
|
||||
unsigned epicsShareAPI ca_read_access ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.accessRights(guard).readPermit();
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_write_access ()
|
||||
*/
|
||||
unsigned epicsShareAPI ca_write_access ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.accessRights(guard).writePermit();
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_name ()
|
||||
*/
|
||||
const char * epicsShareAPI ca_name ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.pName ( guard );
|
||||
}
|
||||
|
||||
unsigned epicsShareAPI ca_search_attempts ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.searchAttempts ( guard );
|
||||
}
|
||||
|
||||
double epicsShareAPI ca_beacon_period ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.beaconPeriod ( guard );
|
||||
}
|
||||
|
||||
double epicsShareAPI ca_receive_watchdog_delay ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.receiveWatchdogDelay ( guard );
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_v42_ok(chid chan)
|
||||
*/
|
||||
int epicsShareAPI ca_v42_ok ( chid pChan )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( pChan->cacCtx.mutexRef () );
|
||||
return pChan->io.ca_v42_ok ( guard );
|
||||
}
|
||||
|
||||
|
||||
107
src/client/oldSubscription.cpp
Normal file
107
src/client/oldSubscription.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "oldAccess.h"
|
||||
|
||||
oldSubscription::oldSubscription (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
oldChannelNotify & chanIn, cacChannel & io,
|
||||
unsigned type, arrayElementCount nElem, unsigned mask,
|
||||
caEventCallBackFunc * pFuncIn, void * pPrivateIn,
|
||||
evid * pEventId ) :
|
||||
chan ( chanIn ), id ( UINT_MAX ), pFunc ( pFuncIn ),
|
||||
pPrivate ( pPrivateIn )
|
||||
{
|
||||
// The users event id *must* be set prior to potentially
|
||||
// calling his callback from within subscribe.
|
||||
if ( pEventId ) {
|
||||
*pEventId = this;
|
||||
}
|
||||
io.subscribe ( guard, type, nElem, mask, *this, &this->id );
|
||||
// Dont touch this pointer after this point because the
|
||||
// 1st update callback might cancel the subscription and
|
||||
// thereby destroy this object.
|
||||
}
|
||||
|
||||
oldSubscription::~oldSubscription ()
|
||||
{
|
||||
}
|
||||
|
||||
void oldSubscription::current (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
unsigned type, arrayElementCount count, const void * pData )
|
||||
{
|
||||
struct event_handler_args args;
|
||||
args.usr = this->pPrivate;
|
||||
args.chid = & this->chan;
|
||||
args.type = static_cast < long > ( type );
|
||||
args.count = static_cast < long > ( count );
|
||||
args.status = ECA_NORMAL;
|
||||
args.dbr = pData;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFuncTmp ) ( args );
|
||||
}
|
||||
}
|
||||
|
||||
void oldSubscription::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * /* pContext */,
|
||||
unsigned type, arrayElementCount count )
|
||||
{
|
||||
if ( status == ECA_CHANDESTROY ) {
|
||||
ca_client_context & cac = this->chan.getClientCtx ();
|
||||
cac.destroySubscription ( guard, *this );
|
||||
}
|
||||
else if ( status != ECA_DISCONN ) {
|
||||
struct event_handler_args args;
|
||||
args.usr = this->pPrivate;
|
||||
args.chid = & this->chan;
|
||||
args.type = type;
|
||||
args.count = count;
|
||||
args.status = status;
|
||||
args.dbr = 0;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFuncTmp ) ( args );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void oldSubscription::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
103
src/client/putCallback.cpp
Normal file
103
src/client/putCallback.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "oldAccess.h"
|
||||
|
||||
putCallback::putCallback (
|
||||
oldChannelNotify & chanIn, caEventCallBackFunc * pFuncIn,
|
||||
void * pPrivateIn ) :
|
||||
chan ( chanIn ), pFunc ( pFuncIn ), pPrivate ( pPrivateIn )
|
||||
{
|
||||
}
|
||||
|
||||
putCallback::~putCallback ()
|
||||
{
|
||||
}
|
||||
|
||||
void putCallback::completion ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
struct event_handler_args args;
|
||||
|
||||
args.usr = this->pPrivate;
|
||||
args.chid = & this->chan;
|
||||
args.type = TYPENOTCONN;
|
||||
args.count = 0;
|
||||
args.status = ECA_NORMAL;
|
||||
args.dbr = 0;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
|
||||
if ( pFuncTmp ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
pFuncTmp ( args );
|
||||
}
|
||||
}
|
||||
|
||||
void putCallback::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * /* pContext */,
|
||||
unsigned type, arrayElementCount count )
|
||||
{
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
struct event_handler_args args;
|
||||
args.usr = this->pPrivate;
|
||||
args.chid = & this->chan;
|
||||
args.type = type;
|
||||
args.count = count;
|
||||
args.status = status;
|
||||
args.dbr = 0;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFuncTmp ) ( args );
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->chan.getClientCtx().destroyPutCallback ( guard, *this );
|
||||
}
|
||||
}
|
||||
|
||||
void putCallback::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
587
src/client/repeater.cpp
Normal file
587
src/client/repeater.cpp
Normal file
@@ -0,0 +1,587 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* REPEATER.cpp
|
||||
*
|
||||
* CA broadcast repeater
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
* Date: 3-27-90
|
||||
*
|
||||
* PURPOSE:
|
||||
* Broadcasts fan out over the LAN, but old IP kernels do not allow
|
||||
* two processes on the same machine to get the same broadcast
|
||||
* (and modern IP kernels do not allow two processes on the same machine
|
||||
* to receive the same unicast).
|
||||
*
|
||||
* This code fans out UDP messages sent to the CA repeater port
|
||||
* to all CA client processes that have subscribed.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* It would be preferable to avoid using the repeater on multicast enhanced
|
||||
* IP kernels, but this is not going to work in all situations because
|
||||
* (according to Steven's TCP/IP illustrated volume I) if a broadcast is
|
||||
* received it goes to all sockets on the same port, but if a unicast is
|
||||
* received it goes to only one of the sockets on the same port (we can only
|
||||
* guess at which one it will be).
|
||||
*
|
||||
* I have observed this behavior under winsock II:
|
||||
* o only one of the sockets on the same port receives the message if we
|
||||
* send to the loopback address
|
||||
* o both of the sockets on the same port receives the message if we send
|
||||
* to the broadcast address
|
||||
*/
|
||||
|
||||
/* verifyClients() Mechanism
|
||||
*
|
||||
* This is required because Solaris and HPUX have half baked versions
|
||||
* of sockets.
|
||||
*
|
||||
* As written, the repeater should be robust against situations where the
|
||||
* IP kernel doesn't implement UDP disconnect on receiving ICMP port
|
||||
* unreachable errors from the destination process. As I recall, this
|
||||
* change was required in the repeater code when we ported from sunos4 to
|
||||
* Solaris. To avoid unreasonable overhead, I decided at the time to check
|
||||
* the validity of all existing connections only when a new client
|
||||
* registers with the repeater (and not when fanning out each beacon
|
||||
* received). -- Jeff
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include "envDefs.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "osiWireFormat.h"
|
||||
#include "taskwd.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "caProto.h"
|
||||
#include "udpiiu.h"
|
||||
#include "repeaterClient.h"
|
||||
|
||||
|
||||
/*
|
||||
* these can be external since there is only one instance
|
||||
* per machine so we dont care about reentrancy
|
||||
*/
|
||||
static tsDLList < repeaterClient > client_list;
|
||||
|
||||
static const unsigned short PORT_ANY = 0u;
|
||||
|
||||
/*
|
||||
* makeSocket()
|
||||
*/
|
||||
static int makeSocket ( unsigned short port, bool reuseAddr, SOCKET * pSock )
|
||||
{
|
||||
SOCKET sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, 0 );
|
||||
|
||||
if ( sock == INVALID_SOCKET ) {
|
||||
*pSock = sock;
|
||||
return SOCKERRNO;
|
||||
}
|
||||
|
||||
/*
|
||||
* no need to bind if unconstrained
|
||||
*/
|
||||
if ( port != PORT_ANY ) {
|
||||
int status;
|
||||
union {
|
||||
struct sockaddr_in ia;
|
||||
struct sockaddr sa;
|
||||
} bd;
|
||||
|
||||
memset ( (char *) &bd, 0, sizeof (bd) );
|
||||
bd.ia.sin_family = AF_INET;
|
||||
bd.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
|
||||
bd.ia.sin_port = htons ( port );
|
||||
status = bind ( sock, &bd.sa, (int) sizeof(bd) );
|
||||
if ( status < 0 ) {
|
||||
status = SOCKERRNO;
|
||||
epicsSocketDestroy ( sock );
|
||||
return status;
|
||||
}
|
||||
if ( reuseAddr ) {
|
||||
epicsSocketEnableAddressReuseDuringTimeWaitState ( sock );
|
||||
}
|
||||
}
|
||||
*pSock = sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
repeaterClient::repeaterClient ( const osiSockAddr &fromIn ) :
|
||||
from ( fromIn ), sock ( INVALID_SOCKET )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
unsigned port = ntohs ( from.ia.sin_port );
|
||||
debugPrintf ( ( "new client %u\n", port ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
bool repeaterClient::connect ()
|
||||
{
|
||||
int status;
|
||||
|
||||
if ( int sockerrno = makeSocket ( PORT_ANY, false, & this->sock ) ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrorToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ), sockerrno );
|
||||
fprintf ( stderr, "%s: no client sock because \"%s\"\n",
|
||||
__FILE__, sockErrBuf );
|
||||
return false;
|
||||
}
|
||||
|
||||
status = ::connect ( this->sock, &this->from.sa, sizeof ( this->from.sa ) );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
fprintf ( stderr, "%s: unable to connect client sock because \"%s\"\n",
|
||||
__FILE__, sockErrBuf );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool repeaterClient::sendConfirm ()
|
||||
{
|
||||
int status;
|
||||
|
||||
caHdr confirm;
|
||||
memset ( (char *) &confirm, '\0', sizeof (confirm) );
|
||||
AlignedWireRef < epicsUInt16 > ( confirm.m_cmmd ) = REPEATER_CONFIRM;
|
||||
confirm.m_available = this->from.ia.sin_addr.s_addr;
|
||||
status = send ( this->sock, (char *) &confirm,
|
||||
sizeof (confirm), 0 );
|
||||
if ( status >= 0 ) {
|
||||
assert ( status == sizeof ( confirm ) );
|
||||
return true;
|
||||
}
|
||||
else if ( SOCKERRNO == SOCK_ECONNREFUSED ) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
debugPrintf ( ( "CA Repeater: confirm req err was \"%s\"\n", sockErrBuf) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool repeaterClient::sendMessage ( const void *pBuf, unsigned bufSize )
|
||||
{
|
||||
int status;
|
||||
|
||||
status = send ( this->sock, (char *) pBuf, bufSize, 0 );
|
||||
if ( status >= 0 ) {
|
||||
assert ( static_cast <unsigned> ( status ) == bufSize );
|
||||
#ifdef DEBUG
|
||||
epicsUInt16 port = ntohs ( this->from.ia.sin_port );
|
||||
debugPrintf ( ("Sent to %u\n", port ) );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
if ( errnoCpy == SOCK_ECONNREFUSED ) {
|
||||
#ifdef DEBUG
|
||||
epicsUInt16 port = ntohs ( this->from.ia.sin_port );
|
||||
debugPrintf ( ("Client refused message %u\n", port ) );
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
debugPrintf ( ( "CA Repeater: UDP send err was \"%s\"\n", sockErrBuf) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
repeaterClient::~repeaterClient ()
|
||||
{
|
||||
if ( this->sock != INVALID_SOCKET ) {
|
||||
epicsSocketDestroy ( this->sock );
|
||||
}
|
||||
#ifdef DEBUG
|
||||
epicsUInt16 port = ntohs ( this->from.ia.sin_port );
|
||||
debugPrintf ( ( "Deleted client %u\n", port ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
void repeaterClient::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
void * repeaterClient::operator new ( size_t size,
|
||||
tsFreeList < repeaterClient, 0x20 > & freeList )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
void repeaterClient::operator delete ( void *pCadaver,
|
||||
tsFreeList < repeaterClient, 0x20 > & freeList )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline unsigned short repeaterClient::port () const
|
||||
{
|
||||
return ntohs ( this->from.ia.sin_port );
|
||||
}
|
||||
|
||||
inline bool repeaterClient::identicalAddress ( const osiSockAddr &fromIn )
|
||||
{
|
||||
if ( fromIn.sa.sa_family == this->from.sa.sa_family ) {
|
||||
if ( fromIn.ia.sin_port == this->from.ia.sin_port) {
|
||||
if ( fromIn.ia.sin_addr.s_addr == this->from.ia.sin_addr.s_addr ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool repeaterClient::identicalPort ( const osiSockAddr &fromIn )
|
||||
{
|
||||
if ( fromIn.sa.sa_family == this->from.sa.sa_family ) {
|
||||
if ( fromIn.ia.sin_port == this->from.ia.sin_port) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool repeaterClient::verify ()
|
||||
{
|
||||
SOCKET tmpSock;
|
||||
int sockerrno = makeSocket ( this->port (), false, & tmpSock );
|
||||
|
||||
if ( sockerrno == SOCK_EADDRINUSE ) {
|
||||
// Normal result, client using port
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( sockerrno == 0 ) {
|
||||
// Client went away, released port
|
||||
epicsSocketDestroy ( tmpSock );
|
||||
}
|
||||
else {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrorToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ), sockerrno );
|
||||
fprintf ( stderr, "CA Repeater: Bind test error \"%s\"\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* verifyClients()
|
||||
*/
|
||||
static void verifyClients ( tsFreeList < repeaterClient, 0x20 > & freeList )
|
||||
{
|
||||
static tsDLList < repeaterClient > theClients;
|
||||
repeaterClient *pclient;
|
||||
|
||||
while ( ( pclient = client_list.get () ) ) {
|
||||
if ( pclient->verify () ) {
|
||||
theClients.add ( *pclient );
|
||||
}
|
||||
else {
|
||||
pclient->~repeaterClient ();
|
||||
freeList.release ( pclient );
|
||||
}
|
||||
}
|
||||
client_list.add ( theClients );
|
||||
}
|
||||
|
||||
/*
|
||||
* fanOut()
|
||||
*/
|
||||
static void fanOut ( const osiSockAddr & from, const void * pMsg,
|
||||
unsigned msgSize, tsFreeList < repeaterClient, 0x20 > & freeList )
|
||||
{
|
||||
static tsDLList < repeaterClient > theClients;
|
||||
repeaterClient *pclient;
|
||||
|
||||
while ( ( pclient = client_list.get () ) ) {
|
||||
theClients.add ( *pclient );
|
||||
/* Dont reflect back to sender */
|
||||
if ( pclient->identicalAddress ( from ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! pclient->sendMessage ( pMsg, msgSize ) ) {
|
||||
if ( ! pclient->verify () ) {
|
||||
theClients.remove ( *pclient );
|
||||
pclient->~repeaterClient ();
|
||||
freeList.release ( pclient );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client_list.add ( theClients );
|
||||
}
|
||||
|
||||
/*
|
||||
* register_new_client()
|
||||
*/
|
||||
static void register_new_client ( osiSockAddr & from,
|
||||
tsFreeList < repeaterClient, 0x20 > & freeList )
|
||||
{
|
||||
bool newClient = false;
|
||||
int status;
|
||||
|
||||
if ( from.sa.sa_family != AF_INET ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* the repeater and its clients must be on the same host
|
||||
*/
|
||||
if ( INADDR_LOOPBACK != ntohl ( from.ia.sin_addr.s_addr ) ) {
|
||||
static SOCKET testSock = INVALID_SOCKET;
|
||||
static bool init = false;
|
||||
|
||||
if ( ! init ) {
|
||||
SOCKET sock;
|
||||
if ( int sockerrno = makeSocket ( PORT_ANY, true, & sock ) ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrorToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ), sockerrno );
|
||||
fprintf ( stderr, "%s: Unable to create repeater bind test socket because \"%s\"\n",
|
||||
__FILE__, sockErrBuf );
|
||||
}
|
||||
else {
|
||||
testSock = sock;
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately on 3.13 beta 11 and before the
|
||||
* repeater would not always allow the loopback address
|
||||
* as a local client address so current clients alternate
|
||||
* between the address of the first non-loopback interface
|
||||
* found and the loopback addresss when subscribing with
|
||||
* the CA repeater until all CA repeaters have been updated
|
||||
* to current code.
|
||||
*/
|
||||
if ( testSock != INVALID_SOCKET ) {
|
||||
osiSockAddr addr;
|
||||
|
||||
addr = from;
|
||||
addr.ia.sin_port = PORT_ANY;
|
||||
|
||||
/* we can only bind to a local address */
|
||||
status = bind ( testSock, &addr.sa, sizeof ( addr ) );
|
||||
if ( status ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tsDLIter < repeaterClient > pclient = client_list.firstIter ();
|
||||
while ( pclient.valid () ) {
|
||||
if ( pclient->identicalPort ( from ) ) {
|
||||
break;
|
||||
}
|
||||
pclient++;
|
||||
}
|
||||
|
||||
repeaterClient *pNewClient;
|
||||
if ( pclient.valid () ) {
|
||||
pNewClient = pclient.pointer ();
|
||||
}
|
||||
else {
|
||||
pNewClient = new ( freeList ) repeaterClient ( from );
|
||||
if ( ! pNewClient ) {
|
||||
fprintf ( stderr, "%s: no memory for new client\n", __FILE__ );
|
||||
return;
|
||||
}
|
||||
if ( ! pNewClient->connect () ) {
|
||||
pNewClient->~repeaterClient ();
|
||||
freeList.release ( pNewClient );
|
||||
return;
|
||||
}
|
||||
client_list.add ( *pNewClient );
|
||||
newClient = true;
|
||||
}
|
||||
|
||||
if ( ! pNewClient->sendConfirm () ) {
|
||||
client_list.remove ( *pNewClient );
|
||||
pNewClient->~repeaterClient ();
|
||||
freeList.release ( pNewClient );
|
||||
# ifdef DEBUG
|
||||
epicsUInt16 port = ntohs ( from.ia.sin_port );
|
||||
debugPrintf ( ( "Deleted repeater client=%u (error while sending ack)\n",
|
||||
port ) );
|
||||
# endif
|
||||
}
|
||||
|
||||
/*
|
||||
* send a noop message to all other clients so that we dont
|
||||
* accumulate sockets when there are no beacons
|
||||
*/
|
||||
caHdr noop;
|
||||
memset ( (char *) &noop, '\0', sizeof ( noop ) );
|
||||
AlignedWireRef < epicsUInt16 > ( noop.m_cmmd ) = CA_PROTO_VERSION;
|
||||
fanOut ( from, &noop, sizeof ( noop ), freeList );
|
||||
|
||||
if ( newClient ) {
|
||||
/*
|
||||
* For HPUX and Solaris we need to verify that the clients
|
||||
* have not gone away - because an ICMP error return does not
|
||||
* get through to send(), which returns no error code.
|
||||
*
|
||||
* This is done each time that a new client is created.
|
||||
* See also the note in the file header.
|
||||
*
|
||||
* This is done here in order to avoid deleting a client
|
||||
* prior to sending its confirm message.
|
||||
*/
|
||||
verifyClients ( freeList );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_repeater ()
|
||||
*/
|
||||
void ca_repeater ()
|
||||
{
|
||||
tsFreeList < repeaterClient, 0x20 > freeList;
|
||||
int size;
|
||||
SOCKET sock;
|
||||
osiSockAddr from;
|
||||
unsigned short port;
|
||||
char * pBuf;
|
||||
|
||||
pBuf = new char [MAX_UDP_RECV];
|
||||
|
||||
{
|
||||
bool success = osiSockAttach();
|
||||
assert ( success );
|
||||
}
|
||||
|
||||
port = envGetInetPortConfigParam ( & EPICS_CA_REPEATER_PORT,
|
||||
static_cast <unsigned short> (CA_REPEATER_PORT) );
|
||||
if ( int sockerrno = makeSocket ( port, true, & sock ) ) {
|
||||
/*
|
||||
* test for server was already started
|
||||
*/
|
||||
if ( sockerrno == SOCK_EADDRINUSE ) {
|
||||
osiSockRelease ();
|
||||
debugPrintf ( ( "CA Repeater: exiting because a repeater is already running\n" ) );
|
||||
delete [] pBuf;
|
||||
return;
|
||||
}
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrorToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ), sockerrno );
|
||||
fprintf ( stderr, "%s: Unable to create repeater socket because \"%s\" - fatal\n",
|
||||
__FILE__, sockErrBuf );
|
||||
osiSockRelease ();
|
||||
delete [] pBuf;
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrintf ( ( "CA Repeater: Attached and initialized\n" ) );
|
||||
|
||||
while ( true ) {
|
||||
osiSocklen_t from_size = sizeof ( from );
|
||||
size = recvfrom ( sock, pBuf, MAX_UDP_RECV, 0,
|
||||
&from.sa, &from_size );
|
||||
if ( size < 0 ) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
// Avoid spurious ECONNREFUSED bug in linux
|
||||
if ( errnoCpy == SOCK_ECONNREFUSED ) {
|
||||
continue;
|
||||
}
|
||||
// Avoid ECONNRESET from connected socket in windows
|
||||
if ( errnoCpy == SOCK_ECONNRESET ) {
|
||||
continue;
|
||||
}
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
fprintf ( stderr, "CA Repeater: unexpected UDP recv err: %s\n",
|
||||
sockErrBuf );
|
||||
continue;
|
||||
}
|
||||
|
||||
caHdr * pMsg = ( caHdr * ) pBuf;
|
||||
|
||||
/*
|
||||
* both zero length message and a registration message
|
||||
* will register a new client
|
||||
*/
|
||||
if ( ( (size_t) size) >= sizeof (*pMsg) ) {
|
||||
if ( AlignedWireRef < epicsUInt16 > ( pMsg->m_cmmd ) == REPEATER_REGISTER ) {
|
||||
register_new_client ( from, freeList );
|
||||
|
||||
/*
|
||||
* strip register client message
|
||||
*/
|
||||
pMsg++;
|
||||
size -= sizeof ( *pMsg );
|
||||
if ( size==0 ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if ( AlignedWireRef < epicsUInt16 > ( pMsg->m_cmmd ) == CA_PROTO_RSRV_IS_UP ) {
|
||||
if ( pMsg->m_available == 0u ) {
|
||||
pMsg->m_available = from.ia.sin_addr.s_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( size == 0 ) {
|
||||
register_new_client ( from, freeList );
|
||||
continue;
|
||||
}
|
||||
|
||||
fanOut ( from, pMsg, size, freeList );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* caRepeaterThread ()
|
||||
*/
|
||||
extern "C" void caRepeaterThread ( void * /* pDummy */ )
|
||||
{
|
||||
taskwdInsert ( epicsThreadGetIdSelf(), NULL, NULL );
|
||||
ca_repeater ();
|
||||
}
|
||||
|
||||
|
||||
72
src/client/repeaterClient.h
Normal file
72
src/client/repeaterClient.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef repeaterClienth
|
||||
#define repeaterClienth
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define repeaterClienth_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef repeaterClienth_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
union osiSockAddr;
|
||||
|
||||
/*
|
||||
* one socket per client so we will get the ECONNREFUSED
|
||||
* error code (and then delete the client)
|
||||
*/
|
||||
class repeaterClient : public tsDLNode < repeaterClient > {
|
||||
public:
|
||||
repeaterClient ( const osiSockAddr & from );
|
||||
~repeaterClient ();
|
||||
bool connect ();
|
||||
bool sendConfirm ();
|
||||
bool sendMessage ( const void *pBuf, unsigned bufSize );
|
||||
bool verify ();
|
||||
bool identicalAddress ( const osiSockAddr &from );
|
||||
bool identicalPort ( const osiSockAddr &from );
|
||||
void * operator new ( size_t size,
|
||||
tsFreeList < repeaterClient, 0x20 > & );
|
||||
epicsPlacementDeleteOperator (( void *,
|
||||
tsFreeList < repeaterClient, 0x20 > & ))
|
||||
private:
|
||||
osiSockAddr from;
|
||||
SOCKET sock;
|
||||
unsigned short port () const;
|
||||
void operator delete ( void * );
|
||||
};
|
||||
|
||||
#endif // repeaterClienth
|
||||
|
||||
|
||||
109
src/client/repeaterSubscribeTimer.cpp
Normal file
109
src/client/repeaterSubscribeTimer.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*
|
||||
*/
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "cac.h"
|
||||
#include "iocinf.h"
|
||||
#include "repeaterSubscribeTimer.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "udpiiu.h"
|
||||
#undef epicsExportSharedSymbols
|
||||
|
||||
static const double repeaterSubscribeTimerInitialPeriod = 10.0; // sec
|
||||
static const double repeaterSubscribeTimerPeriod = 1.0; // sec
|
||||
|
||||
repeaterSubscribeTimer::repeaterSubscribeTimer (
|
||||
repeaterTimerNotify & iiuIn, epicsTimerQueue & queueIn,
|
||||
epicsMutex & cbMutexIn, cacContextNotify & ctxNotifyIn ) :
|
||||
timer ( queueIn.createTimer () ), iiu ( iiuIn ),
|
||||
cbMutex ( cbMutexIn ),ctxNotify ( ctxNotifyIn ),
|
||||
attempts ( 0 ), registered ( false ), once ( false )
|
||||
{
|
||||
}
|
||||
|
||||
repeaterSubscribeTimer::~repeaterSubscribeTimer ()
|
||||
{
|
||||
this->timer.destroy ();
|
||||
}
|
||||
|
||||
void repeaterSubscribeTimer::start ()
|
||||
{
|
||||
this->timer.start (
|
||||
*this, repeaterSubscribeTimerInitialPeriod );
|
||||
}
|
||||
|
||||
void repeaterSubscribeTimer::shutdown (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > cbUnguard ( cbGuard );
|
||||
this->timer.cancel ();
|
||||
}
|
||||
}
|
||||
|
||||
epicsTimerNotify::expireStatus repeaterSubscribeTimer::
|
||||
expire ( const epicsTime & /* currentTime */ )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->stateMutex );
|
||||
|
||||
static const unsigned nTriesToMsg = 50;
|
||||
if ( this->attempts > nTriesToMsg && ! this->once ) {
|
||||
callbackManager mgr ( this->ctxNotify, this->cbMutex );
|
||||
this->iiu.printFormated ( mgr.cbGuard,
|
||||
"CA client library is unable to contact CA repeater after %u tries.\n",
|
||||
nTriesToMsg );
|
||||
this->iiu.printFormated ( mgr.cbGuard,
|
||||
"Silence this message by starting a CA repeater daemon\n") ;
|
||||
this->iiu.printFormated ( mgr.cbGuard,
|
||||
"or by calling ca_pend_event() and or ca_poll() more often.\n" );
|
||||
this->once = true;
|
||||
}
|
||||
|
||||
this->iiu.repeaterRegistrationMessage ( this->attempts );
|
||||
this->attempts++;
|
||||
|
||||
if ( this->registered ) {
|
||||
return noRestart;
|
||||
}
|
||||
else {
|
||||
return expireStatus ( restart, repeaterSubscribeTimerPeriod );
|
||||
}
|
||||
}
|
||||
|
||||
void repeaterSubscribeTimer::show ( unsigned /* level */ ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->stateMutex );
|
||||
|
||||
::printf ( "repeater subscribe timer: attempts=%u registered=%u once=%u\n",
|
||||
this->attempts, this->registered, this->once );
|
||||
}
|
||||
|
||||
void repeaterSubscribeTimer::confirmNotify ()
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->stateMutex );
|
||||
this->registered = true;
|
||||
}
|
||||
|
||||
repeaterTimerNotify::~repeaterTimerNotify () {}
|
||||
82
src/client/repeaterSubscribeTimer.h
Normal file
82
src/client/repeaterSubscribeTimer.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef repeaterSubscribeTimerh
|
||||
#define repeaterSubscribeTimerh
|
||||
|
||||
#include "epicsTimer.h"
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define repeaterSubscribeTimerh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsTimer.h"
|
||||
|
||||
#ifdef repeaterSubscribeTimerh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
class epicsMutex;
|
||||
class cacContextNotify;
|
||||
|
||||
class repeaterTimerNotify {
|
||||
public:
|
||||
virtual ~repeaterTimerNotify () = 0;
|
||||
virtual void repeaterRegistrationMessage (
|
||||
unsigned attemptNumber ) = 0;
|
||||
virtual int printFormated (
|
||||
epicsGuard < epicsMutex > & callbackControl,
|
||||
const char * pformat, ... ) = 0;
|
||||
};
|
||||
|
||||
class repeaterSubscribeTimer : private epicsTimerNotify {
|
||||
public:
|
||||
repeaterSubscribeTimer (
|
||||
repeaterTimerNotify &, epicsTimerQueue &,
|
||||
epicsMutex & cbMutex, cacContextNotify & ctxNotify );
|
||||
virtual ~repeaterSubscribeTimer ();
|
||||
void start ();
|
||||
void shutdown (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void confirmNotify ();
|
||||
void show ( unsigned level ) const;
|
||||
private:
|
||||
epicsTimer & timer;
|
||||
repeaterTimerNotify & iiu;
|
||||
epicsMutex & cbMutex;
|
||||
cacContextNotify & ctxNotify;
|
||||
mutable epicsMutex stateMutex;
|
||||
unsigned attempts;
|
||||
bool registered;
|
||||
bool once;
|
||||
expireStatus expire ( const epicsTime & currentTime );
|
||||
repeaterSubscribeTimer ( const repeaterSubscribeTimer & );
|
||||
repeaterSubscribeTimer & operator = ( const repeaterSubscribeTimer & );
|
||||
};
|
||||
|
||||
#endif // ifdef repeaterSubscribeTimerh
|
||||
399
src/client/searchTimer.cpp
Normal file
399
src/client/searchTimer.cpp
Normal file
@@ -0,0 +1,399 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
//
|
||||
//
|
||||
// L O S A L A M O S
|
||||
// Los Alamos National Laboratory
|
||||
// Los Alamos, New Mexico 87545
|
||||
//
|
||||
// Copyright, 1986, The Regents of the University of California.
|
||||
//
|
||||
// Author: Jeff Hill
|
||||
//
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string> // vxWorks 6.0 requires this include
|
||||
#include <limits.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "envDefs.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "udpiiu.h"
|
||||
#include "nciu.h"
|
||||
|
||||
static const unsigned initialTriesPerFrame = 1u; // initial UDP frames per search try
|
||||
static const unsigned maxTriesPerFrame = 64u; // max UDP frames per search try
|
||||
|
||||
//
|
||||
// searchTimer::searchTimer ()
|
||||
//
|
||||
searchTimer::searchTimer (
|
||||
searchTimerNotify & iiuIn,
|
||||
epicsTimerQueue & queueIn,
|
||||
const unsigned indexIn,
|
||||
epicsMutex & mutexIn,
|
||||
bool boostPossibleIn ) :
|
||||
timeAtLastSend ( epicsTime::getCurrent () ),
|
||||
timer ( queueIn.createTimer () ),
|
||||
iiu ( iiuIn ),
|
||||
mutex ( mutexIn ),
|
||||
framesPerTry ( initialTriesPerFrame ),
|
||||
framesPerTryCongestThresh ( DBL_MAX ),
|
||||
retry ( 0 ),
|
||||
searchAttempts ( 0u ),
|
||||
searchResponses ( 0u ),
|
||||
index ( indexIn ),
|
||||
dgSeqNoAtTimerExpireBegin ( 0u ),
|
||||
dgSeqNoAtTimerExpireEnd ( 0u ),
|
||||
boostPossible ( boostPossibleIn ),
|
||||
stopped ( false )
|
||||
{
|
||||
}
|
||||
|
||||
void searchTimer::start ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->timer.start ( *this, this->period ( guard ) );
|
||||
}
|
||||
|
||||
searchTimer::~searchTimer ()
|
||||
{
|
||||
assert ( this->chanListReqPending.count() == 0 );
|
||||
assert ( this->chanListRespPending.count() == 0 );
|
||||
this->timer.destroy ();
|
||||
}
|
||||
|
||||
void searchTimer::shutdown (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->stopped = true;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > cbUnguard ( cbGuard );
|
||||
this->timer.cancel ();
|
||||
}
|
||||
}
|
||||
|
||||
while ( nciu * pChan = this->chanListReqPending.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
pChan->serviceShutdownNotify ( cbGuard, guard );
|
||||
}
|
||||
while ( nciu * pChan = this->chanListRespPending.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
pChan->serviceShutdownNotify ( cbGuard, guard );
|
||||
}
|
||||
}
|
||||
|
||||
void searchTimer::installChannel (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan )
|
||||
{
|
||||
this->chanListReqPending.add ( chan );
|
||||
chan.channelNode::setReqPendingState ( guard, this->index );
|
||||
}
|
||||
|
||||
void searchTimer::moveChannels (
|
||||
epicsGuard < epicsMutex > & guard, searchTimer & dest )
|
||||
{
|
||||
while ( nciu * pChan = this->chanListRespPending.get () ) {
|
||||
if ( this->searchAttempts > 0 ) {
|
||||
this->searchAttempts--;
|
||||
}
|
||||
dest.installChannel ( guard, *pChan );
|
||||
}
|
||||
while ( nciu * pChan = this->chanListReqPending.get () ) {
|
||||
dest.installChannel ( guard, *pChan );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// searchTimer::expire ()
|
||||
//
|
||||
epicsTimerNotify::expireStatus searchTimer::expire (
|
||||
const epicsTime & currentTime )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
while ( nciu * pChan = this->chanListRespPending.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
this->iiu.noSearchRespNotify (
|
||||
guard, *pChan, this->index );
|
||||
}
|
||||
|
||||
this->timeAtLastSend = currentTime;
|
||||
|
||||
// boost search period for channels not recently
|
||||
// searched for if there was some success
|
||||
if ( this->searchResponses && this->boostPossible ) {
|
||||
while ( nciu * pChan = this->chanListReqPending.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
this->iiu.boostChannel ( guard, *pChan );
|
||||
}
|
||||
}
|
||||
|
||||
if ( this->searchAttempts ) {
|
||||
#if 0
|
||||
//
|
||||
// dynamically adjust the number of UDP frames per
|
||||
// try depending how many search requests are not
|
||||
// replied to
|
||||
//
|
||||
// The variable this->framesPerTry
|
||||
// determines the number of UDP frames to be sent
|
||||
// each time that expire() is called.
|
||||
// If this value is too high we will waste some
|
||||
// network bandwidth. If it is too low we will
|
||||
// use very little of the incoming UDP message
|
||||
// buffer associated with the server's port and
|
||||
// will therefore take longer to connect. We
|
||||
// initialize this->framesPerTry to a prime number
|
||||
// so that it is less likely that the
|
||||
// same channel is in the last UDP frame
|
||||
// sent every time that this is called (and
|
||||
// potentially discarded by a CA server with
|
||||
// a small UDP input queue).
|
||||
//
|
||||
// increase frames per try only if we see better than
|
||||
// a 93.75% success rate for one pass through the list
|
||||
//
|
||||
if ( this->searchResponses >
|
||||
( this->searchAttempts - (this->searchAttempts/16u) ) ) {
|
||||
// increase UDP frames per try if we have a good score
|
||||
if ( this->framesPerTry < maxTriesPerFrame ) {
|
||||
// a congestion avoidance threshold similar to TCP is now used
|
||||
if ( this->framesPerTry < this->framesPerTryCongestThresh ) {
|
||||
this->framesPerTry += this->framesPerTry;
|
||||
}
|
||||
else {
|
||||
this->framesPerTry += (this->framesPerTry/8) + 1;
|
||||
}
|
||||
debugPrintf ( ("Increasing frame count to %u t=%u r=%u\n",
|
||||
this->framesPerTry, this->searchAttempts, this->searchResponses) );
|
||||
}
|
||||
}
|
||||
// if we detect congestion because we have less than a 87.5% success
|
||||
// rate then gradually reduce the frames per try
|
||||
else if ( this->searchResponses <
|
||||
( this->searchAttempts - (this->searchAttempts/8u) ) ) {
|
||||
if ( this->framesPerTry > 1 ) {
|
||||
this->framesPerTry--;
|
||||
}
|
||||
this->framesPerTryCongestThresh = this->framesPerTry/2 + 1;
|
||||
debugPrintf ( ("Congestion detected - set frames per try to %f t=%u r=%u\n",
|
||||
this->framesPerTry, this->searchAttempts, this->searchResponses) );
|
||||
}
|
||||
#else
|
||||
if ( this->searchResponses == this->searchAttempts ) {
|
||||
// increase UDP frames per try if we have a good score
|
||||
if ( this->framesPerTry < maxTriesPerFrame ) {
|
||||
// a congestion avoidance threshold similar to TCP is now used
|
||||
if ( this->framesPerTry < this->framesPerTryCongestThresh ) {
|
||||
double doubled = 2 * this->framesPerTry;
|
||||
if ( doubled > this->framesPerTryCongestThresh ) {
|
||||
this->framesPerTry = this->framesPerTryCongestThresh;
|
||||
}
|
||||
else {
|
||||
this->framesPerTry = doubled;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->framesPerTry += 1.0 / this->framesPerTry;
|
||||
}
|
||||
debugPrintf ( ("Increasing frame count to %g t=%u r=%u\n",
|
||||
this->framesPerTry, this->searchAttempts, this->searchResponses) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->framesPerTryCongestThresh = this->framesPerTry / 2.0;
|
||||
this->framesPerTry = 1u;
|
||||
debugPrintf ( ("Congestion detected - set frames per try to %g t=%u r=%u\n",
|
||||
this->framesPerTry, this->searchAttempts, this->searchResponses) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
this->dgSeqNoAtTimerExpireBegin =
|
||||
this->iiu.datagramSeqNumber ( guard );
|
||||
|
||||
this->searchAttempts = 0;
|
||||
this->searchResponses = 0;
|
||||
|
||||
unsigned nFrameSent = 0u;
|
||||
while ( true ) {
|
||||
nciu * pChan = this->chanListReqPending.get ();
|
||||
if ( ! pChan ) {
|
||||
break;
|
||||
}
|
||||
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
|
||||
bool success = pChan->searchMsg ( guard );
|
||||
if ( ! success ) {
|
||||
if ( this->iiu.datagramFlush ( guard, currentTime ) ) {
|
||||
nFrameSent++;
|
||||
if ( nFrameSent < this->framesPerTry ) {
|
||||
success = pChan->searchMsg ( guard );
|
||||
}
|
||||
}
|
||||
if ( ! success ) {
|
||||
this->chanListReqPending.push ( *pChan );
|
||||
pChan->channelNode::setReqPendingState (
|
||||
guard, this->index );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->chanListRespPending.add ( *pChan );
|
||||
pChan->channelNode::setRespPendingState (
|
||||
guard, this->index );
|
||||
|
||||
if ( this->searchAttempts < UINT_MAX ) {
|
||||
this->searchAttempts++;
|
||||
}
|
||||
}
|
||||
|
||||
// flush out the search request buffer
|
||||
if ( this->iiu.datagramFlush ( guard, currentTime ) ) {
|
||||
nFrameSent++;
|
||||
}
|
||||
|
||||
this->dgSeqNoAtTimerExpireEnd =
|
||||
this->iiu.datagramSeqNumber ( guard ) - 1u;
|
||||
|
||||
# ifdef DEBUG
|
||||
if ( this->searchAttempts ) {
|
||||
char buf[64];
|
||||
currentTime.strftime ( buf, sizeof(buf), "%M:%S.%09f");
|
||||
debugPrintf ( ("sent %u delay sec=%f Rts=%s\n",
|
||||
nFrameSent, this->period(), buf ) );
|
||||
}
|
||||
# endif
|
||||
|
||||
return expireStatus ( restart, this->period ( guard ) );
|
||||
}
|
||||
|
||||
void searchTimer :: show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
::printf ( "searchTimer with period %f\n", this->period ( guard ) );
|
||||
if ( level > 0 ) {
|
||||
::printf ( "channels with search request pending = %u\n",
|
||||
this->chanListReqPending.count () );
|
||||
if ( level > 1u ) {
|
||||
tsDLIterConst < nciu > pChan =
|
||||
this->chanListReqPending.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 2u );
|
||||
pChan++;
|
||||
}
|
||||
}
|
||||
::printf ( "channels with search response pending = %u\n",
|
||||
this->chanListRespPending.count () );
|
||||
if ( level > 1u ) {
|
||||
tsDLIterConst < nciu > pChan =
|
||||
this->chanListRespPending.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 2u );
|
||||
pChan++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Reset the delay to the next search request if we get
|
||||
// at least one response. However, dont reset this delay if we
|
||||
// get a delayed response to an old search request.
|
||||
//
|
||||
void searchTimer::uninstallChanDueToSuccessfulSearchResponse (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan,
|
||||
ca_uint32_t respDatagramSeqNo, bool seqNumberIsValid,
|
||||
const epicsTime & currentTime )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->uninstallChan ( guard, chan );
|
||||
|
||||
if ( this->stopped ) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool validResponse = true;
|
||||
if ( seqNumberIsValid ) {
|
||||
validResponse =
|
||||
this->dgSeqNoAtTimerExpireBegin <= respDatagramSeqNo &&
|
||||
this->dgSeqNoAtTimerExpireEnd >= respDatagramSeqNo;
|
||||
}
|
||||
|
||||
// if we receive a successful response then reset to a
|
||||
// reasonable timer period
|
||||
if ( validResponse ) {
|
||||
double measured = currentTime - this->timeAtLastSend;
|
||||
this->iiu.updateRTTE ( guard, measured );
|
||||
|
||||
if ( this->searchResponses < UINT_MAX ) {
|
||||
this->searchResponses++;
|
||||
if ( this->searchResponses == this->searchAttempts ) {
|
||||
if ( this->chanListReqPending.count () ) {
|
||||
//
|
||||
// when we get 100% success immediately
|
||||
// send another search request
|
||||
//
|
||||
debugPrintf ( ( "All requests succesful, set timer delay to zero\n" ) );
|
||||
this->timer.start ( *this, currentTime );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void searchTimer::uninstallChan (
|
||||
epicsGuard < epicsMutex > & cacGuard, nciu & chan )
|
||||
{
|
||||
cacGuard.assertIdenticalMutex ( this->mutex );
|
||||
unsigned ulistmem =
|
||||
static_cast <unsigned> ( chan.channelNode::listMember );
|
||||
unsigned uReqBase =
|
||||
static_cast <unsigned> ( channelNode::cs_searchReqPending0 );
|
||||
if ( ulistmem == this->index + uReqBase ) {
|
||||
this->chanListReqPending.remove ( chan );
|
||||
}
|
||||
else {
|
||||
unsigned uRespBase =
|
||||
static_cast <unsigned > (
|
||||
channelNode::cs_searchRespPending0 );
|
||||
if ( ulistmem == this->index + uRespBase ) {
|
||||
this->chanListRespPending.remove ( chan );
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error (
|
||||
"uninstalling channel search timer, but channel "
|
||||
"state is wrong" );
|
||||
}
|
||||
}
|
||||
chan.channelNode::listMember = channelNode::cs_none;
|
||||
}
|
||||
|
||||
double searchTimer::period (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return (1 << this->index ) * this->iiu.getRTTE ( guard );
|
||||
}
|
||||
|
||||
searchTimerNotify::~searchTimerNotify () {}
|
||||
108
src/client/searchTimer.h
Normal file
108
src/client/searchTimer.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// L O S A L A M O S
|
||||
// Los Alamos National Laboratory
|
||||
// Los Alamos, New Mexico 87545
|
||||
//
|
||||
// Copyright, 1986, The Regents of the University of California.
|
||||
//
|
||||
//
|
||||
// Author Jeffrey O. Hill
|
||||
// johill@lanl.gov
|
||||
// 505 665 1831
|
||||
//
|
||||
|
||||
#ifndef searchTimerh
|
||||
#define searchTimerh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define searchTimerh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsGuard.h"
|
||||
#include "epicsTimer.h"
|
||||
|
||||
#ifdef searchTimerh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
#include "caProto.h"
|
||||
#include "netiiu.h"
|
||||
|
||||
class searchTimerNotify {
|
||||
public:
|
||||
virtual ~searchTimerNotify () = 0;
|
||||
virtual void boostChannel (
|
||||
epicsGuard < epicsMutex > &, nciu & ) = 0;
|
||||
virtual void noSearchRespNotify (
|
||||
epicsGuard < epicsMutex > &, nciu &, unsigned ) = 0;
|
||||
virtual double getRTTE ( epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual void updateRTTE ( epicsGuard < epicsMutex > &, double rtte ) = 0;
|
||||
virtual bool datagramFlush (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const epicsTime & currentTime ) = 0;
|
||||
virtual ca_uint32_t datagramSeqNumber (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
};
|
||||
|
||||
class searchTimer : private epicsTimerNotify {
|
||||
public:
|
||||
searchTimer (
|
||||
class searchTimerNotify &, epicsTimerQueue &,
|
||||
const unsigned index, epicsMutex &,
|
||||
bool boostPossible );
|
||||
virtual ~searchTimer ();
|
||||
void start ( epicsGuard < epicsMutex > & );
|
||||
void shutdown (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void moveChannels (
|
||||
epicsGuard < epicsMutex > &, searchTimer & dest );
|
||||
void installChannel (
|
||||
epicsGuard < epicsMutex > &, nciu & );
|
||||
void uninstallChan (
|
||||
epicsGuard < epicsMutex > &, nciu & );
|
||||
void uninstallChanDueToSuccessfulSearchResponse (
|
||||
epicsGuard < epicsMutex > &, nciu &,
|
||||
ca_uint32_t respDatagramSeqNo, bool seqNumberIsValid,
|
||||
const epicsTime & currentTime );
|
||||
void show ( unsigned level ) const;
|
||||
private:
|
||||
tsDLList < nciu > chanListReqPending;
|
||||
tsDLList < nciu > chanListRespPending;
|
||||
epicsTime timeAtLastSend;
|
||||
epicsTimer & timer;
|
||||
searchTimerNotify & iiu;
|
||||
epicsMutex & mutex;
|
||||
double framesPerTry; /* # of UDP frames per search try */
|
||||
double framesPerTryCongestThresh; /* one half N tries w congest */
|
||||
unsigned retry;
|
||||
unsigned searchAttempts; /* num search tries after last timer experation */
|
||||
unsigned searchResponses; /* num search resp after last timer experation */
|
||||
const unsigned index;
|
||||
ca_uint32_t dgSeqNoAtTimerExpireBegin;
|
||||
ca_uint32_t dgSeqNoAtTimerExpireEnd;
|
||||
const bool boostPossible;
|
||||
bool stopped;
|
||||
|
||||
expireStatus expire ( const epicsTime & currentTime );
|
||||
double period ( epicsGuard < epicsMutex > & ) const;
|
||||
searchTimer ( const searchTimer & ); // not implemented
|
||||
searchTimer & operator = ( const searchTimer & ); // not implemented
|
||||
};
|
||||
|
||||
#endif // ifdef searchTimerh
|
||||
103
src/client/sgAutoPtr.h
Normal file
103
src/client/sgAutoPtr.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef sgAutoPtrh
|
||||
#define sgAutoPtrh
|
||||
|
||||
template < class T >
|
||||
class sgAutoPtr {
|
||||
public:
|
||||
sgAutoPtr ( epicsGuard < epicsMutex > &, struct CASG & );
|
||||
~sgAutoPtr ();
|
||||
sgAutoPtr < T > & operator = ( T * );
|
||||
T * operator -> ();
|
||||
T & operator * ();
|
||||
T * get ();
|
||||
T * release ();
|
||||
private:
|
||||
T * pNotify;
|
||||
struct CASG & sg;
|
||||
epicsGuard < epicsMutex > & guard;
|
||||
sgAutoPtr & operator = ( const sgAutoPtr & );
|
||||
};
|
||||
|
||||
template < class T >
|
||||
inline sgAutoPtr < T > :: sgAutoPtr (
|
||||
epicsGuard < epicsMutex > & guardIn, struct CASG & sgIn ) :
|
||||
pNotify ( 0 ), sg ( sgIn ), guard ( guardIn )
|
||||
{
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline sgAutoPtr < T > :: ~sgAutoPtr ()
|
||||
{
|
||||
if ( this->pNotify ) {
|
||||
this->sg.ioPendingList.remove ( *this->pNotify );
|
||||
this->sg.client.
|
||||
whenThereIsAnExceptionDestroySyncGroupIO ( this->guard, *this->pNotify );
|
||||
}
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline sgAutoPtr < T > & sgAutoPtr < T > :: operator = ( T * pNotifyIn )
|
||||
{
|
||||
if ( this->pNotify ) {
|
||||
this->sg.ioPendingList.remove ( *this->pNotify );
|
||||
this->sg.client.
|
||||
whenThereIsAnExceptionDestroySyncGroupIO ( this->guard, *this->pNotify );
|
||||
}
|
||||
this->pNotify = pNotifyIn;
|
||||
this->sg.ioPendingList.add ( *this->pNotify );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * sgAutoPtr < T > :: operator -> ()
|
||||
{
|
||||
return this->pNotify;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T & sgAutoPtr < T > :: operator * ()
|
||||
{
|
||||
assert ( this->pNotify );
|
||||
return * this->pNotify;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * sgAutoPtr < T > :: release ()
|
||||
{
|
||||
T * pTmp = this->pNotify;
|
||||
this->pNotify = 0;
|
||||
return pTmp;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * sgAutoPtr < T > :: get ()
|
||||
{
|
||||
return this->pNotify;
|
||||
}
|
||||
|
||||
#endif // sgAutoPtrh
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user