major revisions
This commit is contained in:
213
src/ca/CASG.cpp
Normal file
213
src/ca/CASG.cpp
Normal 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 );
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
TOP=../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
CMPLR = STRICT
|
||||
|
||||
#
|
||||
# includes to install from this subproject
|
||||
#
|
||||
|
||||
@@ -3,8 +3,6 @@ TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
CMPLR = STRICT
|
||||
|
||||
USR_CFLAGS += -DiocCore
|
||||
|
||||
caLib_SRCS += caOsDependent.c
|
||||
|
||||
2783
src/ca/access.cpp
2783
src/ca/access.cpp
File diff suppressed because it is too large
Load Diff
168
src/ca/acctst.c
168
src/ca/acctst.c
@@ -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
15
src/ca/acctstMain.c
Normal 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;
|
||||
}
|
||||
@@ -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
33
src/ca/baseNMIU.cpp
Normal 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
177
src/ca/bhe.cpp
Normal 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
70
src/ca/bhe_IL.h
Normal 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
6
src/ca/caDiagnostics.h
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
enum appendNumberFlag {appendNumber, dontAppendNumber};
|
||||
|
||||
int catime (char *channelName, enum appendNumberFlag appNF);
|
||||
|
||||
int acctst (char *pname);
|
||||
@@ -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
816
src/ca/cac.cpp
Normal 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
273
src/ca/cacChannel.cpp
Normal 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 ¬ify )
|
||||
{
|
||||
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
100
src/ca/cacChannelIO.cpp
Normal 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
107
src/ca/cacIO.h
Normal 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 ¬ify;
|
||||
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 ¬ify ) = 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 ¬ify ) = 0;
|
||||
virtual int subscribe ( unsigned type, unsigned long count, unsigned mask, cacNotify ¬ify ) = 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
60
src/ca/cacNotify.cpp
Normal 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
53
src/ca/cacNotifyIO.cpp
Normal 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 ¬ifyIn ) : 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
55
src/ca/cacServiceList.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
879
src/ca/catime.c
879
src/ca/catime.c
File diff suppressed because it is too large
Load Diff
25
src/ca/catimeMain.c
Normal file
25
src/ca/catimeMain.c
Normal 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;
|
||||
}
|
||||
656
src/ca/conn.cpp
656
src/ca/conn.cpp
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
1
src/ca/disconnectTimer.cpp
Normal file
1
src/ca/disconnectTimer.cpp
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -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
69
src/ca/getCallback.cpp
Normal 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
44
src/ca/inetAddrID_IL.h
Normal 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;
|
||||
}
|
||||
1395
src/ca/iocinf.cpp
1395
src/ca/iocinf.cpp
File diff suppressed because it is too large
Load Diff
834
src/ca/iocinf.h
834
src/ca/iocinf.h
File diff suppressed because it is too large
Load Diff
838
src/ca/nciu.cpp
Normal file
838
src/ca/nciu.cpp
Normal 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 ¬ify )
|
||||
{
|
||||
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 ¬ify)
|
||||
{
|
||||
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 ¬ify)
|
||||
{
|
||||
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
74
src/ca/netReadCopyIO.cpp
Normal 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 );
|
||||
}
|
||||
57
src/ca/netReadNotifyIO.cpp
Normal file
57
src/ca/netReadNotifyIO.cpp
Normal 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 ¬ifyIn ) :
|
||||
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
123
src/ca/netSubscription.cpp
Normal 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 ¬ifyIn ) :
|
||||
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 );
|
||||
}
|
||||
55
src/ca/netWriteNotifyIO.cpp
Normal file
55
src/ca/netWriteNotifyIO.cpp
Normal 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 ¬ifyIn) :
|
||||
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);
|
||||
}
|
||||
@@ -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
30
src/ca/netiiu.cpp
Normal 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
101
src/ca/oldAccess.h
Normal 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
172
src/ca/oldChannel.cpp
Normal 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 );
|
||||
}
|
||||
|
||||
|
||||
66
src/ca/oldSubscription.cpp
Normal file
66
src/ca/oldSubscription.cpp
Normal 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 );
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
71
src/ca/putCallback.cpp
Normal 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 );
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
1084
src/ca/service.cpp
1084
src/ca/service.cpp
File diff suppressed because it is too large
Load Diff
130
src/ca/syncGroupNotify.cpp
Normal file
130
src/ca/syncGroupNotify.cpp
Normal 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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
72
src/ca/tcpRecvWatchdog.cpp
Normal file
72
src/ca/tcpRecvWatchdog.cpp
Normal 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";
|
||||
}
|
||||
46
src/ca/tcpSendWatchdog.cpp
Normal file
46
src/ca/tcpSendWatchdog.cpp
Normal 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
1474
src/ca/tcpiiu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1022
src/ca/udpiiu.cpp
Normal file
1022
src/ca/udpiiu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user