major revisions

This commit is contained in:
Jeff Hill
2000-04-28 01:29:00 +00:00
parent 68c049fa73
commit 547f1b15fa
56 changed files with 8019 additions and 7241 deletions

213
src/ca/CASG.cpp Normal file
View File

@@ -0,0 +1,213 @@
/*
* $Id$
* Author: Jeffrey O. Hill
* hill@luke.lanl.gov
* (505) 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*/
#include "iocinf.h"
#include "oldAccess.h"
tsFreeList < struct CASG > CASG::freeList;
CASG::CASG (cac &cacIn) :
client (cacIn), magic (CASG_MAGIC), opPendCount (0u), seqNo (0u)
{
client.installCASG ( *this );
}
void CASG::destroy ()
{
delete this;
}
CASG::~CASG ()
{
if ( this->verify () ) {
this->mutex.lock ();
tsDLIterBD <syncGroupNotify> notify ( this->ioList.first () );
while ( notify != notify.eol () ) {
notify->destroy ();
notify = this->ioList.first ();
}
this->mutex.unlock ();
this->client.uninstallCASG ( *this );
this->magic = 0;
}
else {
ca_printf ("cac: attempt to destroy invalid sync group ignored\n");
}
}
bool CASG::verify () const
{
return ( this->magic == CASG_MAGIC );
}
/*
* CASG::block ()
*/
int CASG::block ( double timeout )
{
unsigned long initialSeqNo = this->seqNo;
osiTime cur_time;
osiTime beg_time;
double delay;
double remaining;
int status;
if ( timeout < 0.0 ) {
return ECA_TIMEOUT;
}
/*
* dont allow recursion
*/
void *p = threadPrivateGet (cacRecursionLock);
if ( p ) {
return ECA_EVDISALLOW;
}
threadPrivateSet (cacRecursionLock, &cacRecursionLock);
cur_time = osiTime::getCurrent ();
this->client.flush ();
beg_time = cur_time;
delay = 0.0;
status = ECA_NORMAL;
while ( 1 ) {
this->mutex.lock ();
if ( this->seqNo != initialSeqNo ) {
this->mutex.unlock ();
break;
}
if ( this->opPendCount == 0u ) {
this->seqNo++;
this->mutex.unlock ();
break;
}
this->mutex.unlock ();
/*
* Exit if the timeout has expired
* (dont wait forever for an itsy bitsy
* delay which will not be updated if
* select is called with no delay)
*
* current time is only updated by
* cac_select_io() if we specify
* at non-zero delay
*/
remaining = timeout - delay;
if ( remaining <= CAC_SIGNIFICANT_SELECT_DELAY ) {
/*
* Make sure that we take care of
* recv backlog at least once
*/
status = ECA_TIMEOUT;
this->mutex.lock ();
this->seqNo++;
this->mutex.unlock ();
break;
}
remaining = min ( 60.0, remaining );
/*
* wait for asynch notification
*/
this->sem.wait ( remaining );
/*
* force a time update
*/
cur_time = osiTime::getCurrent ();
delay = cur_time - beg_time;
}
threadPrivateSet (cacRecursionLock, NULL);
return status;
}
void CASG::reset ()
{
this->mutex.lock ();
this->opPendCount = 0;
this->seqNo++;
this->mutex.unlock ();
}
void CASG::show ( unsigned level) const
{
printf ("Sync Group: id=%u, magic=%lu, opPend=%lu, seqNo=%lu\n",
this->getId (), this->magic, this->opPendCount, this->seqNo);
if ( level ) {
this->mutex.lock ();
tsDLIterBD <syncGroupNotify> notify ( this->ioList.first () );
while ( notify != notify.eol () ) {
notify->show (level);
}
this->mutex.unlock ();
}
}
bool CASG::ioComplete () const
{
return ( this->opPendCount == 0u );
}
void * CASG::operator new (size_t size)
{
return CASG::freeList.allocate ( size );
}
void CASG::operator delete (void *pCadaver, size_t size)
{
CASG::freeList.release ( pCadaver, size );
}
int CASG::put (chid pChan, unsigned type, unsigned long count, const void *pValue)
{
syncGroupNotify *pNotify = new syncGroupNotify ( *this, 0);
if ( ! pNotify ) {
return ECA_ALLOCMEM;
}
return pChan->write ( type, count, pValue, *pNotify );
}
int CASG::get (chid pChan, unsigned type, unsigned long count, void *pValue)
{
syncGroupNotify *pNotify = new syncGroupNotify ( *this, pValue);
if ( ! pNotify ) {
return ECA_ALLOCMEM;
}
return pChan->read ( type, count, *pNotify );
}

View File

@@ -3,8 +3,6 @@ TOP=../..
include $(TOP)/configure/CONFIG
CMPLR = STRICT
#
# includes to install from this subproject
#
@@ -14,22 +12,46 @@ INC += caeventmask.h
INC += caProto.h
INC += db_access.h
INC += pvAdapter.h
INC += addrList.h
INC += cacIO.h
#LIBSRCS += caOsDependent.c
LIBSRCS += cacChannel.cpp
LIBSRCS += cacChannelIO.cpp
LIBSRCS += cacNotify.cpp
LIBSRCS += cacNotifyIO.cpp
LIBSRCS += cacServiceList.cpp
LIBSRCS += access.cpp
LIBSRCS += processThread.cpp
LIBSRCS += iocinf.cpp
LIBSRCS += service.cpp
LIBSRCS += conn.cpp
LIBSRCS += flow_control.cpp
LIBSRCS += syncgrp.cpp
LIBSRCS += convert.cpp
LIBSRCS += test_event.cpp
#LIBSRCS += bsd_depen.c
LIBSRCS += repeater.cpp
LIBSRCS += ringBuffer.cpp
LIBSRCS += searchTimer.cpp
LIBSRCS += repeaterSubscribeTimer.cpp
LIBSRCS += tcpiiu.cpp
LIBSRCS += udpiiu.cpp
LIBSRCS += netiiu.cpp
LIBSRCS += nciu.cpp
LIBSRCS += baseNMIU.cpp
LIBSRCS += netReadCopyIO.cpp
LIBSRCS += netReadNotifyIO.cpp
LIBSRCS += netWriteNotifyIO.cpp
LIBSRCS += netSubscription.cpp
LIBSRCS += cac.cpp
LIBSRCS += conn.cpp
LIBSRCS += tcpSendWatchdog.cpp
LIBSRCS += tcpRecvWatchdog.cpp
LIBSRCS += bhe.cpp
LIBSRCS += oldChannel.cpp
LIBSRCS += oldSubscription.cpp
LIBSRCS += getCallback.cpp
LIBSRCS += putCallback.cpp
LIBSRCS += syncgrp.cpp
LIBSRCS += CASG.cpp
LIBSRCS += syncGroupNotify.cpp
LIBRARY=ca
@@ -53,8 +75,8 @@ caRepeater_SRCS = caRepeater.cpp
PROD += caRepeater
PROD += catime acctst
catime_SRCS = catime.c
acctst_SRCS = acctst.c
catime_SRCS = catimeMain.c catime.c
acctst_SRCS = acctstMain.c acctst.c
include $(TOP)/configure/RULES

View File

@@ -2,8 +2,6 @@
TOP=../..
include $(TOP)/configure/CONFIG
CMPLR = STRICT
#
# includes to install from this subproject
#

View File

@@ -3,8 +3,6 @@ TOP=../..
include $(TOP)/configure/CONFIG
CMPLR = STRICT
USR_CFLAGS += -DiocCore
caLib_SRCS += caOsDependent.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,8 @@
/*
* CA test/debug routine
* CA regression test
*/
static char *sccsId = "@(#) $Id$";
/*
* ANSI
*/
@@ -25,6 +23,8 @@ static char *sccsId = "@(#) $Id$";
*/
#include "cadef.h"
#include "caDiagnostics.h"
#define EVENT_ROUTINE null_event
#define CONN_ROUTINE conn
@@ -78,7 +78,7 @@ void performGrEnumTest (chid chan);
void performCtrlDoubleTest (chid chan);
int acctst(char *pname)
int acctst (char *pname)
{
chid chix1;
chid chix2;
@@ -198,63 +198,63 @@ int acctst(char *pname)
* look for problems with ca_search(), ca_clear_channel(),
* ca_change_connection_event(), and ca_pend_io(() combo
*/
status = ca_search(pname,& chix3);
SEVCHK(status, NULL);
status = ca_search ( pname,& chix3 );
SEVCHK ( status, NULL );
status = ca_replace_access_rights_event(chix3, accessSecurity_cb);
SEVCHK(status, NULL);
status = ca_replace_access_rights_event ( chix3, accessSecurity_cb );
SEVCHK ( status, NULL );
/*
* verify clear before connect
*/
status = ca_search(pname, &chix4);
SEVCHK(status, NULL);
status = ca_search ( pname, &chix4 );
SEVCHK ( status, NULL );
status = ca_clear_channel(chix4);
SEVCHK(status, NULL);
status = ca_clear_channel ( chix4 );
SEVCHK ( status, NULL );
status = ca_search(pname, &chix4);
SEVCHK(status, NULL);
status = ca_search ( pname, &chix4 );
SEVCHK ( status, NULL );
status = ca_replace_access_rights_event(chix4, accessSecurity_cb);
SEVCHK(status, NULL);
status = ca_replace_access_rights_event ( chix4, accessSecurity_cb );
SEVCHK ( status, NULL );
status = ca_search(pname, &chix2);
SEVCHK(status, NULL);
status = ca_search ( pname, &chix2 );
SEVCHK (status, NULL);
status = ca_replace_access_rights_event(chix2, accessSecurity_cb);
SEVCHK(status, NULL);
status = ca_replace_access_rights_event (chix2, accessSecurity_cb);
SEVCHK ( status, NULL );
status = ca_search(pname, &chix1);
SEVCHK(status, NULL);
status = ca_search ( pname, &chix1 );
SEVCHK ( status, NULL );
status = ca_replace_access_rights_event(chix1, accessSecurity_cb);
SEVCHK(status, NULL);
status = ca_replace_access_rights_event ( chix1, accessSecurity_cb );
SEVCHK ( status, NULL );
status = ca_change_connection_event(chix1,conn);
SEVCHK(status, NULL);
status = ca_change_connection_event ( chix1, conn );
SEVCHK ( status, NULL );
status = ca_change_connection_event(chix1,NULL);
SEVCHK(status, NULL);
status = ca_change_connection_event ( chix1, NULL );
SEVCHK ( status, NULL );
status = ca_change_connection_event(chix1,conn);
SEVCHK(status, NULL);
status = ca_change_connection_event ( chix1, conn );
SEVCHK ( status, NULL );
status = ca_change_connection_event(chix1,NULL);
SEVCHK(status, NULL);
status = ca_change_connection_event ( chix1, NULL );
SEVCHK ( status, NULL );
status = ca_pend_io(1000.0);
SEVCHK(status, NULL);
status = ca_pend_io ( 1000.0 );
SEVCHK ( status, NULL );
assert (ca_state(chix1) == cs_conn);
assert (ca_state(chix2) == cs_conn);
assert (ca_state(chix3) == cs_conn);
assert (ca_state(chix4) == cs_conn);
assert ( ca_state (chix1) == cs_conn );
assert ( ca_state (chix2) == cs_conn );
assert ( ca_state (chix3) == cs_conn );
assert ( ca_state (chix4) == cs_conn );
assert (INVALID_DB_REQ(ca_field_type(chix1)) == FALSE);
assert (INVALID_DB_REQ(ca_field_type(chix2)) == FALSE);
assert (INVALID_DB_REQ(ca_field_type(chix3)) == FALSE);
assert (INVALID_DB_REQ(ca_field_type(chix4)) == FALSE);
assert ( INVALID_DB_REQ (ca_field_type (chix1) ) == FALSE );
assert ( INVALID_DB_REQ (ca_field_type (chix2) ) == FALSE );
assert ( INVALID_DB_REQ (ca_field_type (chix3) ) == FALSE );
assert ( INVALID_DB_REQ (ca_field_type (chix4) ) == FALSE );
printf("%s Read Access=%d Write Access=%d\n",
ca_name(chix1), ca_read_access(chix1), ca_write_access(chix1));
@@ -446,7 +446,7 @@ int acctst(char *pname)
else {
iter = 10ul;
}
floatTest(chix1, base, incr, epsil, iter);
floatTest (chix1, base, incr, epsil, iter);
printf (".");
fflush (stdout);
}
@@ -647,7 +647,7 @@ int acctst(char *pname)
dbr_string_t respStr;
memset(stimStr, 'a', sizeof(stimStr));
status = ca_array_put(DBR_STRING, 1u, chix1, stimStr);
assert(status==ECA_STRTOBIG);
assert(status!=ECA_NORMAL);
sprintf(stimStr, "%u", 8u);
status = ca_array_put(DBR_STRING, 1u, chix1, stimStr);
assert(status==ECA_NORMAL);
@@ -898,19 +898,6 @@ int acctst(char *pname)
return(0);
}
#ifndef iocCore
int main(int argc, char **argv)
{
if(argc == 2){
acctst(argv[1]);
}
else{
printf("usage: %s <chan name>\n", argv[0]);
}
return 0;
}
#endif /*iocCore */
/*
* pend_event_delay_test()
*/
@@ -957,7 +944,7 @@ unsigned iterations)
SEVCHK (status, NULL);
status = ca_get (DBR_FLOAT, chan, &fretval);
SEVCHK (status, NULL);
status = ca_pend_io (100.0);
status = ca_pend_io (10.0);
SEVCHK (status, NULL);
if (fabs(fval-fretval) > epsilon) {
printf ("float test failed val written %f\n", fval);
@@ -1038,7 +1025,7 @@ void null_event (struct event_handler_args args)
/*
* write_event ()
*/
void write_event(struct event_handler_args args)
void write_event (struct event_handler_args args)
{
int status;
dbr_float_t *pFloat = (dbr_float_t *) args.dbr;
@@ -1051,35 +1038,44 @@ void write_event(struct event_handler_args args)
a = *pFloat;
a += 10.1F;
status = ca_array_put(
DBR_FLOAT,
1,
args.chid,
&a);
SEVCHK(status,NULL);
SEVCHK(ca_flush_io(), NULL);
status = ca_array_put ( DBR_FLOAT, 1, args.chid, &a);
SEVCHK ( status, NULL );
SEVCHK ( ca_flush_io (), NULL );
}
void conn(struct connection_handler_args args)
void conn (struct connection_handler_args args)
{
#if 0
if (args.op == CA_OP_CONN_UP)
printf("Channel On Line [%s]\n", ca_name(args.chid));
else if (args.op == CA_OP_CONN_DOWN)
printf("Channel Off Line [%s]\n", ca_name(args.chid));
else
int status;
if (args.op == CA_OP_CONN_UP) {
# if 0
printf("Channel On Line [%s]\n", ca_name(args.chid));
# endif
status = ca_get_callback (DBR_GR_FLOAT, args.chid, get_cb, NULL);
SEVCHK (status, "get call back in connection handler");
status = ca_flush_io ();
SEVCHK (status, "get call back flush in connection handler");
}
else if (args.op == CA_OP_CONN_DOWN) {
# if 0
printf("Channel Off Line [%s]\n", ca_name(args.chid));
# endif
}
else {
printf("Ukn conn ev\n");
#endif
ca_get_callback(DBR_GR_FLOAT, args.chid, get_cb, NULL);
}
}
void get_cb (struct event_handler_args args)
{
if(!(args.status & CA_M_SUCCESS)){
if ( ! ( args.status & CA_M_SUCCESS ) ) {
printf("Get cb failed because \"%s\"\n",
ca_message(args.status));
ca_message (args.status) );
}
else {
conn_cb_count++;
}
conn_cb_count++;
}
/*
@@ -1167,7 +1163,6 @@ void multiple_sg_requests(chid chix, CA_SYNC_GID gid)
}
}
/*
* accessSecurity_cb()
*/
@@ -1192,20 +1187,21 @@ void performGrEnumTest (chid chan)
int status;
unsigned i;
ge.no_str = -1;
status = ca_get (DBR_GR_ENUM, chan, &ge);
SEVCHK (status, "DBR_GR_ENUM ca_get()");
status = ca_pend_io (2.0);
assert (status == ECA_NORMAL);
if (ge.no_str>0) {
count = (unsigned) ge.no_str;
printf ("Enum state str = ");
for (i=0; i<count; i++) {
printf ("\"%s\" ", ge.strs[i]);
}
printf ("\n");
assert ( ge.no_str >= 0 && ge.no_str < NELEMENTS(ge.strs) );
printf ("Enum state str = {");
count = (unsigned) ge.no_str;
for (i=0; i<count; i++) {
printf ("\"%s\" ", ge.strs[i]);
}
printf ("}\n");
}
/*

15
src/ca/acctstMain.c Normal file
View File

@@ -0,0 +1,15 @@
#include <stdio.h>
#include "caDiagnostics.h"
int main(int argc, char **argv)
{
if(argc == 2){
acctst(argv[1]);
}
else{
printf("usage: %s <chan name>\n", argv[0]);
}
return 0;
}

View File

@@ -12,7 +12,10 @@ epicsShareFunc void epicsShareAPI configureChannelAccessAddressList
epicsShareFunc void epicsShareAPI addAddrToChannelAccessAddressList
(ELLLIST *pList, const ENV_PARAM *pEnv, unsigned short port);
epicsShareFunc void epicsShareAPI printChannelAccessAddressList (ELLLIST *pList);
epicsShareFunc void epicsShareAPI printChannelAccessAddressList (const ELLLIST *pList);
epicsShareFunc void epicsShareAPI setPortAndRemoveDuplicates
(ELLLIST *pDestList, ELLLIST *pSrcList, unsigned short port);
#ifdef __cplusplus
}

33
src/ca/baseNMIU.cpp Normal file
View File

@@ -0,0 +1,33 @@
/* $Id$
*
* 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
*/
#include "iocinf.h"
baseNMIU::baseNMIU ( nciu &chanIn ) : chan (chanIn)
{
this->chan.installIO ( *this );
}
void baseNMIU::destroy ()
{
delete this;
}
baseNMIU::~baseNMIU ()
{
this->chan.uninstallIO ( *this );
}
int baseNMIU::subscriptionMsg ()
{
return ECA_NORMAL;
}

177
src/ca/bhe.cpp Normal file
View File

@@ -0,0 +1,177 @@
/* $Id$
*
* 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"
tsFreeList < class bhe > bhe::freeList;
/*
* update beacon period
*
* updates beacon period, and looks for beacon anomalies
*/
bool bhe::updateBeaconPeriod (osiTime programBeginTime)
{
double currentPeriod;
bool netChange = false;
osiTime current = osiTime::getCurrent ();
if ( this->timeStamp == osiTime () ) {
/*
* 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 = current;
/*
* be careful about using beacons to reset the connection
* time out watchdog until we have received a ping response
* from the IOC (this makes the software detect reconnects
* faster when the server is rebooted twice in rapid
* succession before a 1st or 2nd beacon has been received)
*/
if (this->piiu) {
this->piiu->beaconAnomaly = TRUE;
}
return netChange;
}
/*
* compute the beacon period (if we have seen at least two beacons)
*/
currentPeriod = current - this->timeStamp;
if ( this->averagePeriod < 0.0 ) {
ca_real totalRunningTime;
/*
* 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;
/*
* be careful about using beacons to reset the connection
* time out watchdog until we have received a ping response
* from the IOC (this makes the software detect reconnects
* faster when the server is rebooted twice in rapid
* succession before a 2nd beacon has been received)
*/
if (this->piiu) {
this->piiu->beaconAnomaly = TRUE;
}
/*
* 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;
# ifdef DEBUG
{
char name[64];
ipAddrToA ( &this->inetAddr, name, sizeof (name) );
ca_printf (
"new beacon from %s with period=%f running time to first beacon=%f\n",
name, currentPeriod, totalRunningTime );
}
# endif
}
}
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 ) {
if ( this->piiu ) {
/*
* trigger on any missing beacon
* if connected to this server
*/
this->piiu->beaconAnomaly = true;
}
if ( currentPeriod >= this->averagePeriod * 3.25 ) {
/*
* trigger on any 3 contiguous missing beacons
* if not connected to this server
*/
netChange = true;
}
}
# ifdef DEBUG
if (netChange) {
char name[64];
ipAddrToA (&pBHE->inetAddr, name, sizeof(name));
ca_printf (
"net resume seen %s cur=%f avg=%f\n",
name, currentPeriod, pBHE->averagePeriod);
}
# endif
/*
* 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
*/
if ( currentPeriod <= this->averagePeriod * 0.80 ) {
# ifdef DEBUG
{
char name[64];
ipAddrToA ( &this->inetAddr, name, sizeof (name) );
ca_printf (
"reboot seen %s cur=%f avg=%f\n",
name, currentPeriod, this->averagePeriod);
}
# endif
netChange = true;
if ( this->piiu ) {
this->piiu->beaconAnomaly = true;
}
}
/*
* update a running average period
*/
this->averagePeriod = currentPeriod * 0.125 + this->averagePeriod * 0.875;
}
this->timeStamp = current;
return netChange;
}

70
src/ca/bhe_IL.h Normal file
View File

@@ -0,0 +1,70 @@
/*
* $Id$
*
* 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
*/
/*
* 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)
*/
inline bhe::bhe (class cac &cacIn, const osiTime &initialTimeStamp, const inetAddrID &addr) :
cac (cacIn), inetAddrID (addr), piiu (0), timeStamp (initialTimeStamp), averagePeriod (-1.0)
{
# ifdef DEBUG
{
char name[64];
ipAddrToA (&addr, name, sizeof(name));
printf ("created beacon entry for %s\n", name);
}
# endif
}
inline bhe::~bhe ()
{
this->cac.removeBeaconInetAddr (*this);
}
inline void * bhe::operator new ( size_t size )
{
return bhe::freeList.allocate ( size );
}
inline void bhe::operator delete ( void *pCadaver, size_t size )
{
bhe::freeList.release ( pCadaver, size );
}
inline tcpiiu *bhe::getIIU ()const
{
return this->piiu;
}
inline void bhe::bindToIIU (tcpiiu *piiuIn)
{
assert ( this->piiu == 0 );
this->piiu = piiuIn;
}
inline void bhe::destroy ()
{
delete this;
}

6
src/ca/caDiagnostics.h Normal file
View File

@@ -0,0 +1,6 @@
enum appendNumberFlag {appendNumber, dontAppendNumber};
int catime (char *channelName, enum appendNumberFlag appNF);
int acctst (char *pname);

View File

@@ -22,7 +22,7 @@ LOCAL void caExtraEventLabor (void *pArg)
*/
semStatus = semMutexTakeTimeout (pcac->localIIU.putNotifyLock, 60.0 /* sec */);
if (semStatus!=semTakeOK) {
ca_printf (pcac, "cac: put notify deadlock condition detected\n");
ca_printf ("cac: put notify deadlock condition detected\n");
(*pcac->localIIU.pdbAdapter->p_db_post_extra_labor) (pcac->localIIU.evctx);
break;
}

816
src/ca/cac.cpp Normal file
View File

@@ -0,0 +1,816 @@
/* $Id$
*
* 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 "osiProcess.h"
#include "osiSigPipeIgnore.h"
#include "iocinf.h"
#include "inetAddrID_IL.h"
#include "bhe_IL.h"
//
// cac::cac ()
//
cac::cac () :
beaconTable (1024),
endOfBCastList (0),
ioTable (1024),
chanTable (1024),
sgTable (128),
pndrecvcnt (0)
{
long status;
if ( cacRecursionLock == NULL ) {
cacRecursionLock = threadPrivateCreate ();
if ( ! cacRecursionLock ) {
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
}
}
if (!bsdSockAttach()) {
throwWithLocation ( caErrorCode (ECA_INTERNAL) );
}
ellInit (&this->ca_taskVarList);
ellInit (&this->putCvrtBuf);
ellInit (&this->fdInfoFreeList);
ellInit (&this->fdInfoList);
this->ca_printf_func = errlogVprintf;
this->pudpiiu = NULL;
this->ca_exception_func = ca_default_exception_handler;
this->ca_exception_arg = NULL;
this->ca_fd_register_func = NULL;
this->ca_fd_register_arg = NULL;
this->ca_flush_pending = FALSE;
this->ca_number_iiu_in_fc = 0u;
this->ca_manage_conn_active = FALSE;
this->readSeq = 0u;
this->ca_client_lock = semMutexCreate();
if (!this->ca_client_lock) {
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
}
this->ca_io_done_sem = semBinaryCreate(semEmpty);
if (!this->ca_io_done_sem) {
semMutexDestroy (this->ca_client_lock);
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
}
this->ca_blockSem = semBinaryCreate(semEmpty);
if (!this->ca_blockSem) {
semMutexDestroy (this->ca_client_lock);
semBinaryDestroy (this->ca_io_done_sem);
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
}
installSigPipeIgnore ();
{
char tmp[256];
size_t len;
osiGetUserNameReturn gunRet;
gunRet = osiGetUserName ( tmp, sizeof (tmp) );
if (gunRet!=osiGetUserNameSuccess) {
tmp[0] = '\0';
}
len = strlen (tmp) + 1;
this->ca_pUserName = (char *) malloc ( len );
if ( ! this->ca_pUserName ) {
semMutexDestroy (this->ca_client_lock);
semBinaryDestroy (this->ca_io_done_sem);
semBinaryDestroy (this->ca_blockSem);
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
}
strncpy (this->ca_pUserName, tmp, len);
}
/* record the host name */
this->ca_pHostName = localHostName();
if (!this->ca_pHostName) {
semMutexDestroy (this->ca_client_lock);
semBinaryDestroy (this->ca_io_done_sem);
semBinaryDestroy (this->ca_blockSem);
free (this->ca_pUserName);
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
}
this->programBeginTime = osiTime::getCurrent ();
status = envGetDoubleConfigParam (&EPICS_CA_CONN_TMO, &this->ca_connectTMO);
if (status) {
this->ca_connectTMO = CA_CONN_VERIFY_PERIOD;
ca_printf (
"EPICS \"%s\" float fetch failed\n",
EPICS_CA_CONN_TMO.name);
ca_printf (
"Setting \"%s\" = %f\n",
EPICS_CA_CONN_TMO.name,
this->ca_connectTMO);
}
this->ca_server_port =
envGetInetPortConfigParam (&EPICS_CA_SERVER_PORT, CA_SERVER_PORT);
this->pProcThread = new processThread (this);
if ( ! this->pProcThread ) {
semMutexDestroy (this->ca_client_lock);
semBinaryDestroy (this->ca_io_done_sem);
semBinaryDestroy (this->ca_blockSem);
free (this->ca_pUserName);
free (this->ca_pHostName);
throwWithLocation ( caErrorCode (ECA_ALLOCMEM) );
}
threadPrivateSet (caClientContextId, (void *) this);
}
/*
* cac::~cac ()
*
* releases all resources alloc to a channel access client
*/
cac::~cac ()
{
threadPrivateSet (caClientContextId, NULL);
//
// make certain that process thread isnt deleting
// tcpiiu objects at the same that this thread is
//
delete this->pProcThread;
//
// shutdown all tcp connections and wait for threads to exit
//
this->iiuListLock.lock ();
tsDLIterBD <tcpiiu> piiu ( this->iiuListIdle.first () );
while ( piiu != piiu.eol () ) {
tsDLIterBD <tcpiiu> pnext = piiu.itemAfter ();
piiu->suicide ();
piiu = pnext;
}
piiu = this->iiuListRecvPending.first ();
while ( piiu != piiu.eol () ) {
tsDLIterBD <tcpiiu> pnext = piiu.itemAfter ();
piiu->suicide ();
piiu = pnext;
}
this->iiuListLock.unlock ();
//
// shutdown udp and wait for threads to exit
//
if (this->pudpiiu) {
delete this->pudpiiu;
}
LOCK (this);
/* remove put convert block free list */
ellFree (&this->putCvrtBuf);
/* reclaim sync group resources */
this->sgTable.destroyAllEntries ();
/* free select context lists */
ellFree (&this->fdInfoFreeList);
ellFree (&this->fdInfoList);
/*
* free user name string
*/
if (this->ca_pUserName) {
free (this->ca_pUserName);
}
/*
* free host name string
*/
if (this->ca_pHostName) {
free (this->ca_pHostName);
}
this->beaconTable.destroyAllEntries ();
semBinaryDestroy (this->ca_io_done_sem);
semBinaryDestroy (this->ca_blockSem);
semMutexDestroy (this->ca_client_lock);
bsdSockRelease ();
}
void cac::safeDestroyNMIU (unsigned id)
{
LOCK (this);
baseNMIU *pIOBlock = this->ioTable.lookup (id);
if (pIOBlock) {
pIOBlock->destroy ();
}
UNLOCK (this);
}
void cac::processRecvBacklog ()
{
tcpiiu *piiu;
while ( 1 ) {
int status;
unsigned bytesToProcess;
this->iiuListLock.lock ();
piiu = this->iiuListRecvPending.get ();
if (!piiu) {
this->iiuListLock.unlock ();
break;
}
piiu->recvPending = false;
this->iiuListIdle.add (*piiu);
this->iiuListLock.unlock ();
if (piiu->state == iiu_disconnected) {
delete piiu;
continue;
}
char *pProto = (char *) cacRingBufferReadReserveNoBlock
(&piiu->recv, &bytesToProcess);
while (pProto) {
status = piiu->post_msg (pProto, bytesToProcess);
if ( status == ECA_NORMAL ) {
cacRingBufferReadCommit (&piiu->recv, bytesToProcess);
cacRingBufferReadFlush (&piiu->recv);
}
else {
delete piiu;
}
pProto = (char *) cacRingBufferReadReserveNoBlock
(&piiu->recv, &bytesToProcess);
}
}
}
/*
* cac::flush ()
*/
void cac::flush ()
{
/*
* set the push pending flag on all virtual circuits
*/
this->iiuListLock.lock ();
tsDLIterBD<tcpiiu> piiu ( this->iiuListIdle.first () );
while ( piiu != tsDLIterBD<tcpiiu>::eol () ) {
piiu->flush ();
piiu++;
}
piiu = this->iiuListRecvPending.first ();
while ( piiu != tsDLIterBD<tcpiiu>::eol () ) {
piiu->flush ();
piiu++;
}
this->iiuListLock.unlock ();
}
/*
*
* set pending IO count back to zero and
* send a sync to each IOC and back. dont
* count reads until we recv the sync
*
*/
void cac::cleanUpPendIO ()
{
nciu *pchan;
LOCK (this);
this->readSeq++;
this->pndrecvcnt = 0u;
tsDLIter <nciu> iter ( this->pudpiiu->chidList );
while ( ( pchan = iter () ) ) {
pchan->connectTimeoutNotify ();
}
UNLOCK (this);
}
unsigned cac::connectionCount () const
{
unsigned count;
this->iiuListLock.lock ();
count = this->iiuListIdle.count () + this->iiuListRecvPending.count ();
this->iiuListLock.unlock ();
return count;
}
void cac::show (unsigned level) const
{
LOCK (this);
if (this->pudpiiu) {
this->pudpiiu->show (level);
}
this->iiuListLock.lock ();
tsDLIterConstBD <tcpiiu> piiu ( this->iiuListIdle.first () );
while ( piiu != piiu.eol () ) {
piiu->show (level);
piiu++;
}
piiu = this->iiuListRecvPending.first ();
while ( piiu != piiu.eol () ) {
piiu->show (level);
piiu++;
}
this->iiuListLock.unlock ();
UNLOCK (this);
}
void cac::installIIU (tcpiiu &iiu)
{
this->iiuListLock.lock ();
iiu.recvPending = false;
this->iiuListIdle.add (iiu);
this->iiuListLock.unlock ();
if (this->ca_fd_register_func) {
( * this->ca_fd_register_func ) ( (void *) this->ca_fd_register_arg, iiu.sock, TRUE);
}
}
void cac::signalRecvActivityIIU (tcpiiu &iiu)
{
bool change;
this->iiuListLock.lock ();
if ( iiu.recvPending ) {
change = false;
}
else {
this->iiuListIdle.remove (iiu);
this->iiuListRecvPending.add (iiu);
iiu.recvPending = true;
change = true;
}
this->iiuListLock.unlock ();
//
// wakeup after unlock improves performance
//
if (change) {
this->recvActivity.signal ();
}
}
void cac::removeIIU (tcpiiu &iiu)
{
this->iiuListLock.lock ();
if (iiu.recvPending) {
this->iiuListRecvPending.remove (iiu);
}
else {
this->iiuListIdle.remove (iiu);
}
this->iiuListLock.unlock ();
}
/*
* cac::lookupBeaconInetAddr()
*
* LOCK must be applied
*/
bhe * cac::lookupBeaconInetAddr (const inetAddrID &ina)
{
bhe *pBHE;
LOCK (this);
pBHE = this->beaconTable.lookup (ina);
UNLOCK (this);
return pBHE;
}
/*
* cac::createBeaconHashEntry ()
*/
bhe *cac::createBeaconHashEntry (const inetAddrID &ina, const osiTime &initialTimeStamp)
{
bhe *pBHE;
LOCK (this);
pBHE = this->beaconTable.lookup ( ina );
if ( !pBHE ) {
pBHE = new bhe (*this, initialTimeStamp, ina);
if ( pBHE ) {
if ( this->beaconTable.add (*pBHE) < 0 ) {
pBHE->destroy ();
pBHE = 0;
}
}
}
UNLOCK (this);
return pBHE;
}
/*
* cac::beaconNotify
*/
void cac::beaconNotify ( const inetAddrID &addr )
{
bhe *pBHE;
unsigned port;
int netChange;
if ( ! this->pudpiiu ) {
return;
}
LOCK ( this );
/*
* look for it in the hash table
*/
pBHE = this->lookupBeaconInetAddr ( addr );
if (pBHE) {
netChange = pBHE->updateBeaconPeriod (this->programBeginTime);
/*
* update state of health for active virtual circuits
* (only if we are not suspicious about past beacon changes
* until the next echo reply)
*/
tcpiiu *piiu = pBHE->getIIU ();
if ( piiu ) {
if ( ! piiu->beaconAnomaly ) {
piiu->tcpRecvWatchdog::reschedule (); // reset connection activity watchdog
}
}
}
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)
*/
netChange = FALSE;
this->createBeaconHashEntry (addr, osiTime::getCurrent () );
}
if ( ! netChange ) {
UNLOCK (this);
return;
}
/*
* This part is needed when many machines
* have channels in a disconnected state that
* dont exist anywhere on the network. This insures
* that we dont have many CA clients synchronously
* flooding the network with broadcasts (and swamping
* out requests for valid channels).
*
* I fetch the local port number and use the low order bits
* as a pseudo random delay to prevent every one
* from replying at once.
*/
{
struct sockaddr_in saddr;
int saddr_length = sizeof(saddr);
int status;
status = getsockname ( this->pudpiiu->sock, (struct sockaddr *) &saddr,
&saddr_length);
assert ( status >= 0 );
port = ntohs ( saddr.sin_port );
}
{
ca_real delay;
delay = (port&CA_RECAST_PORT_MASK);
delay /= MSEC_PER_SEC;
delay += CA_RECAST_DELAY;
this->pudpiiu->searchTmr.reset ( delay );
}
/*
* set retry count of all disconnected channels
* to zero
*/
tsDLIterBD <nciu> iter ( this->pudpiiu->chidList.first () );
while ( iter != tsDLIterBD<nciu>::eol () ) {
iter->retry = 0u;
iter++;
}
UNLOCK ( this );
# if DEBUG
{
char buf[64];
ipAddrToA (pnet_addr, buf, sizeof (buf) );
printf ("new server available: %s\n", buf);
}
# endif
}
/*
* cac::removeBeaconInetAddr ()
*/
void cac::removeBeaconInetAddr (const inetAddrID &ina)
{
bhe *pBHE;
LOCK (this);
pBHE = this->beaconTable.remove ( ina );
UNLOCK (this);
assert (pBHE);
}
void cac::decrementOutstandingIO (unsigned seqNumber)
{
LOCK (this);
if ( this->readSeq == seqNumber ) {
if ( this->pndrecvcnt > 0u ) {
this->pndrecvcnt--;
}
}
UNLOCK (this);
if ( this->pndrecvcnt == 0u ) {
semBinaryGive (this->ca_io_done_sem);
}
}
void cac::decrementOutstandingIO ()
{
LOCK (this);
if ( this->pndrecvcnt > 0u ) {
this->pndrecvcnt--;
}
UNLOCK (this);
if ( this->pndrecvcnt == 0u ) {
semBinaryGive (this->ca_io_done_sem);
}
}
void cac::incrementOutstandingIO ()
{
LOCK (this);
if ( this->pndrecvcnt < UINT_MAX ) {
this->pndrecvcnt++;
}
UNLOCK (this);
}
unsigned cac::readSequence () const
{
return this->readSeq;
}
int cac::pend (double timeout, int early)
{
int status;
void *p;
/*
* dont allow recursion
*/
p = threadPrivateGet (cacRecursionLock);
if (p) {
return ECA_EVDISALLOW;
}
threadPrivateSet (cacRecursionLock, &cacRecursionLock);
status = this->pendPrivate (timeout, early);
threadPrivateSet (cacRecursionLock, NULL);
return status;
}
/*
* cac::pendPrivate ()
*/
int cac::pendPrivate (double timeout, int early)
{
osiTime cur_time;
osiTime beg_time;
double delay;
this->flush ();
if (this->pndrecvcnt==0u && early) {
return ECA_NORMAL;
}
if ( timeout < 0.0 ) {
if (early) {
this->cleanUpPendIO ();
}
return ECA_TIMEOUT;
}
beg_time = cur_time = osiTime::getCurrent ();
delay = 0.0;
while ( true ) {
ca_real remaining;
if ( timeout == 0.0 ) {
remaining = 60.0;
}
else{
remaining = timeout - delay;
remaining = min ( 60.0, remaining );
/*
* If we are not waiting for any significant delay
* then force the delay to zero so that we avoid
* scheduling delays (which can be substantial
* on some os)
*/
if ( remaining <= CAC_SIGNIFICANT_SELECT_DELAY ) {
if ( early ) {
this->cleanUpPendIO ();
}
return ECA_TIMEOUT;
}
}
/* recv occurs in another thread */
semBinaryTakeTimeout ( this->ca_io_done_sem, remaining );
if ( this->pndrecvcnt == 0 && early ) {
return ECA_NORMAL;
}
cur_time = osiTime::getCurrent ();
if ( timeout != 0.0 ) {
delay = cur_time - beg_time;
}
}
}
bool cac::ioComplete () const
{
if ( this->pndrecvcnt == 0u ) {
return true;
}
else{
return false;
}
}
void cac::installIO ( baseNMIU &io )
{
LOCK (this);
this->ioTable.add ( io );
UNLOCK (this);
}
void cac::uninstallIO ( baseNMIU &io )
{
LOCK (this);
this->ioTable.remove ( io );
UNLOCK (this);
}
baseNMIU * cac::lookupIO (unsigned id)
{
LOCK (this);
baseNMIU * pmiu = this->ioTable.lookup ( id );
UNLOCK (this);
return pmiu;
}
void cac::installChannel (nciu &chan)
{
LOCK (this);
this->chanTable.add ( chan );
UNLOCK (this);
}
void cac::uninstallChannel (nciu &chan)
{
LOCK (this);
this->chanTable.remove ( chan );
UNLOCK (this);
}
nciu * cac::lookupChan (unsigned id)
{
LOCK (this);
nciu * pchan = this->chanTable.lookup ( id );
UNLOCK (this);
return pchan;
}
void cac::installCASG (CASG &sg)
{
LOCK (this);
this->sgTable.add ( sg );
UNLOCK (this);
}
void cac::uninstallCASG (CASG &sg)
{
LOCK (this);
this->sgTable.remove ( sg );
UNLOCK (this);
}
CASG * cac::lookupCASG (unsigned id)
{
LOCK (this);
CASG * psg = this->sgTable.lookup ( id );
if ( psg ) {
if ( ! psg->verify () ) {
psg = 0;
}
}
UNLOCK (this);
return psg;
}
void cac::exceptionNotify (int status, const char *pContext,
const char *pFileName, unsigned lineNo)
{
ca_signal_with_file_and_lineno ( status, pContext, pFileName, lineNo );
}
void cac::exceptionNotify (int status, const char *pContext,
unsigned type, unsigned long count,
const char *pFileName, unsigned lineNo)
{
ca_signal_formated ( status, pFileName, lineNo, "%s type=%d count=%ld\n",
pContext, type, count );
}
void cac::registerService ( cacServiceIO &service )
{
this->services.registerService ( service );
}
bool cac::createChannel (const char *pName, cacChannel &chan)
{
if ( this->services.createChannel (pName, chan) ) {
return true;
}
if ( cacGlobalServiceList.createChannel (pName, chan) ) {
return true;
}
if ( ! this->pudpiiu ) {
this->pudpiiu = new udpiiu ( this );
if ( ! this->pudpiiu ) {
return false;
}
}
nciu *pNetChan = new nciu ( this, chan, pName );
if ( pNetChan ) {
if ( ! pNetChan->fullyConstructed () ) {
pNetChan->destroy ();
return false;
}
else {
return true;
}
}
else {
return false;
}
}

273
src/ca/cacChannel.cpp Normal file
View File

@@ -0,0 +1,273 @@
/*
* $Id$
*
*
* 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"
osiMutex cacChannel::defaultMutex;
cacChannel::cacChannel () : pChannelIO (0)
{
}
cacChannel::~cacChannel ()
{
if ( this->pChannelIO ) {
this->pChannelIO->destroy ();
}
}
void cacChannel::attachIO (cacChannelIO &io)
{
assert ( ! this->pChannelIO );
this->lock ();
this->pChannelIO = &io;
this->ioAttachNotify ();
this->unlock ();
}
int cacChannel::read ( unsigned type, unsigned long count, cacNotify & notify )
{
if ( this->pChannelIO ) {
return pChannelIO->read (type, count, notify);
}
else {
return ECA_DISCONNCHID;
}
}
int cacChannel::read ( unsigned type, unsigned long count, void *pValue )
{
if ( this->pChannelIO ) {
return pChannelIO->read (type, count, pValue);
}
else {
return ECA_DISCONNCHID;
}
}
int cacChannel::write (unsigned type, unsigned long count, const void *pvalue )
{
if ( this->pChannelIO ) {
return pChannelIO->write (type, count, pvalue);
}
else {
return ECA_DISCONNCHID;
}
}
int cacChannel::write (unsigned type, unsigned long count,
const void *pvalue, cacNotify & notify )
{
if ( this->pChannelIO ) {
return pChannelIO->write (type, count, pvalue, notify);
}
else {
return ECA_DISCONNCHID;
}
}
int cacChannel::subscribe ( unsigned type, unsigned long count,
unsigned mask, cacNotify &notify )
{
if ( this->pChannelIO ) {
return pChannelIO->subscribe (type, count, mask, notify);
}
else {
return ECA_DISCONNCHID;
}
}
void cacChannel::hostName ( char *pBuf, unsigned bufLength ) const
{
if ( bufLength ) {
if ( this->pChannelIO ) {
pChannelIO->hostName (pBuf, bufLength);
}
else {
strncpy ( pBuf, "<not connected>", bufLength );
pBuf[bufLength-1u] = '\0';
}
}
}
short cacChannel::nativeType () const
{
if ( this->pChannelIO ) {
return pChannelIO->nativeType ();
}
else {
return TYPENOTCONN;
}
}
unsigned long cacChannel::nativeElementCount () const
{
if ( this->pChannelIO ) {
return pChannelIO->nativeElementCount ();
}
else {
return 0ul;
}
}
channel_state cacChannel::state () const
{
if ( this->pChannelIO ) {
return pChannelIO->state ();
}
else {
return cs_never_conn;
}
}
bool cacChannel::readAccess () const
{
if ( this->pChannelIO ) {
caar ar = pChannelIO->accessRights ();
return ar.read_access;
}
else {
return false;
}
}
bool cacChannel::writeAccess () const
{
if ( this->pChannelIO ) {
caar ar = pChannelIO->accessRights ();
return ar.write_access;
}
else {
return false;
}
}
const char *cacChannel::pName () const
{
if ( this->pChannelIO ) {
return pChannelIO->pName ();
}
else {
return "<disconnected>";
}
}
unsigned cacChannel::searchAttempts () const
{
if ( this->pChannelIO ) {
return pChannelIO->searchAttempts ();
}
else {
return 0u;
}
}
bool cacChannel::ca_v42_ok () const
{
if ( this->pChannelIO ) {
return pChannelIO->ca_v42_ok ();
}
else {
return false;
}
}
bool cacChannel::connected () const
{
if ( this->pChannelIO ) {
return pChannelIO->connected ();
}
else {
return false;
}
}
caar cacChannel::accessRights () const
{
if ( this->pChannelIO ) {
return pChannelIO->accessRights ();
}
else {
caar ar;
ar.read_access = false;
ar.write_access = false;
return ar;
}
}
void cacChannel::ioAttachNotify ()
{
}
void cacChannel::ioReleaseNotify ()
{
}
void cacChannel::connectNotify ()
{
}
void cacChannel::disconnectNotify ()
{
}
void cacChannel::accessRightsNotify ( caar )
{
}
void cacChannel::exceptionNotify ( int status, const char *pContext )
{
ca_signal ( status, pContext );
}
void cacChannel::connectTimeoutNotify ()
{
}
void cacChannel::lock () const
{
this->defaultMutex.lock();
}
void cacChannel::unlock () const
{
this->defaultMutex.unlock();
}
unsigned cacChannel::readSequence () const
{
if ( this->pChannelIO ) {
return this->pChannelIO->readSequence ();
}
else {
return 0u;
}
}
void cacChannel::decrementOutstandingIO ()
{
if ( this->pChannelIO ) {
this->pChannelIO->decrementOutstandingIO ();
}
}
void cacChannel::incrementOutstandingIO ()
{
if ( this->pChannelIO ) {
this->pChannelIO->incrementOutstandingIO ();
}
}

100
src/ca/cacChannelIO.cpp Normal file
View File

@@ -0,0 +1,100 @@
/* $Id$
*
* 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"
cacChannelIO::cacChannelIO ( cacChannel &chanIn ) :
chan ( chanIn )
{
chan.attachIO ( *this );
}
cacChannelIO::~cacChannelIO ()
{
this->chan.lock ();
this->chan.ioReleaseNotify ();
this->chan.pChannelIO = 0;
this->chan.unlock ();
}
void cacChannelIO::connectNotify ()
{
this->chan.connectNotify ();
}
void cacChannelIO::disconnectNotify ()
{
this->chan.disconnectNotify ();
}
void cacChannelIO::connectTimeoutNotify ()
{
this->chan.connectTimeoutNotify ();
}
void cacChannelIO::accessRightsNotify ( caar ar )
{
this->chan.accessRightsNotify ( ar );
}
channel_state cacChannelIO::state () const
{
return cs_conn;
}
caar cacChannelIO::accessRights () const
{
caar ar;
ar.read_access = true;
ar.write_access = true;
return ar;
}
unsigned cacChannelIO::searchAttempts () const
{
return 0u;
}
bool cacChannelIO::ca_v42_ok () const
{
return true;
}
bool cacChannelIO::connected () const
{
return true;
}
unsigned cacChannelIO::readSequence () const
{
return 0u;
}
void cacChannelIO::hostName ( char *pBuf, unsigned bufLength ) const
{
if ( bufLength ) {
int status = gethostname ( pBuf, bufLength );
if ( status ) {
strncpy ( pBuf, "<unknown host>", bufLength );
pBuf[ bufLength - 1u ] = '\0';
}
}
}
void cacChannelIO::incrementOutstandingIO ()
{
}
void cacChannelIO::decrementOutstandingIO ()
{
}

107
src/ca/cacIO.h Normal file
View File

@@ -0,0 +1,107 @@
/*
* $Id$
*
*
* 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 "tsDLList.h"
#include "osiMutex.h"
#include "shareLib.h"
class cacChannel;
class cacNotifyIO;
class epicsShareClass cacNotify {
public:
cacNotify ();
virtual ~cacNotify () = 0;
virtual void destroy () = 0;
virtual void completionNotify ();
virtual void completionNotify ( unsigned type, unsigned long count, const void *pData );
virtual void exceptionNotify ( int status, const char *pContext );
virtual void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count );
private:
cacNotifyIO *pIO;
virtual lock ();
virtual unlock ();
static osiMutex defaultMutex;
friend class cacNotifyIO;
};
class epicsShareClass cacNotifyIO {
public:
cacNotifyIO ( cacNotify &);
virtual ~cacNotifyIO () = 0;
virtual void destroy () = 0;
void completionNotify ();
void completionNotify ( unsigned type, unsigned long count, const void *pData );
void exceptionNotify ( int status, const char *pContext );
void exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count );
private:
cacNotify &notify;
friend class cacNotify;
};
class epicsShareClass cacChannelIO {
public:
cacChannelIO ( cacChannel &chan );
virtual ~cacChannelIO () = 0;
virtual void destroy () = 0;
void connectNotify ();
void disconnectNotify ();
void connectTimeoutNotify ();
void accessRightsNotify ( caar );
virtual const char *pName () const = 0;
private:
virtual int read ( unsigned type, unsigned long count, void *pValue) = 0;
virtual int read ( unsigned type, unsigned long count, cacNotify &notify ) = 0;
virtual int write ( unsigned type, unsigned long count, const void *pValue ) = 0;
virtual int write ( unsigned type, unsigned long count, const void *pValue, cacNotify &notify ) = 0;
virtual int subscribe ( unsigned type, unsigned long count, unsigned mask, cacNotify &notify ) = 0;
virtual short nativeType () const = 0;
virtual unsigned long nativeElementCount () const = 0;
virtual void hostName (char *pBuf, unsigned bufLength) const; // defaults to local host name
virtual channel_state state () const; // defaults to always connected
virtual caar accessRights () const; // defaults to unrestricted access
virtual unsigned searchAttempts () const; // defaults to zero
virtual bool ca_v42_ok () const; // defaults to true
virtual bool connected () const; // defaults to true
virtual unsigned readSequence () const; // defaults to always zero
virtual void incrementOutstandingIO ();
virtual void decrementOutstandingIO ();
cacChannel &chan;
friend class cacChannel;
};
struct cacServiceIO : public tsDLNode <cacServiceIO> {
public:
epicsShareFunc virtual cacChannelIO *createChannelIO ( cacChannel &chan, const char *pName ) = 0;
private:
};
class cacServiceList : private osiMutex {
public:
epicsShareFunc cacServiceList ();
epicsShareFunc void registerService ( cacServiceIO &service );
epicsShareFunc bool createChannel (const char *pName, cacChannel &chan);
private:
tsDLList <cacServiceIO> services;
};
epicsShareExtern cacServiceList cacGlobalServiceList;

60
src/ca/cacNotify.cpp Normal file
View File

@@ -0,0 +1,60 @@
/* $Id$
*
* 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"
osiMutex cacNotify::defaultMutex;
cacNotify::cacNotify () : pIO (0)
{
}
cacNotify::~cacNotify ()
{
cacNotifyIO *pTmpIO = this->pIO;
if ( pTmpIO ) {
this->pIO = 0;
pTmpIO->destroy ();
}
}
cacNotify::lock ()
{
this->defaultMutex.lock ();
}
cacNotify::unlock ()
{
this->defaultMutex.unlock ();
}
void cacNotify::completionNotify ()
{
ca_printf ("CAC: IO completion with no handler installed?\n");
}
void cacNotify::completionNotify ( unsigned type, unsigned long count, const void *pData )
{
ca_printf ("IO completion with no handler installed? type=%u count=%u data pointer=%p\n",
type, count, pData);
}
void cacNotify::exceptionNotify ( int status, const char *pContext )
{
ca_signal (status, pContext);
}
void cacNotify::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count )
{
ca_signal_formated (status, __FILE__, __LINE__, "%s type=%d count=%ld\n",
pContext, type, count);
}

53
src/ca/cacNotifyIO.cpp Normal file
View File

@@ -0,0 +1,53 @@
/* $Id$
*
* 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"
cacNotifyIO::cacNotifyIO ( cacNotify &notifyIn ) : notify ( notifyIn )
{
assert ( ! this->notify.pIO );
this->notify.pIO = this;
}
cacNotifyIO::~cacNotifyIO ()
{
if ( this->notify.pIO == this ) {
this->notify.pIO = 0;
this->notify.destroy ();
}
}
void cacNotifyIO::destroy ()
{
delete this;
}
void cacNotifyIO::completionNotify ()
{
this->notify.completionNotify ();
}
void cacNotifyIO::completionNotify ( unsigned type, unsigned long count, const void *pData )
{
this->notify.completionNotify ( type, count, pData );
}
void cacNotifyIO::exceptionNotify ( int status, const char *pContext )
{
this->notify.exceptionNotify ( status, pContext );
}
void cacNotifyIO::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count )
{
this->notify.exceptionNotify ( status, pContext, type, count );
}

55
src/ca/cacServiceList.cpp Normal file
View File

@@ -0,0 +1,55 @@
/*
* $Id$
*
*
* 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"
epicsShareDef cacServiceList cacGlobalServiceList;
cacServiceList::cacServiceList ()
{
}
void cacServiceList::registerService ( cacServiceIO &service )
{
this->lock ();
this->services.add ( service );
this->unlock ();
}
bool cacServiceList::createChannel (const char *pName, cacChannel &chan)
{
cacChannelIO *pChanIO = 0;
this->lock ();
tsDLIterBD <cacServiceIO> iter ( this->services.first () );
while ( iter != iter.eol () ) {
pChanIO = iter->createChannelIO ( chan, pName );
if ( pChanIO ) {
break;
}
iter++;
}
this->unlock ();
if ( pChanIO ) {
return true;
}
else {
return false;
}
}

View File

@@ -49,11 +49,11 @@
extern "C" {
#endif
typedef void *chid;
typedef chid chanId; /* for when the structures field name is "chid" */
typedef long chtype;
typedef void *evid;
typedef double ca_real;
typedef struct oldChannel *chid;
typedef chid chanId; /* for when the structures field name is "chid" */
typedef long chtype;
typedef struct oldSubscription *evid;
typedef double ca_real;
/* Format for the arguments to user connection handlers */
struct connection_handler_args {
@@ -197,6 +197,8 @@ epicsShareFunc int epicsShareAPI ca_task_initialize (void);
/************************************************************************/
epicsShareFunc int epicsShareAPI ca_task_exit (void);
epicsShareFunc int epicsShareAPI ca_register_service ( struct cacServiceIO *pService );
/************************************************************************
* anachronistic entry points *
* **** Fetching a value while searching no longer supported**** *
@@ -720,6 +722,8 @@ epicsShareFunc void epicsShareAPI ca_signal_formated (long ca_status, const char
* channel R channel identifier
*/
epicsShareFunc const char * epicsShareAPI ca_host_name (chid channel);
/* thread safe version */
const void epicsShareAPI ca_get_host_name ( chid pChan, char *pBuf, unsigned bufLength );
/*
* CA_ADD_FD_REGISTRATION
@@ -870,7 +874,7 @@ epicsShareFunc int epicsShareAPI ca_sg_stat (CA_SYNC_GID gid);
*
* pUserName R new user name string copied from this location
*/
epicsShareFunc int epicsShareAPI ca_modify_user_name (const char *pUserName);
epicsShareFunc int epicsShareAPI ca_modify_user_name ( const char *pUserName );
/*
* CA_MODIFY_HOST_NAME()
@@ -880,7 +884,7 @@ epicsShareFunc int epicsShareAPI ca_modify_user_name (const char *pUserName);
*
* pHostName R new host name string copied from this location
*/
epicsShareFunc int epicsShareAPI ca_modify_host_name (const char *pHostName);
epicsShareFunc int epicsShareAPI ca_modify_host_name ( const char *pHostName );
/*
* ca_v42_ok()

View File

@@ -114,6 +114,7 @@
#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_OPWILLBLOCK DEFMSG(CA_K_WARNING, 53)
#ifndef CA_ERROR_GLBLSOURCE
epicsShareExtern READONLY char *ca_message_text[];
@@ -166,14 +167,15 @@ READONLY char *ca_message_text[]
"IO operations have completed",
"IO operations are in progress",
"Invalid synchronous group identifier",
"Put call back operation collision with put call back operation in progress",
"Put call back operation timed out waiting for put call back operation in progress",
"Read access denied",
"Write access denied",
"Sorry, that anachronistic feature of CA is no longer supported",
"The search request/beacon address list was empty after initialization",
"Data conversion between client's type and the server's type failed",
"Invalid channel identifier",
"Invalid function pointer"
"Invalid function pointer",
"op will block (not to be returned to user)"
};
#endif

File diff suppressed because it is too large Load Diff

25
src/ca/catimeMain.c Normal file
View File

@@ -0,0 +1,25 @@
#include <stdio.h>
#include "caDiagnostics.h"
int main(int argc, char **argv)
{
char *pname;
if(argc <= 1 || argc>3){
printf("usage: %s <channel name> [<if 2nd arg present append number to pv name>]\n",
argv[0]);
return -1;
}
else{
pname = argv[1];
if (argc==3) {
catime(pname, appendNumber);
}
else {
catime(pname, dontAppendNumber);
}
}
return 0;
}

View File

@@ -19,659 +19,3 @@ LOCAL void logRetryInterval (pcac, char *pFN, unsigned lineno);
#define LOGRETRYINTERVAL
#endif
/*
* checkConnWatchdogs()
*/
void checkConnWatchdogs (cac *pcac)
{
tcpiiu *piiu;
ca_real delay;
LOCK (pcac);
piiu = (tcpiiu *) ellFirst (&pcac->ca_iiuList);
while (piiu) {
tcpiiu *pnextiiu = (tcpiiu *) ellNext (&piiu->node);
/*
* mark connection for shutdown if outgoing messages
* are not accepted by TCP/IP for EPICS_CA_CONN_TMO seconds
*/
if (piiu->sendPending) {
delay = tsStampDiffInSeconds (&pcac->currentTime,
&piiu->timeAtSendBlock);
if (delay>pcac->ca_connectTMO) {
initiateShutdownTCPIIU (piiu);
}
}
/*
* otherwise if we dont already have a send timer pending
* mark the connection for shutdown if an echo response
* times out
*/
else if (piiu->echoPending) {
delay = tsStampDiffInSeconds (&pcac->currentTime,
&piiu->timeAtEchoRequest);
if (delay > CA_ECHO_TIMEOUT) {
initiateShutdownTCPIIU (piiu);
}
}
piiu = pnextiiu;
}
UNLOCK (pcac);
}
/*
*
* MANAGE_CONN
*
* manages
* o retry of disconnected channels
* o connection heart beats
*
*
*/
void manage_conn (cac *pcac)
{
tcpiiu *piiu;
ca_real delay;
/*
* prevent recursion
*/
if(pcac->ca_manage_conn_active){
return;
}
pcac->ca_manage_conn_active = TRUE;
/*
* issue connection heartbeat
* (if we dont see a beacon)
*/
LOCK (pcac);
for (piiu = (tcpiiu *) ellFirst (&pcac->ca_iiuList);
piiu; piiu = (tcpiiu *) ellNext (&piiu->node) ) {
if (piiu->state!=iiu_connected) {
continue;
}
/*
* remain backwards compatible with old servers
* ( this isnt an echo request )
*/
if(!CA_V43(CA_PROTOCOL_VERSION, piiu->minor_version_number)){
int stmo;
int rtmo;
delay = tsStampDiffInSeconds (&pcac->currentTime,
&piiu->timeAtEchoRequest);
stmo = delay > CA_RETRY_PERIOD;
delay = tsStampDiffInSeconds (&pcac->currentTime,
&piiu->timeAtLastRecv);
rtmo = delay > CA_RETRY_PERIOD;
if(stmo && rtmo && !piiu->sendPending){
piiu->timeAtEchoRequest = pcac->currentTime;
noop_msg (piiu);
}
continue;
}
if (!piiu->echoPending) {
/*
* check delay since last beacon
*/
delay = tsStampDiffInSeconds (&pcac->currentTime,
&piiu->pBHE->timeStamp);
if (delay>pcac->ca_connectTMO) {
/*
* check delay since last virtual circuit receive
*/
delay = tsStampDiffInSeconds (&pcac->currentTime,
&piiu->timeAtLastRecv);
if (delay>pcac->ca_connectTMO) {
/*
* no activity - so ping through the virtual circuit
*/
echo_request (piiu);
}
}
}
}
UNLOCK (pcac);
/*
* Stop here if there are not any disconnected channels
*/
if (!pcac->pudpiiu) {
pcac->ca_manage_conn_active = FALSE;
return;
}
if (pcac->pudpiiu->niiu.chidList.count == 0) {
pcac->ca_manage_conn_active = FALSE;
return;
}
pcac->ca_manage_conn_active = FALSE;
}
/*
* update beacon period
*
* updates beacon period, and looks for beacon anomalies
*/
LOCAL int updateBeaconPeriod (cac *pcac, bhe *pBHE)
{
ca_real currentPeriod;
int netChange = FALSE;
if (pBHE->timeStamp.secPastEpoch==0 && pBHE->timeStamp.nsec==0) {
/*
* 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)
*/
pBHE->timeStamp = pcac->currentTime;
/*
* be careful about using beacons to reset the connection
* time out watchdog until we have received a ping response
* from the IOC (this makes the software detect reconnects
* faster when the server is rebooted twice in rapid
* succession before a 1st or 2nd beacon has been received)
*/
if (pBHE->piiu) {
pBHE->piiu->beaconAnomaly = TRUE;
}
return netChange;
}
/*
* compute the beacon period (if we have seen at least two beacons)
*/
currentPeriod = tsStampDiffInSeconds (&pcac->currentTime,
&pBHE->timeStamp);
if (pBHE->averagePeriod<0.0) {
ca_real totalRunningTime;
/*
* 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.
*/
pBHE->averagePeriod = currentPeriod;
/*
* be careful about using beacons to reset the connection
* time out watchdog until we have received a ping response
* from the IOC (this makes the software detect reconnects
* faster when the server is rebooted twice in rapid
* succession before a 2nd beacon has been received)
*/
if (pBHE->piiu) {
pBHE->piiu->beaconAnomaly = TRUE;
}
/*
* 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 = tsStampDiffInSeconds (&pBHE->timeStamp,
&pcac->programBeginTime);
if (currentPeriod<=totalRunningTime) {
netChange = TRUE;
# ifdef DEBUG
{
char name[64];
ipAddrToA (&pBHE->inetAddr, name, sizeof(name));
ca_printf (pcac,
"new beacon from %s with period=%f running time to first beacon=%f\n",
name, currentPeriod, totalRunningTime);
}
# endif
}
}
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 >= pBHE->averagePeriod*1.25) {
if (pBHE->piiu) {
/*
* trigger on any missing beacon
* if connected to this server
*/
pBHE->piiu->beaconAnomaly = TRUE;
}
if (currentPeriod >= pBHE->averagePeriod*3.25) {
/*
* trigger on any 3 contiguous missing beacons
* if not connected to this server
*/
netChange = TRUE;
}
}
# ifdef DEBUG
if (netChange) {
char name[64];
ipAddrToA (&pBHE->inetAddr, name, sizeof(name));
ca_printf (pcac,
"net resume seen %s cur=%f avg=%f\n",
name, currentPeriod, pBHE->averagePeriod);
}
# endif
/*
* 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
*/
if (currentPeriod <= pBHE->averagePeriod * 0.80) {
# ifdef DEBUG
{
char name[64];
ipAddrToA (&pBHE->inetAddr, name, sizeof(name));
ca_printf (pcac,
"reboot seen %s cur=%f avg=%f\n",
name, currentPeriod, pBHE->averagePeriod);
}
# endif
netChange = TRUE;
if (pBHE->piiu) {
pBHE->piiu->beaconAnomaly = TRUE;
}
}
/*
* update a running average period
*/
pBHE->averagePeriod = currentPeriod*0.125 + pBHE->averagePeriod*0.875;
}
/*
* update beacon time stamp
*/
pBHE->timeStamp = pcac->currentTime;
return netChange;
}
/*
* MARK_SERVER_AVAILABLE
*/
void mark_server_available (cac *pcac, const struct sockaddr_in *pnet_addr)
{
nciu *chan;
bhe *pBHE;
unsigned port;
int netChange;
if (!pcac->pudpiiu) {
return;
}
LOCK (pcac);
/*
* look for it in the hash table
*/
pBHE = lookupBeaconInetAddr (pcac, pnet_addr);
if (pBHE) {
netChange = updateBeaconPeriod (pcac, pBHE);
/*
* update state of health for active virtual circuits
* (only if we are not suspicious about past beacon changes
* until the next echo reply)
*/
if (pBHE->piiu) {
if (!pBHE->piiu->beaconAnomaly) {
pBHE->piiu->timeAtLastRecv = pcac->currentTime;
}
}
}
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)
*/
netChange = FALSE;
createBeaconHashEntry (pcac, pnet_addr, TRUE);
}
if (!netChange) {
UNLOCK (pcac);
return;
}
/*
* This part is needed when many machines
* have channels in a disconnected state that
* dont exist anywhere on the network. This insures
* that we dont have many CA clients synchronously
* flooding the network with broadcasts (and swamping
* out requests for valid channels).
*
* I fetch the local port number and use the low order bits
* as a pseudo random delay to prevent every one
* from replying at once.
*/
{
struct sockaddr_in saddr;
int saddr_length = sizeof(saddr);
int status;
status = getsockname (
pcac->pudpiiu->sock,
(struct sockaddr *)&saddr,
&saddr_length);
assert (status>=0);
port = ntohs(saddr.sin_port);
}
{
ca_real delay;
delay = (port&CA_RECAST_PORT_MASK);
delay /= MSEC_PER_SEC;
delay += CA_RECAST_DELAY;
pcac->pudpiiu->searchTmr.reset (delay);
}
/*
* set retry count of all disconnected channels
* to zero
*/
chan = (nciu *) ellFirst (&pcac->pudpiiu->niiu.chidList);
while (chan) {
chan->retry = 0u;
chan = (nciu *) ellNext (&chan->node);
}
UNLOCK (pcac);
# if DEBUG
{
char buf[64];
ipAddrToA (pnet_addr, buf, sizeof(buf));
printf ("new server available: %s\n", buf);
}
# endif
}
/*
* bhtHashIP ()
*/
LOCAL unsigned bhtHashIP (cac *pcac, const struct sockaddr_in *pina)
{
unsigned index;
#if BHT_INET_ADDR_MASK != 0xff
# error BHT_INET_ADDR_MASK changed - recode this routine !
#endif
index = pina->sin_addr.s_addr;
index ^= pina->sin_port;
index = (index>>16u) ^ index;
index = (index>>8u) ^ index;
index &= BHT_INET_ADDR_MASK;
assert(index<NELEMENTS(pcac->ca_beaconHash));
return index;
}
/*
* createBeaconHashEntry()
*
* LOCK must be applied
*/
bhe *createBeaconHashEntry(
cac *pcac,
const struct sockaddr_in *pina,
unsigned sawBeacon)
{
bhe *pBHE;
unsigned index;
pBHE = lookupBeaconInetAddr(pcac, pina);
if(pBHE){
return pBHE;
}
index = bhtHashIP (pcac,pina);
pBHE = (bhe *)calloc (1,sizeof(*pBHE));
if(!pBHE){
return NULL;
}
#ifdef DEBUG
{
char name[64];
ipAddrToA (pina, name, sizeof(name));
ca_printf (pcac, "created beacon entry for %s\n", name);
}
#endif
/*
* store the inet address
*/
pBHE->inetAddr = *pina;
/*
* 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
*/
pBHE->averagePeriod = -1.0;
/*
* if creating this in response to a search reply
* and not in response to a beacon then sawBeacon
* is false and we set the beacon time stamp to
* zero (so we can correctly compute the period
* between the 1st and 2nd beacons)
*/
if (sawBeacon) {
LOCK (pcac)
pBHE->timeStamp = pcac->currentTime;
UNLOCK (pcac)
}
else {
pBHE->timeStamp.secPastEpoch = 0;
pBHE->timeStamp.nsec = 0;
}
/*
* install in the hash table
*/
pBHE->pNext = pcac->ca_beaconHash[index];
pcac->ca_beaconHash[index] = pBHE;
return pBHE;
}
/*
* lookupBeaconInetAddr()
*
* LOCK must be applied
*/
bhe *lookupBeaconInetAddr (
cac *pcac,
const struct sockaddr_in *pina)
{
bhe *pBHE;
unsigned index;
index = bhtHashIP (pcac,pina);
pBHE = pcac->ca_beaconHash[index];
while (pBHE) {
if ( pBHE->inetAddr.sin_addr.s_addr == pina->sin_addr.s_addr &&
pBHE->inetAddr.sin_port == pina->sin_port) {
break;
}
pBHE = pBHE->pNext;
}
return pBHE;
}
/*
* removeBeaconInetAddr()
*
* LOCK must be applied
*/
void removeBeaconInetAddr (
cac *pcac,
const struct sockaddr_in *pina)
{
bhe *pBHE;
bhe **ppBHE;
unsigned index;
index = bhtHashIP (pcac,pina);
ppBHE = &pcac->ca_beaconHash[index];
pBHE = *ppBHE;
while (pBHE) {
if ( pBHE->inetAddr.sin_addr.s_addr == pina->sin_addr.s_addr &&
pBHE->inetAddr.sin_port == pina->sin_port) {
*ppBHE = pBHE->pNext;
free (pBHE);
return;
}
ppBHE = &pBHE->pNext;
pBHE = *ppBHE;
}
assert (0);
}
/*
* freeBeaconHash()
*
* LOCK must be applied
*/
void freeBeaconHash(struct cac *ca_temp)
{
bhe *pBHE;
bhe **ppBHE;
int len;
len = NELEMENTS(ca_temp->ca_beaconHash);
for( ppBHE = ca_temp->ca_beaconHash;
ppBHE < &ca_temp->ca_beaconHash[len];
ppBHE++){
pBHE = *ppBHE;
while(pBHE){
bhe *pOld;
pOld = pBHE;
pBHE = pBHE->pNext;
free(pOld);
}
}
}
/*
* Add chan to iiu and guarantee that
* one chan on the B cast iiu list is pointed to by
* ca_pEndOfBCastList
*/
void addToChanList (nciu *chan, netIIU *piiu)
{
LOCK (piiu->iiu.pcas);
if ( piiu == &piiu->iiu.pcas->pudpiiu->niiu ) {
/*
* add to the beginning of the list so that search requests for
* this channel will be sent first (since the retry count is zero)
*/
if (ellCount(&piiu->chidList)==0) {
piiu->iiu.pcas->ca_pEndOfBCastList = chan;
}
/*
* add to the front of the list so that
* search requests for new channels will be sent first
*/
chan->retry = 0u;
ellInsert (&piiu->chidList, NULL, &chan->node);
}
else {
/*
* add to the beginning of the list until we
* have sent the claim message (after which we
* move it to the end of the list)
*/
chan->claimPending = TRUE;
ellInsert (&piiu->chidList, NULL, &chan->node);
}
chan->ciu.piiu = &piiu->iiu;
UNLOCK (piiu->iiu.pcas);
}
/*
* Remove chan from B-cast IIU and guarantee that
* one chan on the list is pointed to by
* ca_pEndOfBCastList
*/
void removeFromChanList (nciu *chan)
{
if ( chan->ciu.piiu == &chan->ciu.piiu->pcas->pudpiiu->niiu.iiu ) {
if (chan->ciu.piiu->pcas->ca_pEndOfBCastList == chan) {
if (ellPrevious(&chan->node)) {
chan->ciu.piiu->pcas->ca_pEndOfBCastList = (nciu *)
ellPrevious (&chan->node);
}
else {
chan->ciu.piiu->pcas->ca_pEndOfBCastList = (nciu *)
ellLast (&chan->ciu.piiu->pcas->pudpiiu->niiu.chidList);
}
}
ellDelete (&chan->ciu.piiu->pcas->pudpiiu->niiu.chidList, &chan->node);
}
else {
tcpiiu *piiu = iiuToTCPIIU (chan->ciu.piiu);
if ( ellCount (&piiu->niiu.chidList) == 1 ) {
initiateShutdownTCPIIU (piiu);
}
ellDelete (&piiu->niiu.chidList, &chan->node);
}
chan->ciu.piiu = NULL;
}

View File

@@ -47,11 +47,6 @@
*
* net format: big endian and IEEE float
*
* typedef void CACVRTFUNC(
* void *pSource,
* void *pDestination,
* int hton,
* unsigned long count);
*/
LOCAL CACVRTFUNC cvrt_string;
@@ -160,7 +155,7 @@ epicsShareDef CACVRTFUNC *cac_dbr_cvrt[]
*
*/
LOCAL void cvrt_string(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -188,7 +183,7 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_short(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -216,7 +211,7 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_char(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -242,7 +237,7 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_long(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -270,7 +265,7 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_enum(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -302,7 +297,7 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_float(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -335,7 +330,7 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_double(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -377,7 +372,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_string(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -415,7 +410,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_short(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -450,7 +445,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_float(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -476,7 +471,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_double(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -505,7 +500,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_enum(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -533,7 +528,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_short(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -570,7 +565,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_char(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -611,7 +606,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_long(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -649,7 +644,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_enum(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -682,7 +677,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_double(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -744,7 +739,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_gr_float(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -807,7 +802,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_short(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -847,7 +842,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_long(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -887,7 +882,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_char(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -925,7 +920,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_double(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -989,7 +984,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_float(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1052,7 +1047,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_ctrl_enum(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1088,7 +1083,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_char(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1119,7 +1114,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_sts_long(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1151,7 +1146,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_string(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1183,7 +1178,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_short(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1217,7 +1212,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_float(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1245,7 +1240,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_double(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1274,7 +1269,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_enum(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1304,7 +1299,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_char(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1336,7 +1331,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_time_long(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1367,7 +1362,7 @@ unsigned long num /* number of values */
*
*/
LOCAL void cvrt_put_ackt(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */
@@ -1401,7 +1396,7 @@ unsigned long num /* number of values */
****************************************************************************/
LOCAL void cvrt_stsack_string(
void *s, /* source */
const void *s, /* source */
void *d, /* destination */
int encode, /* cvrt HOST to NET if T */
unsigned long num /* number of values */

View File

@@ -0,0 +1 @@

View File

@@ -25,7 +25,7 @@ void flow_control_on (tcpiiu *piiu)
{
int status;
LOCK (piiu->niiu.iiu.pcas);
LOCK (piiu->pcas);
/*
* I prefer to avoid going into flow control
@@ -33,10 +33,10 @@ void flow_control_on (tcpiiu *piiu)
*/
if (piiu->contiguous_msg_count >= MAX_CONTIGUOUS_MSG_COUNT) {
if (!piiu->client_busy) {
status = ca_busy_message(piiu);
status = piiu->busyRequestMsg ();
if (status==ECA_NORMAL) {
assert(piiu->niiu.iiu.pcas->ca_number_iiu_in_fc<UINT_MAX);
piiu->niiu.iiu.pcas->ca_number_iiu_in_fc++;
assert(piiu->pcas->ca_number_iiu_in_fc<UINT_MAX);
piiu->pcas->ca_number_iiu_in_fc++;
piiu->client_busy = TRUE;
# if defined(DEBUG)
printf("fc on\n");
@@ -48,7 +48,7 @@ void flow_control_on (tcpiiu *piiu)
piiu->contiguous_msg_count++;
}
UNLOCK (piiu->niiu.iiu.pcas);
UNLOCK (piiu->pcas);
return;
}
@@ -56,14 +56,14 @@ void flow_control_off (tcpiiu *piiu)
{
int status;
LOCK (piiu->niiu.iiu.pcas);
LOCK (piiu->pcas);
piiu->contiguous_msg_count = 0;
if (piiu->client_busy) {
status = ca_ready_message(piiu);
status = piiu->readyRequestMsg ();
if (status==ECA_NORMAL) {
assert (piiu->niiu.iiu.pcas->ca_number_iiu_in_fc>0u);
piiu->niiu.iiu.pcas->ca_number_iiu_in_fc--;
assert (piiu->pcas->ca_number_iiu_in_fc>0u);
piiu->pcas->ca_number_iiu_in_fc--;
piiu->client_busy = FALSE;
# if defined(DEBUG)
printf("fc off\n");
@@ -71,6 +71,6 @@ void flow_control_off (tcpiiu *piiu)
}
}
UNLOCK (piiu->niiu.iiu.pcas);
UNLOCK (piiu->pcas);
return;
}

69
src/ca/getCallback.cpp Normal file
View File

@@ -0,0 +1,69 @@
/*
* $Id$
*
*
* 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 "iocinf.h"
#include "oldAccess.h"
tsFreeList < class getCallback > getCallback::freeList;
getCallback::getCallback (oldChannel &chanIn, caEventCallBackFunc *pFuncIn, void *pPrivateIn) :
chan (chanIn), pFunc (pFuncIn), pPrivate (pPrivateIn)
{
}
getCallback::~getCallback ()
{
}
void getCallback::destroy ()
{
delete this;
}
void getCallback::completionNotify ( unsigned type, unsigned long 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;
(*this->pFunc) (args);
}
void getCallback::exceptionNotify (int status, const char *pContext)
{
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = &this->chan;
args.type = 0;
args.count = 0;
args.status = status;
args.dbr = 0;
(*this->pFunc) (args);
}
void * getCallback::operator new ( size_t size )
{
return getCallback::freeList.allocate ( size );
}
void getCallback::operator delete ( void *pCadaver, size_t size )
{
getCallback::freeList.release ( pCadaver, size );
}

44
src/ca/inetAddrID_IL.h Normal file
View File

@@ -0,0 +1,44 @@
/* $Id$
*
* 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
*/
inline inetAddrID::inetAddrID (const struct sockaddr_in &addrIn) :
addr (addrIn)
{
}
inline bool inetAddrID::operator == (const inetAddrID &rhs)
{
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 (unsigned nBitsHashIndex) const
{
unsigned index;
index = this->addr.sin_addr.s_addr;
index ^= this->addr.sin_port;
return intId < unsigned, 8u, 32u > :: hashEngine (index);
}
inline unsigned inetAddrID::maxIndexBitWidth ()
{
return 32u;
}
inline unsigned inetAddrID::minIndexBitWidth ()
{
return 8u;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

838
src/ca/nciu.cpp Normal file
View File

@@ -0,0 +1,838 @@
/* $Id$
*
* 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"
tsFreeList < class nciu > nciu::freeList;
struct putCvrtBuf {
ELLNODE node;
unsigned long size;
void *pBuf;
};
/*
* nciu::nciu ()
*/
nciu::nciu (cac *pcac, cacChannel &chan, const char *pNameIn) :
cacChannelIO (chan)
{
static const caar defaultAccessRights = { false, false };
size_t strcnt;
strcnt = strlen (pNameIn) + 1;
if ( strcnt > MAX_UDP - sizeof (caHdr) ) {
throwWithLocation ( caErrorCode (ECA_STRTOBIG) );
}
this->pNameStr = reinterpret_cast <char *> ( malloc (strcnt) );
if ( ! this->pNameStr ) {
this->f_fullyConstructed = false;
return;
}
strcpy ( this->pNameStr, pNameIn );
LOCK (pcac);
pcac->installChannel (*this);
this->typeCode = USHRT_MAX; /* invalid initial type */
this->count = 0; /* invalid initial count */
this->sid = UINT_MAX; /* invalid initial server id */
this->ar = defaultAccessRights;
this->nameLength = strcnt;
this->previousConn = 0;
this->f_connected = false;
pcac->pudpiiu->addToChanList (this);
/*
* reset broadcasted search counters
*/
pcac->pudpiiu->searchTmr.reset (0.0);
this->f_fullyConstructed = true;
UNLOCK (pcac);
}
/*
* nciu::~nciu ()
*/
nciu::~nciu ()
{
netiiu *piiuCopy = this->piiu;
if ( ! this->fullyConstructed () ) {
return;
}
if ( this->f_connected ) {
caHdr hdr;
hdr.m_cmmd = htons ( CA_PROTO_CLEAR_CHANNEL );
hdr.m_available = this->getId ();
hdr.m_cid = this->sid;
hdr.m_dataType = htons ( 0 );
hdr.m_count = htons ( 0 );
hdr.m_postsize = 0;
this->piiu->pushStreamMsg (&hdr, NULL, true);
}
LOCK ( this->piiu->pcas );
/*
* remove any IO blocks still attached to this channel
*/
tsDLIterBD <baseNMIU> iter = this->eventq.first ();
while ( iter != iter.eol () ) {
tsDLIterBD <baseNMIU> next = iter.itemAfter ();
iter->destroy ();
iter = next;
}
this->piiu->pcas->uninstallChannel (*this);
this->piiu->removeFromChanList ( this );
free ( reinterpret_cast <void *> (this->pNameStr) );
UNLOCK ( piiuCopy->pcas ); // remove clears this->piiu
}
int nciu::read ( unsigned type, unsigned long count, cacNotify &notify )
{
int status;
caHdr hdr;
ca_uint16_t type_u16;
ca_uint16_t count_u16;
/*
* fail out if channel isnt connected or arguments are
* otherwise invalid
*/
if ( ! this->f_connected ) {
return ECA_DISCONNCHID;
}
if ( INVALID_DB_REQ (type) ) {
return ECA_BADTYPE;
}
if ( ! this->ar.read_access ) {
return ECA_NORDACCESS;
}
if ( count > this->count || count > 0xffff ) {
return ECA_BADCOUNT;
}
if ( count == 0 ) {
count = this->count;
}
/*
* only after range checking type and count cast
* them down to a smaller size
*/
type_u16 = (ca_uint16_t) type;
count_u16 = (ca_uint16_t) count;
LOCK (this->piiu->pcas);
{
netReadNotifyIO *monix = new netReadNotifyIO ( *this, notify );
if ( ! monix ) {
UNLOCK (this->piiu->pcas);
return ECA_ALLOCMEM;
}
hdr.m_cmmd = htons (CA_PROTO_READ_NOTIFY);
hdr.m_dataType = htons (type_u16);
hdr.m_count = htons (count_u16);
hdr.m_available = monix->getId ();
hdr.m_postsize = 0;
hdr.m_cid = this->sid;
}
UNLOCK (this->piiu->pcas);
status = this->piiu->pushStreamMsg (&hdr, NULL, true);
if ( status != ECA_NORMAL ) {
/*
* we need to be careful about touching the monix
* pointer after the lock has been released
*/
this->piiu->pcas->safeDestroyNMIU (hdr.m_available);
}
return status;
}
int nciu::read ( unsigned type, unsigned long count, void *pValue )
{
int status;
caHdr hdr;
ca_uint16_t type_u16;
ca_uint16_t count_u16;
/*
* fail out if channel isnt connected or arguments are
* otherwise invalid
*/
if ( ! this->f_connected ) {
return ECA_DISCONNCHID;
}
if ( INVALID_DB_REQ ( type ) ) {
return ECA_BADTYPE;
}
if ( ! this->ar.read_access ) {
return ECA_NORDACCESS;
}
if ( count > this->count || count > 0xffff ) {
return ECA_BADCOUNT;
}
if ( count == 0 ) {
count = this->count;
}
/*
* only after range checking type and count cast
* them down to a smaller size
*/
type_u16 = ( ca_uint16_t ) type;
count_u16 = ( ca_uint16_t ) count;
LOCK ( this->piiu->pcas );
{
netReadCopyIO *monix = new netReadCopyIO ( *this, type, count, pValue, this->readSequence () );
if ( ! monix ) {
UNLOCK ( this->piiu->pcas );
return ECA_ALLOCMEM;
}
hdr.m_cmmd = htons ( CA_PROTO_READ );
hdr.m_dataType = htons ( type_u16 );
hdr.m_count = htons ( count_u16 );
hdr.m_available = monix->getId ();
hdr.m_postsize = 0;
hdr.m_cid = this->sid;
}
UNLOCK ( this->piiu->pcas );
status = this->piiu->pushStreamMsg ( &hdr, NULL, true );
if ( status != ECA_NORMAL ) {
/*
* we need to be careful about touching the monix
* pointer after the lock has been released
*/
this->piiu->pcas->safeDestroyNMIU ( hdr.m_available );
}
return status;
}
/*
* free_put_convert()
*/
#ifdef CONVERSION_REQUIRED
LOCAL void free_put_convert (cac *pcac, void *pBuf)
{
struct putCvrtBuf *pBufHdr;
pBufHdr = (struct putCvrtBuf *)pBuf;
pBufHdr -= 1;
assert ( pBufHdr->pBuf == (void *) ( pBufHdr + 1 ) );
LOCK (pcac);
ellAdd (&pcac->putCvrtBuf, &pBufHdr->node);
UNLOCK (pcac);
return;
}
#endif /* CONVERSION_REQUIRED */
/*
* check_a_dbr_string()
*/
LOCAL int check_a_dbr_string (const char *pStr, const unsigned count)
{
unsigned i;
for ( i = 0; i < count; i++ ) {
unsigned int strsize = 0;
while ( 1 ) {
if (strsize >= MAX_STRING_SIZE ) {
return ECA_STRTOBIG;
}
if ( pStr[strsize] == '\0' ) {
break;
}
strsize++;
}
pStr += MAX_STRING_SIZE;
}
return ECA_NORMAL;
}
/*
* malloc_put_convert()
*/
#ifdef CONVERSION_REQUIRED
LOCAL void *malloc_put_convert (cac *pcac, unsigned long size)
{
struct putCvrtBuf *pBuf;
LOCK (pcac);
while ( (pBuf = (struct putCvrtBuf *) ellGet(&pcac->putCvrtBuf)) ) {
if(pBuf->size >= size){
break;
}
else {
free (pBuf);
}
}
UNLOCK (pcac);
if (!pBuf) {
pBuf = (struct putCvrtBuf *) malloc (sizeof(*pBuf)+size);
if (!pBuf) {
return NULL;
}
pBuf->size = size;
pBuf->pBuf = (void *) (pBuf+1);
}
return pBuf->pBuf;
}
#endif /* CONVERSION_REQUIRED */
/*
* nciu::issuePut ()
*/
int nciu::issuePut (ca_uint16_t cmd, unsigned id, chtype type,
unsigned long count, const void *pvalue)
{
int status;
caHdr hdr;
unsigned postcnt;
ca_uint16_t type_u16;
ca_uint16_t count_u16;
# ifdef CONVERSION_REQUIRED
void *pCvrtBuf;
# endif /*CONVERSION_REQUIRED*/
/*
* fail out if the conn is down or the arguments are otherwise invalid
*/
if ( ! this->f_connected ) {
return ECA_DISCONNCHID;
}
if ( INVALID_DB_REQ (type) ) {
return ECA_BADTYPE;
}
/*
* compound types not allowed
*/
if ( dbr_value_offset[type] ) {
return ECA_BADTYPE;
}
if ( ! this->ar.write_access ) {
return ECA_NOWTACCESS;
}
if ( count > this->count || count > 0xffff || count == 0 ) {
return ECA_BADCOUNT;
}
if (type==DBR_STRING) {
status = check_a_dbr_string ( (char *) pvalue, count );
if (status != ECA_NORMAL) {
return status;
}
}
postcnt = dbr_size_n (type,count);
if (postcnt>0xffff) {
return ECA_TOLARGE;
}
/*
* only after range checking type and count cast
* them down to a smaller size
*/
type_u16 = (ca_uint16_t) type;
count_u16 = (ca_uint16_t) count;
if (type == DBR_STRING && count == 1) {
char *pstr = (char *)pvalue;
postcnt = strlen(pstr)+1;
}
# ifdef CONVERSION_REQUIRED
{
unsigned i;
void *pdest;
unsigned size_of_one;
size_of_one = dbr_size[type];
pCvrtBuf = pdest = malloc_put_convert (this->piiu->pcas, postcnt);
if (!pdest) {
return ECA_ALLOCMEM;
}
/*
* No compound types here because these types are read only
* and therefore only appropriate for gets or monitors
*
* I changed from a for to a while loop here to avoid bounds
* checker pointer out of range error, and unused pointer
* update when it is a single element.
*/
i=0;
while (TRUE) {
switch (type) {
case DBR_LONG:
*(dbr_long_t *)pdest = htonl (*(dbr_long_t *)pvalue);
break;
case DBR_CHAR:
*(dbr_char_t *)pdest = *(dbr_char_t *)pvalue;
break;
case DBR_ENUM:
case DBR_SHORT:
case DBR_PUT_ACKT:
case DBR_PUT_ACKS:
# if DBR_INT != DBR_SHORT
# error DBR_INT != DBR_SHORT ?
# endif /*DBR_INT != DBR_SHORT*/
*(dbr_short_t *)pdest = htons (*(dbr_short_t *)pvalue);
break;
case DBR_FLOAT:
dbr_htonf ((dbr_float_t *)pvalue, (dbr_float_t *)pdest);
break;
case DBR_DOUBLE:
dbr_htond ((dbr_double_t *)pvalue, (dbr_double_t *)pdest);
break;
case DBR_STRING:
/*
* string size checked above
*/
strcpy ( (char *) pdest, (char *) pvalue );
break;
default:
return ECA_BADTYPE;
}
if (++i>=count) {
break;
}
pdest = ((char *)pdest) + size_of_one;
pvalue = ((char *)pvalue) + size_of_one;
}
pvalue = pCvrtBuf;
}
# endif /*CONVERSION_REQUIRED*/
hdr.m_cmmd = htons (cmd);
hdr.m_dataType = htons (type_u16);
hdr.m_count = htons (count_u16);
hdr.m_cid = this->sid;
hdr.m_available = id;
hdr.m_postsize = (ca_uint16_t) postcnt;
status = this->piiu->pushStreamMsg (&hdr, pvalue, true);
# ifdef CONVERSION_REQUIRED
free_put_convert (this->piiu->pcas, pCvrtBuf);
# endif /*CONVERSION_REQUIRED*/
return status;
}
int nciu::write (unsigned type, unsigned long count, const void *pValue)
{
return this->issuePut (CA_PROTO_WRITE, ~0U, type, count, pValue);
}
int nciu::write (unsigned type, unsigned long count, const void *pValue, cacNotify &notify)
{
netWriteNotifyIO *monix;
unsigned id;
int status;
if ( ! this->f_connected ) {
return ECA_DISCONNCHID;
}
if ( ! this->piiu->ca_v41_ok () ) {
return ECA_NOSUPPORT;
}
/*
* lock around io block create and list add
* so that we are not deleted without
* reclaiming the resource
*/
LOCK (this->piiu->pcas);
monix = new netWriteNotifyIO (*this, notify);
if ( ! monix ) {
UNLOCK (this->piiu->pcas);
return ECA_ALLOCMEM;
}
id = monix->getId ();
UNLOCK (this->piiu->pcas);
status = this->issuePut (CA_PROTO_WRITE_NOTIFY, id, type, count, pValue);
if ( status != ECA_NORMAL ) {
/*
* we need to be careful about touching the monix
* pointer after the lock has been released
*/
this->piiu->pcas->safeDestroyNMIU (id);
}
return status;
}
int nciu::subscribe (unsigned type, unsigned long count,
unsigned mask, cacNotify &notify)
{
netSubscription *pNetMon;
LOCK (this->piiu->pcas);
pNetMon = new netSubscription (*this, type, count,
static_cast <unsigned short> (mask), notify);
if ( ! pNetMon ) {
UNLOCK (this->piiu->pcas);
return ECA_ALLOCMEM;
}
UNLOCK (this->piiu->pcas);
pNetMon->subscriptionMsg ();
return ECA_NORMAL;
}
void nciu::destroy ()
{
delete this;
}
void nciu::hostName ( char *pBuf, unsigned bufLength ) const
{
this->piiu->hostName ( pBuf, bufLength );
}
bool nciu::ca_v42_ok () const
{
return this->piiu->ca_v42_ok ();
}
short nciu::nativeType () const
{
if ( this->f_connected ) {
return static_cast <short> (this->typeCode);
}
else {
return TYPENOTCONN;
}
}
unsigned long nciu::nativeElementCount () const
{
if ( this->f_connected ) {
return this->count;
}
else {
return 0ul;
}
}
channel_state nciu::state () const
{
if (this->f_connected) {
return cs_conn;
}
else if (this->previousConn) {
return cs_prev_conn;
}
else {
return cs_never_conn;
}
}
caar nciu::accessRights () const
{
return this->ar;
}
const char *nciu::pName () const
{
return this->pNameStr;
}
unsigned nciu::searchAttempts () const
{
return this->retry;
}
void nciu::connect (tcpiiu &iiu, unsigned nativeType, unsigned long nativeCount, unsigned sid)
{
LOCK ( iiu.pcas );
if ( this->connected () ) {
ca_printf (
"CAC: Ignored conn resp to conn chan CID=%u SID=%u?\n",
this->getId (), this->sid );
UNLOCK ( iiu.pcas );
return;
}
this->typeCode = nativeType;
this->count = nativeCount;
this->sid = sid;
this->f_connected = true;
this->previousConn = true;
/*
* if less than v4.1 then the server will never
* send access rights and we know that there
* will always be access and call their call back
* here
*/
if ( ! CA_V41 ( CA_PROTOCOL_VERSION, iiu.minor_version_number ) ) {
this->ar.read_access = true;
this->ar.write_access = true;
this->accessRightsNotify ( this->ar );
}
this->connectNotify ();
// resubscribe for monitors from this channel
tsDLIterBD<baseNMIU> iter = this->eventq.first ();
while ( iter != iter.eol () ) {
iter->subscriptionMsg ();
iter++;
}
UNLOCK ( iiu.pcas );
}
void nciu::disconnect ()
{
LOCK (this->piiu->pcas);
this->typeCode = USHRT_MAX;
this->count = 0u;
this->sid = UINT_MAX;
this->ar.read_access = false;
this->ar.write_access = false;
this->f_connected = false;
char hostNameBuf[64];
this->piiu->hostName ( hostNameBuf, sizeof (hostNameBuf) );
/*
* look for events that have an event cancel in progress
*/
tsDLIterBD <baseNMIU> iter = this->eventq.first ();
while ( iter != iter.eol () ) {
tsDLIterBD <baseNMIU> next = iter.itemAfter ();
iter->disconnect ( hostNameBuf );
iter = next;
}
this->disconnectNotify ();
this->accessRightsNotify (this->ar);
UNLOCK ( this->piiu->pcas );
this->piiu->disconnect ( this );
}
/*
* nciu::searchMsg ()
*/
int nciu::searchMsg ()
{
udpiiu *piiu = this->piiu->pcas->pudpiiu;
int status;
caHdr msg;
if ( this->piiu != static_cast<netiiu *> (piiu) ) {
return ECA_INTERNAL;
}
if (this->nameLength > 0xffff) {
return ECA_STRTOBIG;
}
msg.m_cmmd = htons (CA_PROTO_SEARCH);
msg.m_available = this->getId ();
msg.m_dataType = htons (DONTREPLY);
msg.m_count = htons (CA_MINOR_VERSION);
msg.m_cid = this->getId ();
status = this->piiu->pushDatagramMsg (&msg, this->pNameStr, this->nameLength);
if (status != ECA_NORMAL) {
return status;
}
/*
* increment the number of times we have tried to find this thisnel
*/
if (this->retry<MAXCONNTRIES) {
this->retry++;
}
/*
* move the channel to the end of the list so
* that all channels get a equal chance
*/
LOCK (this->piiu->pcas);
this->piiu->chidList.remove (*this);
this->piiu->chidList.add (*this);
UNLOCK (this->piiu->pcas);
return ECA_NORMAL;
}
void nciu::searchReplySetUp (unsigned sid, unsigned typeCode, unsigned long count)
{
this->typeCode = typeCode;
this->count = count;
this->sid = sid;
}
/*
* nciu::claimMsg ()
*/
bool nciu::claimMsg (tcpiiu *piiu)
{
caHdr hdr;
unsigned size;
const char *pStr;
int status;
LOCK (this->piiu->pcas);
if ( ! this->claimPending ) {
return false;
}
if ( this->f_connected ) {
return false;
}
hdr = cacnullmsg;
hdr.m_cmmd = htons (CA_PROTO_CLAIM_CIU);
if ( CA_V44 (CA_PROTOCOL_VERSION, piiu->minor_version_number) ) {
hdr.m_cid = this->getId ();
pStr = this->pNameStr;
size = this->nameLength;
}
else {
hdr.m_cid = this->sid;
pStr = NULL;
size = 0u;
}
hdr.m_postsize = size;
/*
* The available field is used (abused)
* here to communicate the minor version number
* starting with CA 4.1.
*/
hdr.m_available = htonl (CA_MINOR_VERSION);
/*
* If we are out of buffer space then postpone this
* operation until later. This avoids any possibility
* of a push pull deadlock (since this is sent when
* parsing the UDP input buffer).
*/
status = piiu->pushStreamMsg (&hdr, pStr, false);
if ( status == ECA_NORMAL ) {
/*
* move to the end of the list once the claim has been sent
*/
this->claimPending = FALSE;
piiu->chidList.remove (*this);
piiu->chidList.add (*this);
if ( ! CA_V42 (CA_PROTOCOL_VERSION, piiu->minor_version_number) ) {
this->connect (*piiu, this->typeCode, this->count, this->sid);
}
}
else {
piiu->claimRequestsPending = true;
}
UNLOCK (this->piiu->pcas);
if ( status == ECA_NORMAL ) {
return true;
}
else {
return false;
}
}
void nciu::installIO ( baseNMIU &io )
{
LOCK ( this->piiu->pcas );
this->piiu->pcas->installIO ( io );
this->eventq.add ( io );
UNLOCK ( this->piiu->pcas );
}
void nciu::uninstallIO ( baseNMIU &io )
{
LOCK ( this->piiu->pcas );
this->eventq.remove ( io );
this->piiu->pcas->uninstallIO ( io );
UNLOCK ( this->piiu->pcas );
}
bool nciu::connected () const
{
return this->f_connected;
}
unsigned nciu::readSequence () const
{
return this->piiu->pcas->readSequence ();
}
void nciu::incrementOutstandingIO ()
{
this->piiu->pcas->incrementOutstandingIO ();
}
void nciu::decrementOutstandingIO ()
{
this->piiu->pcas->decrementOutstandingIO ();
}
void nciu::decrementOutstandingIO ( unsigned seqNumber )
{
this->piiu->pcas->decrementOutstandingIO ( seqNumber );
}

74
src/ca/netReadCopyIO.cpp Normal file
View File

@@ -0,0 +1,74 @@
/* $Id$
*
* 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"
tsFreeList < class netReadCopyIO > netReadCopyIO::freeList;
netReadCopyIO::netReadCopyIO ( nciu &chanIn, unsigned typeIn, unsigned long countIn,
void *pValueIn, unsigned seqNumberIn ) :
baseNMIU (chanIn), type (typeIn), count (countIn),
pValue (pValueIn), seqNumber (seqNumberIn)
{
chanIn.incrementOutstandingIO ();
}
netReadCopyIO::~netReadCopyIO ()
{
}
void netReadCopyIO::disconnect ( const char *pHostName )
{
this->exceptionNotify ( ECA_DISCONN, pHostName );
delete this;
}
void netReadCopyIO::completionNotify ()
{
this->exceptionNotify ( ECA_INTERNAL, "get completion callback with no data?" );
}
void netReadCopyIO::completionNotify ( unsigned type, unsigned long count, const void *pData )
{
if ( type <= (unsigned) LAST_BUFFER_TYPE ) {
# ifdef CONVERSION_REQUIRED
(*cac_dbr_cvrt[type]) ( pData, this->pValue, FALSE, count );
# else
memcpy (pData, pValue, dbr_size_n ( type, count ) );
# endif
chan.decrementOutstandingIO (this->seqNumber);
}
else {
this->exceptionNotify ( ECA_INTERNAL, "bad data type in message" );
}
}
void netReadCopyIO::exceptionNotify ( int status, const char *pContext )
{
ca_signal (status, pContext);
}
void netReadCopyIO::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count )
{
ca_signal_formated (status, __FILE__, __LINE__, "%s type=%d count=%ld\n",
pContext, type, count);
}
void * netReadCopyIO::operator new ( size_t size )
{
return netReadCopyIO::freeList.allocate ( size );
}
void netReadCopyIO::operator delete ( void *pCadaver, size_t size )
{
netReadCopyIO::freeList.release ( pCadaver, size );
}

View File

@@ -0,0 +1,57 @@
/* $Id$
*
* 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"
tsFreeList < class netReadNotifyIO > netReadNotifyIO::freeList;
netReadNotifyIO::netReadNotifyIO ( nciu &chan, cacNotify &notifyIn ) :
baseNMIU ( chan ), cacNotifyIO ( notifyIn )
{
}
netReadNotifyIO::~netReadNotifyIO ()
{
}
void netReadNotifyIO::destroy ()
{
delete this;
}
void netReadNotifyIO::disconnect ( const char *pHostName )
{
this->cacNotifyIO::exceptionNotify ( ECA_DISCONN, pHostName );
delete this;
}
void netReadNotifyIO::completionNotify ()
{
this->cacNotifyIO::exceptionNotify ( ECA_INTERNAL, "no data returned ?" );
}
void netReadNotifyIO::completionNotify ( unsigned type,
unsigned long count, const void *pData )
{
this->cacNotifyIO::completionNotify ( type, count, pData );
}
void netReadNotifyIO::exceptionNotify ( int status, const char *pContext )
{
this->cacNotifyIO::exceptionNotify ( status, pContext );
}
void netReadNotifyIO::exceptionNotify ( int status, const char *pContext,
unsigned type, unsigned long count )
{
this->cacNotifyIO::exceptionNotify ( status, pContext, type ,count );
}

123
src/ca/netSubscription.cpp Normal file
View File

@@ -0,0 +1,123 @@
/* $Id$
*
* 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"
tsFreeList < class netSubscription > netSubscription::freeList;
netSubscription::netSubscription ( nciu &chan, chtype typeIn, unsigned long countIn,
unsigned short maskIn, cacNotify &notifyIn ) :
baseNMIU (chan), cacNotifyIO (notifyIn),
mask (maskIn), type (typeIn), count (countIn)
{
}
netSubscription::~netSubscription ()
{
if ( this->chan.connected () ) {
caHdr hdr;
ca_uint16_t type, count;
type = (ca_uint16_t) this->chan.nativeType ();
if ( this->chan.nativeElementCount () > 0xffff ) {
count = 0xffff;
}
else {
count = (ca_uint16_t) this->chan.nativeElementCount ();
}
hdr.m_cmmd = htons (CA_PROTO_EVENT_CANCEL);
hdr.m_available = this->id;
hdr.m_dataType = htons (type);
hdr.m_count = htons (count);
hdr.m_cid = this->chan.sid;
hdr.m_postsize = 0;
this->chan.piiu->pushStreamMsg (&hdr, NULL, true);
}
}
void netSubscription::destroy()
{
delete this;
}
int netSubscription::subscriptionMsg ()
{
unsigned long count;
struct monops msg;
ca_float32_t p_delta;
ca_float32_t n_delta;
ca_float32_t tmo;
/*
* clip to the native count and set to the native count if they
* specify zero
*/
if ( this->count > this->chan.nativeElementCount () ){
count = this->chan.nativeElementCount ();
}
else {
count = this->count;
}
/*
* dont allow overflow when converting to ca_uint16_t
*/
if ( count > 0xffff ) {
count = 0xffff;
}
/* msg header */
msg.m_header.m_cmmd = htons (CA_PROTO_EVENT_ADD);
msg.m_header.m_available = this->id;
msg.m_header.m_dataType = htons ( static_cast <ca_uint16_t> (this->type) );
msg.m_header.m_count = htons ( static_cast <ca_uint16_t> (count) );
msg.m_header.m_cid = this->chan.sid;
msg.m_header.m_postsize = sizeof (msg.m_info);
/* msg body */
p_delta = 0.0;
n_delta = 0.0;
tmo = 0.0;
dbr_htonf (&p_delta, &msg.m_info.m_hval);
dbr_htonf (&n_delta, &msg.m_info.m_lval);
dbr_htonf (&tmo, &msg.m_info.m_toval);
msg.m_info.m_mask = htons (this->mask);
msg.m_info.m_pad = 0; /* allow future use */
return this->chan.piiu->pushStreamMsg (&msg.m_header, &msg.m_info, true);
}
void netSubscription::disconnect ( const char *pHostName )
{
}
void netSubscription::completionNotify ()
{
this->cacNotifyIO::completionNotify ();
}
void netSubscription::completionNotify ( unsigned type, unsigned long count, const void *pData )
{
this->cacNotifyIO::completionNotify ( type, count, pData );
}
void netSubscription::exceptionNotify ( int status, const char *pContext )
{
this->cacNotifyIO::exceptionNotify ( status, pContext );
}
void netSubscription::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count )
{
this->cacNotifyIO::exceptionNotify ( status, pContext, type, count );
}

View File

@@ -0,0 +1,55 @@
/* $Id$
*
* 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"
tsFreeList < class netWriteNotifyIO > netWriteNotifyIO::freeList;
netWriteNotifyIO::netWriteNotifyIO (nciu &chan, cacNotify &notifyIn) :
baseNMIU (chan), cacNotifyIO (notifyIn)
{
}
netWriteNotifyIO::~netWriteNotifyIO ()
{
}
void netWriteNotifyIO::destroy ()
{
delete this;
}
void netWriteNotifyIO::disconnect ( const char *pHostName )
{
this->exceptionNotify (ECA_DISCONN, pHostName);
delete this;
}
void netWriteNotifyIO::completionNotify ()
{
this->cacNotifyIO::completionNotify ();
}
void netWriteNotifyIO::completionNotify ( unsigned type, unsigned long count, const void *pData )
{
this->cacNotifyIO::completionNotify ();
}
void netWriteNotifyIO::exceptionNotify ( int status, const char *pContext )
{
this->cacNotifyIO::exceptionNotify (status, pContext);
}
void netWriteNotifyIO::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count )
{
this->cacNotifyIO::exceptionNotify (status, pContext, type, count);
}

View File

@@ -89,7 +89,7 @@ extern "C" {
* net format: big endian and IEEE float
*/
typedef void CACVRTFUNC(void *pSrc, void *pDest, int hton, unsigned long count);
typedef void CACVRTFUNC (const void *pSrc, void *pDest, int hton, unsigned long count);
#ifdef CONVERSION_REQUIRED
/* cvrt is (array of) (pointer to) (function returning) int */

30
src/ca/netiiu.cpp Normal file
View File

@@ -0,0 +1,30 @@
/* $Id$
*
* 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"
/*
* constructNIIU ()
*/
netiiu::netiiu (cac *pcac) : baseIIU (pcac)
{
ellInit (&this->chidList);
}
/*
* netiiu::~netiiu ()
*/
netiiu::~netiiu ()
{
}

101
src/ca/oldAccess.h Normal file
View File

@@ -0,0 +1,101 @@
/*
* $Id$
*
*
* 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
*/
struct oldChannel : public cacChannel {
public:
oldChannel (caCh *pConnCallBack, void *pPrivate);
void destroy ();
void setPrivatePointer (void *);
void * privatePointer () const;
int changeConnCallBack (caCh *pfunc);
int replaceAccessRightsEvent (caArh *pfunc);
void ioAttachNotify ();
void ioReleaseNotify ();
static void * operator new (size_t size);
static void operator delete (void *pCadaver, size_t size);
private:
caCh *pConnCallBack;
void *pPrivate;
caArh *pAccessRightsFunc;
~oldChannel (); // must allocate from pool
void connectTimeoutNotify ();
void connectNotify ();
void disconnectNotify ();
void accessRightsNotify ( caar );
static tsFreeList < struct oldChannel > freeList;
friend int epicsShareAPI ca_array_get (chtype type, unsigned long count, chid pChan, void *pValue);
};
class getCallback : public cacNotify {
public:
getCallback (oldChannel &chan, caEventCallBackFunc *pFunc, void *pPrivate);
void destroy ();
virtual void completionNotify (unsigned type, unsigned long count, const void *pData);
virtual void exceptionNotify (int status, const char *pContext);
static void * operator new ( size_t size );
static void operator delete ( void *pCadaver, size_t size );
private:
oldChannel &chan;
caEventCallBackFunc *pFunc;
void *pPrivate;
~getCallback (); // allocate only out of pool
static tsFreeList < class getCallback > freeList;
};
class putCallback : public cacNotify {
public:
putCallback (oldChannel &chan, caEventCallBackFunc *pFunc, void *pPrivate );
void destroy ();
virtual void completionNotify ();
virtual void exceptionNotify ( int status, const char *pContext );
static void * operator new ( size_t size );
static void operator delete ( void *pCadaver, size_t size );
private:
oldChannel &chan;
caEventCallBackFunc *pFunc;
void *pPrivate;
~putCallback (); // allocate only out of pool
static tsFreeList < class putCallback > freeList;
};
struct oldSubscription : public cacNotify {
public:
oldSubscription ( oldChannel &chan, caEventCallBackFunc *pFunc, void *pPrivate );
void destroy ();
static void * operator new ( size_t size );
static void operator delete ( void *pCadaver, size_t size );
private:
oldChannel &chan;
caEventCallBackFunc *pFunc;
void *pPrivate;
void completionNotify ( unsigned type, unsigned long count, const void *pData );
void exceptionNotify ( int status, const char *pContext );
~oldSubscription (); // must allocate from pool
static tsFreeList < struct oldSubscription > freeList;
};

172
src/ca/oldChannel.cpp Normal file
View File

@@ -0,0 +1,172 @@
/*
* $Id$
*
*
* 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"
#include "oldAccess.h"
tsFreeList < struct oldChannel > oldChannel::freeList;
oldChannel::oldChannel (caCh *pConnCallBackIn, void *pPrivateIn) :
pConnCallBack (pConnCallBackIn), pPrivate (pPrivateIn), pAccessRightsFunc (0)
{
}
oldChannel::~oldChannel ()
{
if ( ! this->pConnCallBack ) {
this->decrementOutstandingIO ();
}
}
void oldChannel::destroy ()
{
delete this;
}
void oldChannel::ioAttachNotify ()
{
this->lock ();
if ( ! this->pConnCallBack ) {
this->incrementOutstandingIO ();
}
this->unlock ();
}
void oldChannel::ioReleaseNotify ()
{
this->lock ();
if ( ! this->pConnCallBack ) {
this->decrementOutstandingIO ();
}
this->unlock ();
}
void oldChannel::setPrivatePointer (void *pPrivateIn)
{
this->pPrivate = pPrivateIn;
}
void * oldChannel::privatePointer () const
{
return this->pPrivate;
}
/*
* cacAlreadyConnHandler ()
* This is installed into channels which dont have
* a connection handler when ca_pend_io() times
* out so that we will not decrement the pending
* recv count in the future.
*/
extern "C" void cacAlreadyConnHandler (struct connection_handler_args)
{
}
void oldChannel::connectTimeoutNotify ()
{
this->lock ();
if ( ! this->pConnCallBack ) {
this->pConnCallBack = cacAlreadyConnHandler;
}
this->unlock ();
}
void oldChannel::connectNotify ()
{
this->lock ();
if ( this->pConnCallBack ) {
caCh *pCCB = this->pConnCallBack;
struct connection_handler_args args;
args.chid = this;
args.op = CA_OP_CONN_UP;
(*pCCB) (args);
}
else {
this->pConnCallBack = cacAlreadyConnHandler;
this->decrementOutstandingIO ();
}
this->unlock ();
}
void oldChannel::disconnectNotify ()
{
if ( this->pConnCallBack ) {
struct connection_handler_args args;
args.chid = this;
args.op = CA_OP_CONN_DOWN;
(*this->pConnCallBack) (args);
}
}
void oldChannel::accessRightsNotify (caar ar)
{
if ( this->pAccessRightsFunc ) {
struct access_rights_handler_args args;
args.chid = this;
args.ar = ar;
( *this->pAccessRightsFunc ) ( args );
}
}
int oldChannel::changeConnCallBack (caCh *pfunc)
{
this->lock ();
if ( pfunc == 0) {
if ( this->pConnCallBack != 0 ) {
if ( this->pConnCallBack != cacAlreadyConnHandler ) {
this->incrementOutstandingIO ();
this->pConnCallBack = 0;
}
}
}
else {
if ( this->pConnCallBack == 0 ) {
this->decrementOutstandingIO ();
}
this->pConnCallBack = pfunc;
}
this->unlock ();
return ECA_NORMAL;
}
int oldChannel::replaceAccessRightsEvent (caArh *pfunc)
{
this->lock ();
this->pAccessRightsFunc = pfunc;
if ( pfunc && this->connected () ) {
struct access_rights_handler_args args;
args.chid = this;
args.ar = this->accessRights ();
(*pfunc) (args);
}
this->unlock ();
return ECA_NORMAL;
}
void * oldChannel::operator new ( size_t size )
{
return oldChannel::freeList.allocate ( size );
}
void oldChannel::operator delete ( void *pCadaver, size_t size )
{
oldChannel::freeList.release ( pCadaver, size );
}

View File

@@ -0,0 +1,66 @@
/* $Id$
*
* 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"
#include "oldAccess.h"
tsFreeList < struct oldSubscription > oldSubscription::freeList;
oldSubscription::oldSubscription ( oldChannel &chanIn, caEventCallBackFunc *pFuncIn, void *pPrivateIn ) :
chan (chanIn), pFunc (pFuncIn), pPrivate (pPrivateIn)
{
}
oldSubscription::~oldSubscription ()
{
}
void oldSubscription::completionNotify (unsigned type, unsigned long 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;
(*this->pFunc) (args);
}
void oldSubscription::exceptionNotify (int status, const char *pContext)
{
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = &this->chan;
args.type = 0;
args.count = 0;
args.status = status;
args.dbr = 0;
(*this->pFunc) (args);
}
void oldSubscription::destroy ()
{
delete this;
}
void * oldSubscription::operator new ( size_t size )
{
return oldSubscription::freeList.allocate ( size );
}
void oldSubscription::operator delete ( void *pCadaver, size_t size )
{
oldSubscription::freeList.release ( pCadaver, size );
}

View File

@@ -1,65 +0,0 @@
/*
* O S _ D E P E N . H
*
*
* OS dependent stuff for channel access
* Author Jeffrey O. Hill
*
* History
* .01 joh 110190 Moved to this file
* .02 joh 082891 on UNIX copy in a new delay into the timeval
* arg to select each call in TCPDELAY in case
* the system modifies my timeval structure.
* Also droped the TCPDELAY to 50 mS
* .03 joh 090391 Updated for V5 vxWorks
* .04 joh 092491 changed order of ops on LOCALTICKS
* .05 joh 092691 added NELEMENTS()
* .06 joh 111991 added EVENTLOCKTEST
* .07 joh 120291 added declaration of taskIdCurrent for
* compiling with V4 vxWorks
* .08 joh 062692 took out printf to logMsg MACRO
* .09 joh 101692 dont quit if select() is interrupted in
* the UNIX version of TCPDELAY
* .10 joh 112092 removed the requirement that VMS locking
* pairs reside at the same C bracket level
* .11 GeG 120992 support VMS/UCX
* .12 CJM 130794 define MYERRNO properly for UCX
* .13 CJM 311094 mods to support DEC C compiler
* .14 joh 100695 removed UNIX include of filio.h and sockio.h
* because they are include by ioctl.h under
* BSD and SVR4 (and they dont exist under linux)
*/
#ifndef INCos_depenh
#define INCos_depenh
static char *os_depenhSccsId = "$Id$";
#ifdef UNIX
# define CA_OS_CONFIGURED
#endif
#ifdef iocCore
# include "osiSem.h"
# include "osiThread.h"
# include "taskwd.h"
# define CA_OS_CONFIGURED
#endif
#ifdef VMS
# define CA_OS_CONFIGURED
#endif /*VMS*/
#ifdef _WIN32
# define CA_OS_CONFIGURED
#endif /*_WIN32*/
#ifndef CA_OS_CONFIGURED
#error Please define one of iocCore, UNIX, VMS, or _WIN32
#endif
#endif /* INCos_depenh */

View File

@@ -17,60 +17,28 @@
#include <iocinf.h>
processThread::processThread () :
processThread::processThread (cac *pcacIn) :
osiThread ("CAC process", 0x1000, threadPriorityMedium),
pcac (pcacIn),
shutDown (false)
{
ellInit (&this->recvActivity);
}
processThread::~processThread ()
{
this->shutDown = true;
this->exit.signal ();
while ( !this->exit.wait (5.0) ) {
this->signalShutDown ();
while ( ! this->exit.wait ( 10.0 ) ) {
printf ("processThread::~processThread (): Warning, thread object destroyed before thread exit \n");
}
}
void processThread::entryPoint ()
{
char *pNode;
tcpiiu *piiu;
while (!this->shutDown) {
while ( 1 ) {
int status;
unsigned bytesToProcess;
this->mutex.lock ();
pNode = (char *) ellGet (&this->recvActivity);
if (pNode) {
piiu = (tcpiiu *) (pNode - offsetof (tcpiiu, recvActivityNode) );
piiu->recvPending = FALSE;
}
this->mutex.unlock ();
if (!pNode) {
break;
}
if ( piiu->state == iiu_connected ) {
char *pProto = (char *) cacRingBufferReadReserveNoBlock
(&piiu->recv, &bytesToProcess);
if (pProto) {
status = post_msg (&piiu->niiu, &piiu->dest.ia,
pProto, bytesToProcess);
if (status!=ECA_NORMAL) {
initiateShutdownTCPIIU (piiu);
}
cacRingBufferReadCommit (&piiu->recv, bytesToProcess);
cacRingBufferReadFlush (&piiu->recv);
}
}
}
this->wakeup.wait ();
int status = ca_attach_context ( this->pcac );
SEVCHK ( status, "attaching to client context in process thread" );
while ( ! this->shutDown ) {
pcac->processRecvBacklog ();
this->pcac->recvActivity.wait ();
}
this->exit.signal ();
}
@@ -78,37 +46,6 @@ void processThread::entryPoint ()
void processThread::signalShutDown ()
{
this->shutDown = true;
this->wakeup.signal ();
this->pcac->recvActivity.signal ();
}
void processThread::installLabor (tcpiiu &iiu)
{
bool addedIt;
this->mutex.lock ();
if ( !iiu.recvPending ) {
iiu.recvPending = TRUE;
ellAdd (&this->recvActivity, &iiu.recvActivityNode);
addedIt = true;
}
else {
addedIt = false;
}
this->mutex.unlock ();
//
// wakeup after unlock improves performance
//
if (addedIt) {
this->wakeup.signal ();
}
}
void processThread::removeLabor (tcpiiu &iiu)
{
this->mutex.lock ();
if (iiu.recvPending) {
ellDelete (&this->recvActivity, &iiu.recvActivityNode);
}
this->mutex.unlock ();
}

71
src/ca/putCallback.cpp Normal file
View File

@@ -0,0 +1,71 @@
/*
* $Id$
*
*
* 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 "iocinf.h"
#include "oldAccess.h"
tsFreeList < class putCallback > putCallback::freeList;
putCallback::putCallback (oldChannel &chanIn, caEventCallBackFunc *pFuncIn, void *pPrivateIn ) :
chan (chanIn), pFunc (pFuncIn), pPrivate (pPrivateIn)
{
}
putCallback::~putCallback ()
{
}
void putCallback::destroy ()
{
delete this;
}
void putCallback::completionNotify ()
{
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = &this->chan;
args.type = 0;
args.count = 0;
args.status = ECA_NORMAL;
args.dbr = 0;
(*this->pFunc) (args);
}
void putCallback::exceptionNotify (int status, const char *pContext)
{
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = &this->chan;
args.type = 0;
args.count = 0;
args.status = status;
args.dbr = 0;
(*this->pFunc) (args);
}
void * putCallback::operator new ( size_t size )
{
return putCallback::freeList.allocate ( size );
}
void putCallback::operator delete ( void *pCadaver, size_t size )
{
putCallback::freeList.release ( pCadaver, size );
}

View File

@@ -123,7 +123,7 @@ LOCAL makeSocketReturn makeSocket (unsigned short port, int reuseAddr)
(char *)&flag, sizeof (flag) );
if (status<0) {
int errnoCpy = SOCKERRNO;
errlogPrintf(
ca_printf (
"%s: set socket option failed because \"%s\"\n",
__FILE__, SOCKERRSTR(errnoCpy));
}
@@ -152,7 +152,7 @@ LOCAL void verifyClients()
msr = makeSocket ( ntohs (pclient->from.sin_port), FALSE );
if ( msr.sock != INVALID_SOCKET ) {
#ifdef DEBUG
errlogPrintf ("Deleted client %d\n",
ca_printf ("Deleted client %d\n",
ntohs (pclient->from.sin_port) );
#endif
ellDelete (&theClients, &pclient->node);
@@ -165,7 +165,7 @@ LOCAL void verifyClients()
* win sock does not set SOCKERRNO when this fails
*/
if ( msr.errNumber != SOCK_EADDRINUSE ) {
errlogPrintf (
ca_printf (
"CA Repeater: bind test err was %d=\"%s\"\n",
msr.errNumber, msr.pErrStr);
}
@@ -199,7 +199,7 @@ LOCAL void fanOut (struct sockaddr_in *pFrom, const char *pMsg, unsigned msgSize
status = send ( pclient->sock, (char *)pMsg, msgSize, 0);
if (status>=0) {
#ifdef DEBUG
errlogPrintf ("Sent to %d\n",
ca_printf ("Sent to %d\n",
ntohs (pclient->from.sin_port));
#endif
}
@@ -207,13 +207,13 @@ LOCAL void fanOut (struct sockaddr_in *pFrom, const char *pMsg, unsigned msgSize
int errnoCpy = SOCKERRNO;
if (errnoCpy == SOCK_ECONNREFUSED) {
#ifdef DEBUG
errlogPrintf ("Deleted client %d\n",
ca_printf ("Deleted client %d\n",
ntohs (pclient->from.sin_port));
#endif
verify = TRUE;
}
else {
errlogPrintf(
ca_printf(
"CA Repeater: UDP fan out err was \"%s\"\n",
SOCKERRSTR(errnoCpy));
}
@@ -253,7 +253,7 @@ LOCAL void register_new_client (struct sockaddr_in *pFrom)
if (!init) {
msr = makeSocket (PORT_ANY, TRUE);
if ( msr.sock == INVALID_SOCKET ) {
errlogPrintf("%s: Unable to create repeater bind test socket because %d=\"%s\"\n",
ca_printf("%s: Unable to create repeater bind test socket because %d=\"%s\"\n",
__FILE__, msr.errNumber, msr.pErrStr);
}
else {
@@ -297,14 +297,14 @@ LOCAL void register_new_client (struct sockaddr_in *pFrom)
if (!pclient) {
pclient = (struct one_client *) calloc (1, sizeof(*pclient));
if (!pclient) {
errlogPrintf ("%s: no memory for new client\n", __FILE__);
ca_printf ("%s: no memory for new client\n", __FILE__);
return;
}
msr = makeSocket (PORT_ANY, FALSE);
if (msr.sock==INVALID_SOCKET) {
free(pclient);
errlogPrintf ("%s: no client sock because %d=\"%s\"\n",
ca_printf ("%s: no client sock because %d=\"%s\"\n",
__FILE__, msr.errNumber, msr.pErrStr);
return;
}
@@ -316,7 +316,7 @@ LOCAL void register_new_client (struct sockaddr_in *pFrom)
sizeof (*pFrom) );
if (status<0) {
int errnoCpy = SOCKERRNO;
errlogPrintf (
ca_printf (
"%s: unable to connect client sock because \"%s\"\n",
__FILE__, SOCKERRSTR(errnoCpy));
socket_close (pclient->sock);
@@ -329,7 +329,7 @@ LOCAL void register_new_client (struct sockaddr_in *pFrom)
ellAdd (&client_list, &pclient->node);
newClient = TRUE;
#ifdef DEBUG
errlogPrintf ( "Added %d\n", ntohs (pFrom->sin_port) );
ca_printf ( "Added %d\n", ntohs (pFrom->sin_port) );
#endif
}
@@ -346,7 +346,7 @@ LOCAL void register_new_client (struct sockaddr_in *pFrom)
}
else if (SOCKERRNO == SOCK_ECONNREFUSED){
#ifdef DEBUG
errlogPrintf ("Deleted repeater client=%d sending ack\n",
ca_printf ("Deleted repeater client=%d sending ack\n",
ntohs (pFrom->sin_port) );
#endif
ellDelete (&client_list, &pclient->node);
@@ -354,7 +354,7 @@ LOCAL void register_new_client (struct sockaddr_in *pFrom)
free (pclient);
}
else {
errlogPrintf ("CA Repeater: confirm err was \"%s\"\n",
ca_printf ("CA Repeater: confirm err was \"%s\"\n",
SOCKERRSTR (SOCKERRNO) );
}
@@ -410,7 +410,7 @@ void epicsShareAPI ca_repeater ()
bsdSockRelease ();
exit (0);
}
errlogPrintf("%s: Unable to create repeater socket because %d=\"%s\" - fatal\n",
ca_printf("%s: Unable to create repeater socket because %d=\"%s\" - fatal\n",
__FILE__, msr.errNumber, msr.pErrStr);
bsdSockRelease ();
exit(0);
@@ -419,7 +419,7 @@ void epicsShareAPI ca_repeater ()
sock = msr.sock;
#ifdef DEBUG
errlogPrintf ("CA Repeater: Attached and initialized\n");
ca_printf ("CA Repeater: Attached and initialized\n");
#endif
while (TRUE) {
@@ -444,7 +444,7 @@ void epicsShareAPI ca_repeater ()
continue;
}
# endif
errlogPrintf ("CA Repeater: unexpected UDP recv err: %s\n",
ca_printf ("CA Repeater: unexpected UDP recv err: %s\n",
SOCKERRSTR(errnoCpy));
continue;
}

View File

@@ -64,19 +64,6 @@ int cacRingBufferConstruct (ringBuffer *pBuf)
*/
void cacRingBufferDestroy (ringBuffer *pBuf)
{
/*
* force any read/write/reserve/commit ops in
* other threads to complete
*/
pBuf->shutDown = 1u;
semBinaryGive (pBuf->readSignal);
semBinaryGive (pBuf->writeSignal);
semMutexMustTake (pBuf->readLock);
semMutexMustTake (pBuf->writeLock);
/*
* clean up
*/
semBinaryDestroy (pBuf->readSignal);
semBinaryDestroy (pBuf->writeSignal);
semMutexDestroy (pBuf->readLock);
@@ -313,16 +300,16 @@ unsigned cacRingBufferWrite (ringBuffer *pRing, const void *pBuf,
unsigned totalBytes = 0;
unsigned curBytes;
semMutexMustTake (pRing->writeLock);
semMutexMustTake ( pRing->writeLock );
while (totalBytes<nBytes) {
curBytes = cacRingBufferWritePartial (pRing,
pBufTmp+totalBytes, nBytes-totalBytes);
if (curBytes==0) {
semBinaryGive (pRing->readSignal);
semBinaryMustTake (pRing->writeSignal);
if (pRing->shutDown) {
semMutexGive (pRing->writeLock);
while ( totalBytes < nBytes ) {
curBytes = cacRingBufferWritePartial ( pRing,
pBufTmp+totalBytes, nBytes-totalBytes );
if ( curBytes == 0 ) {
semBinaryGive ( pRing->readSignal );
semBinaryMustTake ( pRing->writeSignal );
if ( pRing->shutDown ) {
semMutexGive ( pRing->writeLock );
return totalBytes;
}
}
@@ -331,16 +318,21 @@ unsigned cacRingBufferWrite (ringBuffer *pRing, const void *pBuf,
}
}
semMutexGive (pRing->writeLock);
semMutexGive ( pRing->writeLock );
return totalBytes;
}
void cacRingBufferWriteLock (ringBuffer *pBuf)
{
semMutexMustTake (pBuf->writeLock);
}
bool cacRingBufferWriteLockNoBlock (ringBuffer *pBuf, unsigned bytesRequired)
{
semMutexMustTake (pBuf->writeLock);
if (cacRingBufferWriteSize (pBuf)<bytesRequired) {
if ( cacRingBufferWriteSize (pBuf) < bytesRequired ) {
semMutexGive (pBuf->writeLock);
return false;
}
@@ -450,12 +442,20 @@ void cacRingBufferReadCommit (ringBuffer *pRing, unsigned delta)
semMutexGive (pRing->readLock);
}
void cacRingBufferWriteFlush (ringBuffer *pRing)
bool cacRingBufferWriteFlush (ringBuffer *pRing)
{
semBinaryGive (pRing->readSignal);
if ( cacRingBufferReadSize (pRing) ) {
semBinaryGive (pRing->readSignal);
return true;
}
return false;
}
void cacRingBufferReadFlush (ringBuffer *pRing)
bool cacRingBufferReadFlush (ringBuffer *pRing)
{
semBinaryGive (pRing->writeSignal);
if ( cacRingBufferWriteSize (pRing) ) {
semBinaryGive (pRing->writeSignal);
return true;
}
return false;
}

View File

@@ -25,7 +25,6 @@
#define nElementsInRing (1<<nBitsRingIndex)
typedef struct ringBuffer {
char buf[nElementsInRing];
semBinaryId readSignal;
semBinaryId writeSignal;
semMutexId readLock;
@@ -33,6 +32,7 @@ typedef struct ringBuffer {
unsigned rdix; /* index of last char read */
unsigned wtix; /* index of next char to write */
unsigned shutDown;
char buf[nElementsInRing];
} ringBuffer;
int cacRingBufferConstruct (ringBuffer *pBuf);
@@ -44,6 +44,8 @@ unsigned cacRingBufferWrite (ringBuffer *pRing,
unsigned cacRingBufferRead (ringBuffer *pRing,
void *pBuf, unsigned nBytes);
void cacRingBufferWriteLock (ringBuffer *pBuf);
bool cacRingBufferWriteLockNoBlock (ringBuffer *pBuf, unsigned bytesRequired);
void cacRingBufferWriteUnlock (ringBuffer *pBuf);
@@ -58,8 +60,9 @@ void *cacRingBufferReadReserveNoBlock (ringBuffer *pBuf, unsigned *pBytesAvail);
void cacRingBufferReadCommit (ringBuffer *pBuf, unsigned delta);
void cacRingBufferReadFlush (ringBuffer *pBuf);
void cacRingBufferWriteFlush (ringBuffer *pBuf);
// return true if there was something to flush and otherwise false
bool cacRingBufferReadFlush (ringBuffer *pBuf);
bool cacRingBufferWriteFlush (ringBuffer *pBuf);
void cacRingBufferShutDown (ringBuffer *pBuf);

View File

@@ -12,6 +12,12 @@
#include "iocinf.h"
#ifdef DEBUG
# define debugPrintf(argsInParen) printf argsInParen
#else
# define debugPrintf(argsInParen)
#endif
//
// searchTimer::searchTimer ()
//
@@ -33,15 +39,16 @@ searchTimer::searchTimer (udpiiu &iiuIn, osiTimerQueue &queueIn) :
//
// searchTimer::reset ()
//
void searchTimer::reset (double periodIn)
void searchTimer::reset (double delayToNextTry)
{
LOCK (this->iiu.niiu.iiu.pcas);
LOCK (this->iiu.pcas);
this->retry = 0;
this->period = periodIn;
UNLOCK (this->iiu.niiu.iiu.pcas);
this->period = CA_RECAST_DELAY;
UNLOCK (this->iiu.pcas);
if (this->timeRemaining()>this->period) {
this->reschedule (0.0);
if (this->timeRemaining()>delayToNextTry) {
this->reschedule (delayToNextTry);
debugPrintf ( ("reschedualed search timer for completion in %f sec\n", delayToNextTry) );
}
}
@@ -53,7 +60,7 @@ void searchTimer::setRetryInterval (unsigned retryNo)
unsigned idelay;
double delay;
LOCK (this->iiu.niiu.iiu.pcas);
LOCK (this->iiu.pcas);
/*
* set the retry number
@@ -70,11 +77,9 @@ void searchTimer::setRetryInterval (unsigned retryNo)
*/
this->period = min (CA_RECAST_PERIOD, delay);
UNLOCK (this->iiu.niiu.iiu.pcas);
UNLOCK (this->iiu.pcas);
#ifdef DEBUG
printf ("new CA search period is %f sec\n", this->period);
#endif
debugPrintf ( ("new CA search period is %f sec\n", this->period) );
}
//
@@ -86,7 +91,7 @@ void searchTimer::setRetryInterval (unsigned retryNo)
//
void searchTimer::notifySearchResponse (nciu *pChan)
{
LOCK (this->iiu.niiu.iiu.pcas);
LOCK (this->iiu.pcas);
if ( this->retrySeqNoAtListBegin <= pChan->retrySeqNo ) {
if ( this->searchResponses < ULONG_MAX ) {
@@ -94,32 +99,31 @@ void searchTimer::notifySearchResponse (nciu *pChan)
}
}
UNLOCK (this->iiu.niiu.iiu.pcas);
UNLOCK (this->iiu.pcas);
if (pChan->retrySeqNo == this->retrySeqNo) {
this->reschedule (0.0);
}
}
//
// searchTimer::expire ()
//
void searchTimer::expire ()
{
nciu *chan;
nciu *firstChan;
int status;
unsigned nSent=0u;
tsDLIterBD<nciu> chan(0);
tsDLIterBD<nciu> firstChan(0);
int status;
unsigned nSent=0u;
/*
* check to see if there is nothing to do here
*/
if (ellCount(&this->iiu.niiu.chidList)==0) {
if ( ellCount (&this->iiu.chidList) ==0 ) {
return;
}
LOCK (this->iiu.niiu.iiu.pcas);
LOCK ( this->iiu.pcas );
/*
* increment the retry sequence number
@@ -136,7 +140,7 @@ void searchTimer::expire ()
*
* The variable this->framesPerTry
* determines the number of UDP frames to be sent
* each time that retrySearchRequest() is called.
* 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
@@ -168,11 +172,8 @@ void searchTimer::expire ()
else {
this->framesPerTry += (this->framesPerTry/8) + 1;
}
#if 0
printf ("Increasing frame count to %u t=%u r=%u\n",
this->framesPerTry, this->searchTries,
this->searchResponses);
#endif
debugPrintf ( ("Increasing frame count to %u t=%u r=%u\n",
this->framesPerTry, this->searchTries, this->searchResponses) );
}
}
/*
@@ -185,19 +186,17 @@ void searchTimer::expire ()
this->framesPerTry--;
}
this->framesPerTryCongestThresh = this->framesPerTry/2 + 1;
#if 0
printf ("Congestion detected - set frames per try to %u t=%u r=%u\n",
debugPrintf ( ("Congestion detected - set frames per try to %u t=%u r=%u\n",
this->framesPerTry, this->searchTries,
this->searchResponses);
#endif
this->searchResponses) );
}
/*
* a successful cac_search_msg() sends channel to
* a successful chan->searchMsg() sends channel to
* the end of the list
*/
firstChan = chan = (nciu *) ellFirst (&this->iiu.niiu.chidList);
while (chan) {
firstChan = chan = this->iiu.chidList.first ();
while ( chan != chan.eol () ) {
this->minRetry = min (this->minRetry, chan->retry);
@@ -208,11 +207,9 @@ void searchTimer::expire ()
* dont increase the delay between search
* requests
*/
if ( this->iiu.niiu.iiu.pcas->ca_pEndOfBCastList == chan ) {
if ( this->iiu.pcas->endOfBCastList == chan ) {
if ( this->searchResponses == 0u ) {
#if 0
printf ("increasing search try interval\n");
#endif
debugPrintf ( ("increasing search try interval\n") );
this->setRetryInterval (this->minRetry + 1u);
}
@@ -246,16 +243,14 @@ void searchTimer::expire ()
}
this->searchResponses = 0;
#if 0
printf ("saw end of list\n");
#endif
debugPrintf ( ("saw end of list\n") );
}
/*
* this moves the channel to the end of the
* list (if successful)
*/
status = cac_search_msg (chan);
status = chan->searchMsg ();
if (status != ECA_NORMAL) {
nSent++;
@@ -267,7 +262,7 @@ void searchTimer::expire ()
semBinaryGive (this->iiu.xmitSignal);
/* try again */
status = cac_search_msg (chan);
status = chan->searchMsg ();
if (status != ECA_NORMAL) {
break;
}
@@ -278,8 +273,8 @@ void searchTimer::expire ()
}
chan->retrySeqNo = this->retrySeqNo;
chan = (nciu *) ellFirst (&this->iiu.niiu.chidList);
chan = this->iiu.chidList.first ();
/*
* dont send any of the channels twice within one try
*/
@@ -303,15 +298,12 @@ void searchTimer::expire ()
}
}
UNLOCK (this->iiu.niiu.iiu.pcas);
UNLOCK (this->iiu.pcas);
/* flush out the search request buffer */
semBinaryGive (this->iiu.xmitSignal);
#ifdef DEBUG
printf ("sent %u delay sec=%f\n", nSent, this->period);
#endif
debugPrintf ( ("sent %u delay sec=%f\n", nSent, this->period) );
}
void searchTimer::destroy ()
@@ -320,11 +312,11 @@ void searchTimer::destroy ()
bool searchTimer::again () const
{
if (ellCount(&this->iiu.niiu.chidList)==0) {
if ( ellCount (&this->iiu.chidList) == 0 ) {
return false;
}
else {
if (this->retry < MAXCONNTRIES) {
if ( this->retry < MAXCONNTRIES ) {
return true;
}
else {

File diff suppressed because it is too large Load Diff

130
src/ca/syncGroupNotify.cpp Normal file
View File

@@ -0,0 +1,130 @@
/*
* $Id$
* Author: Jeffrey O. Hill
* hill@luke.lanl.gov
* (505) 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*/
#include "iocinf.h"
tsFreeList < class syncGroupNotify > syncGroupNotify::freeList;
syncGroupNotify::syncGroupNotify ( CASG &sgIn, void *pValueIn ) :
sg (sgIn), magic (CASG_MAGIC), pValue (pValueIn), seqNo ( sgIn.seqNo )
{
this->sg.mutex.lock ();
this->sg.ioList.add (*this);
this->sg.opPendCount++;
this->sg.mutex.unlock ();
}
void syncGroupNotify::destroy ()
{
delete this;
}
syncGroupNotify::~syncGroupNotify ()
{
this->sg.mutex.lock ();
this->sg.ioList.remove (*this);
this->sg.mutex.unlock ();
}
void syncGroupNotify::completionNotify ()
{
if ( this->magic != CASG_MAGIC ) {
ca_printf ("cac: sync group io_complete(): bad sync grp op magic number?\n");
return;
}
this->sg.mutex.lock ();
if ( this->seqNo == this->sg.seqNo ) {
assert ( this->sg.opPendCount > 0u );
this->sg.opPendCount--;
}
this->sg.mutex.unlock ();
if ( this->sg.opPendCount == 0 ) {
this->sg.sem.signal ();
}
}
void syncGroupNotify::completionNotify ( unsigned type, unsigned long count, const void *pData )
{
if ( this->magic != CASG_MAGIC ) {
ca_printf ("cac: sync group io_complete(): bad sync grp op magic number?\n");
return;
}
this->sg.mutex.lock ();
if ( this->seqNo == this->sg.seqNo ) {
/*
* Update the user's variable
*/
if ( this->pValue ) {
size_t size = dbr_size_n ( type, count );
memcpy (this->pValue, pData, size);
}
assert ( this->sg.opPendCount > 0u );
this->sg.opPendCount--;
}
this->sg.mutex.unlock ();
if ( this->sg.opPendCount == 0 ) {
this->sg.sem.signal ();
}
}
void syncGroupNotify::show (unsigned level) const
{
printf ( "pending sg op: pVal=%p, magic=%u seqNo=%lu sg=%p\n",
this->pValue, this->magic, this->seqNo, &this->sg);
}
void syncGroupNotify::exceptionNotify ( int status, const char *pContext )
{
ca_signal_formated ( status, __FILE__, __LINE__,
"CA Sync Group request failed because \"%s\"\n", pContext);
}
void syncGroupNotify::exceptionNotify ( int status, const char *pContext, unsigned type, unsigned long count )
{
ca_signal_formated ( status, __FILE__, __LINE__,
"CA Sync Group request failed with type=%d count=%ld because \"%s\"\n",
type, count, pContext);
}
void * syncGroupNotify::operator new (size_t size)
{
return syncGroupNotify::freeList.allocate ( size );
}
void syncGroupNotify::operator delete (void *pCadaver, size_t size)
{
syncGroupNotify::freeList.release ( pCadaver, size );
}

View File

@@ -3,7 +3,6 @@
* Author: Jeffrey O. Hill
* hill@luke.lanl.gov
* (505) 665 1831
* Date: 9-93
*
* Experimental Physics and Industrial Control System (EPICS)
*
@@ -28,266 +27,62 @@
*
*/
#include "freeList.h"
#include "iocinf.h"
/*
* ca_sg_init()
*/
void ca_sg_init (cac *pcac)
{
/*
* init all sync group lists
*/
ellInit (&pcac->activeCASG);
ellInit (&pcac->activeCASGOP);
freeListInitPvt (&pcac->ca_sgFreeListPVT, sizeof(CASG), 32);
freeListInitPvt (&pcac->ca_sgopFreeListPVT, sizeof(CASGOP), 256);
return;
}
/*
* ca_sg_shutdown()
*/
void ca_sg_shutdown (cac *pcac)
{
CASG *pcasg;
CASG *pnextcasg;
int status;
/*
* free all sync group lists
*/
LOCK (pcac);
pcasg = (CASG *) ellFirst (&pcac->activeCASG);
while (pcasg) {
pnextcasg = (CASG *) ellNext (&pcasg->node);
status = ca_sg_delete (pcasg->id);
assert (status==ECA_NORMAL);
pcasg = pnextcasg;
}
assert (ellCount(&pcac->activeCASG)==0);
/*
* per sync group
*/
freeListCleanup(pcac->ca_sgFreeListPVT);
/*
* per sync group op
*/
ellFree (&pcac->activeCASGOP);
freeListCleanup(pcac->ca_sgopFreeListPVT);
UNLOCK (pcac);
return;
}
/*
* ca_sg_create()
*/
int epicsShareAPI ca_sg_create (CA_SYNC_GID *pgid)
int epicsShareAPI ca_sg_create ( CA_SYNC_GID *pgid )
{
int caStatus;
int status;
CASG *pcasg;
cac *pcac;
caStatus = fetchClientContext (&pcac);
caStatus = fetchClientContext ( &pcac );
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
/*
* first look on a free list. If not there
* allocate dynamic memory for it.
*/
pcasg = (CASG *) freeListMalloc (pcac->ca_sgFreeListPVT);
if(!pcasg){
return ECA_ALLOCMEM;
}
LOCK (pcac);
/*
* setup initial values for all of the fields
*
* lock must be applied when allocating an id
* and using the id bucket
*/
memset((char *)pcasg,0,sizeof(*pcasg));
pcasg->magic = CASG_MAGIC;
pcasg->opPendCount = 0;
pcasg->seqNo = 0;
pcasg->sem = semBinaryMustCreate (semEmpty);
do {
pcasg->id = CLIENT_SLOW_ID_ALLOC (pcac);
status = bucketAddItemUnsignedId (pcac->ca_pSlowBucket, &pcasg->id, pcasg);
} while (status == S_bucket_idInUse);
if (status == S_bucket_success) {
/*
* place it on the active sync group list
*/
ellAdd (&pcac->activeCASG, &pcasg->node);
pcasg = new CASG ( *pcac );
if ( pcasg ) {
*pgid = pcasg->getId ();
return ECA_NORMAL;
}
else {
/*
* place it back on the free sync group list
*/
freeListFree(pcac->ca_sgFreeListPVT, pcasg);
UNLOCK (pcac);
if (status == S_bucket_noMemory) {
return ECA_ALLOCMEM;
}
else {
return ECA_INTERNAL;
}
return ECA_ALLOCMEM;
}
UNLOCK (pcac);
*pgid = pcasg->id;
return ECA_NORMAL;
}
/*
* ca_sg_delete()
*/
int epicsShareAPI ca_sg_delete(const CA_SYNC_GID gid)
int epicsShareAPI ca_sg_delete (const CA_SYNC_GID gid)
{
int caStatus;
int status;
CASG *pcasg;
cac *pcac;
int caStatus;
CASG *pcasg;
cac *pcac;
caStatus = fetchClientContext (&pcac);
caStatus = fetchClientContext ( &pcac );
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
LOCK (pcac);
pcasg = (CASG *) bucketLookupItemUnsignedId (pcac->ca_pSlowBucket, &gid);
if (!pcasg || pcasg->magic != CASG_MAGIC) {
UNLOCK (pcac);
pcasg = pcac->lookupCASG ( gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
status = bucketRemoveItemUnsignedId (pcac->ca_pSlowBucket, &gid);
assert (status == S_bucket_success);
semBinaryDestroy(pcasg->sem);
pcasg->magic = 0;
ellDelete(&pcac->activeCASG, &pcasg->node);
UNLOCK (pcac);
freeListFree(pcac->ca_sgFreeListPVT, pcasg);
pcasg->destroy ();
return ECA_NORMAL;
}
/*
* ca_sg_block_private ()
*/
static int ca_sg_block_private (cac *pcac, const CA_SYNC_GID gid, ca_real timeout)
{
TS_STAMP cur_time;
TS_STAMP beg_time;
ca_real delay;
int status;
CASG *pcasg;
unsigned flushCompleted = FALSE;
if (timeout<0.0) {
return ECA_TIMEOUT;
}
status = tsStampGetCurrent (&cur_time);
if (status!=0) {
return ECA_INTERNAL;
}
LOCK (pcac);
pcac->currentTime = cur_time;
pcasg = (CASG *) bucketLookupItemUnsignedId (pcac->ca_pSlowBucket, &gid);
if ( !pcasg || pcasg->magic != CASG_MAGIC ) {
UNLOCK (pcac);
return ECA_BADSYNCGRP;
}
UNLOCK (pcac);
cacFlushAllIIU (pcac);
beg_time = cur_time;
delay = 0.0;
status = ECA_NORMAL;
while (pcasg->opPendCount) {
ca_real remaining;
int tsStatus;
/*
* Exit if the timeout has expired
* (dont wait forever for an itsy bitsy
* delay which will not be updated if
* select is called with no delay)
*
* current time is only updated by
* cac_select_io() if we specify
* at non-zero delay
*/
remaining = timeout-delay;
if (remaining<=CAC_SIGNIFICANT_SELECT_DELAY) {
/*
* Make sure that we take care of
* recv backlog at least once
*/
status = ECA_TIMEOUT;
break;
}
remaining = min (60.0, remaining);
/*
* wait for asynch notification
*/
semBinaryTakeTimeout (pcasg->sem, remaining);
/*
* force a time update
*/
tsStatus = tsStampGetCurrent (&cur_time);
if (tsStatus!=0) {
status = ECA_INTERNAL;
break;
}
LOCK (pcac);
pcac->currentTime = cur_time;
UNLOCK (pcac);
flushCompleted = TRUE;
delay = tsStampDiffInSeconds (&cur_time, &beg_time);
}
pcasg->opPendCount = 0;
pcasg->seqNo++;
return status;
}
/*
* ca_sg_block ()
*/
int epicsShareAPI ca_sg_block (const CA_SYNC_GID gid, ca_real timeout)
{
CASG *pcasg;
cac *pcac;
int status;
@@ -296,20 +91,13 @@ int epicsShareAPI ca_sg_block (const CA_SYNC_GID gid, ca_real timeout)
return status;
}
/*
* dont allow recursion
*/
{
void *p = threadPrivateGet (cacRecursionLock);
if (p) {
return ECA_EVDISALLOW;
}
threadPrivateSet (cacRecursionLock, &cacRecursionLock);
pcasg = pcac->lookupCASG ( gid );
if ( ! pcasg ) {
status = ECA_BADSYNCGRP;
}
else {
status = pcasg->block ( timeout );
}
status = ca_sg_block_private (pcac, gid, timeout);
threadPrivateSet (cacRecursionLock, NULL);
return status;
}
@@ -319,37 +107,34 @@ int epicsShareAPI ca_sg_block (const CA_SYNC_GID gid, ca_real timeout)
*/
int epicsShareAPI ca_sg_reset (const CA_SYNC_GID gid)
{
CASG *pcasg;
cac *pcac;
int caStatus;
CASG *pcasg;
cac *pcac;
int caStatus;
caStatus = fetchClientContext (&pcac);
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
LOCK (pcac);
pcasg = (CASG *) bucketLookupItemUnsignedId (pcac->ca_pSlowBucket, &gid);
if(!pcasg || pcasg->magic != CASG_MAGIC){
UNLOCK (pcac);
return ECA_BADSYNCGRP;
pcasg = pcac->lookupCASG ( gid );
if ( ! pcasg ) {
caStatus = ECA_BADSYNCGRP;
}
else {
caStatus = ECA_NORMAL;
pcasg->reset ();
}
pcasg->opPendCount = 0;
pcasg->seqNo++;
UNLOCK (pcac);
return ECA_NORMAL;
return caStatus;
}
/*
* ca_sg_stat
*/
int epicsShareAPI ca_sg_stat (const CA_SYNC_GID gid)
int epicsShareAPI ca_sg_stat ( const CA_SYNC_GID gid )
{
CASG *pcasg;
CASGOP *pcasgop;
cac *pcac;
cac *pcac;
int caStatus;
caStatus = fetchClientContext (&pcac);
@@ -357,31 +142,13 @@ int epicsShareAPI ca_sg_stat (const CA_SYNC_GID gid)
return caStatus;
}
LOCK (pcac);
pcasg = (CASG *) bucketLookupItemUnsignedId (pcac->ca_pSlowBucket, &gid);
if (!pcasg || pcasg->magic != CASG_MAGIC) {
UNLOCK (pcac);
pcasg = pcac->lookupCASG ( gid );
if ( ! pcasg ) {
printf("Bad Sync Group Id\n");
return ECA_BADSYNCGRP;
caStatus = ECA_BADSYNCGRP;
}
UNLOCK (pcac);
printf("Sync Group: id=%u, magic=%lu, opPend=%lu, seqNo=%lu\n",
pcasg->id, pcasg->magic, pcasg->opPendCount,
pcasg->seqNo);
LOCK (pcac);
pcasgop = (CASGOP *) ellFirst (&pcac->activeCASGOP);
while (pcasgop) {
if (pcasg->id == pcasgop->id) {
printf(
"pending op: id=%u pVal=%x, magic=%lu seqNo=%lu\n",
pcasgop->id, (unsigned)pcasgop->pValue, pcasgop->magic,
pcasgop->seqNo);
}
pcasgop = (CASGOP *) ellNext(&pcasgop->node);
}
UNLOCK (pcac);
pcasg->show (1000u);
return ECA_NORMAL;
}
@@ -389,104 +156,28 @@ int epicsShareAPI ca_sg_stat (const CA_SYNC_GID gid)
/*
* ca_sg_test
*/
int epicsShareAPI ca_sg_test (const CA_SYNC_GID gid)
int epicsShareAPI ca_sg_test ( const CA_SYNC_GID gid )
{
CASG *pcasg;
cac *pcac;
int caStatus;
CASG *pcasg;
cac *pcac;
int caStatus;
caStatus = fetchClientContext (&pcac);
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
LOCK (pcac);
pcasg = (CASG *) bucketLookupItemUnsignedId (pcac->ca_pSlowBucket, &gid);
if(!pcasg || pcasg->magic != CASG_MAGIC){
UNLOCK (pcac);
pcasg = pcac->lookupCASG ( gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
UNLOCK (pcac);
if(pcasg->opPendCount){
return ECA_IOINPROGRESS;
}
else{
if ( pcasg->ioComplete () ) {
return ECA_IODONE;
}
}
/*
* ca_sync_grp_io_complete ()
*/
extern "C" void ca_sync_grp_io_complete (struct event_handler_args args)
{
unsigned long size;
CASGOP *pcasgop;
CASG *pcasg;
pcasgop = (CASGOP *) args.usr;
if (pcasgop->magic != CASG_MAGIC) {
errlogPrintf ("cac: sync group io_complete(): bad sync grp op magic number?\n");
return;
else{
return ECA_IOINPROGRESS;
}
LOCK (pcasgop->pcac);
ellDelete (&pcasgop->pcac->activeCASGOP, &pcasgop->node);
pcasgop->magic = 0;
/*
* ignore stale replies
*/
pcasg = (CASG *) bucketLookupItemUnsignedId (pcasgop->pcac->ca_pSlowBucket, &pcasgop->id);
if (!pcasg || pcasg->seqNo != pcasgop->seqNo) {
UNLOCK (pcasgop->pcac);
return;
}
assert (pcasg->magic == CASG_MAGIC);
assert (pcasg->id == pcasgop->id);
if ( !( args.status & CA_M_SUCCESS ) ) {
ca_printf (
pcasgop->pcac,
"CA Sync Group (id=%d) request failed because \"%s\"\n",
pcasgop->id,
ca_message(args.status) );
UNLOCK (pcasgop->pcac);
freeListFree(pcasgop->pcac->ca_sgopFreeListPVT, pcasgop);
return;
}
/*
* Update the user's variable
* (if its a get)
*/
if (pcasgop->pValue && args.dbr) {
size = dbr_size_n (args.type, args.count);
memcpy (pcasgop->pValue, args.dbr, size);
}
/*
* decrement the outstanding IO ops count
*/
assert (pcasg->opPendCount>=1u);
pcasg->opPendCount--;
UNLOCK (pcasgop->pcac);
freeListFree (pcasgop->pcac->ca_sgopFreeListPVT, pcasgop);
/*
* Wake up any tasks pending
*
* occurs through select on UNIX
*/
if (pcasg->opPendCount == 0) {
semBinaryGive(pcasg->sem);
}
return;
}
/*
@@ -496,59 +187,24 @@ int epicsShareAPI ca_sg_array_put (
const CA_SYNC_GID gid,
chtype type,
unsigned long count,
chid chix,
const void *pvalue)
chid pChan,
const void *pValue)
{
int status;
CASGOP *pcasgop;
CASG *pcasg;
cac *pcac;
cac *pcac;
int caStatus;
caStatus = fetchClientContext (&pcac);
caStatus = fetchClientContext ( &pcac );
if ( caStatus != ECA_NORMAL ) {
return caStatus;
}
/*
* first look on a free list. If not there
* allocate dynamic memory for it.
*/
pcasgop = (CASGOP *) freeListMalloc (pcac->ca_sgopFreeListPVT);
if(!pcasgop){
return ECA_ALLOCMEM;
}
LOCK (pcac);
pcasg = (CASG *) bucketLookupItemUnsignedId (pcac->ca_pSlowBucket, &gid);
if(!pcasg || pcasg->magic != CASG_MAGIC){
UNLOCK (pcac);
freeListFree(pcac->ca_sgopFreeListPVT, pcasgop);
pcasg = pcac->lookupCASG ( gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
memset((char *)pcasgop, 0,sizeof(*pcasgop));
pcasgop->id = gid;
pcasgop->seqNo = pcasg->seqNo;
pcasgop->magic = CASG_MAGIC;
pcasgop->pValue = NULL; /* handler will know its a put */
pcasgop->pcac = pcac;
ellAdd (&pcac->activeCASGOP, &pcasgop->node);
pcasg->opPendCount++;
UNLOCK (pcac);
status = ca_array_put_callback (type, count, chix,
pvalue, ca_sync_grp_io_complete, pcasgop);
if (status != ECA_NORMAL) {
LOCK (pcac);
assert (pcasg->opPendCount>=1u);
pcasg->opPendCount--;
ellDelete (&pcac->activeCASGOP, &pcasgop->node);
UNLOCK (pcac);
freeListFree (pcac->ca_sgopFreeListPVT, pcasgop);
}
return status;
return pcasg->put ( pChan, type, count, pValue );
}
/*
@@ -558,13 +214,11 @@ int epicsShareAPI ca_sg_array_get (
const CA_SYNC_GID gid,
chtype type,
unsigned long count,
chid chix,
void *pvalue)
chid pChan,
void *pValue)
{
int status;
CASGOP *pcasgop;
CASG *pcasg;
cac *pcac;
cac *pcac;
int caStatus;
caStatus = fetchClientContext (&pcac);
@@ -572,44 +226,10 @@ void *pvalue)
return caStatus;
}
/*
* first look on a free list. If not there
* allocate dynamic memory for it.
*/
pcasgop = (CASGOP *) freeListMalloc (pcac->ca_sgopFreeListPVT);
if (!pcasgop) {
return ECA_ALLOCMEM;
}
LOCK (pcac);
pcasg = (CASG *) bucketLookupItemUnsignedId (pcac->ca_pSlowBucket, &gid);
if(!pcasg || pcasg->magic != CASG_MAGIC){
UNLOCK (pcac);
freeListFree(pcac->ca_sgopFreeListPVT, pcasgop);
pcasg = pcac->lookupCASG ( gid );
if ( ! pcasg ) {
return ECA_BADSYNCGRP;
}
memset((char *)pcasgop, 0,sizeof(*pcasgop));
pcasgop->id = gid;
pcasgop->seqNo = pcasg->seqNo;
pcasgop->magic = CASG_MAGIC;
pcasgop->pValue = pvalue;
pcasgop->pcac = pcac;
ellAdd(&pcac->activeCASGOP, &pcasgop->node);
pcasg->opPendCount++;
UNLOCK (pcac);
status = ca_array_get_callback (
type, count, chix, ca_sync_grp_io_complete, pcasgop);
if(status != ECA_NORMAL){
LOCK (pcac);
assert (pcasg->opPendCount>=1u);
pcasg->opPendCount--;
ellDelete (&pcac->activeCASGOP, &pcasgop->node);
UNLOCK (pcac);
freeListFree (pcac->ca_sgopFreeListPVT, pcasgop);
}
return status;
return pcasg->get ( pChan, type, count, pValue );
}

View File

@@ -0,0 +1,72 @@
/* * $Id$
*
* 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"
tcpRecvWatchdog::tcpRecvWatchdog
(double periodIn, osiTimerQueue & queueIn, bool echoProtocolAcceptedIn) :
osiTimer (periodIn, queueIn),
period (periodIn),
echoProtocolAccepted (echoProtocolAcceptedIn),
echoResponsePending (false)
{
}
void tcpRecvWatchdog::echoResponseNotify ()
{
this->echoResponsePending = false;
this->reschedule ( this->period );
}
void tcpRecvWatchdog::expire ()
{
/*
* remain backwards compatible with old servers
* ( this isnt an echo request )
*/
if ( ! this->echoProtocolAccepted ) {
this->noopRequestMsg ();
}
else if ( this->echoResponsePending ) {
ca_printf ( "CA server unresponsive for %f sec. Disconnecting\n", this->period );
this->shutdown ();
}
else {
this->echoRequestMsg ();
this->echoResponsePending = true;
}
}
void tcpRecvWatchdog::destroy ()
{
// ignore timer destroy requests
}
bool tcpRecvWatchdog::again () const
{
return true;
}
double tcpRecvWatchdog::delay () const
{
if (this->echoResponsePending) {
return CA_ECHO_TIMEOUT;
}
else {
return this->period;
}
}
const char *tcpRecvWatchdog::name () const
{
return "TCP Receive Watchdog";
}

View File

@@ -0,0 +1,46 @@
/* * $Id$
*
* 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"
tcpSendWatchdog::tcpSendWatchdog
(double periodIn, osiTimerQueue & queueIn) :
osiTimer (queueIn),
period (periodIn)
{
}
void tcpSendWatchdog::expire ()
{
ca_printf ("Unable to deliver message for %f sec. Disconnecting from CA server\n", this->period);
this->shutdown ();
}
void tcpSendWatchdog::destroy ()
{
// ignore timer destroy requests
}
bool tcpSendWatchdog::again () const
{
return false; // a one shot
}
double tcpSendWatchdog::delay () const
{
return this->period;
}
const char *tcpSendWatchdog::name () const
{
return "TCP Send Watchdog";
}

1474
src/ca/tcpiiu.cpp Normal file

File diff suppressed because it is too large Load Diff

1022
src/ca/udpiiu.cpp Normal file

File diff suppressed because it is too large Load Diff