first cut at multi-threading version
This commit is contained in:
@@ -8,7 +8,10 @@ CMPLR = STRICT
|
||||
#
|
||||
# includes to install from this subproject
|
||||
#
|
||||
INC += cadef.h
|
||||
INC += caerr.h
|
||||
INC += caProto.h
|
||||
INC += db_access.h
|
||||
|
||||
#LIBSRCS += caOsDependent.c
|
||||
LIBSRCS += access.cpp
|
||||
|
||||
@@ -14,13 +14,13 @@ INC += caProto.h
|
||||
#
|
||||
|
||||
# on generic system
|
||||
ca_SRCS_DEFAULT = if_depen.c
|
||||
#ca_SRCS_DEFAULT = if_depen.c
|
||||
|
||||
# on WIN32 only
|
||||
ca_SRCS_WIN32 = windows_depen.c
|
||||
#ca_SRCS_WIN32 = windows_depen.c
|
||||
|
||||
# on vxWorks only
|
||||
ca_SRCS_vxWorks = vxWorks_depen.c
|
||||
#ca_SRCS_vxWorks = vxWorks_depen.c
|
||||
|
||||
# on all systems
|
||||
ca_SRCS += caOsDependent.c
|
||||
|
||||
3508
src/ca/access.c
3508
src/ca/access.c
File diff suppressed because it is too large
Load Diff
3343
src/ca/access.cpp
Normal file
3343
src/ca/access.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2305
src/ca/acctst.c
2305
src/ca/acctst.c
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,16 @@
|
||||
|
||||
|
||||
#include "envDefs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "envDefs.h"
|
||||
#if 0
|
||||
|
||||
void caSetupAddrList(
|
||||
ELLLIST *pList,
|
||||
SOCKET socket);
|
||||
|
||||
void caPrintAddrList(ELLLIST *pList);
|
||||
|
||||
epicsShareFunc void epicsShareAPI caDiscoverInterfaces(
|
||||
@@ -17,7 +19,8 @@ epicsShareFunc void epicsShareAPI caDiscoverInterfaces(
|
||||
unsigned short port,
|
||||
struct in_addr matchAddr);
|
||||
|
||||
epicsShareFunc void epicsShareAPI caAddConfiguredAddr(
|
||||
epicsShareFunc void caAddConfiguredAddr (
|
||||
cac *pcac,
|
||||
ELLLIST *pList,
|
||||
const ENV_PARAM *pEnv,
|
||||
SOCKET socket,
|
||||
@@ -28,15 +31,7 @@ int local_addr(SOCKET socket, struct sockaddr_in *plcladdr);
|
||||
epicsShareFunc unsigned short epicsShareAPI
|
||||
caFetchPortConfig(const ENV_PARAM *pEnv, unsigned short defaultPort);
|
||||
|
||||
typedef union ca_addr {
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr sa;
|
||||
}caAddr;
|
||||
|
||||
typedef struct {
|
||||
ELLNODE node;
|
||||
caAddr destAddr;
|
||||
}caAddrNode;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
* Author: Jeffrey O. Hill
|
||||
* hill@luke.lanl.gov
|
||||
* (505) 665 1831
|
||||
* Date: 9-93
|
||||
*
|
||||
* 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 "osiSleep.h"
|
||||
#include "bsdSocketResource.h"
|
||||
|
||||
/*
|
||||
* cac_select_io()
|
||||
*
|
||||
* NOTE: on multithreaded systems this assumes that the
|
||||
* local implementation of select is reentrant
|
||||
*/
|
||||
int cac_select_io (CA_STATIC *ca_static, struct timeval *ptimeout, int flags)
|
||||
{
|
||||
/*
|
||||
* Use auto timeout so there is no chance of
|
||||
* recursive reuse of ptimeout
|
||||
*/
|
||||
struct timeval autoTimeOut = *ptimeout;
|
||||
long status;
|
||||
IIU *piiu;
|
||||
unsigned long freespace;
|
||||
SOCKET maxfd;
|
||||
caFDInfo *pfdi;
|
||||
int ioPending;
|
||||
|
||||
LOCK;
|
||||
pfdi = (caFDInfo *) ellGet(&ca_static->fdInfoFreeList);
|
||||
|
||||
if (!pfdi) {
|
||||
pfdi = (caFDInfo *) calloc (1, sizeof(*pfdi));
|
||||
if (!pfdi) {
|
||||
ca_printf("CAC: no mem for select ctx?\n");
|
||||
UNLOCK;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ellAdd (&ca_static->fdInfoList, &pfdi->node);
|
||||
|
||||
FD_ZERO (&pfdi->readMask);
|
||||
FD_ZERO (&pfdi->writeMask);
|
||||
|
||||
maxfd = 0;
|
||||
ioPending = FALSE;
|
||||
for( piiu = (IIU *) iiuList.node.next;
|
||||
piiu; piiu = (IIU *) piiu->node.next) {
|
||||
|
||||
if (piiu->state==iiu_disconnected) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!FD_IN_FDSET(piiu->sock_chan))
|
||||
{
|
||||
ca_printf(
|
||||
"%s.%d: file number %d > FD_SETSIZE=%d ignored\n",
|
||||
__FILE__, __LINE__, piiu->sock_chan, FD_SETSIZE);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dont bother receiving if we have insufficient
|
||||
* space for the maximum UDP message, or space
|
||||
* for one TCP byte.
|
||||
*/
|
||||
if (flags&CA_DO_RECVS) {
|
||||
freespace = cacRingBufferWriteSize (&piiu->recv, TRUE);
|
||||
if (freespace>=piiu->minfreespace) {
|
||||
maxfd = max (maxfd,piiu->sock_chan);
|
||||
FD_SET (piiu->sock_chan, &pfdi->readMask);
|
||||
piiu->recvPending = TRUE;
|
||||
ioPending = TRUE;
|
||||
}
|
||||
else {
|
||||
piiu->recvPending = FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
piiu->recvPending = FALSE;
|
||||
}
|
||||
|
||||
if (piiu->state==iiu_connecting) {
|
||||
FD_SET (piiu->sock_chan, &pfdi->writeMask);
|
||||
ioPending = TRUE;
|
||||
}
|
||||
else if (flags&CA_DO_SENDS || piiu->pushPending) {
|
||||
if (cacRingBufferReadSize(&piiu->send, FALSE)>0) {
|
||||
maxfd = max (maxfd,piiu->sock_chan);
|
||||
FD_SET (piiu->sock_chan, &pfdi->writeMask);
|
||||
ioPending = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
UNLOCK;
|
||||
|
||||
/*
|
||||
* win32 requires this (others will
|
||||
* run faster with this installed)
|
||||
*/
|
||||
if (!ioPending) {
|
||||
/*
|
||||
* recover from subtle differences between
|
||||
* windows sockets and UNIX sockets implementation
|
||||
* of select()
|
||||
*/
|
||||
if ( ptimeout->tv_sec!=0 || ptimeout->tv_usec!=0 ) {
|
||||
osiSleep (ptimeout->tv_sec, ptimeout->tv_usec);
|
||||
}
|
||||
status = 0;
|
||||
}
|
||||
else {
|
||||
status = select (maxfd+1, &pfdi->readMask, &pfdi->writeMask,
|
||||
NULL, &autoTimeOut);
|
||||
|
||||
if (status<0) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
|
||||
if (errnoCpy!=SOCK_EINTR) {
|
||||
ca_printf (
|
||||
"CAC: unexpected select fail: %s\n",
|
||||
SOCKERRSTR(errnoCpy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get a new time stamp if we have been waiting
|
||||
* for any significant length of time
|
||||
*/
|
||||
if (ptimeout->tv_sec || ptimeout->tv_usec) {
|
||||
cac_gettimeval (&ca_static->currentTime);
|
||||
}
|
||||
|
||||
LOCK;
|
||||
|
||||
/*
|
||||
* must run through the IIU list even if no IO is pending
|
||||
* if any of the IOCs are in flow control (so that an exit
|
||||
* flow control msg can be sent to each of them that are)
|
||||
*/
|
||||
if (status>0 || (ca_static->ca_number_iiu_in_fc>0u && status>=0)) {
|
||||
status = 0;
|
||||
for (piiu = (IIU *) iiuList.node.next;
|
||||
piiu; piiu = (IIU *) piiu->node.next) {
|
||||
|
||||
if (piiu->state==iiu_disconnected) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FD_ISSET(piiu->sock_chan,&pfdi->readMask)) {
|
||||
unsigned long bytesReceived;
|
||||
|
||||
bytesReceived = (*piiu->recvBytes)(piiu);
|
||||
if (bytesReceived>0) {
|
||||
status++;
|
||||
/*
|
||||
* if we are not blocking and there is a
|
||||
* message present then start to suspect that
|
||||
* we are getting behind
|
||||
*/
|
||||
if (piiu->sock_proto==IPPROTO_TCP) {
|
||||
if (ptimeout->tv_sec==0 && ptimeout->tv_usec==0) {
|
||||
flow_control_on(piiu);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (piiu->recvPending) {
|
||||
/*
|
||||
* if we are looking for incoming messages
|
||||
* and there are none then we are certain that
|
||||
* we are not getting behind
|
||||
*/
|
||||
if (piiu->sock_proto==IPPROTO_TCP) {
|
||||
flow_control_off(piiu);
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(piiu->sock_chan,&pfdi->writeMask)) {
|
||||
unsigned long bytesSent;
|
||||
|
||||
bytesSent = (*piiu->sendBytes)(piiu);
|
||||
if (bytesSent>0) {
|
||||
status++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ellDelete (&ca_static->fdInfoList, &pfdi->node);
|
||||
ellAdd (&ca_static->fdInfoFreeList, &pfdi->node);
|
||||
UNLOCK;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
184
src/ca/caProto.h
184
src/ca/caProto.h
@@ -35,37 +35,37 @@
|
||||
* CA protocol number
|
||||
* TCP/UDP port number (bumped each major protocol change)
|
||||
*/
|
||||
#define CA_PROTOCOL_VERSION 4u
|
||||
#define CA_MINOR_VERSION 8u
|
||||
#define CA_VERSION_STRING "4.8"
|
||||
#define CA_UKN_MINOR_VERSION 0u /* unknown minor version */
|
||||
#define CA_PROTOCOL_VERSION 4u
|
||||
#define CA_MINOR_VERSION 8u
|
||||
#define CA_VERSION_STRING "4.8"
|
||||
#define CA_UKN_MINOR_VERSION 0u /* unknown minor version */
|
||||
#if CA_PROTOCOL_VERSION == 4u
|
||||
#define CA_V41(MAJOR,MINOR) ((MINOR)>=1u)
|
||||
#define CA_V42(MAJOR,MINOR) ((MINOR)>=2u)
|
||||
#define CA_V43(MAJOR,MINOR) ((MINOR)>=3u)
|
||||
#define CA_V44(MAJOR,MINOR) ((MINOR)>=4u)
|
||||
#define CA_V45(MAJOR,MINOR) ((MINOR)>=5u)
|
||||
#define CA_V46(MAJOR,MINOR) ((MINOR)>=6u)
|
||||
#define CA_V47(MAJOR,MINOR) ((MINOR)>=7u)
|
||||
#define CA_V48(MAJOR,MINOR) ((MINOR)>=8u)
|
||||
#define CA_V41(MAJOR,MINOR) ((MINOR)>=1u)
|
||||
#define CA_V42(MAJOR,MINOR) ((MINOR)>=2u)
|
||||
#define CA_V43(MAJOR,MINOR) ((MINOR)>=3u)
|
||||
#define CA_V44(MAJOR,MINOR) ((MINOR)>=4u)
|
||||
#define CA_V45(MAJOR,MINOR) ((MINOR)>=5u)
|
||||
#define CA_V46(MAJOR,MINOR) ((MINOR)>=6u)
|
||||
#define CA_V47(MAJOR,MINOR) ((MINOR)>=7u)
|
||||
#define CA_V48(MAJOR,MINOR) ((MINOR)>=8u)
|
||||
#elif CA_PROTOCOL_VERSION > 4u
|
||||
#define CA_V41(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V42(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V43(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V44(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V45(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V46(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V47(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V48(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V41(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V42(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V43(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V44(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V45(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V46(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V47(MAJOR,MINOR) ( 1u )
|
||||
#define CA_V48(MAJOR,MINOR) ( 1u )
|
||||
#else
|
||||
#define CA_V41(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V42(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V43(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V44(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V45(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V46(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V47(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V48(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V41(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V42(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V43(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V44(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V45(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V46(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V47(MAJOR,MINOR) ( 0u )
|
||||
#define CA_V48(MAJOR,MINOR) ( 0u )
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -74,14 +74,14 @@
|
||||
* environment variables "EPICS_CA_REPEATER_PORT" and
|
||||
* "EPICS_CA_SERVER_PORT"
|
||||
*/
|
||||
#define CA_PORT_BASE IPPORT_USERRESERVED + 56U
|
||||
#define CA_SERVER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u)
|
||||
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u+1u)
|
||||
#define CA_PORT_BASE IPPORT_USERRESERVED + 56U
|
||||
#define CA_SERVER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u)
|
||||
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2u+1u)
|
||||
/* 1492(min of ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP) joh 8-6-97 */
|
||||
#define ETHERNET_MAX_UDP (1482u-20u-8u)
|
||||
#define MAX_UDP 1024u /* original MAX_UDP */
|
||||
#define MAX_TCP (MAX_UDP*16u) /* so waveforms fit */
|
||||
#define MAX_MSG_SIZE (MAX_TCP) /* the larger of tcp and udp max */
|
||||
#define ETHERNET_MAX_UDP (1482u-20u-8u)
|
||||
#define MAX_UDP 1024u /* original MAX_UDP */
|
||||
#define MAX_TCP (MAX_UDP*16u) /* so waveforms fit */
|
||||
#define MAX_MSG_SIZE (MAX_TCP) /* the larger of tcp and udp max */
|
||||
|
||||
/*
|
||||
* architecture independent types
|
||||
@@ -89,39 +89,39 @@
|
||||
* (so far this works on all archs we have ported to)
|
||||
*/
|
||||
typedef unsigned short ca_uint16_t;
|
||||
typedef unsigned int ca_uint32_t;
|
||||
typedef unsigned int ca_uint32_t;
|
||||
typedef float ca_float32_t;
|
||||
typedef ca_uint32_t caResId;
|
||||
typedef ca_uint32_t caResId;
|
||||
|
||||
/* values for m_cmmd */
|
||||
#define CA_PROTO_NOOP 0u /* do nothing, but verify TCP */
|
||||
#define CA_PROTO_EVENT_ADD 1u /* add an event */
|
||||
#define CA_PROTO_EVENT_CANCEL 2u /* cancel an event */
|
||||
#define CA_PROTO_READ 3u /* read and return a channel value*/
|
||||
#define CA_PROTO_WRITE 4u /* write a channel value */
|
||||
#define CA_PROTO_SNAPSHOT 5u /* snapshot of the system */
|
||||
#define CA_PROTO_SEARCH 6u /* IOC channel search */
|
||||
#define CA_PROTO_BUILD 7u /* build - obsolete */
|
||||
#define CA_PROTO_EVENTS_OFF 8u /* flow control */
|
||||
#define CA_PROTO_EVENTS_ON 9u /* flow control */
|
||||
#define CA_PROTO_READ_SYNC 10u /* purge old reads */
|
||||
#define CA_PROTO_ERROR 11u /* an operation failed */
|
||||
#define CA_PROTO_CLEAR_CHANNEL 12u /* free chan resources */
|
||||
#define CA_PROTO_RSRV_IS_UP 13u /* CA server has joined the net */
|
||||
#define CA_PROTO_NOT_FOUND 14u /* channel not found */
|
||||
#define CA_PROTO_READ_NOTIFY 15u /* add a one shot event */
|
||||
#define CA_PROTO_READ_BUILD 16u /* read and build - obsolete */
|
||||
#define REPEATER_CONFIRM 17u /* registration confirmation */
|
||||
#define CA_PROTO_CLAIM_CIU 18u /* client claims resource in server */
|
||||
#define CA_PROTO_WRITE_NOTIFY 19u /* notify after write chan value */
|
||||
#define CA_PROTO_CLIENT_NAME 20u /* CA V4.1 identify client */
|
||||
#define CA_PROTO_HOST_NAME 21u /* CA V4.1 identify client */
|
||||
#define CA_PROTO_ACCESS_RIGHTS 22u /* CA V4.2 asynch access rights chg */
|
||||
#define CA_PROTO_ECHO 23u /* CA V4.3 connection verify */
|
||||
#define REPEATER_REGISTER 24u /* registr for repeater fan out */
|
||||
#define CA_PROTO_SIGNAL 25u /* knock the server out of select */
|
||||
#define CA_PROTO_CLAIM_CIU_FAILED 26u /* unable to create chan resource in server */
|
||||
#define CA_PROTO_SERVER_DISCONN 27u /* server deletes PV (or channel) */
|
||||
/* values for m_cmmd */
|
||||
#define CA_PROTO_NOOP 0u /* do nothing, but verify TCP */
|
||||
#define CA_PROTO_EVENT_ADD 1u /* add an event */
|
||||
#define CA_PROTO_EVENT_CANCEL 2u /* cancel an event */
|
||||
#define CA_PROTO_READ 3u /* read and return a channel value*/
|
||||
#define CA_PROTO_WRITE 4u /* write a channel value */
|
||||
#define CA_PROTO_SNAPSHOT 5u /* snapshot of the system */
|
||||
#define CA_PROTO_SEARCH 6u /* IOC channel search */
|
||||
#define CA_PROTO_BUILD 7u /* build - obsolete */
|
||||
#define CA_PROTO_EVENTS_OFF 8u /* flow control */
|
||||
#define CA_PROTO_EVENTS_ON 9u /* flow control */
|
||||
#define CA_PROTO_READ_SYNC 10u /* purge old reads */
|
||||
#define CA_PROTO_ERROR 11u /* an operation failed */
|
||||
#define CA_PROTO_CLEAR_CHANNEL 12u /* free chan resources */
|
||||
#define CA_PROTO_RSRV_IS_UP 13u /* CA server has joined the net */
|
||||
#define CA_PROTO_NOT_FOUND 14u /* channel not found */
|
||||
#define CA_PROTO_READ_NOTIFY 15u /* add a one shot event */
|
||||
#define CA_PROTO_READ_BUILD 16u /* read and build - obsolete */
|
||||
#define REPEATER_CONFIRM 17u /* registration confirmation */
|
||||
#define CA_PROTO_CLAIM_CIU 18u /* client claims resource in server */
|
||||
#define CA_PROTO_WRITE_NOTIFY 19u /* notify after write chan value */
|
||||
#define CA_PROTO_CLIENT_NAME 20u /* CA V4.1 identify client */
|
||||
#define CA_PROTO_HOST_NAME 21u /* CA V4.1 identify client */
|
||||
#define CA_PROTO_ACCESS_RIGHTS 22u /* CA V4.2 asynch access rights chg */
|
||||
#define CA_PROTO_ECHO 23u /* CA V4.3 connection verify */
|
||||
#define REPEATER_REGISTER 24u /* registr for repeater fan out */
|
||||
#define CA_PROTO_SIGNAL 25u /* knock the server out of select */
|
||||
#define CA_PROTO_CLAIM_CIU_FAILED 26u /* unable to create chan resource in server */
|
||||
#define CA_PROTO_SERVER_DISCONN 27u /* server deletes PV (or channel) */
|
||||
|
||||
#define CA_PROTO_LAST_CMMD CA_PROTO_CLAIM_CIU_FAILED
|
||||
|
||||
@@ -129,28 +129,28 @@ typedef ca_uint32_t caResId;
|
||||
* for use with search and not_found (if search fails and
|
||||
* its not a broadcast tell the client to look elesewhere)
|
||||
*/
|
||||
#define DOREPLY 10u
|
||||
#define DONTREPLY 5u
|
||||
#define DOREPLY 10u
|
||||
#define DONTREPLY 5u
|
||||
|
||||
/* size of object in bytes rounded up to nearest oct word */
|
||||
#define OCT_ROUND(A) ((((unsigned long)(A))+7u)>>3u)
|
||||
#define OCT_SIZEOF(A) (OCT_ROUND(sizeof(A)))
|
||||
#define OCT_ROUND(A) (((A)+7)/8)
|
||||
#define OCT_SIZEOF(A) (OCT_ROUND(sizeof(A)))
|
||||
|
||||
/* size of object in bytes rounded up to nearest long word */
|
||||
#define QUAD_ROUND(A) (((unsigned long)(A))+3u)>>2u)
|
||||
#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A)))
|
||||
#define QUAD_ROUND(A) ((A)+3)/4)
|
||||
#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A)))
|
||||
|
||||
/* size of object in bytes rounded up to nearest short word */
|
||||
#define BI_ROUND(A) ((((unsigned long)(A))+1u)>>1u)
|
||||
#define BI_SIZEOF(A) (BI_ROUND(sizeof(A)))
|
||||
#define BI_ROUND(A) (((A)+1)/2)
|
||||
#define BI_SIZEOF(A) (BI_ROUND(sizeof(A)))
|
||||
|
||||
/*
|
||||
* For communicating access rights to the clients
|
||||
*
|
||||
* (placed in m_available hdr field of CA_PROTO_ACCESS_RIGHTS cmmd
|
||||
*/
|
||||
#define CA_PROTO_ACCESS_RIGHT_READ (1u<<0u)
|
||||
#define CA_PROTO_ACCESS_RIGHT_WRITE (1u<<1u)
|
||||
#define CA_PROTO_ACCESS_RIGHT_READ (1u<<0u)
|
||||
#define CA_PROTO_ACCESS_RIGHT_WRITE (1u<<1u)
|
||||
|
||||
/*
|
||||
* All structures passed in the protocol must have individual
|
||||
@@ -166,30 +166,30 @@ typedef ca_uint32_t caResId;
|
||||
* the common part of each message sent/recv by the
|
||||
* CA server.
|
||||
*/
|
||||
typedef struct ca_hdr {
|
||||
ca_uint16_t m_cmmd; /* operation to be performed */
|
||||
ca_uint16_t m_postsize; /* size of message extension */
|
||||
ca_uint16_t m_dataType; /* operation data type */
|
||||
ca_uint16_t m_count; /* operation data count */
|
||||
ca_uint32_t m_cid; /* channel identifier */
|
||||
ca_uint32_t m_available; /* undefined message location for use
|
||||
* by client processes */
|
||||
typedef struct ca_hdr {
|
||||
ca_uint16_t m_cmmd; /* operation to be performed */
|
||||
ca_uint16_t m_postsize; /* size of message extension */
|
||||
ca_uint16_t m_dataType; /* operation data type */
|
||||
ca_uint16_t m_count; /* operation data count */
|
||||
ca_uint32_t m_cid; /* channel identifier */
|
||||
ca_uint32_t m_available; /* undefined message location for use
|
||||
* by client processes */
|
||||
}caHdr;
|
||||
|
||||
/*
|
||||
* for monitor (event) message extension
|
||||
*/
|
||||
struct mon_info{
|
||||
ca_float32_t m_lval; /* low delta */
|
||||
ca_float32_t m_hval; /* high delta */
|
||||
ca_float32_t m_toval; /* period btween samples */
|
||||
ca_uint16_t m_mask; /* event select mask */
|
||||
ca_uint16_t m_pad; /* extend to 32 bits */
|
||||
ca_float32_t m_lval; /* low delta */
|
||||
ca_float32_t m_hval; /* high delta */
|
||||
ca_float32_t m_toval; /* period btween samples */
|
||||
ca_uint16_t m_mask; /* event select mask */
|
||||
ca_uint16_t m_pad; /* extend to 32 bits */
|
||||
};
|
||||
|
||||
struct monops { /* monitor req opi to ioc */
|
||||
caHdr m_header;
|
||||
struct mon_info m_info;
|
||||
struct monops { /* monitor req opi to ioc */
|
||||
caHdr m_header;
|
||||
struct mon_info m_info;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
75
src/ca/caPutNotify.cpp
Normal file
75
src/ca/caPutNotify.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* caExtraEventLabor ()
|
||||
*/
|
||||
LOCAL void caExtraEventLabor (void *pArg)
|
||||
{
|
||||
cac *pcac = (cac *) pArg;
|
||||
dbcaPutNotify *ppnb;
|
||||
struct event_handler_args args;
|
||||
|
||||
while (TRUE) {
|
||||
semTakeStatus semStatus;
|
||||
|
||||
/*
|
||||
* independent lock used here in order to
|
||||
* avoid any possibility of blocking
|
||||
* the database (or indirectly blocking
|
||||
* one client on another client).
|
||||
*/
|
||||
semStatus = semMutexTakeTimeout (pcac->localIIU.putNotifyLock, 60.0 /* sec */);
|
||||
if (semStatus!=semTakeOK) {
|
||||
ca_printf (pcac, "cac: put notify deadlock condition detected\n");
|
||||
(*pcac->localIIU.pdbAdapter->p_db_post_extra_labor) (pcac->localIIU.evctx);
|
||||
break;
|
||||
}
|
||||
ppnb = (dbcaPutNotify *) ellGet (&pcac->localIIU.putNotifyQue);
|
||||
semMutexGive (pcac->localIIU.putNotifyLock);
|
||||
|
||||
/*
|
||||
* break to loop exit
|
||||
*/
|
||||
if (!ppnb) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* setup arguments and call user's function
|
||||
*/
|
||||
args.usr = ppnb->caUserArg;
|
||||
args.chid = ppnb->dbPutNotify.usrPvt;
|
||||
#error type must be an external type
|
||||
args.type = ppnb->dbPutNotify.dbrType;
|
||||
args.count = ppnb->dbPutNotify.nRequest;
|
||||
args.dbr = NULL;
|
||||
if (ppnb->dbPutNotify.status) {
|
||||
if (ppnb->dbPutNotify.status == S_db_Blocked) {
|
||||
args.status = ECA_PUTCBINPROG;
|
||||
}
|
||||
else {
|
||||
args.status = ECA_PUTFAIL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
args.status = ECA_NORMAL;
|
||||
}
|
||||
|
||||
LOCK (pcac);
|
||||
(*ppnb->caUserCallback) (args);
|
||||
UNLOCK (pcac);
|
||||
|
||||
ppnb->busy = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* wakeup the TCP thread if it is waiting for a cb to complete
|
||||
*/
|
||||
semBinaryGive (pcac->ca_blockSem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* caRepeater.c
|
||||
* share/src/ca/caRepeater.c
|
||||
*
|
||||
* CA broadcast repeater executable
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
* Date: 3-27-90
|
||||
*
|
||||
* PURPOSE:
|
||||
* Broadcasts fan out over the LAN, but old IP kernels do not allow
|
||||
* two processes on the same machine to get the same broadcast
|
||||
* (and modern IP kernels do not allow two processes on the same machine
|
||||
* to receive the same unicast).
|
||||
*
|
||||
* This code fans out UDP messages sent to the CA repeater port
|
||||
* to all CA client processes that have subscribed.
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
* see repeater.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
ca_repeater ();
|
||||
assert (0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
35
src/ca/caRepeater.cpp
Normal file
35
src/ca/caRepeater.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* CA UDP repeater standalone executable
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
* Date: 3-27-90
|
||||
*
|
||||
* PURPOSE:
|
||||
* Broadcasts fan out over the LAN, but old IP kernels do not allow
|
||||
* two processes on the same machine to get the same broadcast
|
||||
* (and modern IP kernels do not allow two processes on the same machine
|
||||
* to receive the same unicast).
|
||||
*
|
||||
* This code fans out UDP messages sent to the CA repeater port
|
||||
* to all CA client processes that have subscribed.
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
* see repeater.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "shareLib.h"
|
||||
|
||||
epicsShareFunc void epicsShareAPI ca_repeater (void);
|
||||
|
||||
int main()
|
||||
{
|
||||
ca_repeater ();
|
||||
assert (0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -25,9 +25,7 @@
|
||||
#define LOCAL static
|
||||
#endif
|
||||
|
||||
#ifndef OK
|
||||
#define OK 0
|
||||
#endif
|
||||
#define CATIME_OK 0
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
@@ -199,7 +197,7 @@ int catime (char *channelName, enum appendNumberFlag appNF)
|
||||
|
||||
SEVCHK (ca_task_exit (), "Unable to free resources at exit");
|
||||
|
||||
return OK;
|
||||
return CATIME_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -216,7 +214,7 @@ LOCAL void printSearchStat(unsigned iterations)
|
||||
double stdDev;
|
||||
|
||||
for (pi=itemList; pi<&itemList[iterations]; pi++) {
|
||||
double retry = pi->chix->retry;
|
||||
double retry = ca_search_attempts (pi->chix);
|
||||
X += retry;
|
||||
XX += retry*retry;
|
||||
if (retry>max) {
|
||||
|
||||
1132
src/ca/conn.c
1132
src/ca/conn.c
File diff suppressed because it is too large
Load Diff
677
src/ca/conn.cpp
Normal file
677
src/ca/conn.cpp
Normal file
@@ -0,0 +1,677 @@
|
||||
/* $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"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define LOGRETRYINTERVAL logRetryInterval(__FILE__, __LINE__);
|
||||
LOCAL void logRetryInterval (pcac, char *pFN, unsigned lineno);
|
||||
#else
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
static char *sccsId = "@(#) $Id$";
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "iocinf.h"
|
||||
@@ -168,8 +166,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
char *pSrc = s;
|
||||
char *pDest = d;
|
||||
char *pSrc = (char *) s;
|
||||
char *pDest = (char *) d;
|
||||
|
||||
/* convert "in place" -> nothing to do */
|
||||
if (s == d)
|
||||
@@ -196,8 +194,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
dbr_short_t *pSrc = s;
|
||||
dbr_short_t *pDest = d;
|
||||
dbr_short_t *pSrc = (dbr_short_t *) s;
|
||||
dbr_short_t *pDest = (dbr_short_t *) d;
|
||||
unsigned long i;
|
||||
|
||||
for(i=0; i<num; i++){
|
||||
@@ -225,8 +223,8 @@ unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
unsigned long i;
|
||||
dbr_char_t *pSrc = s;
|
||||
dbr_char_t *pDest = d;
|
||||
dbr_char_t *pSrc = (dbr_char_t *) s;
|
||||
dbr_char_t *pDest = (dbr_char_t *) d;
|
||||
|
||||
/* convert "in place" -> nothing to do */
|
||||
if (s == d)
|
||||
@@ -251,8 +249,8 @@ unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
unsigned long i;
|
||||
dbr_long_t *pSrc = s;
|
||||
dbr_long_t *pDest = d;
|
||||
dbr_long_t *pSrc = (dbr_long_t *) s;
|
||||
dbr_long_t *pDest = (dbr_long_t *) d;
|
||||
|
||||
for(i=0; i<num; i++){
|
||||
*pDest = dbr_ntohl( *pSrc );
|
||||
@@ -282,8 +280,8 @@ unsigned long num /* number of values */
|
||||
dbr_enum_t *pSrc;
|
||||
dbr_enum_t *pDest;
|
||||
|
||||
pSrc = s;
|
||||
pDest = d;
|
||||
pSrc = (dbr_enum_t *) s;
|
||||
pDest = (dbr_enum_t *) d;
|
||||
for(i=0; i<num; i++){
|
||||
*pDest = dbr_ntohs(*pSrc);
|
||||
/*
|
||||
@@ -311,8 +309,8 @@ unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
unsigned long i;
|
||||
dbr_float_t *pSrc = s;
|
||||
dbr_float_t *pDest = d;
|
||||
dbr_float_t *pSrc = (dbr_float_t *) s;
|
||||
dbr_float_t *pDest = (dbr_float_t *) d;
|
||||
|
||||
for(i=0; i<num; i++){
|
||||
if(encode){
|
||||
@@ -344,8 +342,8 @@ unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
unsigned long i;
|
||||
dbr_double_t *pSrc = s;
|
||||
dbr_double_t *pDest = d;
|
||||
dbr_double_t *pSrc = (dbr_double_t *) s;
|
||||
dbr_double_t *pDest = (dbr_double_t *) d;
|
||||
|
||||
for(i=0; i<num; i++){
|
||||
if(encode){
|
||||
@@ -385,8 +383,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_sts_string *pSrc = s;
|
||||
struct dbr_sts_string *pDest = d;
|
||||
struct dbr_sts_string *pSrc = (struct dbr_sts_string *) s;
|
||||
struct dbr_sts_string *pDest = (struct dbr_sts_string *) d;
|
||||
|
||||
/* convert ieee to vax format or vax to ieee */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -423,8 +421,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_sts_int *pSrc = s;
|
||||
struct dbr_sts_int *pDest = d;
|
||||
struct dbr_sts_int *pSrc = (struct dbr_sts_int *) s;
|
||||
struct dbr_sts_int *pDest = (struct dbr_sts_int *) d;
|
||||
|
||||
/* convert vax to ieee or ieee to vax format -- same code*/
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -458,8 +456,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_sts_float *pSrc = s;
|
||||
struct dbr_sts_float *pDest = d;
|
||||
struct dbr_sts_float *pSrc = (struct dbr_sts_float *) s;
|
||||
struct dbr_sts_float *pDest = (struct dbr_sts_float *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -484,8 +482,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_sts_double *pSrc = s;
|
||||
struct dbr_sts_double *pDest = d;
|
||||
struct dbr_sts_double *pSrc = (struct dbr_sts_double *) s;
|
||||
struct dbr_sts_double *pDest = (struct dbr_sts_double *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -513,8 +511,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_sts_enum *pSrc = s;
|
||||
struct dbr_sts_enum *pDest = d;
|
||||
struct dbr_sts_enum *pSrc = (struct dbr_sts_enum *) s;
|
||||
struct dbr_sts_enum *pDest = (struct dbr_sts_enum *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -541,8 +539,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_gr_int *pSrc = s;
|
||||
struct dbr_gr_int *pDest = d;
|
||||
struct dbr_gr_int *pSrc = (struct dbr_gr_int *) s;
|
||||
struct dbr_gr_int *pDest = (struct dbr_gr_int *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -578,8 +576,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_gr_char *pSrc = s;
|
||||
struct dbr_gr_char *pDest = d;
|
||||
struct dbr_gr_char *pSrc = (struct dbr_gr_char *) s;
|
||||
struct dbr_gr_char *pDest = (struct dbr_gr_char *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -619,8 +617,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_gr_long *pSrc = s;
|
||||
struct dbr_gr_long *pDest = d;
|
||||
struct dbr_gr_long *pSrc = (struct dbr_gr_long *) s;
|
||||
struct dbr_gr_long *pDest = (struct dbr_gr_long *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -657,8 +655,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_gr_enum *pSrc = s;
|
||||
struct dbr_gr_enum *pDest = d;
|
||||
struct dbr_gr_enum *pSrc = (struct dbr_gr_enum *) s;
|
||||
struct dbr_gr_enum *pDest = (struct dbr_gr_enum *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -690,8 +688,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_gr_double *pSrc = s;
|
||||
struct dbr_gr_double *pDest = d;
|
||||
struct dbr_gr_double *pSrc = (struct dbr_gr_double *) s;
|
||||
struct dbr_gr_double *pDest = (struct dbr_gr_double *) d;
|
||||
|
||||
/* these are same for vax to ieee or ieee to vax */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -752,8 +750,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_gr_float *pSrc = s;
|
||||
struct dbr_gr_float *pDest = d;
|
||||
struct dbr_gr_float *pSrc = (struct dbr_gr_float *) s;
|
||||
struct dbr_gr_float *pDest = (struct dbr_gr_float *) d;
|
||||
|
||||
/* these are same for vax to ieee or ieee to vax */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -815,8 +813,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_ctrl_int *pSrc = s;
|
||||
struct dbr_ctrl_int *pDest = d;
|
||||
struct dbr_ctrl_int *pSrc = (struct dbr_ctrl_int *) s;
|
||||
struct dbr_ctrl_int *pDest = (struct dbr_ctrl_int *) d;
|
||||
|
||||
/* vax to ieee or ieee to vax -- same code */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -855,8 +853,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_ctrl_long *pSrc = s;
|
||||
struct dbr_ctrl_long *pDest = d;
|
||||
struct dbr_ctrl_long *pSrc = (struct dbr_ctrl_long*) s;
|
||||
struct dbr_ctrl_long *pDest = (struct dbr_ctrl_long *) d;
|
||||
|
||||
/* vax to ieee or ieee to vax -- same code */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -895,8 +893,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_ctrl_char *pSrc = s;
|
||||
struct dbr_ctrl_char *pDest = d;
|
||||
struct dbr_ctrl_char *pSrc = (struct dbr_ctrl_char *) s;
|
||||
struct dbr_ctrl_char *pDest = (struct dbr_ctrl_char *) d;
|
||||
|
||||
/* vax to ieee or ieee to vax -- same code */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -933,8 +931,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_ctrl_double *pSrc = s;
|
||||
struct dbr_ctrl_double *pDest = d;
|
||||
struct dbr_ctrl_double *pSrc = (struct dbr_ctrl_double *) s;
|
||||
struct dbr_ctrl_double *pDest = (struct dbr_ctrl_double *) d;
|
||||
|
||||
/* these are the same for ieee to vax or vax to ieee */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -997,8 +995,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_ctrl_float *pSrc = s;
|
||||
struct dbr_ctrl_float *pDest = d;
|
||||
struct dbr_ctrl_float *pSrc = (struct dbr_ctrl_float *) s;
|
||||
struct dbr_ctrl_float *pDest = (struct dbr_ctrl_float *) d;
|
||||
|
||||
/* these are the same for ieee to vaax or vax to ieee */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -1060,8 +1058,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_ctrl_enum *pSrc = s;
|
||||
struct dbr_ctrl_enum *pDest = d;
|
||||
struct dbr_ctrl_enum *pSrc = (struct dbr_ctrl_enum *) s;
|
||||
struct dbr_ctrl_enum *pDest = (struct dbr_ctrl_enum *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -1096,8 +1094,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_sts_char *pSrc = s;
|
||||
struct dbr_sts_char *pDest = d;
|
||||
struct dbr_sts_char *pSrc = (struct dbr_sts_char *) s;
|
||||
struct dbr_sts_char *pDest = (struct dbr_sts_char *) d;
|
||||
|
||||
/* convert vax to ieee or ieee to vax format -- same code*/
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -1127,8 +1125,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_sts_long *pSrc = s;
|
||||
struct dbr_sts_long *pDest = d;
|
||||
struct dbr_sts_long *pSrc = (struct dbr_sts_long *) s;
|
||||
struct dbr_sts_long *pDest = (struct dbr_sts_long *) d;
|
||||
|
||||
/* convert vax to ieee or ieee to vax format -- same code*/
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -1159,8 +1157,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_time_string *pSrc = s;
|
||||
struct dbr_time_string *pDest = d;
|
||||
struct dbr_time_string *pSrc = (struct dbr_time_string *) s;
|
||||
struct dbr_time_string *pDest = (struct dbr_time_string *) d;
|
||||
|
||||
/* convert ieee to vax format or vax to ieee */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -1191,8 +1189,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_time_short *pSrc = s;
|
||||
struct dbr_time_short *pDest = d;
|
||||
struct dbr_time_short *pSrc = (struct dbr_time_short *) s;
|
||||
struct dbr_time_short *pDest = (struct dbr_time_short *) d;
|
||||
|
||||
/* convert vax to ieee or ieee to vax format -- same code*/
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -1225,8 +1223,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_time_float *pSrc = s;
|
||||
struct dbr_time_float *pDest = d;
|
||||
struct dbr_time_float *pSrc = (struct dbr_time_float *) s;
|
||||
struct dbr_time_float *pDest = (struct dbr_time_float *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -1253,8 +1251,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_time_double *pSrc = s;
|
||||
struct dbr_time_double *pDest = d;
|
||||
struct dbr_time_double *pSrc = (struct dbr_time_double *) s;
|
||||
struct dbr_time_double *pDest = (struct dbr_time_double *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -1282,8 +1280,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_time_enum *pSrc = s;
|
||||
struct dbr_time_enum *pDest = d;
|
||||
struct dbr_time_enum *pSrc = (struct dbr_time_enum *) s;
|
||||
struct dbr_time_enum *pDest = (struct dbr_time_enum *) d;
|
||||
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
pDest->severity = dbr_ntohs(pSrc->severity);
|
||||
@@ -1312,8 +1310,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_time_char *pSrc = s;
|
||||
struct dbr_time_char *pDest = d;
|
||||
struct dbr_time_char *pSrc = (struct dbr_time_char *) s;
|
||||
struct dbr_time_char *pDest = (struct dbr_time_char *) d;
|
||||
|
||||
/* convert vax to ieee or ieee to vax format -- same code*/
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -1344,8 +1342,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_time_long *pSrc = s;
|
||||
struct dbr_time_long *pDest = d;
|
||||
struct dbr_time_long *pSrc = (struct dbr_time_long *) s;
|
||||
struct dbr_time_long *pDest = (struct dbr_time_long *) d;
|
||||
|
||||
/* convert vax to ieee or ieee to vax format -- same code*/
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -1375,8 +1373,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
dbr_put_ackt_t *pSrc = s;
|
||||
dbr_put_ackt_t *pDest = d;
|
||||
dbr_put_ackt_t *pSrc = (dbr_put_ackt_t *) s;
|
||||
dbr_put_ackt_t *pDest = (dbr_put_ackt_t *) d;
|
||||
unsigned long i;
|
||||
|
||||
for(i=0; i<num; i++){
|
||||
@@ -1409,8 +1407,8 @@ int encode, /* cvrt HOST to NET if T */
|
||||
unsigned long num /* number of values */
|
||||
)
|
||||
{
|
||||
struct dbr_stsack_string *pSrc = s;
|
||||
struct dbr_stsack_string *pDest = d;
|
||||
struct dbr_stsack_string *pSrc = (struct dbr_stsack_string *) s;
|
||||
struct dbr_stsack_string *pDest = (struct dbr_stsack_string *) d;
|
||||
|
||||
/* convert ieee to vax format or vax to ieee */
|
||||
pDest->status = dbr_ntohs(pSrc->status);
|
||||
@@ -40,7 +40,7 @@ int evtime(char *pname)
|
||||
status = ca_pend_io(10.0);
|
||||
if(status != ECA_NORMAL){
|
||||
printf("%s not found\n", pname);
|
||||
return OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = ca_add_event(
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/* */
|
||||
/* History */
|
||||
/* ------- */
|
||||
/* 06xx89 joh First Release */
|
||||
/* 060591 joh delinting */
|
||||
/* */
|
||||
/*_begin */
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/* Title: IOC network flow control module */
|
||||
/* File: atcs:[ca]flow_control.c */
|
||||
/* Environment: VMS. UNIX, VRTX */
|
||||
/* Equipment: VAX, SUN, VME */
|
||||
/* */
|
||||
/* */
|
||||
/* Purpose */
|
||||
/* ------- */
|
||||
/* */
|
||||
/* ioc flow control module */
|
||||
/* */
|
||||
/* */
|
||||
/* Special comments */
|
||||
/* ------- -------- */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
/*_end */
|
||||
|
||||
static char *sccsId = "@(#) $Id$";
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
|
||||
/*
|
||||
* FLOW CONTROL
|
||||
*
|
||||
* Keep track of how many times messages have
|
||||
* come with out a break in between and
|
||||
* suppress monitors if we are behind
|
||||
* (an update is sent when we catch up)
|
||||
*/
|
||||
|
||||
void flow_control_on(struct ioc_in_use *piiu)
|
||||
{
|
||||
int status;
|
||||
CA_STATIC *ca_static;
|
||||
|
||||
ca_static = piiu->pcas;
|
||||
LOCK;
|
||||
|
||||
/*
|
||||
* I prefer to avoid going into flow control
|
||||
* as this impacts the performance of batched fetches
|
||||
*/
|
||||
if (piiu->contiguous_msg_count >= MAX_CONTIGUOUS_MSG_COUNT) {
|
||||
if (!piiu->client_busy) {
|
||||
status = ca_busy_message(piiu);
|
||||
if (status==ECA_NORMAL) {
|
||||
assert(ca_static->ca_number_iiu_in_fc<UINT_MAX);
|
||||
ca_static->ca_number_iiu_in_fc++;
|
||||
piiu->client_busy = TRUE;
|
||||
# if defined(DEBUG)
|
||||
printf("fc on\n");
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
piiu->contiguous_msg_count++;
|
||||
}
|
||||
|
||||
UNLOCK;
|
||||
return;
|
||||
}
|
||||
|
||||
void flow_control_off(struct ioc_in_use *piiu)
|
||||
{
|
||||
int status;
|
||||
CA_STATIC *ca_static;
|
||||
|
||||
ca_static = piiu->pcas;
|
||||
LOCK;
|
||||
|
||||
piiu->contiguous_msg_count = 0;
|
||||
if (piiu->client_busy) {
|
||||
status = ca_ready_message(piiu);
|
||||
if (status==ECA_NORMAL) {
|
||||
assert(ca_static->ca_number_iiu_in_fc>0u);
|
||||
ca_static->ca_number_iiu_in_fc--;
|
||||
piiu->client_busy = FALSE;
|
||||
# if defined(DEBUG)
|
||||
printf("fc off\n");
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK;
|
||||
return;
|
||||
}
|
||||
76
src/ca/flow_control.cpp
Normal file
76
src/ca/flow_control.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/* $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"
|
||||
|
||||
/*
|
||||
* FLOW CONTROL
|
||||
*
|
||||
* Keep track of how many times messages have
|
||||
* come with out a break in between and
|
||||
* suppress monitors if we are behind
|
||||
* (an update is sent when we catch up)
|
||||
*/
|
||||
|
||||
void flow_control_on (tcpiiu *piiu)
|
||||
{
|
||||
int status;
|
||||
|
||||
LOCK (piiu->niiu.iiu.pcas);
|
||||
|
||||
/*
|
||||
* I prefer to avoid going into flow control
|
||||
* as this impacts the performance of batched fetches
|
||||
*/
|
||||
if (piiu->contiguous_msg_count >= MAX_CONTIGUOUS_MSG_COUNT) {
|
||||
if (!piiu->client_busy) {
|
||||
status = ca_busy_message(piiu);
|
||||
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++;
|
||||
piiu->client_busy = TRUE;
|
||||
# if defined(DEBUG)
|
||||
printf("fc on\n");
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
piiu->contiguous_msg_count++;
|
||||
}
|
||||
|
||||
UNLOCK (piiu->niiu.iiu.pcas);
|
||||
return;
|
||||
}
|
||||
|
||||
void flow_control_off (tcpiiu *piiu)
|
||||
{
|
||||
int status;
|
||||
|
||||
LOCK (piiu->niiu.iiu.pcas);
|
||||
|
||||
piiu->contiguous_msg_count = 0;
|
||||
if (piiu->client_busy) {
|
||||
status = ca_ready_message(piiu);
|
||||
if (status==ECA_NORMAL) {
|
||||
assert (piiu->niiu.iiu.pcas->ca_number_iiu_in_fc>0u);
|
||||
piiu->niiu.iiu.pcas->ca_number_iiu_in_fc--;
|
||||
piiu->client_busy = FALSE;
|
||||
# if defined(DEBUG)
|
||||
printf("fc off\n");
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK (piiu->niiu.iiu.pcas);
|
||||
return;
|
||||
}
|
||||
@@ -1,326 +0,0 @@
|
||||
/* if_depen.c */
|
||||
/* share/src/ca/$Id$ */
|
||||
|
||||
/*
|
||||
* Author: Jeff Hill
|
||||
* Date: 04-05-94
|
||||
* 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
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* 8/87 Jeff Hill Init Release
|
||||
* 072792 Jeff Hill better messages
|
||||
* 09-DEC-1992 Gerhard Grygiel (GeG) support VMS/UCX
|
||||
* 050593 Jeff Hill now checks all N interfaces
|
||||
* (and not N-1 interfaces)
|
||||
*/
|
||||
|
||||
|
||||
static char *sccsId = "@(#) $Id$";
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ifDepenDebugPrintf(argsInParen) printf argsInParen
|
||||
#else
|
||||
#define ifDepenDebugPrintf(argsInParen)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dont use ca_static based lock macros here because this is
|
||||
* also called by the server. All locks required are applied at
|
||||
* a higher level.
|
||||
*/
|
||||
|
||||
/*
|
||||
* local_addr()
|
||||
*
|
||||
* A valid non-loopback local address is required in the
|
||||
* beacon message in certain situations where
|
||||
* there are beacon repeaters and there are addresses
|
||||
* in the EPICS_CA_ADDRESS_LIST for which we dont have
|
||||
* a strictly correct local server address on a multi-interface
|
||||
* system. In this situation we use the first valid non-loopback local
|
||||
* address found in the beacon message.
|
||||
*/
|
||||
int local_addr(int s, struct sockaddr_in *plcladdr)
|
||||
{
|
||||
int status;
|
||||
struct ifconf ifconf;
|
||||
struct ifreq ifreq[25];
|
||||
struct ifreq *pifreq;
|
||||
static struct sockaddr_in addr;
|
||||
static char init = FALSE;
|
||||
struct sockaddr_in *tmpaddr;
|
||||
|
||||
if (init){
|
||||
*plcladdr = addr;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* get the addr of the first interface found
|
||||
* (report inconsistent interfaces however)
|
||||
*/
|
||||
ifconf.ifc_len = sizeof ifreq;
|
||||
ifconf.ifc_req = ifreq;
|
||||
status = socket_ioctl(s, SIOCGIFCONF, &ifconf);
|
||||
if (status < 0 || ifconf.ifc_len == 0) {
|
||||
ca_printf(
|
||||
"CAC: SIOCGIFCONF ioctl failed because \"%s\"\n",
|
||||
SOCKERRSTR(SOCKERRNO));
|
||||
ifconf.ifc_len = 0;
|
||||
}
|
||||
|
||||
ifDepenDebugPrintf ( ("local_addr: %ld net intf(s) found\n",
|
||||
(unsigned long) (ifconf.ifc_len/sizeof(*pifreq))) );
|
||||
|
||||
for ( pifreq = ifconf.ifc_req;
|
||||
((size_t)ifconf.ifc_len) >= sizeof(*pifreq);
|
||||
pifreq++, ifconf.ifc_len -= sizeof(*pifreq)) {
|
||||
unsigned flags;
|
||||
|
||||
status = socket_ioctl(s, SIOCGIFFLAGS, pifreq);
|
||||
if (status == ERROR){
|
||||
ca_printf("local_addr: net intf flags fetch for %s failed\n", pifreq->ifr_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* flags are stored in a union now
|
||||
*/
|
||||
flags = (unsigned) pifreq->ifr_flags;
|
||||
|
||||
if (!(flags & IFF_UP)) {
|
||||
ifDepenDebugPrintf ( ("local_addr: net intf %s was down\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* dont use the loop back interface
|
||||
*/
|
||||
if (flags & IFF_LOOPBACK) {
|
||||
ifDepenDebugPrintf ( ("local_addr: ignoring loopback interface: %s\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
status = socket_ioctl(s, SIOCGIFADDR, pifreq);
|
||||
if (status == ERROR){
|
||||
ifDepenDebugPrintf ( ("local_addr: could not obtain addr for %s\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pifreq->ifr_addr.sa_family != AF_INET){
|
||||
ifDepenDebugPrintf ( ("local_addr: interface %s was not AF_INET\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
ifDepenDebugPrintf ( ("local_addr: net intf %s found\n", pifreq->ifr_name) );
|
||||
|
||||
tmpaddr = (struct sockaddr_in *) &pifreq->ifr_addr;
|
||||
|
||||
init = TRUE;
|
||||
addr = *tmpaddr;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!init){
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
*plcladdr = addr;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* caDiscoverInterfaces()
|
||||
*
|
||||
* This routine is provided with the address of an ELLLIST, a socket
|
||||
* a destination port number, and a match address. When the
|
||||
* routine returns there will be one additional inet address
|
||||
* (a caAddrNode) in the list for each inet interface found that
|
||||
* is up and isnt a loop back interface (match addr is INADDR_ANY)
|
||||
* or it matches the specified interface (match addr isnt INADDR_ANY).
|
||||
* If the interface supports broadcast then I add its broadcast
|
||||
* address to the list. If the interface is a point to
|
||||
* point link then I add the destination address of the point to
|
||||
* point link to the list. In either case I set the port number
|
||||
* in the address node to the port supplied in the argument
|
||||
* list.
|
||||
*
|
||||
* LOCK should be applied here for (pList)
|
||||
* (this is also called from the server)
|
||||
*/
|
||||
void epicsShareAPI caDiscoverInterfaces
|
||||
(ELLLIST *pList, int socket, unsigned short port, struct in_addr matchAddr)
|
||||
{
|
||||
struct sockaddr_in *pInetAddr;
|
||||
caAddrNode *pNode;
|
||||
int status;
|
||||
struct ifconf ifconf;
|
||||
struct ifreq *pIfreqList;
|
||||
struct ifreq *pifreq;
|
||||
unsigned long nelem;
|
||||
|
||||
/*
|
||||
* use pool so that we avoid using to much stack space
|
||||
* under vxWorks
|
||||
*
|
||||
* nelem is set to the maximum interfaces
|
||||
* on one machine here
|
||||
*/
|
||||
nelem = 100;
|
||||
pIfreqList = (struct ifreq *)calloc(nelem, sizeof(*pifreq));
|
||||
if(!pIfreqList){
|
||||
return;
|
||||
}
|
||||
|
||||
ifconf.ifc_len = nelem*sizeof(*pifreq);
|
||||
ifconf.ifc_req = pIfreqList;
|
||||
status = socket_ioctl(socket, SIOCGIFCONF, &ifconf);
|
||||
if (status < 0 || ifconf.ifc_len == 0) {
|
||||
free(pIfreqList);
|
||||
return;
|
||||
}
|
||||
|
||||
nelem = ifconf.ifc_len/sizeof(struct ifreq);
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: %ld net intf(s) found\n", nelem) );
|
||||
|
||||
for (pifreq = pIfreqList; pifreq<(pIfreqList+nelem); pifreq++) {
|
||||
unsigned flags;
|
||||
|
||||
status = socket_ioctl(socket, SIOCGIFFLAGS, pifreq);
|
||||
if (status) {
|
||||
ca_printf ("caDiscoverInterfaces: net intf flags fetch for %s failed\n", pifreq->ifr_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* flags are stored in a union now
|
||||
*/
|
||||
flags = (unsigned) pifreq->ifr_flags;
|
||||
|
||||
/*
|
||||
* dont bother with interfaces that have been disabled
|
||||
*/
|
||||
if (!(flags & IFF_UP)) {
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: net intf %s was down\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* dont use the loop back interface
|
||||
*/
|
||||
if (flags & IFF_LOOPBACK) {
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: ignoring loopback interface: %s\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch the local address for this interface
|
||||
*/
|
||||
status = socket_ioctl(socket, SIOCGIFADDR, pifreq);
|
||||
if (status){
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: could not obtain addr for %s\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If its not an internet inteface
|
||||
* then dont use it.
|
||||
*/
|
||||
if (pifreq->ifr_addr.sa_family != AF_INET) {
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: interface %s was not AF_INET\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* save the interface's IP address
|
||||
*/
|
||||
pInetAddr = (struct sockaddr_in *)&pifreq->ifr_addr;
|
||||
|
||||
/*
|
||||
* if it isnt a wildcarded interface then look for
|
||||
* an exact match
|
||||
*/
|
||||
if (matchAddr.s_addr != htonl(INADDR_ANY)) {
|
||||
if (pInetAddr->sin_addr.s_addr != matchAddr.s_addr) {
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: net intf %s didnt match\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is an interface that supports
|
||||
* broadcast fetch the broadcast address.
|
||||
*
|
||||
* Otherwise if this is a point to point
|
||||
* interface then use the destination address.
|
||||
*
|
||||
* Otherwise CA will not query through the
|
||||
* interface.
|
||||
*/
|
||||
if (flags & IFF_BROADCAST) {
|
||||
status = socket_ioctl(
|
||||
socket,
|
||||
SIOCGIFBRDADDR,
|
||||
pifreq);
|
||||
if (status) {
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: net intf %s: bcast addr fetch fail\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if(flags & IFF_POINTOPOINT){
|
||||
status = socket_ioctl(
|
||||
socket,
|
||||
SIOCGIFDSTADDR,
|
||||
pifreq);
|
||||
if (status){
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: net intf %s: pt to pt addr fetch fail\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else{
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: net intf %s: not pt to pt or bcast\n", pifreq->ifr_name) );
|
||||
continue;
|
||||
}
|
||||
|
||||
ifDepenDebugPrintf ( ("caDiscoverInterfaces: net intf %s found\n", pifreq->ifr_name) );
|
||||
|
||||
pNode = (caAddrNode *) calloc(1,sizeof(*pNode));
|
||||
if(!pNode){
|
||||
ca_printf ("caDiscoverInterfaces: malloc failed for net intf %s: \n", pifreq->ifr_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
pNode->destAddr.in = *pInetAddr;
|
||||
pNode->destAddr.in.sin_port = htons(port);
|
||||
|
||||
/*
|
||||
* LOCK applied externally
|
||||
*/
|
||||
ellAdd(pList, &pNode->node);
|
||||
}
|
||||
|
||||
free(pIfreqList);
|
||||
}
|
||||
|
||||
1988
src/ca/iocinf.c
1988
src/ca/iocinf.c
File diff suppressed because it is too large
Load Diff
1570
src/ca/iocinf.cpp
Normal file
1570
src/ca/iocinf.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1045
src/ca/iocinf.h
1045
src/ca/iocinf.h
File diff suppressed because it is too large
Load Diff
@@ -47,6 +47,9 @@ extern "C" {
|
||||
#elif (defined(__ALPHA) && defined(VMS) || defined(__alpha)) && defined(VMS)
|
||||
# define CA_FLOAT_MIT
|
||||
# define CA_LITTLE_ENDIAN
|
||||
#elif (defined(__ALPHA) && defined(__VMS) || defined(__alpha)) && defined(__VMS)
|
||||
# define CA_FLOAT_MIT
|
||||
# define CA_LITTLE_ENDIAN
|
||||
#elif (defined(__ALPHA) && defined(UNIX) || defined(__alpha)) && defined(UNIX)
|
||||
# define CA_FLOAT_IEEE
|
||||
# define CA_LITTLE_ENDIAN
|
||||
|
||||
@@ -59,20 +59,7 @@ static char *os_depenhSccsId = "$Id$";
|
||||
#error Please define one of iocCore, UNIX, VMS, or _WIN32
|
||||
#endif
|
||||
|
||||
#if defined(iocCore)
|
||||
# define POST_IO_EV semBinaryGive(io_done_sem)
|
||||
# define VXTASKIDNONE 0
|
||||
# define LOCK semMutexMustTake(client_lock);
|
||||
# define UNLOCK semMutexGive(client_lock);
|
||||
# define EVENTLOCKTEST (lock_tid==threadGetIdSelf())
|
||||
# define VXTHISTASKID threadGetIdSelf();
|
||||
# define abort() threadSuspend(threadGetIdSelf())
|
||||
#else
|
||||
# define POST_IO_EV
|
||||
# define LOCK
|
||||
# define UNLOCK
|
||||
# define EVENTLOCKTEST (post_msg_active)
|
||||
#endif /*defined(iocCore) */
|
||||
|
||||
|
||||
#endif /* INCos_depenh */
|
||||
|
||||
|
||||
114
src/ca/processThread.cpp
Normal file
114
src/ca/processThread.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
|
||||
/*
|
||||
* $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>
|
||||
|
||||
processThread::processThread () :
|
||||
osiThread ("CAC process", 0x1000, threadPriorityMedium),
|
||||
shutDown (false)
|
||||
{
|
||||
ellInit (&this->recvActivity);
|
||||
}
|
||||
|
||||
processThread::~processThread ()
|
||||
{
|
||||
this->shutDown = true;
|
||||
this->exit.signal ();
|
||||
while ( !this->exit.wait (5.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 ();
|
||||
}
|
||||
this->exit.signal ();
|
||||
}
|
||||
|
||||
void processThread::signalShutDown ()
|
||||
{
|
||||
this->shutDown = true;
|
||||
this->wakeup.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 ();
|
||||
}
|
||||
@@ -1,576 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* REPEATER.C
|
||||
*
|
||||
* CA broadcast repeater
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
* Date: 3-27-90
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Jeff HIll, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 665-1831
|
||||
* E-mail: johill@lanl.gov
|
||||
*
|
||||
* PURPOSE:
|
||||
* Broadcasts fan out over the LAN, but old IP kernels do not allow
|
||||
* two processes on the same machine to get the same broadcast
|
||||
* (and modern IP kernels do not allow two processes on the same machine
|
||||
* to receive the same unicast).
|
||||
*
|
||||
* This code fans out UDP messages sent to the CA repeater port
|
||||
* to all CA client processes that have subscribed.
|
||||
*
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 060691 joh Took out 4 byte count at message begin to
|
||||
* in preparation for SPARC alignment
|
||||
* .02 042892 joh No longer checking the status from free
|
||||
* since it varies from OS to OS
|
||||
* .03 042892 joh made local routines static
|
||||
* .04 072392 joh set reuse addr socket option so that
|
||||
* the repeater will restart if it gets killed
|
||||
* .05 072392 joh no longer needs to loop waiting for the timeout
|
||||
* to expire because of the change introduced
|
||||
* in .04
|
||||
* .06 120492 joh removed unnecessary includes
|
||||
* .07 120992 joh now uses dll list routines
|
||||
* .08 102993 joh toggle set sock opt to set
|
||||
* .09 070195 joh discover client has vanished by connecting its
|
||||
* datagram socket (and watching for ECONNREFUSED)
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.48 1999/09/02 21:44:50 jhill
|
||||
* improved the way that socket error numbers are converted to strings,
|
||||
* changed () to (void) in func proto, and fixed missing parameter to
|
||||
* checkConnWatchdogs() bug resulting from this
|
||||
*
|
||||
* Revision 1.47 1998/09/29 20:50:37 jhill
|
||||
* more robust in situations wherelocal IP cant be determined
|
||||
*
|
||||
* Revision 1.46 1998/09/24 21:22:54 jhill
|
||||
* conn.c
|
||||
*
|
||||
* Revision 1.45 1998/06/16 00:58:12 jhill
|
||||
* attach to winsock when its a static build
|
||||
*
|
||||
* Revision 1.44 1998/05/29 00:03:20 jhill
|
||||
* allow CA to run systems w/o local interface query capabilities (ie cygwin32)
|
||||
*
|
||||
* Revision 1.43 1998/04/15 21:58:29 jhill
|
||||
* fixed the doc
|
||||
*
|
||||
* Revision 1.42 1998/02/27 01:04:03 jhill
|
||||
* fixed benign WIN32 message from overwritten errno
|
||||
*
|
||||
* Revision 1.41 1998/02/05 22:34:33 jhill
|
||||
* dont delete client if send returns ECONNREFUSED
|
||||
*
|
||||
* Revision 1.40 1997/08/04 23:37:15 jhill
|
||||
* added beacon anomaly flag init/allow ip 255.255.255.255
|
||||
*
|
||||
* Revision 1.39 1997/04/23 17:05:09 jhill
|
||||
* pc port changes
|
||||
*
|
||||
* Revision 1.38 1996/11/02 00:51:04 jhill
|
||||
* many pc port, const in API, and other changes
|
||||
*
|
||||
* Revision 1.37 1996/09/04 20:02:32 jhill
|
||||
* fixed gcc warning
|
||||
*
|
||||
* Revision 1.36 1996/07/12 00:40:48 jhill
|
||||
* fixed client disconnect problem under solaris
|
||||
*
|
||||
* Revision 1.32.6.1 1996/07/12 00:39:59 jhill
|
||||
* fixed client disconnect problem under solaris
|
||||
*
|
||||
* Revision 1.35 1996/07/10 23:30:11 jhill
|
||||
* fixed GNU warnings
|
||||
*
|
||||
* Revision 1.34 1996/06/19 17:59:24 jhill
|
||||
* many 3.13 beta changes
|
||||
*
|
||||
* Revision 1.33 1995/11/29 19:19:05 jhill
|
||||
* Added $log$
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* It would be preferable to avoid using the repeater on multicast enhanced IP kernels, but
|
||||
* this is not going to work in all situations because (according to Steven's TCP/IP
|
||||
* illustrated volume I) if a broadcast is received it goes to all sockets on the same port,
|
||||
* but if a unicast is received it goes to only one of the sockets on the same port
|
||||
* (we can only guess at which one it will be).
|
||||
*
|
||||
* I have observed this behavior under winsock II:
|
||||
* o only one of the sockets on the same port receives the message if we send to the
|
||||
* loop back address
|
||||
* o both of the sockets on the same port receives the message if we send to the
|
||||
* broadcast address
|
||||
*
|
||||
*/
|
||||
|
||||
static char *sccsId = "@(#)$Id$";
|
||||
|
||||
#include "iocinf.h"
|
||||
#include "bsdSocketResource.h"
|
||||
|
||||
/*
|
||||
* one socket per client so we will get the ECONNREFUSED
|
||||
* error code (and then delete the client)
|
||||
*/
|
||||
struct one_client{
|
||||
ELLNODE node;
|
||||
struct sockaddr_in from;
|
||||
SOCKET sock;
|
||||
};
|
||||
|
||||
/*
|
||||
* these can be external since there is only one instance
|
||||
* per machine so we dont care about reentrancy
|
||||
*/
|
||||
static ELLLIST client_list;
|
||||
|
||||
static char buf[ETHERNET_MAX_UDP];
|
||||
|
||||
#define PORT_ANY 0U
|
||||
typedef struct {
|
||||
SOCKET sock;
|
||||
int errNumber;
|
||||
const char *pErrStr;
|
||||
}makeSocketReturn;
|
||||
|
||||
LOCAL void register_new_client(struct sockaddr_in *pLocal,
|
||||
struct sockaddr_in *pFrom);
|
||||
LOCAL void verifyClients();
|
||||
LOCAL makeSocketReturn makeSocket (unsigned short port, int reuseAddr);
|
||||
LOCAL void fanOut(struct sockaddr_in *pFrom, const char *pMsg, unsigned msgSize);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* ca_repeater()
|
||||
*
|
||||
*
|
||||
*/
|
||||
void epicsShareAPI ca_repeater()
|
||||
{
|
||||
int status;
|
||||
int size;
|
||||
SOCKET sock;
|
||||
struct sockaddr_in from;
|
||||
struct sockaddr_in local;
|
||||
int from_size = sizeof from;
|
||||
unsigned short port;
|
||||
makeSocketReturn msr;
|
||||
|
||||
assert (bsdSockAttach());
|
||||
|
||||
port = caFetchPortConfig(
|
||||
&EPICS_CA_REPEATER_PORT,
|
||||
CA_REPEATER_PORT);
|
||||
|
||||
ellInit(&client_list);
|
||||
|
||||
msr = makeSocket(port, TRUE);
|
||||
if (msr.sock==INVALID_SOCKET) {
|
||||
/*
|
||||
* test for server was already started
|
||||
*/
|
||||
if (msr.errNumber==SOCK_EADDRINUSE) {
|
||||
bsdSockRelease();
|
||||
exit(0);
|
||||
}
|
||||
ca_printf("%s: Unable to create repeater socket because %d=\"%s\" - fatal\n",
|
||||
__FILE__,
|
||||
msr.errNumber,
|
||||
msr.pErrStr);
|
||||
bsdSockRelease();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sock = msr.sock;
|
||||
|
||||
status = local_addr (sock, &local);
|
||||
if(status != OK){
|
||||
/*
|
||||
* use the loop back address to communicate with the CA repeater
|
||||
* if this os does not have interface query capabilities
|
||||
*
|
||||
* this will only work with 3.13 beta 12 CA clients or later
|
||||
*/
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
||||
local.sin_port = htons (0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
ca_printf("CA Repeater: Attached and initialized\n");
|
||||
#endif
|
||||
|
||||
while(TRUE){
|
||||
caHdr *pMsg;
|
||||
|
||||
size = recvfrom(
|
||||
sock,
|
||||
buf,
|
||||
sizeof(buf),
|
||||
0,
|
||||
(struct sockaddr *)&from,
|
||||
&from_size);
|
||||
|
||||
if(size < 0){
|
||||
int errnoCpy = SOCKERRNO;
|
||||
# ifdef linux
|
||||
/*
|
||||
* Avoid spurious ECONNREFUSED bug
|
||||
* in linux
|
||||
*/
|
||||
if (errnoCpy==SOCK_ECONNREFUSED) {
|
||||
continue;
|
||||
}
|
||||
# endif
|
||||
ca_printf("CA Repeater: unexpected UDP recv err: %s\n",
|
||||
SOCKERRSTR(errnoCpy));
|
||||
continue;
|
||||
}
|
||||
|
||||
pMsg = (caHdr *) buf;
|
||||
|
||||
/*
|
||||
* both zero length message and a registration message
|
||||
* will register a new client
|
||||
*/
|
||||
if( ((size_t)size) >= sizeof(*pMsg)){
|
||||
if(ntohs(pMsg->m_cmmd) == REPEATER_REGISTER){
|
||||
register_new_client(&local, &from);
|
||||
|
||||
/*
|
||||
* strip register client message
|
||||
*/
|
||||
pMsg++;
|
||||
size -= sizeof(*pMsg);
|
||||
if (size==0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(size == 0){
|
||||
register_new_client(&local, &from);
|
||||
continue;
|
||||
}
|
||||
|
||||
fanOut(&from, (char *) pMsg, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* fanOut()
|
||||
*/
|
||||
LOCAL void fanOut(struct sockaddr_in *pFrom, const char *pMsg, unsigned msgSize)
|
||||
{
|
||||
ELLLIST theClients;
|
||||
struct one_client *pclient;
|
||||
int status;
|
||||
int verify = FALSE;
|
||||
|
||||
ellInit(&theClients);
|
||||
while ( (pclient=(struct one_client *)ellGet(&client_list)) ) {
|
||||
ellAdd(&theClients, &pclient->node);
|
||||
|
||||
/*
|
||||
* Dont reflect back to sender
|
||||
*/
|
||||
if(pFrom->sin_port == pclient->from.sin_port &&
|
||||
pFrom->sin_addr.s_addr == pclient->from.sin_addr.s_addr){
|
||||
continue;
|
||||
}
|
||||
|
||||
status = send(
|
||||
pclient->sock,
|
||||
(char *)pMsg,
|
||||
msgSize,
|
||||
0);
|
||||
if (status>=0) {
|
||||
#ifdef DEBUG
|
||||
ca_printf ("Sent to %d\n",
|
||||
ntohs (pclient->from.sin_port));
|
||||
#endif
|
||||
}
|
||||
if(status < 0){
|
||||
int errnoCpy = SOCKERRNO;
|
||||
if (errnoCpy == SOCK_ECONNREFUSED) {
|
||||
#ifdef DEBUG
|
||||
ca_printf ("Deleted client %d\n",
|
||||
ntohs (pclient->from.sin_port));
|
||||
#endif
|
||||
verify = TRUE;
|
||||
}
|
||||
else {
|
||||
ca_printf(
|
||||
"CA Repeater: UDP fan out err was \"%s\"\n",
|
||||
SOCKERRSTR(errnoCpy));
|
||||
}
|
||||
}
|
||||
}
|
||||
ellConcat(&client_list, &theClients);
|
||||
|
||||
if (verify) {
|
||||
verifyClients ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* verifyClients()
|
||||
* (this is required because solaris has a half baked version of sockets)
|
||||
*/
|
||||
LOCAL void verifyClients()
|
||||
{
|
||||
ELLLIST theClients;
|
||||
struct one_client *pclient;
|
||||
makeSocketReturn msr;
|
||||
|
||||
ellInit(&theClients);
|
||||
while ( (pclient=(struct one_client *)ellGet(&client_list)) ) {
|
||||
ellAdd(&theClients, &pclient->node);
|
||||
|
||||
msr = makeSocket(ntohs(pclient->from.sin_port), FALSE);
|
||||
if (msr.sock!=INVALID_SOCKET) {
|
||||
#ifdef DEBUG
|
||||
ca_printf("Deleted client %d\n",
|
||||
ntohs(pclient->from.sin_port));
|
||||
#endif
|
||||
ellDelete(&theClients, &pclient->node);
|
||||
socket_close(msr.sock);
|
||||
socket_close(pclient->sock);
|
||||
free(pclient);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* win sock does not set SOCKERRNO when this fails
|
||||
*/
|
||||
if (msr.errNumber!=SOCK_EADDRINUSE) {
|
||||
ca_printf(
|
||||
"CA Repeater: bind test err was %d=\"%s\"\n",
|
||||
msr.errNumber, msr.pErrStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
ellConcat(&client_list, &theClients);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* makeSocket()
|
||||
*/
|
||||
LOCAL makeSocketReturn makeSocket(unsigned short port, int reuseAddr)
|
||||
{
|
||||
int status;
|
||||
struct sockaddr_in bd;
|
||||
makeSocketReturn msr;
|
||||
int true = 1;
|
||||
|
||||
msr.sock = socket( AF_INET, /* domain */
|
||||
SOCK_DGRAM, /* type */
|
||||
0); /* deflt proto */
|
||||
if (msr.sock == INVALID_SOCKET) {
|
||||
msr.errNumber = SOCKERRNO;
|
||||
msr.pErrStr = SOCKERRSTR(msr.errNumber);
|
||||
return msr;
|
||||
}
|
||||
|
||||
/*
|
||||
* no need to bind if unconstrained
|
||||
*/
|
||||
if (port != PORT_ANY) {
|
||||
|
||||
memset((char *)&bd, 0, sizeof(bd));
|
||||
bd.sin_family = AF_INET;
|
||||
bd.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
bd.sin_port = htons(port);
|
||||
status = bind(msr.sock, (struct sockaddr *)&bd, (int)sizeof(bd));
|
||||
if (status<0) {
|
||||
msr.errNumber = SOCKERRNO;
|
||||
msr.pErrStr = SOCKERRSTR(msr.errNumber);
|
||||
socket_close(msr.sock);
|
||||
msr.sock = INVALID_SOCKET;
|
||||
return msr;
|
||||
}
|
||||
if (reuseAddr) {
|
||||
status = setsockopt(
|
||||
msr.sock,
|
||||
SOL_SOCKET,
|
||||
SO_REUSEADDR,
|
||||
(char *)&true,
|
||||
sizeof(true));
|
||||
if (status<0) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
ca_printf(
|
||||
"%s: set socket option failed because \"%s\"\n",
|
||||
__FILE__, SOCKERRSTR(errnoCpy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msr.errNumber = 0;
|
||||
msr.pErrStr = "no error";
|
||||
return msr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* register_new_client()
|
||||
*/
|
||||
LOCAL void register_new_client(
|
||||
struct sockaddr_in *pLocal,
|
||||
struct sockaddr_in *pFrom)
|
||||
{
|
||||
int status;
|
||||
struct one_client *pclient;
|
||||
caHdr confirm;
|
||||
caHdr noop;
|
||||
int newClient = FALSE;
|
||||
makeSocketReturn msr;
|
||||
|
||||
if (pFrom->sin_family != AF_INET) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* the repeater and its clients must be on the same host
|
||||
*/
|
||||
if (htonl(INADDR_LOOPBACK) != pFrom->sin_addr.s_addr) {
|
||||
|
||||
/*
|
||||
* Unfortunately on 3.13 beta 11 and before the
|
||||
* repeater would not always allow the loopback address
|
||||
* as a local client address so all clients must continue to
|
||||
* use the address from the first non-loopback interface
|
||||
* found to communicate with the CA repeater until all
|
||||
* CA repeaters have been restarted.
|
||||
*/
|
||||
if (pLocal->sin_addr.s_addr != pFrom->sin_addr.s_addr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for(pclient = (struct one_client *) ellFirst(&client_list);
|
||||
pclient; pclient = (struct one_client *) ellNext(&pclient->node)){
|
||||
|
||||
if (pFrom->sin_port == pclient->from.sin_port) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pclient) {
|
||||
pclient = (struct one_client *)calloc (1, sizeof(*pclient));
|
||||
if (!pclient) {
|
||||
ca_printf("%s: no memory for new client\n",
|
||||
__FILE__);
|
||||
return;
|
||||
}
|
||||
|
||||
msr = makeSocket(PORT_ANY, FALSE);
|
||||
if (msr.sock==INVALID_SOCKET) {
|
||||
free(pclient);
|
||||
ca_printf("%s: no client sock because %d=\"%s\"\n",
|
||||
__FILE__,
|
||||
msr.errNumber,
|
||||
msr.pErrStr);
|
||||
return;
|
||||
}
|
||||
|
||||
pclient->sock = msr.sock;
|
||||
|
||||
status = connect(pclient->sock,
|
||||
(struct sockaddr *)pFrom,
|
||||
sizeof(*pFrom));
|
||||
if (status<0) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
ca_printf(
|
||||
"%s: unable to connect client sock because \"%s\"\n",
|
||||
__FILE__, SOCKERRSTR(errnoCpy));
|
||||
socket_close(pclient->sock);
|
||||
free(pclient);
|
||||
return;
|
||||
}
|
||||
|
||||
pclient->from = *pFrom;
|
||||
|
||||
ellAdd (&client_list, &pclient->node);
|
||||
newClient = TRUE;
|
||||
#ifdef DEBUG
|
||||
ca_printf (
|
||||
"Added %d\n",
|
||||
ntohs(pFrom->sin_port));
|
||||
#endif
|
||||
}
|
||||
|
||||
memset((char *)&confirm, '\0', sizeof(confirm));
|
||||
confirm.m_cmmd = htons(REPEATER_CONFIRM);
|
||||
confirm.m_available = pFrom->sin_addr.s_addr;
|
||||
status = send(
|
||||
pclient->sock,
|
||||
(char *)&confirm,
|
||||
sizeof(confirm),
|
||||
0);
|
||||
if (status >= 0) {
|
||||
assert(status == sizeof(confirm));
|
||||
}
|
||||
else if (SOCKERRNO == SOCK_ECONNREFUSED){
|
||||
#ifdef DEBUG
|
||||
ca_printf("Deleted repeater client=%d sending ack\n",
|
||||
ntohs(pFrom->sin_port));
|
||||
#endif
|
||||
ellDelete(&client_list, &pclient->node);
|
||||
socket_close(pclient->sock);
|
||||
free(pclient);
|
||||
}
|
||||
else {
|
||||
ca_printf("CA Repeater: confirm err was \"%s\"\n",
|
||||
SOCKERRSTR(SOCKERRNO));
|
||||
}
|
||||
|
||||
/*
|
||||
* send a noop message to all other clients so that we dont
|
||||
* accumulate sockets when there are no beacons
|
||||
*/
|
||||
memset((char *)&noop, '\0', sizeof(noop));
|
||||
confirm.m_cmmd = htons(CA_PROTO_NOOP);
|
||||
fanOut(pFrom, (char *)&noop, sizeof(noop));
|
||||
|
||||
if (newClient) {
|
||||
/*
|
||||
* on solaris we need to verify that the clients
|
||||
* have not gone away (because ICMP does not
|
||||
* get through to send()
|
||||
*
|
||||
* this is done each time that a new client is
|
||||
* created
|
||||
*
|
||||
* this is done here in order to avoid deleting
|
||||
* a client prior to sending its confirm message
|
||||
*/
|
||||
verifyClients();
|
||||
}
|
||||
}
|
||||
|
||||
490
src/ca/repeater.cpp
Normal file
490
src/ca/repeater.cpp
Normal file
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* REPEATER.C
|
||||
*
|
||||
* CA broadcast repeater
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
* Date: 3-27-90
|
||||
*
|
||||
* Control System Software for the GTA Project
|
||||
*
|
||||
* Copyright 1988, 1989, the Regents of the University of California.
|
||||
*
|
||||
* This software was produced under a U.S. Government contract
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory, which is
|
||||
* operated by the University of California for the U.S. Department
|
||||
* of Energy.
|
||||
*
|
||||
* Developed by the Controls and Automation Group (AT-8)
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Direct inqueries to:
|
||||
* Jeff HIll, AT-8, Mail Stop H820
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
* Phone: (505) 665-1831
|
||||
* E-mail: johill@lanl.gov
|
||||
*
|
||||
* PURPOSE:
|
||||
* Broadcasts fan out over the LAN, but old IP kernels do not allow
|
||||
* two processes on the same machine to get the same broadcast
|
||||
* (and modern IP kernels do not allow two processes on the same machine
|
||||
* to receive the same unicast).
|
||||
*
|
||||
* This code fans out UDP messages sent to the CA repeater port
|
||||
* to all CA client processes that have subscribed.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* It would be preferable to avoid using the repeater on multicast enhanced IP kernels, but
|
||||
* this is not going to work in all situations because (according to Steven's TCP/IP
|
||||
* illustrated volume I) if a broadcast is received it goes to all sockets on the same port,
|
||||
* but if a unicast is received it goes to only one of the sockets on the same port
|
||||
* (we can only guess at which one it will be).
|
||||
*
|
||||
* I have observed this behavior under winsock II:
|
||||
* o only one of the sockets on the same port receives the message if we send to the
|
||||
* loop back address
|
||||
* o both of the sockets on the same port receives the message if we send to the
|
||||
* broadcast address
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iocinf.h"
|
||||
#include "taskwd.h"
|
||||
|
||||
/*
|
||||
* one socket per client so we will get the ECONNREFUSED
|
||||
* error code (and then delete the client)
|
||||
*/
|
||||
struct one_client {
|
||||
ELLNODE node;
|
||||
struct sockaddr_in from;
|
||||
SOCKET sock;
|
||||
};
|
||||
|
||||
/*
|
||||
* these can be external since there is only one instance
|
||||
* per machine so we dont care about reentrancy
|
||||
*/
|
||||
static ELLLIST client_list;
|
||||
|
||||
static char buf[ETHERNET_MAX_UDP];
|
||||
|
||||
static const unsigned short PORT_ANY = 0u;
|
||||
|
||||
typedef struct {
|
||||
SOCKET sock;
|
||||
int errNumber;
|
||||
const char *pErrStr;
|
||||
} makeSocketReturn;
|
||||
|
||||
/*
|
||||
* makeSocket()
|
||||
*/
|
||||
LOCAL makeSocketReturn makeSocket (unsigned short port, int reuseAddr)
|
||||
{
|
||||
int status;
|
||||
struct sockaddr_in bd;
|
||||
makeSocketReturn msr;
|
||||
int flag;
|
||||
|
||||
msr.sock = socket (AF_INET, SOCK_DGRAM, 0);
|
||||
if (msr.sock == INVALID_SOCKET) {
|
||||
msr.errNumber = SOCKERRNO;
|
||||
msr.pErrStr = SOCKERRSTR (msr.errNumber);
|
||||
return msr;
|
||||
}
|
||||
|
||||
/*
|
||||
* no need to bind if unconstrained
|
||||
*/
|
||||
if (port != PORT_ANY) {
|
||||
|
||||
memset ( (char *) &bd, 0, sizeof (bd) );
|
||||
bd.sin_family = AF_INET;
|
||||
bd.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||
bd.sin_port = htons (port);
|
||||
status = bind (msr.sock, (struct sockaddr *)&bd, (int)sizeof(bd));
|
||||
if (status<0) {
|
||||
msr.errNumber = SOCKERRNO;
|
||||
msr.pErrStr = SOCKERRSTR (msr.errNumber);
|
||||
socket_close (msr.sock);
|
||||
msr.sock = INVALID_SOCKET;
|
||||
return msr;
|
||||
}
|
||||
if (reuseAddr) {
|
||||
flag = TRUE;
|
||||
status = setsockopt ( msr.sock, SOL_SOCKET, SO_REUSEADDR,
|
||||
(char *)&flag, sizeof (flag) );
|
||||
if (status<0) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
errlogPrintf(
|
||||
"%s: set socket option failed because \"%s\"\n",
|
||||
__FILE__, SOCKERRSTR(errnoCpy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msr.errNumber = 0;
|
||||
msr.pErrStr = "no error";
|
||||
return msr;
|
||||
}
|
||||
|
||||
/*
|
||||
* verifyClients()
|
||||
* (this is required because solaris has a half baked version of sockets)
|
||||
*/
|
||||
LOCAL void verifyClients()
|
||||
{
|
||||
ELLLIST theClients;
|
||||
struct one_client *pclient;
|
||||
makeSocketReturn msr;
|
||||
|
||||
ellInit(&theClients);
|
||||
while ( (pclient=(struct one_client *)ellGet(&client_list)) ) {
|
||||
ellAdd (&theClients, &pclient->node);
|
||||
|
||||
msr = makeSocket ( ntohs (pclient->from.sin_port), FALSE );
|
||||
if ( msr.sock != INVALID_SOCKET ) {
|
||||
#ifdef DEBUG
|
||||
errlogPrintf ("Deleted client %d\n",
|
||||
ntohs (pclient->from.sin_port) );
|
||||
#endif
|
||||
ellDelete (&theClients, &pclient->node);
|
||||
socket_close (msr.sock);
|
||||
socket_close (pclient->sock);
|
||||
free (pclient);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* win sock does not set SOCKERRNO when this fails
|
||||
*/
|
||||
if ( msr.errNumber != SOCK_EADDRINUSE ) {
|
||||
errlogPrintf (
|
||||
"CA Repeater: bind test err was %d=\"%s\"\n",
|
||||
msr.errNumber, msr.pErrStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
ellConcat (&client_list, &theClients);
|
||||
}
|
||||
|
||||
/*
|
||||
* fanOut()
|
||||
*/
|
||||
LOCAL void fanOut (struct sockaddr_in *pFrom, const char *pMsg, unsigned msgSize)
|
||||
{
|
||||
ELLLIST theClients;
|
||||
struct one_client *pclient;
|
||||
int status;
|
||||
int verify = FALSE;
|
||||
|
||||
ellInit(&theClients);
|
||||
while ( ( pclient = (struct one_client *) ellGet (&client_list) ) ) {
|
||||
ellAdd(&theClients, &pclient->node);
|
||||
|
||||
/*
|
||||
* Dont reflect back to sender
|
||||
*/
|
||||
if(pFrom->sin_port == pclient->from.sin_port &&
|
||||
pFrom->sin_addr.s_addr == pclient->from.sin_addr.s_addr){
|
||||
continue;
|
||||
}
|
||||
|
||||
status = send ( pclient->sock, (char *)pMsg, msgSize, 0);
|
||||
if (status>=0) {
|
||||
#ifdef DEBUG
|
||||
errlogPrintf ("Sent to %d\n",
|
||||
ntohs (pclient->from.sin_port));
|
||||
#endif
|
||||
}
|
||||
if(status < 0){
|
||||
int errnoCpy = SOCKERRNO;
|
||||
if (errnoCpy == SOCK_ECONNREFUSED) {
|
||||
#ifdef DEBUG
|
||||
errlogPrintf ("Deleted client %d\n",
|
||||
ntohs (pclient->from.sin_port));
|
||||
#endif
|
||||
verify = TRUE;
|
||||
}
|
||||
else {
|
||||
errlogPrintf(
|
||||
"CA Repeater: UDP fan out err was \"%s\"\n",
|
||||
SOCKERRSTR(errnoCpy));
|
||||
}
|
||||
}
|
||||
}
|
||||
ellConcat(&client_list, &theClients);
|
||||
|
||||
if (verify) {
|
||||
verifyClients ();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* register_new_client()
|
||||
*/
|
||||
LOCAL void register_new_client (struct sockaddr_in *pFrom)
|
||||
{
|
||||
int status;
|
||||
struct one_client *pclient;
|
||||
caHdr confirm;
|
||||
caHdr noop;
|
||||
int newClient = FALSE;
|
||||
makeSocketReturn msr;
|
||||
|
||||
if (pFrom->sin_family != AF_INET) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* the repeater and its clients must be on the same host
|
||||
*/
|
||||
if (htonl(INADDR_LOOPBACK) != pFrom->sin_addr.s_addr) {
|
||||
static SOCKET testSock = INVALID_SOCKET;
|
||||
static int init;
|
||||
struct sockaddr_in ina;
|
||||
|
||||
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",
|
||||
__FILE__, msr.errNumber, msr.pErrStr);
|
||||
}
|
||||
else {
|
||||
testSock = msr.sock;
|
||||
}
|
||||
init = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately on 3.13 beta 11 and before the
|
||||
* repeater would not always allow the loopback address
|
||||
* as a local client address so current clients alternate
|
||||
* between the address of the first non-loopback interface
|
||||
* found and the loopback addresss when subscribing with
|
||||
* the CA repeater until all CA repeaters have been updated
|
||||
* to current code.
|
||||
*/
|
||||
if ( testSock != INVALID_SOCKET ) {
|
||||
ina = *pFrom;
|
||||
ina.sin_port = PORT_ANY;
|
||||
|
||||
/* we can only bind to a local address */
|
||||
status = bind ( testSock, (struct sockaddr *)&ina, (int) sizeof(ina) );
|
||||
if (status) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (pclient = (struct one_client *) ellFirst (&client_list);
|
||||
pclient; pclient = (struct one_client *) ellNext (&pclient->node)){
|
||||
|
||||
if (pFrom->sin_port == pclient->from.sin_port) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pclient) {
|
||||
pclient = (struct one_client *) calloc (1, sizeof(*pclient));
|
||||
if (!pclient) {
|
||||
errlogPrintf ("%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",
|
||||
__FILE__, msr.errNumber, msr.pErrStr);
|
||||
return;
|
||||
}
|
||||
|
||||
pclient->sock = msr.sock;
|
||||
|
||||
status = connect ( pclient->sock,
|
||||
(struct sockaddr *) pFrom,
|
||||
sizeof (*pFrom) );
|
||||
if (status<0) {
|
||||
int errnoCpy = SOCKERRNO;
|
||||
errlogPrintf (
|
||||
"%s: unable to connect client sock because \"%s\"\n",
|
||||
__FILE__, SOCKERRSTR(errnoCpy));
|
||||
socket_close (pclient->sock);
|
||||
free (pclient);
|
||||
return;
|
||||
}
|
||||
|
||||
pclient->from = *pFrom;
|
||||
|
||||
ellAdd (&client_list, &pclient->node);
|
||||
newClient = TRUE;
|
||||
#ifdef DEBUG
|
||||
errlogPrintf ( "Added %d\n", ntohs (pFrom->sin_port) );
|
||||
#endif
|
||||
}
|
||||
|
||||
memset ( (char *) &confirm, '\0', sizeof (confirm) );
|
||||
confirm.m_cmmd = htons (REPEATER_CONFIRM);
|
||||
confirm.m_available = pFrom->sin_addr.s_addr;
|
||||
status = send(
|
||||
pclient->sock,
|
||||
(char *)&confirm,
|
||||
sizeof(confirm),
|
||||
0);
|
||||
if (status >= 0) {
|
||||
assert(status == sizeof(confirm));
|
||||
}
|
||||
else if (SOCKERRNO == SOCK_ECONNREFUSED){
|
||||
#ifdef DEBUG
|
||||
errlogPrintf ("Deleted repeater client=%d sending ack\n",
|
||||
ntohs (pFrom->sin_port) );
|
||||
#endif
|
||||
ellDelete (&client_list, &pclient->node);
|
||||
socket_close (pclient->sock);
|
||||
free (pclient);
|
||||
}
|
||||
else {
|
||||
errlogPrintf ("CA Repeater: confirm err was \"%s\"\n",
|
||||
SOCKERRSTR (SOCKERRNO) );
|
||||
}
|
||||
|
||||
/*
|
||||
* send a noop message to all other clients so that we dont
|
||||
* accumulate sockets when there are no beacons
|
||||
*/
|
||||
memset ( (char *) &noop, '\0', sizeof (noop) );
|
||||
confirm.m_cmmd = htons (CA_PROTO_NOOP);
|
||||
fanOut ( pFrom, (char *)&noop, sizeof (noop) );
|
||||
|
||||
if (newClient) {
|
||||
/*
|
||||
* on solaris we need to verify that the clients
|
||||
* have not gone away (because ICMP does not
|
||||
* get through to send()
|
||||
*
|
||||
* this is done each time that a new client is
|
||||
* created
|
||||
*
|
||||
* this is done here in order to avoid deleting
|
||||
* a client prior to sending its confirm message
|
||||
*/
|
||||
verifyClients ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_repeater()
|
||||
*/
|
||||
void epicsShareAPI ca_repeater ()
|
||||
{
|
||||
int size;
|
||||
SOCKET sock;
|
||||
struct sockaddr_in from;
|
||||
int from_size = sizeof from;
|
||||
unsigned short port;
|
||||
makeSocketReturn msr;
|
||||
|
||||
assert (bsdSockAttach());
|
||||
|
||||
port = caFetchPortConfig ( NULL, &EPICS_CA_REPEATER_PORT, CA_REPEATER_PORT );
|
||||
|
||||
ellInit(&client_list);
|
||||
|
||||
msr = makeSocket (port, TRUE);
|
||||
if ( msr.sock == INVALID_SOCKET ) {
|
||||
/*
|
||||
* test for server was already started
|
||||
*/
|
||||
if ( msr.errNumber == SOCK_EADDRINUSE ) {
|
||||
bsdSockRelease ();
|
||||
exit (0);
|
||||
}
|
||||
errlogPrintf("%s: Unable to create repeater socket because %d=\"%s\" - fatal\n",
|
||||
__FILE__, msr.errNumber, msr.pErrStr);
|
||||
bsdSockRelease ();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sock = msr.sock;
|
||||
|
||||
#ifdef DEBUG
|
||||
errlogPrintf ("CA Repeater: Attached and initialized\n");
|
||||
#endif
|
||||
|
||||
while (TRUE) {
|
||||
caHdr *pMsg;
|
||||
|
||||
size = recvfrom(
|
||||
sock,
|
||||
buf,
|
||||
sizeof(buf),
|
||||
0,
|
||||
(struct sockaddr *)&from,
|
||||
&from_size);
|
||||
|
||||
if(size < 0){
|
||||
int errnoCpy = SOCKERRNO;
|
||||
# ifdef linux
|
||||
/*
|
||||
* Avoid spurious ECONNREFUSED bug
|
||||
* in linux
|
||||
*/
|
||||
if (errnoCpy==SOCK_ECONNREFUSED) {
|
||||
continue;
|
||||
}
|
||||
# endif
|
||||
errlogPrintf ("CA Repeater: unexpected UDP recv err: %s\n",
|
||||
SOCKERRSTR(errnoCpy));
|
||||
continue;
|
||||
}
|
||||
|
||||
pMsg = (caHdr *) buf;
|
||||
|
||||
/*
|
||||
* both zero length message and a registration message
|
||||
* will register a new client
|
||||
*/
|
||||
if ( ( (size_t) size) >= sizeof (*pMsg) ) {
|
||||
if ( ntohs(pMsg->m_cmmd) == REPEATER_REGISTER ) {
|
||||
register_new_client (&from);
|
||||
|
||||
/*
|
||||
* strip register client message
|
||||
*/
|
||||
pMsg++;
|
||||
size -= sizeof (*pMsg);
|
||||
if (size==0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (size == 0) {
|
||||
register_new_client (&from);
|
||||
continue;
|
||||
}
|
||||
|
||||
fanOut (&from, (char *) pMsg, size);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* caRepeaterThread ()
|
||||
*/
|
||||
void caRepeaterThread (void *pDummy)
|
||||
{
|
||||
taskwdInsert (threadGetIdSelf(), NULL, NULL);
|
||||
ca_repeater();
|
||||
}
|
||||
|
||||
|
||||
55
src/ca/repeaterSubscribeTimer.cpp
Normal file
55
src/ca/repeaterSubscribeTimer.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"
|
||||
|
||||
repeaterSubscribeTimer::repeaterSubscribeTimer (udpiiu &iiuIn, osiTimerQueue &queueIn) :
|
||||
osiTimer (queueIn), iiu (iiuIn)
|
||||
{
|
||||
}
|
||||
|
||||
void repeaterSubscribeTimer::expire ()
|
||||
{
|
||||
this->iiu.contactRepeater = 1u;
|
||||
semBinaryGive (this->iiu.xmitSignal);
|
||||
}
|
||||
|
||||
void repeaterSubscribeTimer::destroy ()
|
||||
{
|
||||
}
|
||||
|
||||
bool repeaterSubscribeTimer::again () const
|
||||
{
|
||||
if (this->iiu.repeaterContacted) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
double repeaterSubscribeTimer::delay () const
|
||||
{
|
||||
return REPEATER_TRY_PERIOD;
|
||||
}
|
||||
|
||||
void repeaterSubscribeTimer::show (unsigned level) const
|
||||
{
|
||||
}
|
||||
|
||||
const char *repeaterSubscribeTimer::name () const
|
||||
{
|
||||
return "repeaterSubscribeTimer";
|
||||
}
|
||||
|
||||
461
src/ca/ringBuffer.cpp
Normal file
461
src/ca/ringBuffer.cpp
Normal file
@@ -0,0 +1,461 @@
|
||||
|
||||
/*
|
||||
* $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 <string.h>
|
||||
|
||||
#include "ringBuffer.h"
|
||||
|
||||
static const unsigned ringIndexMask = nElementsInRing-1;
|
||||
|
||||
/*
|
||||
* cacRingBufferConstruct ()
|
||||
*/
|
||||
int cacRingBufferConstruct (ringBuffer *pBuf)
|
||||
{
|
||||
pBuf->shutDown = 0u;
|
||||
pBuf->rdix = 0u;
|
||||
pBuf->wtix = 1u;
|
||||
|
||||
pBuf->readSignal = semBinaryCreate (semEmpty);
|
||||
if (!pBuf->readSignal) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pBuf->writeSignal = semBinaryCreate (semEmpty);
|
||||
if (!pBuf->writeSignal) {
|
||||
semBinaryDestroy (pBuf->readSignal);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pBuf->readLock = semMutexCreate ();
|
||||
if (!pBuf->readLock) {
|
||||
semBinaryDestroy (pBuf->readSignal);
|
||||
semBinaryDestroy (pBuf->writeSignal);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pBuf->writeLock = semMutexCreate ();
|
||||
if (!pBuf->writeLock) {
|
||||
semBinaryDestroy (pBuf->readSignal);
|
||||
semBinaryDestroy (pBuf->writeSignal);
|
||||
semMutexDestroy (pBuf->readLock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* cacRingBufferDestroy ()
|
||||
*/
|
||||
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);
|
||||
semMutexDestroy (pBuf->writeLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* cacRingBufferShutDown ();
|
||||
*/
|
||||
void cacRingBufferShutDown (ringBuffer *pBuf)
|
||||
{
|
||||
pBuf->shutDown = 1u;
|
||||
semBinaryGive (pBuf->readSignal);
|
||||
semBinaryGive (pBuf->writeSignal);
|
||||
}
|
||||
|
||||
/*
|
||||
* cacRingBufferReadSize ()
|
||||
*/
|
||||
static inline unsigned cacRingBufferReadSize (ringBuffer *pBuf)
|
||||
{
|
||||
unsigned long count;
|
||||
|
||||
if ( pBuf->wtix <= pBuf->rdix ) {
|
||||
static const unsigned bufSizeM1 = sizeof (pBuf->buf) - 1u;
|
||||
count = ( bufSizeM1 - pBuf->rdix ) + pBuf->wtix;
|
||||
}
|
||||
else {
|
||||
count = (pBuf->wtix - pBuf->rdix) - 1u;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* cacRingBufferContiguousReadSize ()
|
||||
*/
|
||||
static inline unsigned cacRingBufferContiguousReadSize (ringBuffer *pBuf)
|
||||
{
|
||||
static const unsigned bufSizeM1 = sizeof (pBuf->buf) - 1u;
|
||||
unsigned long count;
|
||||
|
||||
if ( pBuf->wtix <= pBuf->rdix ) {
|
||||
if (pBuf->rdix==bufSizeM1) {
|
||||
count = pBuf->wtix;
|
||||
}
|
||||
else {
|
||||
count = bufSizeM1 - pBuf->rdix;
|
||||
}
|
||||
}
|
||||
else {
|
||||
count = (pBuf->wtix - pBuf->rdix) - 1u;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* cacRingBufferWriteSize ()
|
||||
*/
|
||||
static inline unsigned cacRingBufferWriteSize (ringBuffer *pBuf)
|
||||
{
|
||||
unsigned long count;
|
||||
|
||||
if (pBuf->wtix <= pBuf->rdix) {
|
||||
count = pBuf->rdix - pBuf->wtix;
|
||||
}
|
||||
else {
|
||||
count = ( sizeof (pBuf->buf) - pBuf->wtix ) + pBuf->rdix;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* cacRingBufferContiguousWriteSize ()
|
||||
*/
|
||||
static inline unsigned cacRingBufferContiguousWriteSize (ringBuffer *pBuf)
|
||||
{
|
||||
unsigned long count;
|
||||
|
||||
if (pBuf->wtix <= pBuf->rdix) {
|
||||
count = pBuf->rdix - pBuf->wtix;
|
||||
}
|
||||
else {
|
||||
count = sizeof (pBuf->buf) - pBuf->wtix;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* cacRingBufferReadPartial ()
|
||||
*
|
||||
* returns the number of bytes read which may be less than
|
||||
* the number requested.
|
||||
*/
|
||||
static inline unsigned cacRingBufferReadPartial (ringBuffer *pRing, void *pBuf,
|
||||
unsigned nBytes)
|
||||
{
|
||||
unsigned totalBytes;
|
||||
|
||||
if ( pRing->wtix < pRing->rdix ) {
|
||||
static const unsigned bufSizeM1 = sizeof (pRing->buf) - 1u;
|
||||
unsigned nBytesAvail1stBlock, nBytesAvail2ndBlock;
|
||||
|
||||
nBytesAvail1stBlock = bufSizeM1 - pRing->rdix;
|
||||
nBytesAvail2ndBlock = pRing->wtix;
|
||||
if ( nBytesAvail1stBlock >= nBytes ) {
|
||||
totalBytes = nBytes;
|
||||
memcpy ( pBuf, pRing->buf + pRing->rdix + 1u, totalBytes );
|
||||
}
|
||||
else {
|
||||
char *pChar = (char *) pBuf;
|
||||
memcpy ( pBuf, pRing->buf + pRing->rdix + 1u, nBytesAvail1stBlock );
|
||||
nBytes -= nBytesAvail1stBlock;
|
||||
if ( nBytesAvail2ndBlock > nBytes ) {
|
||||
nBytesAvail2ndBlock = nBytes;
|
||||
}
|
||||
memcpy ( pChar + nBytesAvail1stBlock, pRing->buf, nBytesAvail2ndBlock);
|
||||
totalBytes = nBytesAvail1stBlock + nBytesAvail2ndBlock;
|
||||
}
|
||||
pRing->rdix += totalBytes;
|
||||
pRing->rdix &= ringIndexMask;
|
||||
}
|
||||
else if ( pRing->wtix > pRing->rdix ) {
|
||||
totalBytes = (pRing->wtix - pRing->rdix) - 1;
|
||||
if ( totalBytes > nBytes ) {
|
||||
totalBytes = nBytes;
|
||||
}
|
||||
memcpy (pBuf, pRing->buf+pRing->rdix+1, totalBytes);
|
||||
pRing->rdix += totalBytes;
|
||||
pRing->rdix &= ringIndexMask;
|
||||
}
|
||||
else {
|
||||
totalBytes = 0;
|
||||
}
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* cacRingBufferRead ()
|
||||
*
|
||||
* returns the number of bytes read which may be less than
|
||||
* the number requested.
|
||||
*/
|
||||
unsigned cacRingBufferRead (ringBuffer *pRing, void *pBuf,
|
||||
unsigned nBytes)
|
||||
{
|
||||
unsigned char *pBufTmp = (unsigned char *) pBuf;
|
||||
unsigned totalBytes = 0;
|
||||
unsigned curBytes;
|
||||
|
||||
semMutexMustTake (pRing->readLock);
|
||||
|
||||
while (totalBytes<nBytes) {
|
||||
curBytes = cacRingBufferReadPartial (pRing,
|
||||
pBufTmp+totalBytes, nBytes-totalBytes);
|
||||
if (curBytes==0) {
|
||||
semBinaryMustTake (pRing->readSignal);
|
||||
if (pRing->shutDown) {
|
||||
semMutexGive (pRing->readLock);
|
||||
return totalBytes;
|
||||
}
|
||||
}
|
||||
else {
|
||||
totalBytes += curBytes;
|
||||
}
|
||||
}
|
||||
|
||||
semMutexGive (pRing->readLock);
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* cacRingBufferWritePartial ()
|
||||
*
|
||||
* returns the number of bytes written which may be less than
|
||||
* the number requested.
|
||||
*/
|
||||
static inline unsigned cacRingBufferWritePartial (ringBuffer *pRing,
|
||||
const void *pBuf, unsigned nBytes)
|
||||
{
|
||||
unsigned totalBytes;
|
||||
|
||||
if ( pRing->wtix < pRing->rdix ) {
|
||||
totalBytes = pRing->rdix - pRing->wtix;
|
||||
if ( totalBytes > nBytes ) {
|
||||
totalBytes = nBytes;
|
||||
}
|
||||
memcpy (pRing->buf+pRing->wtix, pBuf, totalBytes);
|
||||
pRing->wtix += totalBytes;
|
||||
pRing->wtix &= ringIndexMask;
|
||||
}
|
||||
else if ( pRing->wtix > pRing->rdix ) {
|
||||
unsigned nBytesAvail1stBlock, nBytesAvail2ndBlock;
|
||||
|
||||
nBytesAvail1stBlock = sizeof (pRing->buf) - pRing->wtix;
|
||||
nBytesAvail2ndBlock = pRing->rdix;
|
||||
if ( nBytesAvail1stBlock >= nBytes ) {
|
||||
totalBytes = nBytes;
|
||||
memcpy ( pRing->buf+pRing->wtix, pBuf, totalBytes );
|
||||
}
|
||||
else {
|
||||
char *pChar = (char *) pBuf;
|
||||
memcpy ( pRing->buf+pRing->wtix, pBuf, nBytesAvail1stBlock );
|
||||
nBytes -= nBytesAvail1stBlock;
|
||||
if ( nBytesAvail2ndBlock > nBytes ) {
|
||||
nBytesAvail2ndBlock = nBytes;
|
||||
}
|
||||
memcpy (pRing->buf, pChar+nBytesAvail1stBlock,
|
||||
nBytesAvail2ndBlock);
|
||||
totalBytes = nBytesAvail2ndBlock + nBytesAvail1stBlock;
|
||||
}
|
||||
pRing->wtix += totalBytes;
|
||||
pRing->wtix &= ringIndexMask;
|
||||
}
|
||||
else {
|
||||
totalBytes = 0;
|
||||
}
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* cacRingBufferWrite ()
|
||||
*
|
||||
* returns the number of bytes written which may be less than
|
||||
* the number requested.
|
||||
*/
|
||||
unsigned cacRingBufferWrite (ringBuffer *pRing, const void *pBuf,
|
||||
unsigned nBytes)
|
||||
{
|
||||
unsigned char *pBufTmp = (unsigned char *) pBuf;
|
||||
unsigned totalBytes = 0;
|
||||
unsigned curBytes;
|
||||
|
||||
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);
|
||||
return totalBytes;
|
||||
}
|
||||
}
|
||||
else {
|
||||
totalBytes += curBytes;
|
||||
}
|
||||
}
|
||||
|
||||
semMutexGive (pRing->writeLock);
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
bool cacRingBufferWriteLockNoBlock (ringBuffer *pBuf, unsigned bytesRequired)
|
||||
{
|
||||
semMutexMustTake (pBuf->writeLock);
|
||||
|
||||
if (cacRingBufferWriteSize (pBuf)<bytesRequired) {
|
||||
semMutexGive (pBuf->writeLock);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cacRingBufferWriteUnlock (ringBuffer *pBuf)
|
||||
{
|
||||
semMutexGive (pBuf->writeLock);
|
||||
}
|
||||
|
||||
void *cacRingBufferWriteReserve (ringBuffer *pRing, unsigned *pBytesAvail)
|
||||
{
|
||||
unsigned avail;
|
||||
|
||||
semMutexMustTake (pRing->writeLock);
|
||||
|
||||
avail = cacRingBufferContiguousWriteSize (pRing);
|
||||
while (avail==0) {
|
||||
semBinaryGive (pRing->readSignal);
|
||||
semBinaryMustTake (pRing->writeSignal);
|
||||
if (pRing->shutDown) {
|
||||
semMutexGive (pRing->writeLock);
|
||||
*pBytesAvail = 0u;
|
||||
return 0;
|
||||
}
|
||||
avail = cacRingBufferContiguousWriteSize (pRing);
|
||||
}
|
||||
|
||||
*pBytesAvail = avail;
|
||||
|
||||
return (void *) &pRing->buf[pRing->wtix];
|
||||
}
|
||||
|
||||
void *cacRingBufferWriteReserveNoBlock (ringBuffer *pRing, unsigned *pBytesAvail)
|
||||
{
|
||||
unsigned avail;
|
||||
|
||||
semMutexMustTake (pRing->writeLock);
|
||||
|
||||
avail = cacRingBufferContiguousWriteSize (pRing);
|
||||
|
||||
if ( avail==0 || pRing->shutDown ) {
|
||||
*pBytesAvail = 0u;
|
||||
semMutexGive (pRing->writeLock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*pBytesAvail = avail;
|
||||
|
||||
return (void *) &pRing->buf[pRing->wtix];
|
||||
}
|
||||
|
||||
void cacRingBufferWriteCommit (ringBuffer *pRing, unsigned delta)
|
||||
{
|
||||
pRing->wtix += delta;
|
||||
pRing->wtix &= ringIndexMask;
|
||||
semMutexGive (pRing->writeLock);
|
||||
}
|
||||
|
||||
void *cacRingBufferReadReserve (ringBuffer *pRing, unsigned *pBytesAvail)
|
||||
{
|
||||
unsigned avail;
|
||||
|
||||
semMutexMustTake (pRing->readLock);
|
||||
|
||||
avail = cacRingBufferContiguousReadSize (pRing);
|
||||
while (avail==0) {
|
||||
semBinaryMustTake (pRing->readSignal);
|
||||
if (pRing->shutDown) {
|
||||
semMutexGive (pRing->readLock);
|
||||
*pBytesAvail = 0u;
|
||||
return NULL;
|
||||
}
|
||||
avail = cacRingBufferContiguousReadSize (pRing);
|
||||
}
|
||||
|
||||
*pBytesAvail = avail;
|
||||
|
||||
return (void *) &pRing->buf[(pRing->rdix+1) & ringIndexMask];
|
||||
}
|
||||
|
||||
void *cacRingBufferReadReserveNoBlock (ringBuffer *pRing, unsigned *pBytesAvail)
|
||||
{
|
||||
unsigned avail;
|
||||
|
||||
semMutexMustTake (pRing->readLock);
|
||||
|
||||
avail = cacRingBufferContiguousReadSize (pRing);
|
||||
|
||||
if ( avail==0 || pRing->shutDown ) {
|
||||
*pBytesAvail = 0u;
|
||||
semMutexGive (pRing->readLock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*pBytesAvail = avail;
|
||||
|
||||
return (void *) &pRing->buf[(pRing->rdix+1) & ringIndexMask];
|
||||
}
|
||||
|
||||
|
||||
void cacRingBufferReadCommit (ringBuffer *pRing, unsigned delta)
|
||||
{
|
||||
pRing->rdix += delta;
|
||||
pRing->rdix &= ringIndexMask;
|
||||
semMutexGive (pRing->readLock);
|
||||
}
|
||||
|
||||
void cacRingBufferWriteFlush (ringBuffer *pRing)
|
||||
{
|
||||
semBinaryGive (pRing->readSignal);
|
||||
}
|
||||
|
||||
void cacRingBufferReadFlush (ringBuffer *pRing)
|
||||
{
|
||||
semBinaryGive (pRing->writeSignal);
|
||||
}
|
||||
66
src/ca/ringBuffer.h
Normal file
66
src/ca/ringBuffer.h
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 Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef ringBufferh
|
||||
#define ringBufferh
|
||||
|
||||
#include "osiSem.h"
|
||||
|
||||
#define nBitsRingIndex 14
|
||||
#define nElementsInRing (1<<nBitsRingIndex)
|
||||
|
||||
typedef struct ringBuffer {
|
||||
char buf[nElementsInRing];
|
||||
semBinaryId readSignal;
|
||||
semBinaryId writeSignal;
|
||||
semMutexId readLock;
|
||||
semMutexId writeLock;
|
||||
unsigned rdix; /* index of last char read */
|
||||
unsigned wtix; /* index of next char to write */
|
||||
unsigned shutDown;
|
||||
} ringBuffer;
|
||||
|
||||
int cacRingBufferConstruct (ringBuffer *pBuf);
|
||||
void cacRingBufferDestroy (ringBuffer *pBuf);
|
||||
|
||||
unsigned cacRingBufferWrite (ringBuffer *pRing,
|
||||
const void *pBuf, unsigned nBytes);
|
||||
|
||||
unsigned cacRingBufferRead (ringBuffer *pRing,
|
||||
void *pBuf, unsigned nBytes);
|
||||
|
||||
bool cacRingBufferWriteLockNoBlock (ringBuffer *pBuf, unsigned bytesRequired);
|
||||
|
||||
void cacRingBufferWriteUnlock (ringBuffer *pBuf);
|
||||
|
||||
void *cacRingBufferWriteReserve (ringBuffer *pBuf, unsigned *pAvailBytes);
|
||||
|
||||
void cacRingBufferWriteCommit (ringBuffer *pBuf, unsigned delta);
|
||||
|
||||
void *cacRingBufferReadReserve (ringBuffer *pBuf, unsigned *pBytesAvail);
|
||||
|
||||
void *cacRingBufferReadReserveNoBlock (ringBuffer *pBuf, unsigned *pBytesAvail);
|
||||
|
||||
void cacRingBufferReadCommit (ringBuffer *pBuf, unsigned delta);
|
||||
|
||||
void cacRingBufferReadFlush (ringBuffer *pBuf);
|
||||
void cacRingBufferWriteFlush (ringBuffer *pBuf);
|
||||
|
||||
void cacRingBufferShutDown (ringBuffer *pBuf);
|
||||
|
||||
#endif /* ringBufferh */
|
||||
348
src/ca/searchTimer.cpp
Normal file
348
src/ca/searchTimer.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
|
||||
/* * $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"
|
||||
|
||||
//
|
||||
// searchTimer::searchTimer ()
|
||||
//
|
||||
searchTimer::searchTimer (udpiiu &iiuIn, osiTimerQueue &queueIn) :
|
||||
osiTimer (queueIn),
|
||||
iiu (iiuIn),
|
||||
framesPerTry (INITIALTRIESPERFRAME),
|
||||
framesPerTryCongestThresh (UINT_MAX),
|
||||
minRetry (UINT_MAX),
|
||||
retry (0u),
|
||||
searchTries (0u),
|
||||
searchResponses (0u),
|
||||
retrySeqNo (0u),
|
||||
retrySeqNoAtListBegin (0u),
|
||||
period (CA_RECAST_DELAY)
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// searchTimer::reset ()
|
||||
//
|
||||
void searchTimer::reset (double period)
|
||||
{
|
||||
LOCK (this->iiu.niiu.iiu.pcas);
|
||||
this->retry = 0;
|
||||
this->period = period;
|
||||
UNLOCK (this->iiu.niiu.iiu.pcas);
|
||||
|
||||
if (this->timeRemaining()>period) {
|
||||
this->reschedule (0.0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* searchTimer::setRetryInterval ()
|
||||
*/
|
||||
void searchTimer::setRetryInterval (unsigned retryNo)
|
||||
{
|
||||
unsigned idelay;
|
||||
double delay;
|
||||
|
||||
LOCK (this->iiu.niiu.iiu.pcas);
|
||||
|
||||
/*
|
||||
* set the retry number
|
||||
*/
|
||||
this->retry = min (retryNo, MAXCONNTRIES+1u);
|
||||
|
||||
/*
|
||||
* set the retry interval
|
||||
*/
|
||||
idelay = 1u << min (this->retry, CHAR_BIT*sizeof(idelay)-1u);
|
||||
delay = idelay * CA_RECAST_DELAY; /* sec */
|
||||
/*
|
||||
* place upper limit on the retry delay
|
||||
*/
|
||||
this->period = min (CA_RECAST_PERIOD, delay);
|
||||
|
||||
UNLOCK (this->iiu.niiu.iiu.pcas);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("new CA search period is %f sec\n", this->period);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// searchTimer::notifySearchResponse ()
|
||||
//
|
||||
// Reset the delay to the next search request if we get
|
||||
// at least one response. However, dont reset this delay if we
|
||||
// get a delayed response to an old search request.
|
||||
//
|
||||
void searchTimer::notifySearchResponse (nciu *pChan)
|
||||
{
|
||||
LOCK (this->iiu.niiu.iiu.pcas);
|
||||
|
||||
if ( this->retrySeqNoAtListBegin <= pChan->retrySeqNo ) {
|
||||
if ( this->searchResponses < ULONG_MAX ) {
|
||||
this->searchResponses++;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK (this->iiu.niiu.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;
|
||||
|
||||
/*
|
||||
* check to see if there is nothing to do here
|
||||
*/
|
||||
if (ellCount(&this->iiu.niiu.chidList)==0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK (this->iiu.niiu.iiu.pcas);
|
||||
|
||||
/*
|
||||
* increment the retry sequence number
|
||||
*/
|
||||
this->retrySeqNo++; /* allowed to roll over */
|
||||
|
||||
/*
|
||||
* dynamically adjust the number of UDP frames per
|
||||
* try depending how many search requests are not
|
||||
* replied to
|
||||
*
|
||||
* This determines how many search request can be
|
||||
* sent together (at the same instant in time).
|
||||
*
|
||||
* The variable this->framesPerTry
|
||||
* determines the number of UDP frames to be sent
|
||||
* each time that retrySearchRequest() is called.
|
||||
* If this value is too high we will waste some
|
||||
* network bandwidth. If it is too low we will
|
||||
* use very little of the incoming UDP message
|
||||
* buffer associated with the server's port and
|
||||
* will therefore take longer to connect. We
|
||||
* initialize this->framesPerTry
|
||||
* to a prime number so that it is less likely that the
|
||||
* same channel is in the last UDP frame
|
||||
* sent every time that this is called (and
|
||||
* potentially discarded by a CA server with
|
||||
* a small UDP input queue).
|
||||
*/
|
||||
/*
|
||||
* increase frames per try only if we see better than
|
||||
* a 93.75% success rate for one pass through the list
|
||||
*/
|
||||
if (this->searchResponses >
|
||||
(this->searchTries-(this->searchTries/16u)) ) {
|
||||
/*
|
||||
* increase UDP frames per try if we have a good score
|
||||
*/
|
||||
if ( this->framesPerTry < MAXTRIESPERFRAME ) {
|
||||
/*
|
||||
* a congestion avoidance threshold similar to TCP is now used
|
||||
*/
|
||||
if ( this->framesPerTry < this->framesPerTryCongestThresh ) {
|
||||
this->framesPerTry += this->framesPerTry;
|
||||
}
|
||||
else {
|
||||
this->framesPerTry += (this->framesPerTry/8) + 1;
|
||||
}
|
||||
#if 0
|
||||
printf ("Increasing frame count to %u t=%u r=%u\n",
|
||||
this->framesPerTry, this->searchTries,
|
||||
this->searchResponses);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*
|
||||
* if we detect congestion because we have less than a 87.5% success
|
||||
* rate then gradually reduce the frames per try
|
||||
*/
|
||||
else if ( this->searchResponses <
|
||||
(this->searchTries-(this->searchTries/8u)) ) {
|
||||
if (this->framesPerTry>1) {
|
||||
this->framesPerTry--;
|
||||
}
|
||||
this->framesPerTryCongestThresh = this->framesPerTry/2 + 1;
|
||||
#if 0
|
||||
printf ("Congestion detected - set frames per try to %u t=%u r=%u\n",
|
||||
this->framesPerTry, this->searchTries,
|
||||
this->searchResponses);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* a successful cac_search_msg() sends channel to
|
||||
* the end of the list
|
||||
*/
|
||||
firstChan = chan = (nciu *) ellFirst (&this->iiu.niiu.chidList);
|
||||
while (chan) {
|
||||
|
||||
this->minRetry = min (this->minRetry, chan->retry);
|
||||
|
||||
/*
|
||||
* clear counter when we reach the end of the list
|
||||
*
|
||||
* if we are making some progress then
|
||||
* dont increase the delay between search
|
||||
* requests
|
||||
*/
|
||||
if ( this->iiu.niiu.iiu.pcas->ca_pEndOfBCastList == chan ) {
|
||||
if ( this->searchResponses == 0u ) {
|
||||
#if 0
|
||||
printf ("increasing search try interval\n");
|
||||
#endif
|
||||
this->setRetryInterval (this->minRetry + 1u);
|
||||
}
|
||||
|
||||
this->minRetry = UINT_MAX;
|
||||
|
||||
/*
|
||||
* increment the retry sequence number
|
||||
* (this prevents the time of the next search
|
||||
* try from being set to the current time if
|
||||
* we are handling a response from an old
|
||||
* search message)
|
||||
*/
|
||||
this->retrySeqNo++; /* allowed to roll over */
|
||||
|
||||
/*
|
||||
* so that old search tries will not update the counters
|
||||
*/
|
||||
this->retrySeqNoAtListBegin = this->retrySeqNo;
|
||||
|
||||
/*
|
||||
* reset the search try/response counters at the end of the list
|
||||
* (sequence number) so that we dont overflow, but dont subtract
|
||||
* out tries that dont have a matching response yet in case they
|
||||
* are delayed
|
||||
*/
|
||||
if ( this->searchTries > this->searchResponses ) {
|
||||
this->searchTries -= this->searchResponses;
|
||||
}
|
||||
else {
|
||||
this->searchTries = 0;
|
||||
}
|
||||
this->searchResponses = 0;
|
||||
|
||||
#if 0
|
||||
printf ("saw end of list\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* this moves the channel to the end of the
|
||||
* list (if successful)
|
||||
*/
|
||||
status = cac_search_msg (chan);
|
||||
if (status != ECA_NORMAL) {
|
||||
nSent++;
|
||||
|
||||
if (nSent>=this->framesPerTry) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* flush out the search request buffer */
|
||||
semBinaryGive (this->iiu.xmitSignal);
|
||||
|
||||
/* try again */
|
||||
status = cac_search_msg (chan);
|
||||
if (status != ECA_NORMAL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->searchTries<ULONG_MAX) {
|
||||
this->searchTries++;
|
||||
}
|
||||
|
||||
chan->retrySeqNo = this->retrySeqNo;
|
||||
chan = (nciu *) ellFirst (&this->iiu.niiu.chidList);
|
||||
|
||||
/*
|
||||
* dont send any of the channels twice within one try
|
||||
*/
|
||||
if (chan==firstChan) {
|
||||
/*
|
||||
* add one to nSent because there may be
|
||||
* one more partial frame to be sent
|
||||
*/
|
||||
nSent++;
|
||||
|
||||
/*
|
||||
* cap this->framesPerTry to
|
||||
* the number of frames required for all of
|
||||
* the unresolved channels
|
||||
*/
|
||||
if (this->framesPerTry>nSent) {
|
||||
this->framesPerTry = nSent;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK (this->iiu.niiu.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
|
||||
|
||||
}
|
||||
|
||||
void searchTimer::destroy ()
|
||||
{
|
||||
}
|
||||
|
||||
bool searchTimer::again () const
|
||||
{
|
||||
if (ellCount(&this->iiu.niiu.chidList)==0) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (this->retry < MAXCONNTRIES) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double searchTimer::delay () const
|
||||
{
|
||||
return this->period;
|
||||
}
|
||||
|
||||
void searchTimer::show (unsigned level) const
|
||||
{
|
||||
}
|
||||
|
||||
const char *searchTimer::name () const
|
||||
{
|
||||
return "CAC Search Timer";
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
645
src/ca/syncgrp.c
645
src/ca/syncgrp.c
@@ -1,645 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
* Author: Jeffrey O. Hill
|
||||
* hill@luke.lanl.gov
|
||||
* (505) 665 1831
|
||||
* Date: 9-93
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* $Log$
|
||||
* Revision 1.27 1999/07/16 17:08:05 jhill
|
||||
* fixed bug occurring when connection dropped while waiting to send, and
|
||||
* initialize new search gongestion thresh parm
|
||||
*
|
||||
* Revision 1.26.6.1 1999/07/15 21:02:25 jhill
|
||||
* fixed bug where client disconnects while waiting to send TCP
|
||||
*
|
||||
* Revision 1.26 1997/08/04 23:37:18 jhill
|
||||
* added beacon anomaly flag init/allow ip 255.255.255.255
|
||||
*
|
||||
* Revision 1.24 1997/06/13 09:14:26 jhill
|
||||
* connect/search proto changes
|
||||
*
|
||||
* Revision 1.23 1997/04/29 06:12:42 jhill
|
||||
* use free lists
|
||||
*
|
||||
* Revision 1.22 1996/11/22 19:08:02 jhill
|
||||
* added const to API
|
||||
*
|
||||
* Revision 1.21 1996/11/02 00:51:08 jhill
|
||||
* many pc port, const in API, and other changes
|
||||
*
|
||||
* Revision 1.20 1996/07/10 23:30:12 jhill
|
||||
* fixed GNU warnings
|
||||
*
|
||||
* Revision 1.19 1996/06/19 17:59:29 jhill
|
||||
* many 3.13 beta changes
|
||||
*
|
||||
* Revision 1.18 1995/10/12 01:36:39 jhill
|
||||
* New ca_flush_io() mechanism
|
||||
*
|
||||
* Revision 1.17 1995/09/29 22:13:59 jhill
|
||||
* check for nill dbr pointer
|
||||
*
|
||||
* Revision 1.16 1995/08/22 00:27:55 jhill
|
||||
* added cvs style mod log
|
||||
*
|
||||
*
|
||||
* NOTES:
|
||||
* 1) Need to fix if the OP is on a FD that
|
||||
* becomes disconneted it will stay on the
|
||||
* queue forever.
|
||||
*/
|
||||
|
||||
#include "iocinf.h"
|
||||
#include "freeList.h"
|
||||
|
||||
LOCAL void io_complete(struct event_handler_args args);
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_init()
|
||||
*/
|
||||
void ca_sg_init(CA_STATIC *ca_static)
|
||||
{
|
||||
/*
|
||||
* init all sync group lists
|
||||
*/
|
||||
freeListInitPvt(&ca_static->ca_sgFreeListPVT,sizeof(CASG),32);
|
||||
freeListInitPvt(&ca_static->ca_sgopFreeListPVT,sizeof(CASGOP),256);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_shutdown()
|
||||
*/
|
||||
void ca_sg_shutdown(CA_STATIC *ca_static)
|
||||
{
|
||||
CASG *pcasg;
|
||||
CASG *pnextcasg;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* free all sync group lists
|
||||
*/
|
||||
LOCK;
|
||||
pcasg = (CASG *) ellFirst (&ca_static->activeCASG);
|
||||
while (pcasg) {
|
||||
pnextcasg = (CASG *) ellNext (&pcasg->node);
|
||||
status = ca_sg_delete (pcasg->id);
|
||||
assert (status==ECA_NORMAL);
|
||||
pcasg = pnextcasg;
|
||||
}
|
||||
assert (ellCount(&ca_static->activeCASG)==0);
|
||||
|
||||
/*
|
||||
* per sync group
|
||||
*/
|
||||
freeListCleanup(ca_static->ca_sgFreeListPVT);
|
||||
|
||||
/*
|
||||
* per sync group op
|
||||
*/
|
||||
ellFree (&ca_static->activeCASGOP);
|
||||
freeListCleanup(ca_static->ca_sgopFreeListPVT);
|
||||
|
||||
UNLOCK;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_create()
|
||||
*/
|
||||
int epicsShareAPI ca_sg_create(CA_SYNC_GID *pgid)
|
||||
{
|
||||
int status;
|
||||
CASG *pcasg;
|
||||
CA_OSD_GET_CA_STATIC
|
||||
|
||||
/*
|
||||
* Force the CA client id bucket to
|
||||
* init if needed.
|
||||
* Return error if unable to init.
|
||||
*/
|
||||
INITCHK;
|
||||
|
||||
/*
|
||||
* first look on a free list. If not there
|
||||
* allocate dynamic memory for it.
|
||||
*/
|
||||
pcasg = (CASG *) freeListMalloc(ca_static->ca_sgFreeListPVT);
|
||||
if(!pcasg){
|
||||
return ECA_ALLOCMEM;
|
||||
}
|
||||
|
||||
LOCK;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
#ifdef iocCore
|
||||
pcasg->sem = semBinaryCreate(semEmpty);
|
||||
assert(pcasg->sem );
|
||||
#endif
|
||||
|
||||
do {
|
||||
pcasg->id = CLIENT_SLOW_ID_ALLOC;
|
||||
status = bucketAddItemUnsignedId (pSlowBucket,
|
||||
&pcasg->id, pcasg);
|
||||
} while (status == S_bucket_idInUse);
|
||||
|
||||
if (status == S_bucket_success) {
|
||||
/*
|
||||
* place it on the active sync group list
|
||||
*/
|
||||
ellAdd (&ca_static->activeCASG, &pcasg->node);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* place it back on the free sync group list
|
||||
*/
|
||||
freeListFree(ca_static->ca_sgFreeListPVT, pcasg);
|
||||
UNLOCK;
|
||||
if (status == S_bucket_noMemory) {
|
||||
return ECA_ALLOCMEM;
|
||||
}
|
||||
else {
|
||||
return ECA_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK;
|
||||
|
||||
*pgid = pcasg->id;
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_delete()
|
||||
*/
|
||||
int epicsShareAPI ca_sg_delete(const CA_SYNC_GID gid)
|
||||
{
|
||||
int status;
|
||||
CASG *pcasg;
|
||||
CA_OSD_GET_CA_STATIC
|
||||
|
||||
/*
|
||||
* Force the CA client id bucket to
|
||||
* init if needed.
|
||||
* Return error if unable to init.
|
||||
*/
|
||||
INITCHK;
|
||||
|
||||
LOCK;
|
||||
|
||||
pcasg = bucketLookupItemUnsignedId(pSlowBucket, &gid);
|
||||
if(!pcasg || pcasg->magic != CASG_MAGIC){
|
||||
UNLOCK;
|
||||
return ECA_BADSYNCGRP;
|
||||
}
|
||||
|
||||
status = bucketRemoveItemUnsignedId(pSlowBucket, &gid);
|
||||
assert (status == S_bucket_success);
|
||||
|
||||
#ifdef iocCore
|
||||
semBinaryDestroy(pcasg->sem);
|
||||
#endif
|
||||
pcasg->magic = 0;
|
||||
ellDelete(&ca_static->activeCASG, &pcasg->node);
|
||||
UNLOCK;
|
||||
|
||||
freeListFree(ca_static->ca_sgFreeListPVT, pcasg);
|
||||
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_block()
|
||||
*/
|
||||
int epicsShareAPI ca_sg_block(const CA_SYNC_GID gid, ca_real timeout)
|
||||
{
|
||||
struct timeval beg_time;
|
||||
ca_real delay;
|
||||
int status;
|
||||
CASG *pcasg;
|
||||
CA_OSD_GET_CA_STATIC
|
||||
|
||||
/*
|
||||
* Force the CA client id bucket to
|
||||
* init if needed.
|
||||
* Return error if unable to init.
|
||||
*/
|
||||
INITCHK;
|
||||
|
||||
if(timeout<0.0){
|
||||
return ECA_TIMEOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* until CAs input mechanism is
|
||||
* revised we have to dissallow
|
||||
* this routine from an event routine
|
||||
* (to avoid excess recursion)
|
||||
*/
|
||||
if(EVENTLOCKTEST){
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
|
||||
LOCK;
|
||||
pcasg = bucketLookupItemUnsignedId(pSlowBucket, &gid);
|
||||
if(!pcasg || pcasg->magic != CASG_MAGIC){
|
||||
UNLOCK;
|
||||
return ECA_BADSYNCGRP;
|
||||
}
|
||||
UNLOCK;
|
||||
|
||||
/*
|
||||
* always flush at least once.
|
||||
*/
|
||||
ca_static->ca_flush_pending = TRUE;
|
||||
|
||||
cac_gettimeval (&ca_static->currentTime);
|
||||
beg_time = ca_static->currentTime;
|
||||
delay = 0.0;
|
||||
|
||||
status = ECA_NORMAL;
|
||||
while(pcasg->opPendCount){
|
||||
ca_real remaining;
|
||||
struct timeval tmo;
|
||||
|
||||
/*
|
||||
* Exit if the timeout has expired
|
||||
* (dont wait forever for an itsy bitsy
|
||||
* delay which will no be updated if
|
||||
* select is called with no delay)
|
||||
*
|
||||
* current time is only updated by
|
||||
* cac_select_io() if we specify
|
||||
* at least 1 usec to wait
|
||||
*/
|
||||
remaining = timeout-delay;
|
||||
if (remaining<=(1.0/USEC_PER_SEC)) {
|
||||
/*
|
||||
* Make sure that we take care of
|
||||
* recv backlog at least once
|
||||
*/
|
||||
tmo.tv_sec = 0L;
|
||||
tmo.tv_usec = 0L;
|
||||
cac_mux_io (ca_static, &tmo, TRUE);
|
||||
status = ECA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow for CA background labor
|
||||
*/
|
||||
remaining = min(cac_fetch_poll_period(ca_static), remaining);
|
||||
|
||||
/*
|
||||
* wait for asynch notification
|
||||
*/
|
||||
tmo.tv_sec = (long) remaining;
|
||||
tmo.tv_usec = (long) ((remaining-tmo.tv_sec)*USEC_PER_SEC);
|
||||
#ifndef iocCore
|
||||
cac_mux_io(ca_static,&tmo, TRUE);
|
||||
#else
|
||||
{
|
||||
struct timeval itimeout;
|
||||
double waitTime;
|
||||
itimeout.tv_usec = 0;
|
||||
itimeout.tv_sec = 0;
|
||||
cac_mux_io(ca_static,&itimeout, TRUE);
|
||||
waitTime = tmo.tv_sec + tmo.tv_usec/1000.0;
|
||||
if(waitTime>POLLDELAY) waitTime = POLLDELAY;
|
||||
semBinaryTakeTimeout(ca_static->ca_io_done_sem,waitTime);
|
||||
/*
|
||||
*force a time update because we are not
|
||||
*going to get one with a nill timeout in ca_mux_io()
|
||||
*/
|
||||
cac_gettimeval (&ca_static->currentTime);
|
||||
}
|
||||
#endif
|
||||
delay = cac_time_diff (&ca_static->currentTime, &beg_time);
|
||||
}
|
||||
pcasg->opPendCount = 0;
|
||||
pcasg->seqNo++;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_reset
|
||||
*/
|
||||
int epicsShareAPI ca_sg_reset(const CA_SYNC_GID gid)
|
||||
{
|
||||
CASG *pcasg;
|
||||
CA_OSD_GET_CA_STATIC
|
||||
|
||||
LOCK;
|
||||
pcasg = bucketLookupItemUnsignedId(pSlowBucket, &gid);
|
||||
if(!pcasg || pcasg->magic != CASG_MAGIC){
|
||||
UNLOCK;
|
||||
return ECA_BADSYNCGRP;
|
||||
}
|
||||
|
||||
pcasg->opPendCount = 0;
|
||||
pcasg->seqNo++;
|
||||
UNLOCK;
|
||||
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_stat
|
||||
*/
|
||||
int epicsShareAPI ca_sg_stat(const CA_SYNC_GID gid)
|
||||
{
|
||||
CASG *pcasg;
|
||||
CASGOP *pcasgop;
|
||||
CA_OSD_GET_CA_STATIC
|
||||
|
||||
LOCK;
|
||||
pcasg = bucketLookupItemUnsignedId(pSlowBucket, &gid);
|
||||
if(!pcasg || pcasg->magic != CASG_MAGIC){
|
||||
UNLOCK;
|
||||
printf("Bad Sync Group Id\n");
|
||||
return ECA_BADSYNCGRP;
|
||||
}
|
||||
UNLOCK;
|
||||
|
||||
printf("Sync Group: id=%u, magic=%lu, opPend=%lu, seqNo=%lu\n",
|
||||
pcasg->id, pcasg->magic, pcasg->opPendCount,
|
||||
pcasg->seqNo);
|
||||
|
||||
LOCK;
|
||||
pcasgop = (CASGOP *) ellFirst(&ca_static->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);
|
||||
}
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_test
|
||||
*/
|
||||
int epicsShareAPI ca_sg_test(const CA_SYNC_GID gid)
|
||||
{
|
||||
CASG *pcasg;
|
||||
CA_OSD_GET_CA_STATIC
|
||||
|
||||
LOCK;
|
||||
pcasg = bucketLookupItemUnsignedId(pSlowBucket, &gid);
|
||||
if(!pcasg || pcasg->magic != CASG_MAGIC){
|
||||
UNLOCK;
|
||||
return ECA_BADSYNCGRP;
|
||||
}
|
||||
UNLOCK;
|
||||
|
||||
if(pcasg->opPendCount){
|
||||
return ECA_IOINPROGRESS;
|
||||
}
|
||||
else{
|
||||
return ECA_IODONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_array_put()
|
||||
*/
|
||||
int epicsShareAPI ca_sg_array_put(
|
||||
const CA_SYNC_GID gid,
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chix,
|
||||
const void *pvalue)
|
||||
{
|
||||
int status;
|
||||
CASGOP *pcasgop;
|
||||
CASG *pcasg;
|
||||
CA_OSD_GET_CA_STATIC
|
||||
|
||||
/*
|
||||
* first look on a free list. If not there
|
||||
* allocate dynamic memory for it.
|
||||
*/
|
||||
pcasgop = (CASGOP *) freeListMalloc(ca_static->ca_sgopFreeListPVT);
|
||||
if(!pcasgop){
|
||||
return ECA_ALLOCMEM;
|
||||
}
|
||||
|
||||
LOCK;
|
||||
pcasg = bucketLookupItemUnsignedId(pSlowBucket, &gid);
|
||||
if(!pcasg || pcasg->magic != CASG_MAGIC){
|
||||
UNLOCK;
|
||||
freeListFree(ca_static->ca_sgopFreeListPVT, pcasgop);
|
||||
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 */
|
||||
ellAdd(&ca_static->activeCASGOP, &pcasgop->node);
|
||||
pcasg->opPendCount++;
|
||||
UNLOCK;
|
||||
|
||||
status = ca_array_put_callback(
|
||||
type,
|
||||
count,
|
||||
chix,
|
||||
pvalue,
|
||||
io_complete,
|
||||
pcasgop);
|
||||
|
||||
if(status != ECA_NORMAL){
|
||||
LOCK;
|
||||
assert(pcasg->opPendCount>=1u);
|
||||
pcasg->opPendCount--;
|
||||
ellDelete(&ca_static->activeCASGOP, &pcasgop->node);
|
||||
UNLOCK;
|
||||
freeListFree(ca_static->ca_sgopFreeListPVT, pcasgop);
|
||||
}
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* ca_sg_array_get()
|
||||
*/
|
||||
int epicsShareAPI ca_sg_array_get(
|
||||
const CA_SYNC_GID gid,
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chix,
|
||||
void *pvalue)
|
||||
{
|
||||
int status;
|
||||
CASGOP *pcasgop;
|
||||
CASG *pcasg;
|
||||
CA_OSD_GET_CA_STATIC
|
||||
|
||||
/*
|
||||
* first look on a free list. If not there
|
||||
* allocate dynamic memory for it.
|
||||
*/
|
||||
pcasgop = (CASGOP *) freeListMalloc(ca_static->ca_sgopFreeListPVT);
|
||||
if(!pcasgop){
|
||||
return ECA_ALLOCMEM;
|
||||
}
|
||||
|
||||
LOCK;
|
||||
pcasg = bucketLookupItemUnsignedId(pSlowBucket, &gid);
|
||||
if(!pcasg || pcasg->magic != CASG_MAGIC){
|
||||
UNLOCK;
|
||||
freeListFree(ca_static->ca_sgopFreeListPVT, pcasgop);
|
||||
return ECA_BADSYNCGRP;
|
||||
}
|
||||
|
||||
memset((char *)pcasgop, 0,sizeof(*pcasgop));
|
||||
pcasgop->id = gid;
|
||||
pcasgop->seqNo = pcasg->seqNo;
|
||||
pcasgop->magic = CASG_MAGIC;
|
||||
pcasgop->pValue = pvalue;
|
||||
ellAdd(&ca_static->activeCASGOP, &pcasgop->node);
|
||||
pcasg->opPendCount++;
|
||||
|
||||
UNLOCK;
|
||||
|
||||
status = ca_array_get_callback(
|
||||
type,
|
||||
count,
|
||||
chix,
|
||||
io_complete,
|
||||
pcasgop);
|
||||
|
||||
if(status != ECA_NORMAL){
|
||||
LOCK;
|
||||
assert(pcasg->opPendCount>=1u);
|
||||
pcasg->opPendCount--;
|
||||
ellDelete(&ca_static->activeCASGOP, &pcasgop->node);
|
||||
UNLOCK;
|
||||
freeListFree(ca_static->ca_sgopFreeListPVT, pcasgop);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* io_complete()
|
||||
*/
|
||||
LOCAL void io_complete(struct event_handler_args args)
|
||||
{
|
||||
unsigned long size;
|
||||
CASGOP *pcasgop;
|
||||
CASG *pcasg;
|
||||
CA_OSD_GET_CA_STATIC
|
||||
|
||||
pcasgop = args.usr;
|
||||
assert(pcasgop->magic == CASG_MAGIC);
|
||||
|
||||
LOCK;
|
||||
ellDelete(&ca_static->activeCASGOP, &pcasgop->node);
|
||||
pcasgop->magic = 0;
|
||||
|
||||
/*
|
||||
* ignore stale replies
|
||||
*/
|
||||
pcasg = bucketLookupItemUnsignedId(pSlowBucket, &pcasgop->id);
|
||||
if(!pcasg || pcasg->seqNo != pcasgop->seqNo){
|
||||
UNLOCK;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(pcasg->magic == CASG_MAGIC);
|
||||
assert(pcasg->id == pcasgop->id);
|
||||
|
||||
if(!(args.status&CA_M_SUCCESS)){
|
||||
ca_printf(
|
||||
"CA Sync Group (id=%d) request failed because \"%s\"\n",
|
||||
pcasgop->id,
|
||||
ca_message(args.status));
|
||||
UNLOCK;
|
||||
freeListFree(ca_static->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;
|
||||
|
||||
freeListFree(ca_static->ca_sgopFreeListPVT, pcasgop);
|
||||
|
||||
/*
|
||||
* Wake up any tasks pending
|
||||
*
|
||||
* occurs through select on UNIX
|
||||
*/
|
||||
#ifdef iocCore
|
||||
if(pcasg->opPendCount == 0){
|
||||
semBinaryGive(pcasg->sem);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
619
src/ca/syncgrp.cpp
Normal file
619
src/ca/syncgrp.cpp
Normal file
@@ -0,0 +1,619 @@
|
||||
/*
|
||||
* $Id$
|
||||
* Author: Jeffrey O. Hill
|
||||
* hill@luke.lanl.gov
|
||||
* (505) 665 1831
|
||||
* Date: 9-93
|
||||
*
|
||||
* 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 "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 caStatus;
|
||||
int status;
|
||||
CASG *pcasg;
|
||||
cac *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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK (pcac);
|
||||
|
||||
*pgid = pcasg->id;
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_sg_delete()
|
||||
*/
|
||||
int epicsShareAPI ca_sg_delete(const CA_SYNC_GID gid)
|
||||
{
|
||||
int caStatus;
|
||||
int status;
|
||||
CASG *pcasg;
|
||||
cac *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);
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
cac *pcac;
|
||||
int status;
|
||||
|
||||
status = fetchClientContext (&pcac);
|
||||
if ( status != ECA_NORMAL ) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* dont allow recursion
|
||||
*/
|
||||
{
|
||||
void *p = threadPrivateGet (cacRecursionLock);
|
||||
if (p) {
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
threadPrivateSet (cacRecursionLock, &cacRecursionLock);
|
||||
}
|
||||
|
||||
status = ca_sg_block_private (pcac, gid, timeout);
|
||||
|
||||
threadPrivateSet (cacRecursionLock, NULL);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_sg_reset
|
||||
*/
|
||||
int epicsShareAPI ca_sg_reset (const CA_SYNC_GID gid)
|
||||
{
|
||||
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->opPendCount = 0;
|
||||
pcasg->seqNo++;
|
||||
UNLOCK (pcac);
|
||||
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_sg_stat
|
||||
*/
|
||||
int epicsShareAPI ca_sg_stat (const CA_SYNC_GID gid)
|
||||
{
|
||||
CASG *pcasg;
|
||||
CASGOP *pcasgop;
|
||||
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);
|
||||
printf("Bad Sync Group Id\n");
|
||||
return 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);
|
||||
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_sg_test
|
||||
*/
|
||||
int epicsShareAPI ca_sg_test (const CA_SYNC_GID gid)
|
||||
{
|
||||
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;
|
||||
}
|
||||
UNLOCK (pcac);
|
||||
|
||||
if(pcasg->opPendCount){
|
||||
return ECA_IOINPROGRESS;
|
||||
}
|
||||
else{
|
||||
return ECA_IODONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* io_complete()
|
||||
*/
|
||||
LOCAL void 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_sg_array_put()
|
||||
*/
|
||||
int epicsShareAPI ca_sg_array_put (
|
||||
const CA_SYNC_GID gid,
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chix,
|
||||
const void *pvalue)
|
||||
{
|
||||
int status;
|
||||
CASGOP *pcasgop;
|
||||
CASG *pcasg;
|
||||
cac *pcac;
|
||||
int caStatus;
|
||||
|
||||
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);
|
||||
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, 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* ca_sg_array_get()
|
||||
*/
|
||||
int epicsShareAPI ca_sg_array_get (
|
||||
const CA_SYNC_GID gid,
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chix,
|
||||
void *pvalue)
|
||||
{
|
||||
int status;
|
||||
CASGOP *pcasgop;
|
||||
CASG *pcasg;
|
||||
cac *pcac;
|
||||
int caStatus;
|
||||
|
||||
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);
|
||||
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,
|
||||
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;
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* T E S T _ E V E N T . C
|
||||
* Author: Jeffrey O. Hill
|
||||
* simple stub for testing monitors
|
||||
*
|
||||
*
|
||||
* History
|
||||
* joh 031891 printed type in decimal instead of hex
|
||||
* joh 072792 better messages
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
static char *sccsId = "$Id$";
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
|
||||
void epicsShareAPI ca_test_event(struct event_handler_args args)
|
||||
{
|
||||
ca_printf("CAC: ~~~### in test event for [%s] ###~~~\n",args.chid+1);
|
||||
ca_printf("CAC: User argument\t%x\n", args.usr);
|
||||
ca_printf("CAC: Native channel data type\t%d\n", ca_field_type(args.chid));
|
||||
ca_printf("CAC: Monitor data type\t%d\n", args.type);
|
||||
ca_printf("CAC: CA Status \"%s\"\n", ca_message(args.status));
|
||||
|
||||
if(!args.dbr || !(CA_M_SUCCESS&args.status)){
|
||||
return;
|
||||
}
|
||||
|
||||
switch(args.type){
|
||||
case DBR_STRING:
|
||||
ca_printf("CAC: Value:\t<%s>\n",args.dbr);
|
||||
break;
|
||||
case DBR_CHAR:
|
||||
ca_printf("CAC: Value:\t<%d>\n",*(char *)args.dbr);
|
||||
break;
|
||||
#if DBR_INT != DBR_SHORT
|
||||
case DBR_INT:
|
||||
#endif
|
||||
case DBR_SHORT:
|
||||
case DBR_ENUM:
|
||||
ca_printf("CAC: Value:\t<%d>\n",*(short *)args.dbr);
|
||||
break;
|
||||
case DBR_LONG:
|
||||
ca_printf("CAC: Value:\t<%d>\n",*(long *)args.dbr);
|
||||
break;
|
||||
case DBR_FLOAT:
|
||||
ca_printf("CAC: Value:\t<%f>\n",*(float *)args.dbr);
|
||||
break;
|
||||
case DBR_DOUBLE:
|
||||
ca_printf("CAC: Value:\t<%lf>\n",*(double *)args.dbr);
|
||||
break;
|
||||
case DBR_STS_STRING:
|
||||
ca_printf("CAC: Value:\t<%s>\n",((struct dbr_sts_string *)args.dbr)->value);
|
||||
break;
|
||||
case DBR_STS_INT:
|
||||
ca_printf("CAC: Value:\t<%d>\n",((struct dbr_sts_int *)args.dbr)->value);
|
||||
break;
|
||||
case DBR_STS_FLOAT:
|
||||
ca_printf("CAC: Value:\t<%f>\n",((struct dbr_sts_float *)args.dbr)->value);
|
||||
break;
|
||||
case DBR_STS_ENUM:
|
||||
ca_printf("CAC: Value:\t<%d>\n",((struct dbr_sts_enum *)args.dbr)->value);
|
||||
break;
|
||||
case DBR_GR_FLOAT:
|
||||
ca_printf("CAC: Value:\t<%f>\n",((struct dbr_gr_float *)args.dbr)->value);
|
||||
break;
|
||||
default:
|
||||
ca_printf( "CAC: Sorry test_event does not handle data type %d yet\n",
|
||||
args.type);
|
||||
}
|
||||
}
|
||||
|
||||
75
src/ca/test_event.cpp
Normal file
75
src/ca/test_event.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
*
|
||||
* T E S T _ E V E N T . C
|
||||
* Author: Jeffrey O. Hill
|
||||
* simple stub for testing monitors
|
||||
*
|
||||
*
|
||||
* History
|
||||
* joh 031891 printed type in decimal instead of hex
|
||||
* joh 072792 better messages
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
|
||||
void epicsShareAPI ca_test_event(struct event_handler_args args)
|
||||
{
|
||||
printf ("CAC: ~~~### in test event for [%s] ###~~~\n", ca_name(args.chid));
|
||||
printf ("CAC: User argument\t%p\n", args.usr);
|
||||
printf ("CAC: Native channel data type\t%d\n", ca_field_type(args.chid));
|
||||
printf ("CAC: Monitor data type\t%ld\n", args.type);
|
||||
printf ("CAC: CA Status \"%s\"\n", ca_message(args.status));
|
||||
|
||||
if(!args.dbr || !(CA_M_SUCCESS&args.status)){
|
||||
return;
|
||||
}
|
||||
|
||||
switch(args.type){
|
||||
case DBR_STRING:
|
||||
printf ("CAC: Value:\t<%s>\n", (const char *)args.dbr);
|
||||
break;
|
||||
case DBR_CHAR:
|
||||
printf ("CAC: Value:\t<%d>\n",*(char *)args.dbr);
|
||||
break;
|
||||
#if DBR_INT != DBR_SHORT
|
||||
case DBR_INT:
|
||||
#endif
|
||||
case DBR_SHORT:
|
||||
case DBR_ENUM:
|
||||
printf ("CAC: Value:\t<%d>\n",*(short *)args.dbr);
|
||||
break;
|
||||
case DBR_LONG:
|
||||
printf ("CAC: Value:\t<%ld>\n",*(long *)args.dbr);
|
||||
break;
|
||||
case DBR_FLOAT:
|
||||
printf ("CAC: Value:\t<%f>\n",*(float *)args.dbr);
|
||||
break;
|
||||
case DBR_DOUBLE:
|
||||
printf ("CAC: Value:\t<%f>\n",*(double *)args.dbr);
|
||||
break;
|
||||
case DBR_STS_STRING:
|
||||
printf ("CAC: Value:\t<%s>\n",((struct dbr_sts_string *)args.dbr)->value);
|
||||
break;
|
||||
case DBR_STS_INT:
|
||||
printf ("CAC: Value:\t<%d>\n",((struct dbr_sts_int *)args.dbr)->value);
|
||||
break;
|
||||
case DBR_STS_FLOAT:
|
||||
printf ("CAC: Value:\t<%f>\n",((struct dbr_sts_float *)args.dbr)->value);
|
||||
break;
|
||||
case DBR_STS_ENUM:
|
||||
printf ("CAC: Value:\t<%d>\n",((struct dbr_sts_enum *)args.dbr)->value);
|
||||
break;
|
||||
case DBR_GR_FLOAT:
|
||||
printf ("CAC: Value:\t<%f>\n",((struct dbr_gr_float *)args.dbr)->value);
|
||||
break;
|
||||
default:
|
||||
printf ( "CAC: Sorry test_event does not handle data type %ld yet\n",
|
||||
args.type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,6 +191,7 @@ struct dbr_alDouble {DBRalDouble};
|
||||
#define S_db_bkptLogic (M_dbAccess|61) /*Logic error in breakpoint routine*/
|
||||
#define S_db_cntSpwn (M_dbAccess|63) /*Cannot spawn dbContTask*/
|
||||
#define S_db_cntCont (M_dbAccess|65) /*Cannot resume dbContTask*/
|
||||
#define S_db_noMemory (M_dbAccess|66) /*unable to allocate data structure from pool*/
|
||||
|
||||
/* Global Database Access Routines*/
|
||||
#define dbGetLink(PLNK,DBRTYPE,PBUFFER,OPTIONS,NREQUEST) \
|
||||
|
||||
Reference in New Issue
Block a user