Compare commits

..

18 Commits

Author SHA1 Message Date
Andrew Johnson
524ceee2c8 Reset DEVELOPMENT_FLAG for ca-4.13.1 release 2017-12-14 16:10:24 -06:00
Andrew Johnson
37e6c875ba Update version number in CAref.
Also removed Amaya and validator stuff.
2017-12-14 16:09:57 -06:00
Andrew Johnson
796279cc0d Move CA version numbers into cfg/CONFIG_CA_VERSION 2017-12-06 22:26:31 -06:00
Andrew Johnson
ee10014a62 Install caModuleDirs.pm into bin/<host>
Adjust capr.pl to use it from there.
Host arch's may use different absolute paths to the same Base directory,
so they can't share a single copy of that module.
2017-12-06 22:22:26 -06:00
Andrew Johnson
7a6fff0334 Include <top>/../RELEASE.<host>.local 2017-12-06 20:32:07 -06:00
Andrew Johnson
5dfd1fc0f0 Export tool configurations as cfg/CONFIG_* files 2017-11-14 21:47:40 -06:00
Andrew Johnson
c3a6cfcf0d RELEASE file must define EPICS_BASE when building modules 2017-11-11 23:54:36 -06:00
Andrew Johnson
9ac5f7fbc1 Remove spurious files from configure 2017-11-10 15:27:59 -06:00
Andrew Johnson
2ebd193681 Merge changes from 3.16 branch and below into ca/master 2017-11-01 16:14:53 -05:00
Ralph Lange
b6c78adaaa Merge 3.16 into ca/master 2017-10-20 17:01:44 +02:00
Andrew Johnson
ed7798ba08 Use 'make test-results' target 2017-09-22 14:39:18 -05:00
Andrew Johnson
abb8136817 Update comments in RELEASE file 2017-09-22 14:36:24 -05:00
Andrew Johnson
33f503722e Add caModuleDirs.pm, needed for capr.pl 2017-09-22 14:15:27 -05:00
Ralph Lange
79739f3eec travis-ci: fix RTEMS/qemu builds 2017-09-22 10:04:27 +02:00
Ralph Lange
7458569f10 ci: add single module build for Travis CI 2017-09-21 13:05:40 +02:00
Ralph Lange
701309fc4a Freeze SONAME=4.13.1 2017-09-20 16:43:23 +02:00
Ralph Lange
765b53e3fd client: add module version numbering 2017-09-19 17:02:48 +02:00
Ralph Lange
c55fb421ce Structural changes to create ca module 2017-09-19 17:02:36 +02:00
714 changed files with 39856 additions and 111359 deletions

View File

@@ -41,8 +41,17 @@ EOF
install -d "$HOME/.source"
cd "$HOME/.source"
add_base_module() {
MODULE=$1
BRANCH=$2
( cd epics-base/modules && \
git clone --quiet --depth 5 --branch "$MODULE"/"$BRANCH" https://github.com/${REPOBASE:-epics-base}/epics-base.git "$MODULE" && \
cd "$MODULE" && git log -n1 )
}
git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
(cd epics-base && git log -n1 )
( cd epics-base && git log -n1 )
add_base_module libcom "${BRLIBCOM:-master}"
EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`

View File

@@ -16,10 +16,10 @@ install:
script:
- ./.ci/travis-build.sh
env:
- BRCORE=master
- CMPLR=clang
- USR_CXXFLAGS=-std=c++11
- CMPLR=clang USR_CXXFLAGS=-std=c++11
- BRCORE=master BRLIBCOM=master TEST=NO
- CMPLR=clang TEST=NO
- USR_CXXFLAGS=-std=c++11 TEST=NO
- CMPLR=clang USR_CXXFLAGS=-std=c++11 TEST=NO
- WINE=32 TEST=NO STATIC=YES
- WINE=32 TEST=NO STATIC=NO
- RTEMS=4.10 TEST=NO

View File

@@ -11,15 +11,8 @@ TOP = .
include $(TOP)/configure/CONFIG
DIRS += configure src
src_DEPEND_DIRS = configure
DIRS += RTEMS
RTEMS_DEPEND_DIRS = src
DIRS += vxWorks
vxWorks_DEPEND_DIRS = src
DIRS += test
test_DEPEND_DIRS = RTEMS vxWorks
include $(TOP)/configure/RULES_TOP

View File

@@ -1,29 +0,0 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
TOP = ..
include $(TOP)/configure/CONFIG
include $(TOP)/configure/CONFIG_LIBCOM_VERSION
INC += epicsRtemsInitHooks.h
rtemsCom_SRCS += rtems_init.c
rtemsCom_SRCS += rtems_config.c
rtemsCom_SRCS += rtems_netconfig.c
rtemsCom_SRCS += rtems_util.c
rtemsCom_SRCS += setBootConfigFromNVRAM.c
rtemsCom_SRCS += epicsRtemsInitHookPre.c
rtemsCom_SRCS += epicsRtemsInitHookPost.c
LIBRARY_RTEMS = rtemsCom
# shared library ABI version.
SHRLIB_VERSION = $(EPICS_LIBCOM_MAJOR_VERSION).$(EPICS_LIBCOM_MINOR_VERSION).$(EPICS_LIBCOM_MAINTENANCE_VERSION)
include $(TOP)/configure/RULES

View File

@@ -1,18 +0,0 @@
/*************************************************************************\
* Copyright (c) 2006 The University of Chicago, as Operator of Argonne
* National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Dummy version -- use if application does not provide its own version
*/
#include "epicsRtemsInitHooks.h"
int
epicsRtemsInitPostSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config)
{
return 0;
}

View File

@@ -1,18 +0,0 @@
/*************************************************************************\
* Copyright (c) 2006 The University of Chicago, as Operator of Argonne
* National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Dummy version -- use if application does not provide its own version
*/
#include "epicsRtemsInitHooks.h"
int
epicsRtemsInitPreSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config)
{
return 0;
}

View File

@@ -1,23 +0,0 @@
/*************************************************************************\
* Copyright (c) 2006 The University of Chicago, as Operator of Argonne
* National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Hooks into RTEMS startup code
*/
#include <bsp.h>
#include <rtems/rtems_bsdnet.h>
extern char *env_nfsServer;
extern char *env_nfsPath;
extern char *env_nfsMountPoint;
/*
* Return 0 for success, non-zero for failure (will cause panic)
*/
int epicsRtemsInitPreSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config);
int epicsRtemsInitPostSetBootConfigFromNVRAM(struct rtems_bsdnet_config *config);

View File

@@ -1,71 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* RTEMS configuration for EPICS
* Author: W. Eric Norum
* norume@aps.anl.gov
* (630) 252-4793
*/
#include <rtems.h>
/*
***********************************************************************
* RTEMS CONFIGURATION *
***********************************************************************
*/
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#if __RTEMS_MAJOR__>4 || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || (__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
# define CONFIGURE_UNIFIED_WORK_AREAS
#else
# define CONFIGURE_EXECUTIVE_RAM_SIZE (2000*1024)
#endif
#define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(30)
#define CONFIGURE_MAXIMUM_SEMAPHORES rtems_resource_unlimited(500)
#define CONFIGURE_MAXIMUM_TIMERS rtems_resource_unlimited(20)
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES rtems_resource_unlimited(5)
#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 150
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
#define CONFIGURE_MAXIMUM_DRIVERS 8
#define CONFIGURE_MICROSECONDS_PER_TICK 20000
#define CONFIGURE_INIT_TASK_PRIORITY 80
#define CONFIGURE_MALLOC_STATISTICS 1
#define CONFIGURE_INIT
#define CONFIGURE_INIT_TASK_INITIAL_MODES (RTEMS_PREEMPT | \
RTEMS_NO_TIMESLICE | \
RTEMS_NO_ASR | \
RTEMS_INTERRUPT_LEVEL(0))
#define CONFIGURE_INIT_TASK_ATTRIBUTES (RTEMS_FLOATING_POINT | RTEMS_LOCAL)
#define CONFIGURE_INIT_TASK_STACK_SIZE (16*1024)
rtems_task Init (rtems_task_argument argument);
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_FILESYSTEM_NFS
#define CONFIGURE_FILESYSTEM_IMFS
/*
* This should be made BSP dependent, not CPU dependent but I know of no
* appropriate conditionals to use.
* The new general time support makes including the RTC driverr less important.
*/
#if !defined(mpc604) && !defined(__mc68040__) && !defined(__mcf5200__) && !defined(mpc7455) && !defined(__arm__) && !defined(__nios2__)/* don't have RTC code */
#define CONFIGURE_APPLICATION_NEEDS_RTC_DRIVER
#endif
#include <bsp.h>
#include <rtems/confdefs.h>

View File

@@ -1,668 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* RTEMS startup task for EPICS
* Author: W. Eric Norum
* eric.norum@usask.ca
* (306) 966-5394
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <rtems.h>
#include <rtems/malloc.h>
#include <rtems/error.h>
#include <rtems/stackchk.h>
#include <rtems/rtems_bsdnet.h>
#include <rtems/imfs.h>
#include <librtemsNfs.h>
#include <bsp.h>
#include "epicsThread.h"
#include "epicsTime.h"
#include "epicsExit.h"
#include "envDefs.h"
#include "errlog.h"
#include "logClient.h"
#include "osiUnistd.h"
#include "iocsh.h"
#include "osdTime.h"
#include "epicsRtemsInitHooks.h"
/*
* Prototypes for some functions not in header files
*/
void tzset(void);
int fileno(FILE *);
int main(int argc, char **argv);
static void
logReset (void)
{
void rtems_bsp_reset_cause(char *buf, size_t capacity) __attribute__((weak));
void (*fp)(char *buf, size_t capacity) = rtems_bsp_reset_cause;
if (fp) {
char buf[80];
fp(buf, sizeof buf);
errlogPrintf ("Startup after %s.\n", buf);
}
else {
errlogPrintf ("Startup.\n");
}
}
/*
***********************************************************************
* FATAL ERROR REPORTING *
***********************************************************************
*/
/*
* Delay for a while, then terminate
*/
static void
delayedPanic (const char *msg)
{
extern rtems_interval rtemsTicksPerSecond;
rtems_task_wake_after (rtemsTicksPerSecond);
rtems_panic (msg);
}
/*
* Log error and terminate
*/
void
LogFatal (const char *msg, ...)
{
va_list ap;
va_start (ap, msg);
errlogVprintf (msg, ap);
va_end (ap);
delayedPanic (msg);
}
/*
* Log RTEMS error and terminate
*/
void
LogRtemsFatal (const char *msg, rtems_status_code sc)
{
errlogPrintf ("%s: %s\n", msg, rtems_status_text (sc));
delayedPanic (msg);
}
/*
* Log network error and terminate
*/
void
LogNetFatal (const char *msg, int err)
{
errlogPrintf ("%s: %d\n", msg, err);
delayedPanic (msg);
}
void *
mustMalloc(int size, const char *msg)
{
void *p;
if ((p = malloc (size)) == NULL)
LogFatal ("Can't allocate space for %s.\n", msg);
return p;
}
/*
***********************************************************************
* REMOTE FILE ACCESS *
***********************************************************************
*/
#ifdef OMIT_NFS_SUPPORT
# include <rtems/tftp.h>
#endif
static int
initialize_local_filesystem(char **argv)
{
extern char _DownloadLocation[] __attribute__((weak));
extern char _FlashBase[] __attribute__((weak));
extern char _FlashSize[] __attribute__((weak));
argv[0] = rtems_bsdnet_bootp_boot_file_name;
if (_FlashSize && (_DownloadLocation || _FlashBase)) {
extern char _edata[];
size_t flashIndex = _edata - _DownloadLocation;
char *header = _FlashBase + flashIndex;
if (memcmp(header + 257, "ustar ", 8) == 0) {
int fd;
printf ("***** Unpack in-memory file system (IMFS) *****\n");
if (rtems_tarfs_load("/", (unsigned char *)header, (size_t)_FlashSize - flashIndex) != 0) {
printf("Can't unpack tar filesystem\n");
return 0;
}
if ((fd = open(rtems_bsdnet_bootp_cmdline, 0)) >= 0) {
close(fd);
printf ("***** Found startup script (%s) in IMFS *****\n", rtems_bsdnet_bootp_cmdline);
argv[1] = rtems_bsdnet_bootp_cmdline;
return 1;
}
printf ("***** Startup script (%s) not in IMFS *****\n", rtems_bsdnet_bootp_cmdline);
}
}
return 0;
}
#ifndef OMIT_NFS_SUPPORT
#if __RTEMS_MAJOR__>4 || \
(__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || \
(__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
int
nfsMount(char *uidhost, char *path, char *mntpoint)
{
int devl = strlen(uidhost) + strlen(path) + 2;
char *dev;
int rval = -1;
if ((dev = malloc(devl)) == NULL) {
fprintf(stderr,"nfsMount: out of memory\n");
return -1;
}
sprintf(dev, "%s:%s", uidhost, path);
printf("Mount %s on %s\n", dev, mntpoint);
if (rtems_mkdir(mntpoint, S_IRWXU | S_IRWXG | S_IRWXO))
printf("Warning -- unable to make directory \"%s\"\n", mntpoint);
if (mount(dev, mntpoint, RTEMS_FILESYSTEM_TYPE_NFS,
RTEMS_FILESYSTEM_READ_WRITE, NULL)) {
perror("mount failed");
}
else {
rval = 0;
}
free(dev);
return rval;
}
#define NFS_INIT
#else
#define NFS_INIT rpcUdpInit(); nfsInit(0,0);
#endif
#endif
static void
initialize_remote_filesystem(char **argv, int hasLocalFilesystem)
{
#ifdef OMIT_NFS_SUPPORT
printf ("***** Initializing TFTP *****\n");
#if __RTEMS_MAJOR__>4 || \
(__RTEMS_MAJOR__==4 && __RTEMS_MINOR__>9) || \
(__RTEMS_MAJOR__==4 && __RTEMS_MINOR__==9 && __RTEMS_REVISION__==99)
mount_and_make_target_path(NULL,
"/TFTP",
RTEMS_FILESYSTEM_TYPE_TFTPFS,
RTEMS_FILESYSTEM_READ_WRITE,
NULL);
#else
rtems_bsdnet_initialize_tftp_filesystem ();
#endif
if (!hasLocalFilesystem) {
char *path;
int pathsize = 200;
int l;
path = mustMalloc(pathsize, "Command path name ");
strcpy (path, "/TFTP/BOOTP_HOST/epics/");
l = strlen (path);
if (gethostname (&path[l], pathsize - l - 10) || (path[l] == '\0'))
{
LogFatal ("Can't get host name");
}
strcat (path, "/st.cmd");
argv[1] = path;
}
#else
char *server_name;
char *server_path;
char *mount_point;
char *cp;
int l = 0;
printf ("***** Initializing NFS *****\n");
NFS_INIT
if (env_nfsServer && env_nfsPath && env_nfsMountPoint) {
server_name = env_nfsServer;
server_path = env_nfsPath;
mount_point = env_nfsMountPoint;
cp = mount_point;
while ((cp = strchr(cp+1, '/')) != NULL) {
*cp = '\0';
if ((mkdir (mount_point, 0755) != 0)
&& (errno != EEXIST))
LogFatal("Can't create directory \"%s\": %s.\n",
mount_point, strerror(errno));
*cp = '/';
}
argv[1] = rtems_bsdnet_bootp_cmdline;
}
else if (hasLocalFilesystem) {
return;
}
else {
/*
* Use first component of nvram/bootp command line pathname
* to set up initial NFS mount. A "/tftpboot/" is prepended
* if the pathname does not begin with a '/'. This allows
* NFS and TFTP to have a similar view of the remote system.
*/
if (rtems_bsdnet_bootp_cmdline[0] == '/')
cp = rtems_bsdnet_bootp_cmdline + 1;
else
cp = rtems_bsdnet_bootp_cmdline;
cp = strchr(cp, '/');
if ((cp == NULL)
|| ((l = cp - rtems_bsdnet_bootp_cmdline) == 0))
LogFatal("\"%s\" is not a valid command pathname.\n", rtems_bsdnet_bootp_cmdline);
cp = mustMalloc(l + 20, "NFS mount paths");
server_path = cp;
server_name = rtems_bsdnet_bootp_server_name;
if (rtems_bsdnet_bootp_cmdline[0] == '/') {
mount_point = server_path;
strncpy(mount_point, rtems_bsdnet_bootp_cmdline, l);
mount_point[l] = '\0';
argv[1] = rtems_bsdnet_bootp_cmdline;
/*
* Its probably common to embed the mount point in the server
* name so, when this is occurring, dont clobber the mount point
* by appending the first node from the command path. This allows
* the mount point to be a different path then the server's mount
* path.
*
* This allows for example a line similar to as follows the DHCP
* configuration file.
*
* server-name "159.233@192.168.0.123:/vol/vol0/bootRTEMS";
*/
if ( server_name ) {
const size_t allocSize = strlen ( server_name ) + 2;
char * const pServerName = mustMalloc( allocSize,
"NFS mount paths");
char * const pServerPath = mustMalloc ( allocSize,
"NFS mount paths");
const int scanfStatus = sscanf (
server_name,
"%[^:] : / %s",
pServerName,
pServerPath + 1u );
if ( scanfStatus == 2 ) {
pServerPath[0u]= '/';
server_name = pServerName;
server_path = pServerPath;
}
else {
free ( pServerName );
free ( pServerPath );
}
}
}
else {
char *abspath = mustMalloc(strlen(rtems_bsdnet_bootp_cmdline)+2,"Absolute command path");
strcpy(server_path, "/tftpboot/");
mount_point = server_path + strlen(server_path);
strncpy(mount_point, rtems_bsdnet_bootp_cmdline, l);
mount_point[l] = '\0';
mount_point--;
strcpy(abspath, "/");
strcat(abspath, rtems_bsdnet_bootp_cmdline);
argv[1] = abspath;
}
}
errlogPrintf("nfsMount(\"%s\", \"%s\", \"%s\")\n",
server_name, server_path, mount_point);
nfsMount(server_name, server_path, mount_point);
#endif
}
static
char rtems_etc_hosts[] = "127.0.0.1 localhost\n";
/* If it doesn't already exist, create /etc/hosts with an entry for 'localhost' */
static
void fixup_hosts(void)
{
FILE *fp;
int ret;
struct stat STAT;
ret=stat("/etc/hosts", &STAT);
if(ret==0)
{
return; /* already exists, assume file */
} else if(errno!=ENOENT) {
perror("error: fixup_hosts stat /etc/hosts");
return;
}
ret = mkdir("/etc", 0775);
if(ret!=0 && errno!=EEXIST)
{
perror("error: fixup_hosts create /etc");
return;
}
if((fp=fopen("/etc/hosts", "w"))==NULL)
{
perror("error: fixup_hosts create /etc/hosts");
}
if(fwrite(rtems_etc_hosts, 1, sizeof(rtems_etc_hosts)-1, fp)!=sizeof(rtems_etc_hosts)-1)
{
perror("error: failed to write /etc/hosts");
}
fclose(fp);
}
/*
* Get to the startup script directory
* The TFTP filesystem requires a trailing '/' on chdir arguments.
*/
static void
set_directory (const char *commandline)
{
const char *cp;
char *directoryPath;
int l;
cp = strrchr(commandline, '/');
if (cp == NULL) {
l = 0;
cp = "/";
}
else {
l = cp - commandline;
cp = commandline;
}
directoryPath = mustMalloc(l + 2, "Command path directory ");
strncpy(directoryPath, cp, l);
directoryPath[l] = '/';
directoryPath[l+1] = '\0';
if (chdir (directoryPath) < 0)
LogFatal ("Can't set initial directory(%s): %s\n", directoryPath, strerror(errno));
else
errlogPrintf("chdir(\"%s\")\n", directoryPath);
free(directoryPath);
}
/*
***********************************************************************
* RTEMS/EPICS COMMANDS *
***********************************************************************
*/
/*
* RTEMS status
*/
static void
rtems_netstat (unsigned int level)
{
rtems_bsdnet_show_if_stats ();
rtems_bsdnet_show_mbuf_stats ();
if (level >= 1) {
rtems_bsdnet_show_inet_routes ();
}
if (level >= 2) {
rtems_bsdnet_show_ip_stats ();
rtems_bsdnet_show_icmp_stats ();
rtems_bsdnet_show_udp_stats ();
rtems_bsdnet_show_tcp_stats ();
}
}
static const iocshArg netStatArg0 = { "level",iocshArgInt};
static const iocshArg * const netStatArgs[1] = {&netStatArg0};
static const iocshFuncDef netStatFuncDef = {"netstat",1,netStatArgs};
static void netStatCallFunc(const iocshArgBuf *args)
{
rtems_netstat(args[0].ival);
}
static const iocshFuncDef heapSpaceFuncDef = {"heapSpace",0,NULL};
static void heapSpaceCallFunc(const iocshArgBuf *args)
{
rtems_malloc_statistics_t s;
double x;
malloc_get_statistics(&s);
x = s.space_available - (unsigned long)(s.lifetime_allocated - s.lifetime_freed);
if (x >= 1024*1024)
printf("Heap space: %.1f MB\n", x / (1024 * 1024));
else
printf("Heap space: %.1f kB\n", x / 1024);
}
#ifndef OMIT_NFS_SUPPORT
static const iocshArg nfsMountArg0 = { "[uid.gid@]host",iocshArgString};
static const iocshArg nfsMountArg1 = { "server path",iocshArgString};
static const iocshArg nfsMountArg2 = { "mount point",iocshArgString};
static const iocshArg * const nfsMountArgs[3] = {&nfsMountArg0,&nfsMountArg1,
&nfsMountArg2};
static const iocshFuncDef nfsMountFuncDef = {"nfsMount",3,nfsMountArgs};
static void nfsMountCallFunc(const iocshArgBuf *args)
{
char *cp = args[2].sval;
while ((cp = strchr(cp+1, '/')) != NULL) {
*cp = '\0';
if ((mkdir (args[2].sval, 0755) != 0) && (errno != EEXIST)) {
printf("Can't create directory \"%s\": %s.\n",
args[2].sval, strerror(errno));
return;
}
*cp = '/';
}
nfsMount(args[0].sval, args[1].sval, args[2].sval);
}
#endif
/*
* Register RTEMS-specific commands
*/
static void iocshRegisterRTEMS (void)
{
iocshRegister(&netStatFuncDef, netStatCallFunc);
iocshRegister(&heapSpaceFuncDef, heapSpaceCallFunc);
#ifndef OMIT_NFS_SUPPORT
iocshRegister(&nfsMountFuncDef, nfsMountCallFunc);
#endif
}
/*
* Set up the console serial line (no handshaking)
*/
static void
initConsole (void)
{
struct termios t;
if (tcgetattr (fileno (stdin), &t) < 0) {
printf ("tcgetattr failed: %s\n", strerror (errno));
return;
}
t.c_iflag &= ~(IXOFF | IXON | IXANY);
if (tcsetattr (fileno (stdin), TCSANOW, &t) < 0) {
printf ("tcsetattr failed: %s\n", strerror (errno));
return;
}
}
/*
* Ensure that the configuration object files
* get pulled in from the library
*/
extern rtems_configuration_table Configuration;
extern struct rtems_bsdnet_config rtems_bsdnet_config;
const void *rtemsConfigArray[] = {
&Configuration,
&rtems_bsdnet_config
};
/*
* Hook to ensure that BSP cleanup code gets run on exit
*/
static void
exitHandler(void)
{
rtems_shutdown_executive(0);
}
/*
* RTEMS Startup task
*/
rtems_task
Init (rtems_task_argument ignored)
{
int result;
char *argv[3] = { NULL, NULL, NULL };
char *cp;
rtems_task_priority newpri;
rtems_status_code sc;
rtems_time_of_day now;
/*
* Explain why we're here
*/
logReset();
/*
* Architecture-specific hooks
*/
if (epicsRtemsInitPreSetBootConfigFromNVRAM(&rtems_bsdnet_config) != 0)
delayedPanic("epicsRtemsInitPreSetBootConfigFromNVRAM");
if (rtems_bsdnet_config.bootp == NULL) {
extern void setBootConfigFromNVRAM(void);
setBootConfigFromNVRAM();
}
if (epicsRtemsInitPostSetBootConfigFromNVRAM(&rtems_bsdnet_config) != 0)
delayedPanic("epicsRtemsInitPostSetBootConfigFromNVRAM");
/*
* Override RTEMS configuration
*/
rtems_task_set_priority (
RTEMS_SELF,
epicsThreadGetOssPriorityValue(epicsThreadPriorityIocsh),
&newpri);
/*
* Create a reasonable environment
*/
initConsole ();
putenv ("TERM=xterm");
putenv ("IOCSH_HISTSIZE=20");
/*
* Display some OS information
*/
printf("\n***** RTEMS Version: %s *****\n",
rtems_get_version_string());
/*
* Start network
*/
if ((cp = getenv("EPICS_TS_NTP_INET")) != NULL)
rtems_bsdnet_config.ntp_server[0] = cp;
if (rtems_bsdnet_config.network_task_priority == 0)
{
unsigned int p;
if (epicsThreadHighestPriorityLevelBelow(epicsThreadPriorityScanLow, &p)
== epicsThreadBooleanStatusSuccess)
{
rtems_bsdnet_config.network_task_priority = epicsThreadGetOssPriorityValue(p);
}
}
printf("\n***** Initializing network *****\n");
rtems_bsdnet_initialize_network();
initialize_remote_filesystem(argv, initialize_local_filesystem(argv));
fixup_hosts();
/*
* More environment: iocsh prompt and hostname
*/
{
char hostname[1024];
gethostname(hostname, 1023);
char *cp = mustMalloc(strlen(hostname)+3, "iocsh prompt");
sprintf(cp, "%s> ", hostname);
epicsEnvSet ("IOCSH_PS1", cp);
epicsEnvSet("IOC_NAME", hostname);
}
/*
* Use BSP-supplied time of day if available otherwise supply default time.
* It is very likely that other time synchronization facilities in EPICS
* will soon override this value.
*/
if (rtems_clock_get(RTEMS_CLOCK_GET_TOD,&now) != RTEMS_SUCCESSFUL) {
now.year = 2001;
now.month = 1;
now.day = 1;
now.hour = 0;
now.minute = 0;
now.second = 0;
now.ticks = 0;
if ((sc = rtems_clock_set (&now)) != RTEMS_SUCCESSFUL)
printf ("***** Can't set time: %s\n", rtems_status_text (sc));
}
if (getenv("TZ") == NULL) {
const char *tzp = envGetConfigParamPtr(&EPICS_TIMEZONE);
if (tzp == NULL) {
printf("Warning -- no timezone information available -- times will be displayed as GMT.\n");
}
else {
char tz[10];
int minWest, toDst = 0, fromDst = 0;
if(sscanf(tzp, "%9[^:]::%d:%d:%d", tz, &minWest, &toDst, &fromDst) < 2) {
printf("Warning: EPICS_TIMEZONE (%s) unrecognizable -- times will be displayed as GMT.\n", tzp);
}
else {
char posixTzBuf[40];
char *p = posixTzBuf;
p += sprintf(p, "%cST%d:%.2d", tz[0], minWest/60, minWest%60);
if (toDst != fromDst)
p += sprintf(p, "%cDT", tz[0]);
epicsEnvSet("TZ", posixTzBuf);
}
}
}
tzset();
osdTimeRegister();
/*
* Run the EPICS startup script
*/
printf ("***** Preparing EPICS application *****\n");
iocshRegisterRTEMS ();
set_directory (argv[1]);
epicsEnvSet ("IOC_STARTUP_SCRIPT", argv[1]);
atexit(exitHandler);
errlogFlush();
printf ("***** Starting EPICS application *****\n");
result = main ((sizeof argv / sizeof argv[0]) - 1, argv);
printf ("***** IOC application terminating *****\n");
epicsThreadSleep(1.0);
epicsExit(result);
}

View File

@@ -1,120 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* RTEMS network configuration for EPICS
* Author: W. Eric Norum
* eric.norum@usask.ca
* (306) 966-5394
*
* This file can be copied to an application source dirctory
* and modified to override the values shown below.
*/
#include <stdio.h>
#include <bsp.h>
#include <rtems/rtems_bsdnet.h>
extern void rtems_bsdnet_loopattach();
static struct rtems_bsdnet_ifconfig loopback_config = {
"lo0", /* name */
(int (*)(struct rtems_bsdnet_ifconfig *, int))rtems_bsdnet_loopattach, /* attach function */
NULL, /* link to next interface */
"127.0.0.1", /* IP address */
"255.0.0.0", /* IP net mask */
};
/*
* The following conditionals select the network interface card.
*
* On RTEMS-pc386 targets all network drivers which support run-time
* probing are linked.
* On other targets the network interface specified by the board-support
* package is used.
* To use a different NIC for a particular application, copy this file to the
* application directory and make the appropriate changes.
*/
#if defined(__i386__)
extern int rtems_fxp_attach (struct rtems_bsdnet_ifconfig *, int);
static struct rtems_bsdnet_ifconfig fxp_driver_config = {
"fxp1", /* name */
rtems_fxp_attach, /* attach function */
&loopback_config, /* link to next interface */
};
extern int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *, int);
static struct rtems_bsdnet_ifconfig e3c509_driver_config = {
"ep0", /* name */
rtems_3c509_driver_attach, /* attach function */
&fxp_driver_config, /* link to next interface */
};
#define FIRST_DRIVER_CONFIG &e3c509_driver_config
#else
# if defined(__PPC)
/*
* FIXME: This really belongs in the BSP
*/
# ifndef RTEMS_BSP_NETWORK_DRIVER_NAME
# define RTEMS_BSP_NETWORK_DRIVER_NAME "dc1"
# endif
# ifndef RTEMS_BSP_NETWORK_DRIVER_ATTACH
# define RTEMS_BSP_NETWORK_DRIVER_ATTACH rtems_dec21140_driver_attach
extern int rtems_dec21140_driver_attach();
# endif
# endif
static struct rtems_bsdnet_ifconfig bsp_driver_config = {
RTEMS_BSP_NETWORK_DRIVER_NAME, /* name */
RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* attach function */
&loopback_config, /* link to next interface */
};
#define FIRST_DRIVER_CONFIG &bsp_driver_config
#endif
/*
* Allow configure/os/CONFIG_SITE.Common.RTEMS to provide domain name
*/
#ifdef RTEMS_NETWORK_CONFIG_DNS_DOMAINNAME
# define XSTR(x) STR(x)
# define STR(x) #x
# define MY_DOMAINNAME XSTR(RTEMS_NETWORK_CONFIG_DNS_DOMAINNAME)
#else
# define MY_DOMAINNAME NULL
#endif
/*
* Allow non-BOOTP network configuration
*/
#ifndef MY_DO_BOOTP
# define MY_DO_BOOTP rtems_bsdnet_do_bootp
#endif
/*
* Allow site- and BSP-specific network buffer space configuration.
* The macro values are specified in KBytes.
*/
#ifndef RTEMS_NETWORK_CONFIG_MBUF_SPACE
# define RTEMS_NETWORK_CONFIG_MBUF_SPACE 180
#endif
#ifndef RTEMS_NETWORK_CONFIG_CLUSTER_SPACE
# define RTEMS_NETWORK_CONFIG_CLUSTER_SPACE 350
#endif
/*
* Network configuration
*/
struct rtems_bsdnet_config rtems_bsdnet_config = {
FIRST_DRIVER_CONFIG, /* Link to next interface */
MY_DO_BOOTP, /* How to find network config */
10, /* If 0 then the network daemons will run at a */
/* priority just less than the lowest-priority */
/* EPICS scan thread. */
/* If non-zero then the network daemons will run */
/* at this *RTEMS* priority */
RTEMS_NETWORK_CONFIG_MBUF_SPACE*1024,
RTEMS_NETWORK_CONFIG_CLUSTER_SPACE*1024,
NULL, /* Host name */
MY_DOMAINNAME, /* Domain name */
};

View File

@@ -1,44 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* RTEMS utilitiy routines for EPICS
* Author: W. Eric Norum
* eric@cls.usask.ca
* (306) 966-6055
*
* Supplies routines that are present in vxWorks but missing in RTEMS.
*/
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
/*
* Like connect(), but with an explicit timeout
*/
int connectWithTimeout (int sfd,
struct sockaddr *addr,
int addrlen,
struct timeval *timeout)
{
struct timeval sv;
socklen_t svlen = sizeof sv;
int ret;
if (!timeout)
return connect (sfd, addr, addrlen);
if (getsockopt (sfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&sv, &svlen) < 0)
return -1;
if (setsockopt (sfd, SOL_SOCKET, SO_RCVTIMEO, (char *)timeout, sizeof *timeout) < 0)
return -1;
ret = connect (sfd, addr, addrlen);
setsockopt (sfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&sv, sizeof sv);
return ret;
}

View File

@@ -1,370 +0,0 @@
/*************************************************************************\
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#include <rtems/rtems_bsdnet.h>
#include <bsp.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <epicsStdlib.h>
#include <epicsStdio.h>
#include <epicsString.h>
#include <envDefs.h>
char *env_nfsServer;
char *env_nfsPath;
char *env_nfsMountPoint;
/*
* Split argument string of form nfs_server:nfs_export:<path>
* The nfs_export component will be used as:
* - the path to the directory exported from the NFS server
* - the local mount point
* - a prefix of <path>
* For example, the argument string:
* romeo:/export/users:smith/ioc/iocexample/st.cmd
* would:
* - mount /export/users from NFS server romeo on /export/users
* - chdir to /export/users/smith/ioc/iocexample
* - read commands from st.cmd
*/
static void
splitRtemsBsdnetBootpCmdline(void)
{
char *cp1, *cp2, *cp3;
if ((cp1 = rtems_bsdnet_bootp_cmdline) == NULL)
return;
if (((cp2 = strchr(cp1, ':')) != NULL)
&& (((cp3 = strchr(cp2+1, ' ')) != NULL)
|| ((cp3 = strchr(cp2+1, ':')) != NULL))) {
int l1 = cp2 - cp1;
int l2 = cp3 - cp2 - 1;
int l3 = strlen(cp3) - 1;
if (l1 && l2 && l3) {
*cp2++ = '\0';
*cp3 = '\0';
env_nfsServer = cp1;
env_nfsMountPoint = env_nfsPath = epicsStrDup(cp2);
*cp3 = '/';
rtems_bsdnet_bootp_cmdline = cp2;
}
}
}
/*
* Split NFS mount information of the form nfs_server:host_path:local_path
*/
static void
splitNfsMountPath(char *nfsString)
{
char *cp2, *cp3;
if (nfsString == NULL)
return;
if (((cp2 = strchr(nfsString, ':')) != NULL)
&& (((cp3 = strchr(cp2+1, ' ')) != NULL)
|| ((cp3 = strchr(cp2+1, ':')) != NULL))) {
int l1 = cp2 - nfsString;
int l2 = cp3 - cp2 - 1;
int l3 = strlen(cp3) - 1;
if (l1 && l2 && l3) {
*cp2++ = '\0';
*cp3++ = '\0';
env_nfsServer = nfsString;
env_nfsPath = cp2;
env_nfsMountPoint = cp3;
}
}
}
#if defined(HAVE_MOTLOAD)
/*
* Motorola MOTLOAD NVRAM Access
*/
static char *
gev(const char *parm, volatile char *nvp)
{
const char *val;
const char *name;
char *ret;
char c;
for (;;) {
if (*nvp == '\0')
return NULL;
name = parm;
while ((c = *nvp++) != '\0') {
if ((c == '=') && (*name == '\0')) {
val = (char *)nvp;
while (*nvp++ != '\0')
continue;
ret = malloc(nvp - val);
if (ret == NULL)
return NULL;
strcpy(ret, val);
return ret;
}
if (c != *name++) {
while (*nvp++ != '\0')
continue;
break;
}
}
}
}
static char *
motScriptParm(const char *mot_script_boot, char parm)
{
const char *cp;
char *ret;
int l;
while (*mot_script_boot != '\0') {
if (isspace(*(unsigned char *)mot_script_boot)
&& (*(mot_script_boot+1) == '-')
&& (*(mot_script_boot+2) == parm)) {
mot_script_boot += 3;
cp = mot_script_boot;
while ((*mot_script_boot != '\0') &&
!isspace(*(unsigned char *)mot_script_boot))
mot_script_boot++;
l = mot_script_boot - cp;
ret = malloc(l+1);
if (ret == NULL)
return NULL;
strncpy(ret, cp, l);
*(ret+l) = '\0';
return ret;
}
mot_script_boot++;
}
return NULL;
}
void
setBootConfigFromNVRAM(void)
{
char *cp;
const char *mot_script_boot;
char *nvp;
# if defined(BSP_NVRAM_BASE_ADDR)
nvp = (volatile unsigned char *)(BSP_NVRAM_BASE_ADDR+0x70f8);
# elif defined(BSP_I2C_VPD_EEPROM_DEV_NAME)
char gev_buf[3592];
int fd;
if ((fd = open(BSP_I2C_VPD_EEPROM_DEV_NAME, 0)) < 0) {
printf("Can't open %s: %s\n", BSP_I2C_VPD_EEPROM_DEV_NAME, strerror(errno));
return;
}
lseek(fd, 0x10f8, SEEK_SET);
if (read(fd, gev_buf, sizeof gev_buf) != sizeof gev_buf) {
printf("Can't read %s: %s\n", BSP_I2C_VPD_EEPROM_DEV_NAME, strerror(errno));
return;
}
close(fd);
nvp = gev_buf;
# else
# error "No way to read GEV!"
# endif
if (rtems_bsdnet_config.bootp != NULL)
return;
mot_script_boot = gev("mot-script-boot", nvp);
if ((rtems_bsdnet_bootp_server_name = gev("mot-/dev/enet0-sipa", nvp)) == NULL)
rtems_bsdnet_bootp_server_name = motScriptParm(mot_script_boot, 's');
if ((rtems_bsdnet_config.gateway = gev("mot-/dev/enet0-gipa", nvp)) == NULL)
rtems_bsdnet_config.gateway = motScriptParm(mot_script_boot, 'g');
if ((rtems_bsdnet_config.ifconfig->ip_netmask = gev("mot-/dev/enet0-snma", nvp)) == NULL)
rtems_bsdnet_config.ifconfig->ip_netmask = motScriptParm(mot_script_boot, 'm');
rtems_bsdnet_config.name_server[0] = gev("rtems-dns-server", nvp);
if (rtems_bsdnet_config.name_server[0] == NULL)
rtems_bsdnet_config.name_server[0] = rtems_bsdnet_bootp_server_name;
cp = gev("rtems-dns-domainname", nvp);
if (cp)
rtems_bsdnet_config.domainname = cp;
if ((rtems_bsdnet_config.ifconfig->ip_address = gev("mot-/dev/enet0-cipa", nvp)) == NULL)
rtems_bsdnet_config.ifconfig->ip_address = motScriptParm(mot_script_boot, 'c');
rtems_bsdnet_config.hostname = gev("rtems-client-name", nvp);
if (rtems_bsdnet_config.hostname == NULL)
rtems_bsdnet_config.hostname = rtems_bsdnet_config.ifconfig->ip_address;
if ((rtems_bsdnet_bootp_boot_file_name = gev("mot-/dev/enet0-file", nvp)) == NULL)
rtems_bsdnet_bootp_boot_file_name = motScriptParm(mot_script_boot, 'f');
rtems_bsdnet_bootp_cmdline = gev("epics-script", nvp);
splitRtemsBsdnetBootpCmdline();
splitNfsMountPath(gev("epics-nfsmount", nvp));
rtems_bsdnet_config.ntp_server[0] = gev("epics-ntpserver", nvp);
if (rtems_bsdnet_config.ntp_server[0] == NULL)
rtems_bsdnet_config.ntp_server[0] = rtems_bsdnet_bootp_server_name;
if ((cp = gev("epics-tz", nvp)) != NULL)
epicsEnvSet("TZ", cp);
}
#elif defined(HAVE_PPCBUG)
/*
* Motorola PPCBUG NVRAM Access
*/
struct ppcbug_nvram {
uint32_t PacketVersionIdentifier;
uint32_t NodeControlMemoryAddress;
uint32_t BootFileLoadAddress;
uint32_t BootFileExecutionAddress;
uint32_t BootFileExecutionDelay;
uint32_t BootFileLength;
uint32_t BootFileByteOffset;
uint32_t TraceBufferAddress;
uint32_t ClientIPAddress;
uint32_t ServerIPAddress;
uint32_t SubnetIPAddressMask;
uint32_t BroadcastIPAddressMask;
uint32_t GatewayIPAddress;
uint8_t BootpRarpRetry;
uint8_t TftpRarpRetry;
uint8_t BootpRarpControl;
uint8_t UpdateControl;
char BootFilenameString[64];
char ArgumentFilenameString[64];
};
static char *addr(char *cbuf, uint32_t addr)
{
struct in_addr a;
if ((a.s_addr = addr) == 0)
return NULL;
return (char *)inet_ntop(AF_INET, &a, cbuf, INET_ADDRSTRLEN);
}
void
setBootConfigFromNVRAM(void)
{
static struct ppcbug_nvram nvram;
static char ip_address[INET_ADDRSTRLEN];
static char ip_netmask[INET_ADDRSTRLEN];
static char server[INET_ADDRSTRLEN];
static char gateway[INET_ADDRSTRLEN];
if (rtems_bsdnet_config.bootp != NULL)
return;
/*
* Get network configuation from PPCBUG.
* The 'correct' way to do this would be to issue a .NETCFIG PPCBUG
* system call. Unfortunately it is very difficult to issue such a
* call once RTEMS is up and running so we just copy from the 'known'
* location of the network configuration parameters.
* Care must be taken to access the NVRAM a byte at a time.
*/
#if defined(NVRAM_INDIRECT)
{
volatile char *addrLo = (volatile char *)0x80000074;
volatile char *addrHi = (volatile char *)0x80000075;
volatile char *data = (volatile char *)0x80000077;
int addr = 0x1000;
char *d = (char *)&nvram;
while (d < ((char *)&nvram + sizeof nvram)) {
*addrLo = addr & 0xFF;
*addrHi = (addr >> 8) & 0xFF;
*d++ = *data;
addr++;
}
}
#else
{
volatile char *s = (volatile char *)0xFFE81000;
char *d = (char *)&nvram;
while (d < ((char *)&nvram + sizeof nvram))
*d++ = *s++;
}
#endif
/*
* Assume that the boot server is also the name, log and ntp server!
*/
rtems_bsdnet_config.name_server[0] =
rtems_bsdnet_config.ntp_server[0] =
rtems_bsdnet_bootp_server_name = addr(server, nvram.ServerIPAddress);
rtems_bsdnet_bootp_server_address.s_addr = nvram.ServerIPAddress;
/*
* Nothing better to use as host name!
*/
rtems_bsdnet_config.ifconfig->ip_address =
rtems_bsdnet_config.hostname = addr(ip_address, nvram.ClientIPAddress);
rtems_bsdnet_config.gateway = addr(gateway, nvram.GatewayIPAddress);
rtems_bsdnet_config.ifconfig->ip_netmask = addr(ip_netmask, nvram.SubnetIPAddressMask);
rtems_bsdnet_bootp_boot_file_name = nvram.BootFilenameString;
rtems_bsdnet_bootp_cmdline = nvram.ArgumentFilenameString;
splitRtemsBsdnetBootpCmdline();
}
#elif defined(__mcf528x__)
static char *
env(const char *parm, const char *defaultValue)
{
const char *cp = bsp_getbenv(parm);
if (!cp) {
if (!defaultValue)
return NULL;
cp = defaultValue;
printf ("%s environment variable missing -- using %s.\n", parm, cp);
}
return epicsStrDup(cp);
}
void
setBootConfigFromNVRAM(void)
{
const char *cp1;
if (rtems_bsdnet_config.bootp != NULL)
return;
rtems_bsdnet_config.gateway = env("GATEWAY", NULL);
rtems_bsdnet_config.ifconfig->ip_netmask = env("NETMASK", "255.255.252.0");
rtems_bsdnet_bootp_server_name = env("SERVER", "192.168.0.1");
rtems_bsdnet_config.name_server[0] = env("NAMESERVER", rtems_bsdnet_bootp_server_name);
rtems_bsdnet_config.ntp_server[0] = env("NTPSERVER", rtems_bsdnet_bootp_server_name);
cp1 = env("DOMAIN", NULL);
if (cp1 != NULL)
rtems_bsdnet_config.domainname = cp1;
rtems_bsdnet_config.hostname = env("HOSTNAME", "iocNobody");
rtems_bsdnet_config.ifconfig->ip_address = env("IPADDR0", "192.168.0.2");
rtems_bsdnet_bootp_boot_file_name = env("BOOTFILE", "uC5282App.boot");
rtems_bsdnet_bootp_cmdline = env("CMDLINE", "epics/iocBoot/iocNobody/st.cmd");
splitNfsMountPath(env("NFSMOUNT", NULL));
if ((cp1 = env("TZ", NULL)) != NULL)
epicsEnvSet("TZ", cp1);
}
#else
/*
* Placeholder for systems without NVRAM
*/
void
setBootConfigFromNVRAM(void)
{
printf("SYSTEM HAS NO NON-VOLATILE RAM!\n");
printf("YOU MUST USE SOME OTHER METHOD TO OBTAIN NETWORK CONFIGURATION\n");
}
#endif

View File

@@ -2,10 +2,6 @@
#
# Do not make changes to this file!
ifeq ($(strip $(EPICS_HOST_ARCH)),)
$(warning EPICS_HOST_ARCH is not set.)
endif
# Allow user to override where the build rules come from
RULES = $(EPICS_BASE)
@@ -17,18 +13,6 @@ ifdef T_A
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
ifeq ($(strip $(RULES)),)
ifeq ($(strip $(EPICS_BASE)),)
$(warning Build error: EPICS_BASE not set after including RELEASE files.)
else
$(warning Build error: EPICS_BASE set but RULES variable empty.)
endif
$(error Makefiles loaded: $(MAKEFILE_LIST))
# Die before the include of $(CONFIG)/CONFIG below does
endif
BUILDING_LIBCOM = DEFINED
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG

View File

@@ -1,13 +1,9 @@
#*************************************************************************
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
# Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/libCom/Makefile.
SRC_DIRS += $(LIBCOM)/dbmf
INC += dbmf.h
Com_SRCS += dbmf.c
# Libraries needed to link a host tool
EPICS_BASE_HOST_LIBS = ca Com

View File

@@ -0,0 +1,4 @@
EPICS_CA_MAJOR_VERSION = 4
EPICS_CA_MINOR_VERSION = 13
EPICS_CA_MAINTENANCE_VERSION = 1
EPICS_CA_DEVELOPMENT_FLAG = 0

View File

@@ -1,25 +0,0 @@
#*************************************************************************
# Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# Set EPICS_LIBCOM if necessary
ifndef EPICS_LIBCOM
EPICS_LIBCOM = $(if $(BUILDING_LIBCOM),$(INSTALL_LOCATION),$(EPICS_BASE))
# Paths to tools built here
EPICS_LIBCOM_HOST_BIN ?= $(EPICS_LIBCOM)/bin/$(EPICS_HOST_ARCH)
endif
# Set location of locally generated tools
YACC = $(abspath $(EPICS_LIBCOM_HOST_BIN))/antelope$(HOSTEXE)
LEX = $(abspath $(EPICS_LIBCOM_HOST_BIN))/e_flex$(HOSTEXE) \
-S$(EPICS_LIBCOM)/include/flex.skel.static
# Default stack size for osiThread
OSITHREAD_USE_DEFAULT_STACK = NO
OSITHREAD_DEFAULT_STACK_FLAGS_YES = -DOSITHREAD_USE_DEFAULT_STACK
BASE_CPPFLAGS += $(OSITHREAD_DEFAULT_STACK_FLAGS_$(OSITHREAD_USE_DEFAULT_STACK))

View File

@@ -1,4 +0,0 @@
EPICS_LIBCOM_MAJOR_VERSION = 3
EPICS_LIBCOM_MINOR_VERSION = 17
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
EPICS_LIBCOM_DEVELOPMENT_FLAG = 1

View File

@@ -9,7 +9,7 @@ include $(TOP)/configure/CONFIG
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
CFG += CONFIG_LIBCOM_MODULE
CFG += CONFIG_LIBCOM_VERSION
CFG += CONFIG_CA_MODULE
CFG += CONFIG_CA_VERSION
include $(TOP)/configure/RULES

View File

@@ -26,6 +26,7 @@
#MYMODULE = $(MODULES)/my-module
# If building the EPICS modules individually, set these:
#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0
#EPICS_BASE = $(MODULES)/core-7.0.1
# Set RULES here if you want to use build rules from elsewhere:

View File

@@ -1,84 +1,25 @@
#*************************************************************************
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
# Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in the file LICENSE that is included with this distribution.
#*************************************************************************
TOP = ..
include $(TOP)/configure/CONFIG
# Uncomment this to remove the (benign) valgrind helper stubs
#USR_CFLAGS += -DNVALGRIND
# Channel Access Client
LIBCOM = $(TOP)/src
DIRS += client
INC += valgrind/valgrind.h
DIRS += tools
tools_DEPEND_DIRS = client
INC += libComVersion.h
INC += libComVersionNum.h
DIRS += perl
perl_DEPEND_DIRS = client
include $(LIBCOM)/as/Makefile
include $(LIBCOM)/bucketLib/Makefile
include $(LIBCOM)/calc/Makefile
include $(LIBCOM)/cvtFast/Makefile
include $(LIBCOM)/cppStd/Makefile
include $(LIBCOM)/cxxTemplates/Makefile
include $(LIBCOM)/dbmf/Makefile
include $(LIBCOM)/ellLib/Makefile
include $(LIBCOM)/env/Makefile
include $(LIBCOM)/error/Makefile
include $(LIBCOM)/fdmgr/Makefile
include $(LIBCOM)/flex/Makefile
include $(LIBCOM)/freeList/Makefile
include $(LIBCOM)/gpHash/Makefile
include $(LIBCOM)/iocsh/Makefile
include $(LIBCOM)/log/Makefile
include $(LIBCOM)/macLib/Makefile
include $(LIBCOM)/misc/Makefile
include $(LIBCOM)/osi/Makefile
include $(LIBCOM)/pool/Makefile
include $(LIBCOM)/ring/Makefile
include $(LIBCOM)/taskwd/Makefile
include $(LIBCOM)/timer/Makefile
include $(LIBCOM)/yacc/Makefile
include $(LIBCOM)/yajl/Makefile
DIRS += template
# Library to build:
LIBRARY=Com
Com_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
Com_RCS = Com.rc
ifeq ($(T_A),$(EPICS_HOST_ARCH))
# Antelope & flex are needed to finish libCom
DELAY_INSTALL_LIBS = YES
endif
EXPANDVARS += EPICS_LIBCOM_MAJOR_VERSION
EXPANDVARS += EPICS_LIBCOM_MINOR_VERSION
EXPANDVARS += EPICS_LIBCOM_MAINTENANCE_VERSION
EXPANDVARS += EPICS_LIBCOM_DEVELOPMENT_FLAG
EXPANDFLAGS += $(foreach var,$(EXPANDVARS),-D$(var)="$(strip $($(var)))")
# shared library ABI version.
SHRLIB_VERSION = 3.17.0
include $(TOP)/configure/RULES
include $(LIBCOM)/as/RULES
include $(LIBCOM)/env/RULES
include $(LIBCOM)/error/RULES
include $(LIBCOM)/flex/RULES
include $(LIBCOM)/misc/RULES
include $(LIBCOM)/osi/RULES
include $(LIBCOM)/yajl/RULES
# Can't use EXPAND as generated headers must appear
# in O.Common, but EXPAND emits rules for O.$(T_A)
../O.Common/libComVersionNum.h: ../libComVersionNum.h@
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
include $(TOP)/configure/RULES_DIRS

View File

@@ -1,22 +0,0 @@
#*************************************************************************
# Copyright (c) 2010 Brookhaven Science Associates, as Operator of
# Brookhaven National Lab.
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#************************************************************************
# This is a Makefile fragment, see src/libCom/Makefile.
SRC_DIRS += $(LIBCOM)/as
INC += asLib.h
INC += asTrapWrite.h
Com_SRCS += asLib.c
Com_SRCS += asTrapWrite.c
CLEANS += asLib.c asLib_lex.c

View File

@@ -1,21 +0,0 @@
#*************************************************************************
# Copyright (c) 2010 Brookhaven Science Associates, as Operator of
# Brookhaven National Lab.
# Copyright (c) 2011 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#************************************************************************
# This is a Makefile fragment, see src/libCom/Makefile.
# Extra rule since asLib_lex.c is included by asLib.c
asLib$(DEP): asLib_lex.c
asLib.c: asLib_lex.c
# Ensure that lexer and parser are built before they are needed
asLib.c: $(INSTALL_HOST_BIN)/antelope$(HOSTEXE)
asLib_lex.c: $(INSTALL_HOST_BIN)/e_flex$(HOSTEXE)
asLib_lex.c: $(INSTALL_INCLUDE)/flex.skel.static

View File

@@ -1,244 +0,0 @@
/* asLib.h */
/*************************************************************************\
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 09-27-93*/
#ifndef INCasLibh
#define INCasLibh
#include "shareLib.h"
#include "ellLib.h"
#include "errMdef.h"
#include "errlog.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct asgMember *ASMEMBERPVT;
typedef struct asgClient *ASCLIENTPVT;
typedef int (*ASINPUTFUNCPTR)(char *buf,int max_size);
typedef enum{
asClientCOAR /*Change of access rights*/
/*For now this is all*/
} asClientStatus;
typedef void (*ASCLIENTCALLBACK) (ASCLIENTPVT,asClientStatus);
/* The following routines are macros with the following syntax
long asCheckGet(ASCLIENTPVT asClientPvt);
long asCheckPut(ASCLIENTPVT asClientPvt);
*/
#define asCheckGet(asClientPvt) \
(!asActive || ((asClientPvt)->access >= asREAD))
#define asCheckPut(asClientPvt) \
(!asActive || ((asClientPvt)->access >= asWRITE))
/* More convenience macros
void *asTrapWriteWithData(ASCLIENTPVT asClientPvt,
const char *userid, const char *hostid, void *addr,
int dbrType, int no_elements, void *data);
void asTrapWriteAfter(ASCLIENTPVT asClientPvt);
*/
#define asTrapWriteWithData(asClientPvt, user, host, addr, type, count, data) \
((asActive && (asClientPvt)->trapMask) \
? asTrapWriteBeforeWithData((user), (host), (addr), (type), (count), (data)) \
: 0)
#define asTrapWriteAfter(pvt) \
if (pvt) asTrapWriteAfterWrite(pvt)
/* This macro is for backwards compatibility, upgrade any code
calling it to use asTrapWriteWithData() instead ASAP:
void *asTrapWriteBefore(ASCLIENTPVT asClientPvt,
const char *userid, const char *hostid, void *addr);
*/
#define asTrapWriteBefore(asClientPvt, user, host, addr) \
asTrapWriteWithData(asClientPvt, user, host, addr, 0, 0, NULL)
epicsShareFunc long epicsShareAPI asInitialize(ASINPUTFUNCPTR inputfunction);
epicsShareFunc long epicsShareAPI asInitFile(
const char *filename,const char *substitutions);
epicsShareFunc long epicsShareAPI asInitFP(FILE *fp,const char *substitutions);
/*caller must provide permanent storage for asgName*/
epicsShareFunc long epicsShareAPI asAddMember(
ASMEMBERPVT *asMemberPvt,const char *asgName);
epicsShareFunc long epicsShareAPI asRemoveMember(ASMEMBERPVT *asMemberPvt);
/*caller must provide permanent storage for newAsgName*/
epicsShareFunc long epicsShareAPI asChangeGroup(
ASMEMBERPVT *asMemberPvt,const char *newAsgName);
epicsShareFunc void * epicsShareAPI asGetMemberPvt(ASMEMBERPVT asMemberPvt);
epicsShareFunc void epicsShareAPI asPutMemberPvt(
ASMEMBERPVT asMemberPvt,void *userPvt);
/*client must provide permanent storage for user and host*/
epicsShareFunc long epicsShareAPI asAddClient(
ASCLIENTPVT *asClientPvt,ASMEMBERPVT asMemberPvt,
int asl,const char *user,char *host);
/*client must provide permanent storage for user and host*/
epicsShareFunc long epicsShareAPI asChangeClient(
ASCLIENTPVT asClientPvt,int asl,const char *user,char *host);
epicsShareFunc long epicsShareAPI asRemoveClient(ASCLIENTPVT *asClientPvt);
epicsShareFunc void * epicsShareAPI asGetClientPvt(ASCLIENTPVT asClientPvt);
epicsShareFunc void epicsShareAPI asPutClientPvt(
ASCLIENTPVT asClientPvt,void *userPvt);
epicsShareFunc long epicsShareAPI asRegisterClientCallback(
ASCLIENTPVT asClientPvt, ASCLIENTCALLBACK pcallback);
epicsShareFunc long epicsShareAPI asComputeAllAsg(void);
/* following declared below after ASG is declared
epicsShareFunc long epicsShareAPI asComputeAsg(ASG *pasg);
*/
epicsShareFunc long epicsShareAPI asCompute(ASCLIENTPVT asClientPvt);
epicsShareFunc int epicsShareAPI asDump(
void (*memcallback)(ASMEMBERPVT,FILE *),
void (*clientcallback)(ASCLIENTPVT,FILE *),int verbose);
epicsShareFunc int epicsShareAPI asDumpFP(FILE *fp,
void (*memcallback)(ASMEMBERPVT,FILE *),
void (*clientcallback)(ASCLIENTPVT,FILE *),int verbose);
epicsShareFunc int epicsShareAPI asDumpUag(const char *uagname);
epicsShareFunc int epicsShareAPI asDumpUagFP(FILE *fp,const char *uagname);
epicsShareFunc int epicsShareAPI asDumpHag(const char *hagname);
epicsShareFunc int epicsShareAPI asDumpHagFP(FILE *fp,const char *hagname);
epicsShareFunc int epicsShareAPI asDumpRules(const char *asgname);
epicsShareFunc int epicsShareAPI asDumpRulesFP(FILE *fp,const char *asgname);
epicsShareFunc int epicsShareAPI asDumpMem(const char *asgname,
void (*memcallback)(ASMEMBERPVT,FILE *),int clients);
epicsShareFunc int epicsShareAPI asDumpMemFP(FILE *fp,const char *asgname,
void (*memcallback)(ASMEMBERPVT,FILE *),int clients);
epicsShareFunc int epicsShareAPI asDumpHash(void);
epicsShareFunc int epicsShareAPI asDumpHashFP(FILE *fp);
epicsShareFunc void * epicsShareAPI asTrapWriteBeforeWithData(
const char *userid, const char *hostid, void *addr,
int dbrType, int no_elements, void *data);
epicsShareFunc void epicsShareAPI asTrapWriteAfterWrite(void *pvt);
#define S_asLib_clientsExist (M_asLib| 1) /*Client Exists*/
#define S_asLib_noUag (M_asLib| 2) /*User Access Group does not exist*/
#define S_asLib_noHag (M_asLib| 3) /*Host Access Group does not exist*/
#define S_asLib_noAccess (M_asLib| 4) /*access security: no access allowed*/
#define S_asLib_noModify (M_asLib| 5) /*access security: no modification allowed*/
#define S_asLib_badConfig (M_asLib| 6) /*access security: bad configuration file*/
#define S_asLib_badCalc (M_asLib| 7) /*access security: bad calculation espression*/
#define S_asLib_dupAsg (M_asLib| 8) /*Duplicate Access Security Group */
#define S_asLib_InitFailed (M_asLib| 9) /*access security: Init failed*/
#define S_asLib_asNotActive (M_asLib|10) /*access security is not active*/
#define S_asLib_badMember (M_asLib|11) /*access security: bad ASMEMBERPVT*/
#define S_asLib_badClient (M_asLib|12) /*access security: bad ASCLIENTPVT*/
#define S_asLib_badAsg (M_asLib|13) /*access security: bad ASG*/
#define S_asLib_noMemory (M_asLib|14) /*access security: no Memory */
/*Private declarations */
epicsShareExtern int asActive;
/* definition of access rights*/
typedef enum{asNOACCESS,asREAD,asWRITE} asAccessRights;
struct gphPvt;
/*Base pointers for access security*/
typedef struct asBase{
ELLLIST uagList;
ELLLIST hagList;
ELLLIST asgList;
struct gphPvt *phash;
} ASBASE;
epicsShareExtern volatile ASBASE *pasbase;
/*Defs for User Access Groups*/
typedef struct{
ELLNODE node;
char *user;
} UAGNAME;
typedef struct uag{
ELLNODE node;
char *name;
ELLLIST list; /*list of UAGNAME*/
} UAG;
/*Defs for Host Access Groups*/
typedef struct{
ELLNODE node;
char *host;
} HAGNAME;
typedef struct hag{
ELLNODE node;
char *name;
ELLLIST list; /*list of HAGNAME*/
} HAG;
/*Defs for Access SecurityGroups*/
typedef struct {
ELLNODE node;
UAG *puag;
}ASGUAG;
typedef struct {
ELLNODE node;
HAG *phag;
}ASGHAG;
#define AS_TRAP_WRITE 1
typedef struct{
ELLNODE node;
asAccessRights access;
int level;
unsigned long inpUsed; /*bitmap of which inputs are used*/
int result; /*Result of calc converted to TRUE/FALSE*/
char *calc;
void *rpcl;
ELLLIST uagList; /*List of ASGUAG*/
ELLLIST hagList; /*List of ASGHAG*/
int trapMask;
} ASGRULE;
typedef struct{
ELLNODE node;
char *inp;
void *capvt;
struct asg *pasg;
int inpIndex;
}ASGINP;
typedef struct asg{
ELLNODE node;
char *name;
ELLLIST inpList;
ELLLIST ruleList;
ELLLIST memberList;
double *pavalue; /*pointer to array of input values*/
unsigned long inpBad; /*bitmap of which inputs are bad*/
unsigned long inpChanged; /*bitmap of inputs that changed*/
} ASG;
typedef struct asgMember {
ELLNODE node;
ASG *pasg;
ELLLIST clientList;
const char *asgName;
void *userPvt;
} ASGMEMBER;
typedef struct asgClient {
ELLNODE node;
ASGMEMBER *pasgMember;
const char *user;
char *host;
void *userPvt;
ASCLIENTCALLBACK pcallback;
int level;
asAccessRights access;
int trapMask;
} ASGCLIENT;
epicsShareFunc long epicsShareAPI asComputeAsg(ASG *pasg);
/*following is "friend" function*/
epicsShareFunc void * epicsShareAPI asCalloc(size_t nobj,size_t size);
epicsShareFunc char * epicsShareAPI asStrdup(unsigned char *str);
epicsShareFunc void asFreeAll(ASBASE *pasbase);
#ifdef __cplusplus
}
#endif
#endif /*INCasLibh*/

View File

@@ -1,230 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
%{
static int yyerror(char *);
static int yy_start;
#include "asLibRoutines.c"
static int yyFailed = FALSE;
static int line_num=1;
static UAG *yyUag=NULL;
static HAG *yyHag=NULL;
static ASG *yyAsg=NULL;
static ASGRULE *yyAsgRule=NULL;
%}
%start asconfig
%token tokenUAG tokenHAG tokenASG tokenRULE tokenCALC
%token <Str> tokenINP
%token <Int> tokenINTEGER
%token <Str> tokenSTRING
%union
{
int Int;
char *Str;
}
%%
asconfig: asconfig asconfig_item
| asconfig_item
asconfig_item: tokenUAG uag_head uag_body
| tokenUAG uag_head
| tokenHAG hag_head hag_body
| tokenHAG hag_head
| tokenASG asg_head asg_body
| tokenASG asg_head
;
uag_head: '(' tokenSTRING ')'
{
yyUag = asUagAdd($2);
if(!yyUag) yyerror("");
free((void *)$2);
}
;
uag_body: '{' uag_user_list '}'
{
;
}
;
uag_user_list: uag_user_list ',' uag_user_list_name
| uag_user_list_name
;
uag_user_list_name: tokenSTRING
{
if (asUagAddUser(yyUag,$1))
yyerror("");
free((void *)$1);
}
;
hag_head: '(' tokenSTRING ')'
{
yyHag = asHagAdd($2);
if(!yyHag) yyerror("");
free((void *)$2);
}
;
hag_body: '{' hag_host_list '}'
;
hag_host_list: hag_host_list ',' hag_host_list_name
| hag_host_list_name
;
hag_host_list_name: tokenSTRING
{
if (asHagAddHost(yyHag,$1))
yyerror("");
free((void *)$1);
}
;
asg_head: '(' tokenSTRING ')'
{
yyAsg = asAsgAdd($2);
if(!yyAsg) yyerror("");
free((void *)$2);
}
;
asg_body: '{' asg_body_list '}'
{
}
asg_body_list: asg_body_list asg_body_item
| asg_body_item
asg_body_item: inp_config | rule_config
;
inp_config: tokenINP '(' tokenSTRING ')'
{
if (asAsgAddInp(yyAsg,$3,$<Int>1))
yyerror("");
free((void *)$3);
}
;
rule_config: tokenRULE rule_head rule_body
| tokenRULE rule_head
rule_head: rule_head_manditory rule_head_options
rule_head_manditory: '(' tokenINTEGER ',' tokenSTRING
{
asAccessRights rights;
if((strcmp($4,"NONE")==0)) {
rights=asNOACCESS;
} else if((strcmp($4,"READ")==0)) {
rights=asREAD;
} else if((strcmp($4,"WRITE")==0)) {
rights=asWRITE;
} else {
yyerror("Access rights must be NONE, READ or WRITE");
rights = asNOACCESS;
}
yyAsgRule = asAsgAddRule(yyAsg,rights,$2);
free((void *)$4);
}
;
rule_head_options: ')'
| rule_log_options
rule_log_options: ',' tokenSTRING ')'
{
if((strcmp($2,"TRAPWRITE")==0)) {
long status;
status = asAsgAddRuleOptions(yyAsgRule,AS_TRAP_WRITE);
if(status) yyerror("");
} else if((strcmp($2,"NOTRAPWRITE")!=0)) {
yyerror("Log options must be TRAPWRITE or NOTRAPWRITE");
}
free((void *)$2);
}
;
rule_body: '{' rule_list '}'
;
rule_list: rule_list rule_list_item
| rule_list_item
;
rule_list_item: tokenUAG '(' rule_uag_list ')'
| tokenHAG '(' rule_hag_list ')'
| tokenCALC '(' tokenSTRING ')'
{
if (asAsgRuleCalc(yyAsgRule,$3))
yyerror("");
free((void *)$3);
}
;
rule_uag_list: rule_uag_list ',' rule_uag_list_name
| rule_uag_list_name
;
rule_uag_list_name: tokenSTRING
{
if (asAsgRuleUagAdd(yyAsgRule,$1))
yyerror("");
free((void *)$1);
}
;
rule_hag_list: rule_hag_list ',' rule_hag_list_name
| rule_hag_list_name
;
rule_hag_list_name: tokenSTRING
{
if (asAsgRuleHagAdd(yyAsgRule,$1))
yyerror("");
free((void *)$1);
}
;
%%
#include "asLib_lex.c"
static int yyerror(char *str)
{
if (strlen(str))
errlogPrintf("%s at line %d\n", str, line_num);
else
errlogPrintf("Error at line %d\n", line_num);
yyFailed = TRUE;
return 0;
}
static int myParse(ASINPUTFUNCPTR inputfunction)
{
static int FirstFlag = 1;
int rtnval;
my_yyinput = &inputfunction;
if (!FirstFlag) {
line_num=1;
yyFailed = FALSE;
yyreset();
yyrestart(NULL);
}
FirstFlag = 0;
rtnval = yyparse();
if(rtnval!=0 || yyFailed) return(-1); else return(0);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,94 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
newline "\n"
backslash "\\"
doublequote "\""
comment "#"
whitespace [ \t\r]
escape {backslash}.
stringchar [^"\n\\]
name [a-zA-Z0-9_\-+:.\[\]<>;]
digit [0-9]
punctuation [(){},]
link [A-L]
%{
static ASINPUTFUNCPTR *my_yyinput;
#undef YY_INPUT
#define YY_INPUT(b,r,ms) (r=(*my_yyinput)((char *)b,ms))
static int yyreset(void)
{
line_num=1;
BEGIN INITIAL;
return(0);
}
%}
%%
UAG { return(tokenUAG); }
HAG { return(tokenHAG); }
ASG { return(tokenASG); }
RULE { return(tokenRULE); }
CALC { return(tokenCALC); }
INP{link} {
yylval.Int = (unsigned char)yytext[3];
yylval.Int -= 'A';
return(tokenINP);
}
{digit}+ { /*integer*/
yylval.Int = atoi((char *)yytext);
return(tokenINTEGER);
}
{name}+ { /*unquoted string*/
yylval.Str=asStrdup(yytext);
return(tokenSTRING);
}
{doublequote}({stringchar}|{escape})*{doublequote} { /* quoted string */
yylval.Str=asStrdup(yytext+1);
yylval.Str[strlen(yylval.Str)-1] = '\0';
return(tokenSTRING);
}
{doublequote}({stringchar}|{escape})*{newline} { /* bad string */
yyerror("Newline in quoted string, closing quote missing");
}
{punctuation} { return(yytext[0]); }
{newline} { line_num++; }
{comment}.* ;
{whitespace} ;
. {
char message[40];
YY_BUFFER_STATE *dummy=0;
if (isprint((int) yytext[0])) {
sprintf(message, "Invalid character '%c'", yytext[0]);
}
else {
sprintf(message, "Invalid character 0x%2.2x", yytext[0]);
}
yyerror(message);
/*The following suppress compiler warning messages*/
if (0) yyunput('c',(unsigned char *) message);
if (0) yy_switch_to_buffer(*dummy);
}
%%

View File

@@ -1,175 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*asTrapWrite.c */
/* Author: Marty Kraimer Date: 07NOV2000 */
/* Matthias Clausen and Vladis Korobov at DESY
* implemented the first logging of Channel Access Puts
* This implementation uses many ideas from their implementation
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#define epicsExportSharedSymbols
#include "ellLib.h"
#include "freeList.h"
#include "epicsStdio.h"
#include "cantProceed.h"
#include "epicsMutex.h"
#include "ellLib.h"
#include "asLib.h"
#include "asTrapWrite.h"
typedef struct listenerPvt {
ELLNODE node;
struct listener *plistener;
void *userPvt;
}listenerPvt;
typedef struct listener{
ELLNODE node;
asTrapWriteListener func;
}listener;
typedef struct writeMessage {
ELLNODE node;
asTrapWriteMessage message;
ELLLIST listenerPvtList;
}writeMessage;
typedef struct asTrapWritePvt
{
ELLLIST listenerList;
ELLLIST writeMessageList;
void *freeListWriteMessage;
void *freeListListenerPvt;
epicsMutexId lock;
}asTrapWritePvt;
static asTrapWritePvt *pasTrapWritePvt = 0;
static void asTrapWriteInit(void)
{
pasTrapWritePvt = callocMustSucceed(1,sizeof(asTrapWritePvt),"asTrapWriteInit");
ellInit(&pasTrapWritePvt->listenerList);
ellInit(&pasTrapWritePvt->writeMessageList);
freeListInitPvt(
&pasTrapWritePvt->freeListWriteMessage,sizeof(writeMessage),20);
freeListInitPvt(
&pasTrapWritePvt->freeListListenerPvt,sizeof(listenerPvt),20);
pasTrapWritePvt->lock = epicsMutexMustCreate();
}
asTrapWriteId epicsShareAPI asTrapWriteRegisterListener(
asTrapWriteListener func)
{
listener *plistener;
if(pasTrapWritePvt==0) asTrapWriteInit();
plistener = callocMustSucceed(1,sizeof(listener),"asTrapWriteRegisterListener");
plistener->func = func;
epicsMutexMustLock(pasTrapWritePvt->lock);
ellAdd(&pasTrapWritePvt->listenerList,&plistener->node);
epicsMutexUnlock(pasTrapWritePvt->lock);
return((asTrapWriteId)plistener);
}
void epicsShareAPI asTrapWriteUnregisterListener(asTrapWriteId id)
{
listener *plistener = (listener *)id;
writeMessage *pwriteMessage;
if(pasTrapWritePvt==0) return;
epicsMutexMustLock(pasTrapWritePvt->lock);
pwriteMessage = (writeMessage *)ellFirst(&pasTrapWritePvt->writeMessageList);
while(pwriteMessage) {
listenerPvt *plistenerPvt
= (listenerPvt *)ellFirst(&pwriteMessage->listenerPvtList);
while(plistenerPvt) {
listenerPvt *pnext
= (listenerPvt *)ellNext(&plistenerPvt->node);
if(plistenerPvt->plistener == plistener) {
ellDelete(&pwriteMessage->listenerPvtList,&plistenerPvt->node);
freeListFree(pasTrapWritePvt->freeListListenerPvt, plistenerPvt);
}
plistenerPvt = pnext;
}
pwriteMessage = (writeMessage *)ellNext(&pwriteMessage->node);
}
ellDelete(&pasTrapWritePvt->listenerList,&plistener->node);
free(plistener);
epicsMutexUnlock(pasTrapWritePvt->lock);
}
void * epicsShareAPI asTrapWriteBeforeWithData(
const char *userid, const char *hostid, void *addr,
int dbrType, int no_elements, void *data)
{
writeMessage *pwriteMessage;
listener *plistener;
if (pasTrapWritePvt == 0 ||
ellCount(&pasTrapWritePvt->listenerList) <= 0) return 0;
pwriteMessage = (writeMessage *)freeListCalloc(
pasTrapWritePvt->freeListWriteMessage);
pwriteMessage->message.userid = userid;
pwriteMessage->message.hostid = hostid;
pwriteMessage->message.serverSpecific = addr;
pwriteMessage->message.dbrType = dbrType;
pwriteMessage->message.no_elements = no_elements;
pwriteMessage->message.data = data;
ellInit(&pwriteMessage->listenerPvtList);
epicsMutexMustLock(pasTrapWritePvt->lock);
ellAdd(&pasTrapWritePvt->writeMessageList, &pwriteMessage->node);
plistener = (listener *)ellFirst(&pasTrapWritePvt->listenerList);
while (plistener) {
listenerPvt *plistenerPvt = (listenerPvt *)freeListCalloc(
pasTrapWritePvt->freeListListenerPvt);
plistenerPvt->plistener = plistener;
pwriteMessage->message.userPvt = 0;
plistener->func(&pwriteMessage->message, 0);
plistenerPvt->userPvt = pwriteMessage->message.userPvt;
ellAdd(&pwriteMessage->listenerPvtList, &plistenerPvt->node);
plistener = (listener *)ellNext(&plistener->node);
}
epicsMutexUnlock(pasTrapWritePvt->lock);
return pwriteMessage;
}
void epicsShareAPI asTrapWriteAfterWrite(void *pvt)
{
writeMessage *pwriteMessage = (writeMessage *)pvt;
listenerPvt *plistenerPvt;
if (pwriteMessage == 0 ||
pasTrapWritePvt == 0) return;
epicsMutexMustLock(pasTrapWritePvt->lock);
plistenerPvt = (listenerPvt *)ellFirst(&pwriteMessage->listenerPvtList);
while (plistenerPvt) {
listenerPvt *pnext = (listenerPvt *)ellNext(&plistenerPvt->node);
listener *plistener = plistenerPvt->plistener;
pwriteMessage->message.userPvt = plistenerPvt->userPvt;
plistener->func(&pwriteMessage->message, 1);
ellDelete(&pwriteMessage->listenerPvtList, &plistenerPvt->node);
freeListFree(pasTrapWritePvt->freeListListenerPvt, plistenerPvt);
plistenerPvt = pnext;
}
ellDelete(&pasTrapWritePvt->writeMessageList, &pwriteMessage->node);
freeListFree(pasTrapWritePvt->freeListWriteMessage, pwriteMessage);
epicsMutexUnlock(pasTrapWritePvt->lock);
}

View File

@@ -1,56 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*asTrapWrite.h*/
/* Author: Marty Kraimer Date: 07NOV2000 */
#ifndef INCasTrapWriteh
#define INCasTrapWriteh
#include "shareLib.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct asTrapWriteMessage {
const char *userid;
const char *hostid;
void *serverSpecific;
void *userPvt;
int dbrType; /* Data type from ca/db_access.h, NOT dbFldTypes.h */
int no_elements;
void *data; /* Might be NULL if no data is available */
} asTrapWriteMessage;
typedef void *asTrapWriteId;
typedef void(*asTrapWriteListener)(asTrapWriteMessage *pmessage,int after);
epicsShareFunc asTrapWriteId epicsShareAPI asTrapWriteRegisterListener(
asTrapWriteListener func);
epicsShareFunc void epicsShareAPI asTrapWriteUnregisterListener(
asTrapWriteId id);
/*
* asTrapWriteListener is called before and after the write is performed.
* The listener can set userPvt on the before call and retrieve it after
* after = (0,1) (before,after) the put.
*
* Each asTrapWriteMessage can change or may be deleted after
* the user's asTrapWriteListener returns
*
* asTrapWriteListener delays the associated server thread so it must not
* do anything that causes to to block.
*/
#ifdef __cplusplus
}
#endif
#endif /*INCasTrapWriteh*/

View File

@@ -1,12 +0,0 @@
#*************************************************************************
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/libCom/Makefile.
SRC_DIRS += $(LIBCOM)/bucketLib
INC += bucketLib.h
Com_SRCS += bucketLib.c

View File

@@ -1,522 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Jeffrey O. Hill
* hill@atdiv.lanl.gov
* (505) 665 1831
* Date: 9-93
*
* NOTES:
* .01 Storage for identifier must persist until an item is deleted
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#define epicsExportSharedSymbols
#include "epicsAssert.h"
#include "freeList.h" /* bucketLib uses freeListLib inside the DLL */
#include "bucketLib.h"
/*
* these data type dependent routines are
* provided in the bucketLib.c
*/
typedef BUCKETID bucketHash(BUCKET *pb, const void *pId);
typedef ITEM **bucketCompare(ITEM **ppi, const void *pId);
static bucketCompare bucketUnsignedCompare;
static bucketCompare bucketPointerCompare;
static bucketCompare bucketStringCompare;
static bucketHash bucketUnsignedHash;
static bucketHash bucketPointerHash;
static bucketHash bucketStringHash;
typedef struct {
bucketHash *pHash;
bucketCompare *pCompare;
buckTypeOfId type;
}bucketSET;
static bucketSET BSET[] = {
{bucketUnsignedHash, bucketUnsignedCompare, bidtUnsigned},
{bucketPointerHash, bucketPointerCompare, bidtPointer},
{bucketStringHash, bucketStringCompare, bidtString}
};
static int bucketAddItem(BUCKET *prb, bucketSET *pBSET,
const void *pId, const void *pApp);
static void *bucketLookupItem(BUCKET *pb, bucketSET *pBSET, const void *pId);
/*
* bucket id bit width
*/
#define BUCKETID_BIT_WIDTH (sizeof(BUCKETID)*CHAR_BIT)
/*
* Maximum bucket size
*/
#define BUCKET_MAX_WIDTH 12
/*
* bucketUnsignedCompare()
*/
static ITEM **bucketUnsignedCompare (ITEM **ppi, const void *pId)
{
unsigned id;
unsigned *pItemId;
ITEM *pi;
id = * (unsigned *) pId;
while ( (pi = *ppi) ) {
if (bidtUnsigned == pi->type) {
pItemId = (unsigned *) pi->pId;
if (id == *pItemId) {
return ppi;
}
}
ppi = &pi->pItem;
}
return NULL;
}
/*
* bucketPointerCompare()
*/
static ITEM **bucketPointerCompare (ITEM **ppi, const void *pId)
{
void *ptr;
void **pItemId;
ITEM *pi;
ptr = * (void **) pId;
while ( (pi = *ppi) ) {
if (bidtPointer == pi->type ) {
pItemId = (void **) pi->pId;
if (ptr == *pItemId) {
return ppi;
}
}
ppi = &pi->pItem;
}
return NULL;
}
/*
* bucketStringCompare ()
*/
static ITEM **bucketStringCompare (ITEM **ppi, const void *pId)
{
const char *pStr = pId;
ITEM *pi;
int status;
while ( (pi = *ppi) ) {
if (bidtString == pi->type) {
status = strcmp (pStr, (char *)pi->pId);
if (status == '\0') {
return ppi;
}
}
ppi = &pi->pItem;
}
return NULL;
}
/*
* bucketUnsignedHash ()
*/
static BUCKETID bucketUnsignedHash (BUCKET *pb, const void *pId)
{
const unsigned *pUId = (const unsigned *) pId;
unsigned src;
BUCKETID hashid;
src = *pUId;
hashid = src;
src = src >> pb->hashIdNBits;
while (src) {
hashid = hashid ^ src;
src = src >> pb->hashIdNBits;
}
hashid = hashid & pb->hashIdMask;
return hashid;
}
/*
* bucketPointerHash ()
*/
static BUCKETID bucketPointerHash (BUCKET *pb, const void *pId)
{
void * const *ppId = (void * const *) pId;
size_t src;
BUCKETID hashid;
/*
* This makes the assumption that size_t
* can be used to hold a pointer value
* (this assumption may not port to all
* CPU architectures)
*/
src = (size_t) *ppId;
hashid = src;
src = src >> pb->hashIdNBits;
while(src){
hashid = hashid ^ src;
src = src >> pb->hashIdNBits;
}
hashid = hashid & pb->hashIdMask;
return hashid;
}
/*
* bucketStringHash ()
*/
static BUCKETID bucketStringHash (BUCKET *pb, const void *pId)
{
const char *pStr = (const char *) pId;
BUCKETID hashid;
unsigned i;
hashid = 0;
i = 1;
while(*pStr){
hashid += *pStr * i;
pStr++;
i++;
}
hashid = hashid % (pb->hashIdMask+1);
return hashid;
}
/*
* bucketCreate()
*/
epicsShareFunc BUCKET * epicsShareAPI bucketCreate (unsigned nHashTableEntries)
{
BUCKETID mask;
unsigned nbits;
BUCKET *pb;
/*
* no absurd sized buckets
*/
if (nHashTableEntries<=1) {
fprintf (stderr, "Tiny bucket create failed\n");
return NULL;
}
/*
* count the number of bits in the bucket id
*/
if ( BUCKETID_BIT_WIDTH > 0 ) {
for (nbits=0; nbits<BUCKETID_BIT_WIDTH; nbits++) {
mask = (1<<nbits) - 1;
if ( ((nHashTableEntries-1) & ~mask) == 0){
break;
}
}
}
else {
mask = 0;
nbits = 0;
}
/*
* indexWidth must be specified at least one
* bit less than the bit size of type BUCKETID
*/
if (nbits>=BUCKETID_BIT_WIDTH) {
fprintf (
stderr,
"%s at %d: Requested index width=%d to large. max=%ld\n",
__FILE__,
__LINE__,
nbits,
(long)(BUCKETID_BIT_WIDTH-1));
return NULL;
}
pb = (BUCKET *) calloc(1, sizeof(*pb));
if (!pb) {
return pb;
}
pb->hashIdMask = mask;
pb->hashIdNBits = nbits;
freeListInitPvt(&pb->freeListPVT, sizeof(ITEM), 1024);
pb->pTable = (ITEM **) calloc (mask+1, sizeof(*pb->pTable));
if (!pb->pTable) {
freeListCleanup(pb->freeListPVT);
free (pb);
return NULL;
}
return pb;
}
/*
* bucketFree()
*/
epicsShareFunc int epicsShareAPI bucketFree (BUCKET *prb)
{
/*
* deleting a bucket with entries in use
* will cause memory leaks and is not allowed
*/
assert (prb->nInUse==0);
/*
* free the free list
*/
freeListCleanup(prb->freeListPVT);
free (prb->pTable);
free (prb);
return S_bucket_success;
}
/*
* bucketAddItem()
*/
epicsShareFunc int epicsShareAPI
bucketAddItemUnsignedId(BUCKET *prb, const unsigned *pId, const void *pApp)
{
return bucketAddItem(prb, &BSET[bidtUnsigned], pId, pApp);
}
epicsShareFunc int epicsShareAPI
bucketAddItemPointerId(BUCKET *prb, void * const *pId, const void *pApp)
{
return bucketAddItem(prb, &BSET[bidtPointer], pId, pApp);
}
epicsShareFunc int epicsShareAPI
bucketAddItemStringId(BUCKET *prb, const char *pId, const void *pApp)
{
return bucketAddItem(prb, &BSET[bidtString], pId, pApp);
}
static int bucketAddItem(BUCKET *prb, bucketSET *pBSET, const void *pId, const void *pApp)
{
BUCKETID hashid;
ITEM **ppi;
ITEM **ppiExists;
ITEM *pi;
/*
* try to get it off the free list first. If
* that fails then malloc()
*/
pi = (ITEM *) freeListMalloc(prb->freeListPVT);
if (!pi) {
return S_bucket_noMemory;
}
/*
* create the hash index
*/
hashid = (*pBSET->pHash) (prb, pId);
pi->pApp = pApp;
pi->pId = pId;
pi->type = pBSET->type;
assert ((hashid & ~prb->hashIdMask) == 0);
ppi = &prb->pTable[hashid];
/*
* Dont reuse a resource id !
*/
ppiExists = (*pBSET->pCompare) (ppi, pId);
if (ppiExists) {
freeListFree(prb->freeListPVT,pi);
return S_bucket_idInUse;
}
pi->pItem = *ppi;
prb->pTable[hashid] = pi;
prb->nInUse++;
return S_bucket_success;
}
/*
* bucketLookupAndRemoveItem ()
*/
static void *bucketLookupAndRemoveItem (BUCKET *prb, bucketSET *pBSET, const void *pId)
{
BUCKETID hashid;
ITEM **ppi;
ITEM *pi;
void *pApp;
/*
* create the hash index
*/
hashid = (*pBSET->pHash) (prb, pId);
assert((hashid & ~prb->hashIdMask) == 0);
ppi = &prb->pTable[hashid];
ppi = (*pBSET->pCompare) (ppi, pId);
if(!ppi){
return NULL;
}
prb->nInUse--;
pi = *ppi;
*ppi = pi->pItem;
pApp = (void *) pi->pApp;
/*
* stuff it on the free list
*/
freeListFree(prb->freeListPVT, pi);
return pApp;
}
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId)
{
return bucketLookupAndRemoveItem(prb, &BSET[bidtUnsigned], pId);
}
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemPointerId (BUCKET *prb, void * const *pId)
{
return bucketLookupAndRemoveItem(prb, &BSET[bidtPointer], pId);
}
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemStringId (BUCKET *prb, const char *pId)
{
return bucketLookupAndRemoveItem(prb, &BSET[bidtString], pId);
}
/*
* bucketRemoveItem()
*/
epicsShareFunc int epicsShareAPI
bucketRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId)
{
return bucketLookupAndRemoveItem(prb, &BSET[bidtUnsigned], pId)?S_bucket_success:S_bucket_uknId;
}
epicsShareFunc int epicsShareAPI
bucketRemoveItemPointerId (BUCKET *prb, void * const *pId)
{
return bucketLookupAndRemoveItem(prb, &BSET[bidtPointer], pId)?S_bucket_success:S_bucket_uknId;
}
epicsShareFunc int epicsShareAPI
bucketRemoveItemStringId (BUCKET *prb, const char *pId)
{
return bucketLookupAndRemoveItem(prb, &BSET[bidtString], pId)?S_bucket_success:S_bucket_uknId;
}
/*
* bucketLookupItem()
*/
epicsShareFunc void * epicsShareAPI
bucketLookupItemUnsignedId (BUCKET *prb, const unsigned *pId)
{
return bucketLookupItem(prb, &BSET[bidtUnsigned], pId);
}
epicsShareFunc void * epicsShareAPI
bucketLookupItemPointerId (BUCKET *prb, void * const *pId)
{
return bucketLookupItem(prb, &BSET[bidtPointer], pId);
}
epicsShareFunc void * epicsShareAPI
bucketLookupItemStringId (BUCKET *prb, const char *pId)
{
return bucketLookupItem(prb, &BSET[bidtString], pId);
}
static void *bucketLookupItem (BUCKET *pb, bucketSET *pBSET, const void *pId)
{
BUCKETID hashid;
ITEM **ppi;
/*
* create the hash index
*/
hashid = (*pBSET->pHash) (pb, pId);
assert((hashid & ~pb->hashIdMask) == 0);
/*
* at the bottom level just
* linear search for it.
*/
ppi = (*pBSET->pCompare) (&pb->pTable[hashid], pId);
if(ppi){
return (void *) (*ppi)->pApp;
}
return NULL;
}
/*
* bucketShow()
*/
epicsShareFunc int epicsShareAPI bucketShow(BUCKET *pb)
{
ITEM **ppi;
ITEM *pi;
unsigned nElem;
double X;
double XX;
double mean;
double stdDev;
unsigned count;
unsigned maxEntries;
printf( " Bucket entries in use = %d bytes in use = %ld\n",
pb->nInUse,
(long) (sizeof(*pb)+(pb->hashIdMask+1)*
sizeof(ITEM *)+pb->nInUse*sizeof(ITEM)));
ppi = pb->pTable;
nElem = pb->hashIdMask+1;
X = 0.0;
XX = 0.0;
maxEntries = 0;
while (ppi < &pb->pTable[nElem]) {
pi = *ppi;
count = 0;
while (pi) {
count++;
pi = pi->pItem;
}
X += count;
XX += count*count;
if (count > maxEntries) maxEntries = count;
ppi++;
}
mean = X/nElem;
stdDev = sqrt(XX/nElem - mean*mean);
printf( " Bucket entries/hash id - mean = %f std dev = %f max = %d\n",
mean,
stdDev,
maxEntries);
return S_bucket_success;
}

View File

@@ -1,91 +0,0 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Jeffrey O. Hill
* hill@luke.lanl.gov
* (505) 665 1831
* Date: 9-93
*
* NOTES:
* .01 Storage for identifier must persist until an item is deleted
*/
#ifndef INCbucketLibh
#define INCbucketLibh
#ifdef __cplusplus
extern "C" {
#endif
#include "errMdef.h"
#include "epicsTypes.h"
#include "shareLib.h"
typedef unsigned BUCKETID;
typedef enum {bidtUnsigned, bidtPointer, bidtString} buckTypeOfId;
typedef struct item{
struct item *pItem;
const void *pId;
const void *pApp;
buckTypeOfId type;
}ITEM;
typedef struct bucket{
ITEM **pTable;
void *freeListPVT;
unsigned hashIdMask;
unsigned hashIdNBits;
unsigned nInUse;
}BUCKET;
epicsShareFunc BUCKET * epicsShareAPI bucketCreate (unsigned nHashTableEntries);
epicsShareFunc int epicsShareAPI bucketFree (BUCKET *prb);
epicsShareFunc int epicsShareAPI bucketShow (BUCKET *pb);
/*
* !! Identifier must exist (and remain constant) at the specified address until
* the item is deleted from the bucket !!
*/
epicsShareFunc int epicsShareAPI bucketAddItemUnsignedId (BUCKET *prb,
const unsigned *pId, const void *pApp);
epicsShareFunc int epicsShareAPI bucketAddItemPointerId (BUCKET *prb,
void * const *pId, const void *pApp);
epicsShareFunc int epicsShareAPI bucketAddItemStringId (BUCKET *prb,
const char *pId, const void *pApp);
epicsShareFunc int epicsShareAPI bucketRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId);
epicsShareFunc int epicsShareAPI bucketRemoveItemPointerId (BUCKET *prb, void * const *pId);
epicsShareFunc int epicsShareAPI bucketRemoveItemStringId (BUCKET *prb, const char *pId);
epicsShareFunc void * epicsShareAPI bucketLookupItemUnsignedId (BUCKET *prb, const unsigned *pId);
epicsShareFunc void * epicsShareAPI bucketLookupItemPointerId (BUCKET *prb, void * const *pId);
epicsShareFunc void * epicsShareAPI bucketLookupItemStringId (BUCKET *prb, const char *pId);
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemUnsignedId (BUCKET *prb, const unsigned *pId);
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemPointerId (BUCKET *prb, void * const *pId);
epicsShareFunc void * epicsShareAPI bucketLookupAndRemoveItemStringId (BUCKET *prb, const char *pId);
/*
* Status returned by bucketLib functions
*/
#define BUCKET_SUCCESS S_bucket_success
#define S_bucket_success 0
#define S_bucket_noMemory (M_bucket | 1) /*Memory allocation failed*/
#define S_bucket_idInUse (M_bucket | 2) /*Identifier already in use*/
#define S_bucket_uknId (M_bucket | 3) /*Unknown identifier*/
#ifdef __cplusplus
}
#endif
#endif /*INCbucketLibh*/

View File

@@ -1,14 +0,0 @@
#*************************************************************************
# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/libCom/Makefile.
SRC_DIRS += $(LIBCOM)/calc
INC += postfix.h
Com_SRCS += postfix.c
Com_SRCS += calcPerform.c

View File

@@ -1,504 +0,0 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Julie Sander and Bob Dalesio
* Date: 07-27-87
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#define epicsExportSharedSymbols
#include "osiUnistd.h"
#include "dbDefs.h"
#include "epicsMath.h"
#include "epicsTypes.h"
#include "errlog.h"
#include "postfix.h"
#include "postfixPvt.h"
static double calcRandom(void);
static int cond_search(const char **ppinst, int match);
#ifndef PI
#define PI 3.14159265358979323
#endif
/* Turn off global optimization for 64-bit MSVC builds */
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
# pragma optimize("g", off)
#endif
/* calcPerform
*
* Evalutate the postfix expression
*/
epicsShareFunc long
calcPerform(double *parg, double *presult, const char *pinst)
{
double stack[CALCPERFORM_STACK+1]; /* zero'th entry not used */
double *ptop; /* stack pointer */
double top; /* value from top of stack */
epicsInt32 itop; /* integer from top of stack */
epicsUInt32 utop; /* unsigned integer from top of stack */
int op;
int nargs;
/* initialize */
ptop = stack;
/* RPN evaluation loop */
while ((op = *pinst++) != END_EXPRESSION){
switch (op){
case LITERAL_DOUBLE:
memcpy(++ptop, pinst, sizeof(double));
pinst += sizeof(double);
break;
case LITERAL_INT:
memcpy(&itop, pinst, sizeof(epicsInt32));
*++ptop = itop;
pinst += sizeof(epicsInt32);
break;
case FETCH_VAL:
*++ptop = *presult;
break;
case FETCH_A:
case FETCH_B:
case FETCH_C:
case FETCH_D:
case FETCH_E:
case FETCH_F:
case FETCH_G:
case FETCH_H:
case FETCH_I:
case FETCH_J:
case FETCH_K:
case FETCH_L:
*++ptop = parg[op - FETCH_A];
break;
case STORE_A:
case STORE_B:
case STORE_C:
case STORE_D:
case STORE_E:
case STORE_F:
case STORE_G:
case STORE_H:
case STORE_I:
case STORE_J:
case STORE_K:
case STORE_L:
parg[op - STORE_A] = *ptop--;
break;
case CONST_PI:
*++ptop = PI;
break;
case CONST_D2R:
*++ptop = PI/180.;
break;
case CONST_R2D:
*++ptop = 180./PI;
break;
case UNARY_NEG:
*ptop = - *ptop;
break;
case ADD:
top = *ptop--;
*ptop += top;
break;
case SUB:
top = *ptop--;
*ptop -= top;
break;
case MULT:
top = *ptop--;
*ptop *= top;
break;
case DIV:
top = *ptop--;
*ptop /= top;
break;
case MODULO:
itop = (epicsInt32) *ptop--;
if (itop)
*ptop = (epicsInt32) *ptop % itop;
else
*ptop = epicsNAN;
break;
case POWER:
top = *ptop--;
*ptop = pow(*ptop, top);
break;
case ABS_VAL:
*ptop = fabs(*ptop);
break;
case EXP:
*ptop = exp(*ptop);
break;
case LOG_10:
*ptop = log10(*ptop);
break;
case LOG_E:
*ptop = log(*ptop);
break;
case MAX:
nargs = *pinst++;
while (--nargs) {
top = *ptop--;
if (*ptop < top || isnan(top))
*ptop = top;
}
break;
case MIN:
nargs = *pinst++;
while (--nargs) {
top = *ptop--;
if (*ptop > top || isnan(top))
*ptop = top;
}
break;
case SQU_RT:
*ptop = sqrt(*ptop);
break;
case ACOS:
*ptop = acos(*ptop);
break;
case ASIN:
*ptop = asin(*ptop);
break;
case ATAN:
*ptop = atan(*ptop);
break;
case ATAN2:
top = *ptop--;
*ptop = atan2(top, *ptop); /* Ouch!: Args backwards! */
break;
case COS:
*ptop = cos(*ptop);
break;
case SIN:
*ptop = sin(*ptop);
break;
case TAN:
*ptop = tan(*ptop);
break;
case COSH:
*ptop = cosh(*ptop);
break;
case SINH:
*ptop = sinh(*ptop);
break;
case TANH:
*ptop = tanh(*ptop);
break;
case CEIL:
*ptop = ceil(*ptop);
break;
case FLOOR:
*ptop = floor(*ptop);
break;
case FINITE:
nargs = *pinst++;
top = finite(*ptop);
while (--nargs) {
--ptop;
top = top && finite(*ptop);
}
*ptop = top;
break;
case ISINF:
*ptop = isinf(*ptop);
break;
case ISNAN:
nargs = *pinst++;
top = isnan(*ptop);
while (--nargs) {
--ptop;
top = top || isnan(*ptop);
}
*ptop = top;
break;
case NINT:
top = *ptop;
*ptop = (epicsInt32) (top >= 0 ? top + 0.5 : top - 0.5);
break;
case RANDOM:
*++ptop = calcRandom();
break;
case REL_OR:
top = *ptop--;
*ptop = *ptop || top;
break;
case REL_AND:
top = *ptop--;
*ptop = *ptop && top;
break;
case REL_NOT:
*ptop = ! *ptop;
break;
/* For bitwise operations on values with bit 31 set, double values
* must first be cast to unsigned to correctly set that bit; the
* double value must be negative in that case. The result must be
* cast to a signed integer before converting to the double result.
*/
case BIT_OR:
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop | utop);
break;
case BIT_AND:
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop & utop);
break;
case BIT_EXCL_OR:
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop ^ utop);
break;
case BIT_NOT:
utop = *ptop;
*ptop = (epicsInt32) ~utop;
break;
/* The shift operators use signed integers, so a right-shift will
* extend the sign bit into the left-hand end of the value. The
* double-casting through unsigned here is important, see above.
*/
case RIGHT_SHIFT:
utop = *ptop--;
*ptop = ((epicsInt32) (epicsUInt32) *ptop) >> (utop & 31);
break;
case LEFT_SHIFT:
utop = *ptop--;
*ptop = ((epicsInt32) (epicsUInt32) *ptop) << (utop & 31);
break;
case NOT_EQ:
top = *ptop--;
*ptop = *ptop != top;
break;
case LESS_THAN:
top = *ptop--;
*ptop = *ptop < top;
break;
case LESS_OR_EQ:
top = *ptop--;
*ptop = *ptop <= top;
break;
case EQUAL:
top = *ptop--;
*ptop = *ptop == top;
break;
case GR_OR_EQ:
top = *ptop--;
*ptop = *ptop >= top;
break;
case GR_THAN:
top = *ptop--;
*ptop = *ptop > top;
break;
case COND_IF:
if (*ptop-- == 0.0 &&
cond_search(&pinst, COND_ELSE)) return -1;
break;
case COND_ELSE:
if (cond_search(&pinst, COND_END)) return -1;
break;
case COND_END:
break;
default:
errlogPrintf("calcPerform: Bad Opcode %d at %p\n", op, pinst-1);
return -1;
}
}
/* The stack should now have one item on it, the expression value */
if (ptop != stack + 1)
return -1;
*presult = *ptop;
return 0;
}
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
# pragma optimize("", on)
#endif
epicsShareFunc long
calcArgUsage(const char *pinst, unsigned long *pinputs, unsigned long *pstores)
{
unsigned long inputs = 0;
unsigned long stores = 0;
char op;
while ((op = *pinst++) != END_EXPRESSION) {
switch (op) {
case LITERAL_DOUBLE:
pinst += sizeof(double);
break;
case LITERAL_INT:
pinst += sizeof(epicsInt32);
break;
case MIN:
case MAX:
case FINITE:
case ISNAN:
pinst++;
break;
case FETCH_A:
case FETCH_B:
case FETCH_C:
case FETCH_D:
case FETCH_E:
case FETCH_F:
case FETCH_G:
case FETCH_H:
case FETCH_I:
case FETCH_J:
case FETCH_K:
case FETCH_L:
/* Don't claim to use an arg we already stored to */
inputs |= (1 << (op - FETCH_A)) & ~stores;
break;
case STORE_A:
case STORE_B:
case STORE_C:
case STORE_D:
case STORE_E:
case STORE_F:
case STORE_G:
case STORE_H:
case STORE_I:
case STORE_J:
case STORE_K:
case STORE_L:
stores |= (1 << (op - STORE_A));
break;
default:
break;
}
}
if (pinputs) *pinputs = inputs;
if (pstores) *pstores = stores;
return 0;
}
/* Generate a random number between 0 and 1 using the algorithm
* seed = (multy * seed) + addy Random Number Generator by Knuth
* SemiNumerical Algorithms
* Chapter 1
* randy = seed / 65535.0 To normalize the number between 0 - 1
*/
static unsigned short seed = 0xa3bf;
static unsigned short multy = 191 * 8 + 5; /* 191 % 8 == 5 */
static unsigned short addy = 0x3141;
static double calcRandom(void)
{
seed = (seed * multy) + addy;
/* between 0 - 1 */
return (double) seed / 65535.0;
}
/* Search the instruction stream for a matching operator, skipping any
* other conditional instructions found, and leave *ppinst pointing to
* the next instruction to be executed.
*/
static int cond_search(const char **ppinst, int match)
{
const char *pinst = *ppinst;
int count = 1;
int op;
while ((op = *pinst++) != END_EXPRESSION) {
if (op == match && --count == 0) {
*ppinst = pinst;
return 0;
}
switch (op) {
case LITERAL_DOUBLE:
pinst += sizeof(double);
break;
case LITERAL_INT:
pinst += sizeof(epicsInt32);
break;
case MIN:
case MAX:
case FINITE:
case ISNAN:
pinst++;
break;
case COND_IF:
count++;
break;
}
}
return 1;
}

View File

@@ -1,626 +0,0 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Subroutines used to convert an infix expression to a postfix expression
*
* Original Author: Bob Dalesio
* Date: 12-12-86
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define epicsExportSharedSymbols
#include "dbDefs.h"
#include "epicsAssert.h"
#include "epicsStdlib.h"
#include "epicsString.h"
#include "epicsTypes.h"
#include "postfix.h"
#include "postfixPvt.h"
#include "shareLib.h"
/* declarations for postfix */
/* element types */
typedef enum {
OPERAND,
LITERAL_OPERAND,
STORE_OPERATOR,
UNARY_OPERATOR,
VARARG_OPERATOR,
BINARY_OPERATOR,
SEPERATOR,
CLOSE_PAREN,
CONDITIONAL,
EXPR_TERMINATOR,
} element_type;
/* element table
*
* structure of an element
*/
typedef struct expression_element{
char *name; /* character representation of an element */
char in_stack_pri; /* priority on translation stack */
char in_coming_pri; /* priority in input string */
signed char runtime_effect; /* stack change, positive means push */
element_type type; /* element type */
rpn_opcode code; /* postfix opcode */
} ELEMENT;
/*
* NOTE: Keep these lists sorted. Elements are searched in reverse order,
* and where two names start with the same substring we must pick out the
* longest name first (hence the sort requirement).
* NOTE: All VARARG_OPERATORs have to be made known to the calcExprDump()
* routine at the end of this file.
*/
static const ELEMENT operands[] = {
/* name prio's stack element type opcode */
{"!", 7, 8, 0, UNARY_OPERATOR, REL_NOT},
{"(", 0, 8, 0, UNARY_OPERATOR, NOT_GENERATED},
{"-", 7, 8, 0, UNARY_OPERATOR, UNARY_NEG},
{".", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"0", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"0X", 0, 0, 1, LITERAL_OPERAND,LITERAL_INT},
{"1", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"2", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"3", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"4", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"5", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"6", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"7", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"8", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"9", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"A", 0, 0, 1, OPERAND, FETCH_A},
{"ABS", 7, 8, 0, UNARY_OPERATOR, ABS_VAL},
{"ACOS", 7, 8, 0, UNARY_OPERATOR, ACOS},
{"ASIN", 7, 8, 0, UNARY_OPERATOR, ASIN},
{"ATAN", 7, 8, 0, UNARY_OPERATOR, ATAN},
{"ATAN2", 7, 8, -1, UNARY_OPERATOR, ATAN2},
{"B", 0, 0, 1, OPERAND, FETCH_B},
{"C", 0, 0, 1, OPERAND, FETCH_C},
{"CEIL", 7, 8, 0, UNARY_OPERATOR, CEIL},
{"COS", 7, 8, 0, UNARY_OPERATOR, COS},
{"COSH", 7, 8, 0, UNARY_OPERATOR, COSH},
{"D", 0, 0, 1, OPERAND, FETCH_D},
{"D2R", 0, 0, 1, OPERAND, CONST_D2R},
{"E", 0, 0, 1, OPERAND, FETCH_E},
{"EXP", 7, 8, 0, UNARY_OPERATOR, EXP},
{"F", 0, 0, 1, OPERAND, FETCH_F},
{"FINITE", 7, 8, 0, VARARG_OPERATOR,FINITE},
{"FLOOR", 7, 8, 0, UNARY_OPERATOR, FLOOR},
{"G", 0, 0, 1, OPERAND, FETCH_G},
{"H", 0, 0, 1, OPERAND, FETCH_H},
{"I", 0, 0, 1, OPERAND, FETCH_I},
{"INF", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"ISINF", 7, 8, 0, UNARY_OPERATOR, ISINF},
{"ISNAN", 7, 8, 0, VARARG_OPERATOR,ISNAN},
{"J", 0, 0, 1, OPERAND, FETCH_J},
{"K", 0, 0, 1, OPERAND, FETCH_K},
{"L", 0, 0, 1, OPERAND, FETCH_L},
{"LN", 7, 8, 0, UNARY_OPERATOR, LOG_E},
{"LOG", 7, 8, 0, UNARY_OPERATOR, LOG_10},
{"LOGE", 7, 8, 0, UNARY_OPERATOR, LOG_E},
{"MAX", 7, 8, 0, VARARG_OPERATOR,MAX},
{"MIN", 7, 8, 0, VARARG_OPERATOR,MIN},
{"NINT", 7, 8, 0, UNARY_OPERATOR, NINT},
{"NAN", 0, 0, 1, LITERAL_OPERAND,LITERAL_DOUBLE},
{"NOT", 7, 8, 0, UNARY_OPERATOR, BIT_NOT},
{"PI", 0, 0, 1, OPERAND, CONST_PI},
{"R2D", 0, 0, 1, OPERAND, CONST_R2D},
{"RNDM", 0, 0, 1, OPERAND, RANDOM},
{"SIN", 7, 8, 0, UNARY_OPERATOR, SIN},
{"SINH", 7, 8, 0, UNARY_OPERATOR, SINH},
{"SQR", 7, 8, 0, UNARY_OPERATOR, SQU_RT},
{"SQRT", 7, 8, 0, UNARY_OPERATOR, SQU_RT},
{"TAN", 7, 8, 0, UNARY_OPERATOR, TAN},
{"TANH", 7, 8, 0, UNARY_OPERATOR, TANH},
{"VAL", 0, 0, 1, OPERAND, FETCH_VAL},
{"~", 7, 8, 0, UNARY_OPERATOR, BIT_NOT},
};
static const ELEMENT operators[] = {
/* name prio's stack element type opcode */
{"!=", 3, 3, -1, BINARY_OPERATOR,NOT_EQ},
{"#", 3, 3, -1, BINARY_OPERATOR,NOT_EQ},
{"%", 5, 5, -1, BINARY_OPERATOR,MODULO},
{"&", 2, 2, -1, BINARY_OPERATOR,BIT_AND},
{"&&", 2, 2, -1, BINARY_OPERATOR,REL_AND},
{")", 0, 0, 0, CLOSE_PAREN, NOT_GENERATED},
{"*", 5, 5, -1, BINARY_OPERATOR,MULT},
{"**", 6, 6, -1, BINARY_OPERATOR,POWER},
{"+", 4, 4, -1, BINARY_OPERATOR,ADD},
{",", 0, 0, 0, SEPERATOR, NOT_GENERATED},
{"-", 4, 4, -1, BINARY_OPERATOR,SUB},
{"/", 5, 5, -1, BINARY_OPERATOR,DIV},
{":", 0, 0, -1, CONDITIONAL, COND_ELSE},
{":=", 0, 0, -1, STORE_OPERATOR, STORE_A},
{";", 0, 0, 0, EXPR_TERMINATOR,NOT_GENERATED},
{"<", 3, 3, -1, BINARY_OPERATOR,LESS_THAN},
{"<<", 2, 2, -1, BINARY_OPERATOR,LEFT_SHIFT},
{"<=", 3, 3, -1, BINARY_OPERATOR,LESS_OR_EQ},
{"=", 3, 3, -1, BINARY_OPERATOR,EQUAL},
{"==", 3, 3, -1, BINARY_OPERATOR,EQUAL},
{">", 3, 3, -1, BINARY_OPERATOR,GR_THAN},
{">=", 3, 3, -1, BINARY_OPERATOR,GR_OR_EQ},
{">>", 2, 2, -1, BINARY_OPERATOR,RIGHT_SHIFT},
{"?", 0, 0, -1, CONDITIONAL, COND_IF},
{"AND", 2, 2, -1, BINARY_OPERATOR,BIT_AND},
{"OR", 1, 1, -1, BINARY_OPERATOR,BIT_OR},
{"XOR", 1, 1, -1, BINARY_OPERATOR,BIT_EXCL_OR},
{"^", 6, 6, -1, BINARY_OPERATOR,POWER},
{"|", 1, 1, -1, BINARY_OPERATOR,BIT_OR},
{"||", 1, 1, -1, BINARY_OPERATOR,REL_OR},
};
/* get_element
*
* find the next expression element in the infix expression
*/
static int
get_element(int opnd, const char **ppsrc, const ELEMENT **ppel)
{
const ELEMENT *ptable, *pel;
*ppel = NULL;
while (isspace((int) (unsigned char) **ppsrc)) ++*ppsrc;
if (**ppsrc == '\0') return FALSE;
if (opnd) {
ptable = operands;
pel = ptable + NELEMENTS(operands) - 1;
} else {
ptable = operators;
pel = ptable + NELEMENTS(operators) - 1;
}
while (pel >= ptable) {
size_t len = strlen(pel->name);
if (epicsStrnCaseCmp(*ppsrc, pel->name, len) == 0) {
*ppel = pel;
*ppsrc += len;
return TRUE;
}
--pel;
}
return FALSE;
}
/* postfix
*
* convert an infix expression to a postfix expression
*/
epicsShareFunc long
postfix(const char *psrc, char *pout, short *perror)
{
ELEMENT stack[80];
ELEMENT *pstacktop = stack;
const ELEMENT *pel;
int operand_needed = TRUE;
int runtime_depth = 0;
int cond_count = 0;
char * const pdest = pout;
char *pnext;
if (psrc == NULL || *psrc == '\0' ||
pout == NULL || perror == NULL) {
if (perror) *perror = CALC_ERR_NULL_ARG;
if (pout) *pout = END_EXPRESSION;
return -1;
}
/* place the expression elements into postfix */
*pout = END_EXPRESSION;
*perror = CALC_ERR_NONE;
while (get_element(operand_needed, &psrc, &pel)) {
switch (pel->type) {
case OPERAND:
*pout++ = pel->code;
runtime_depth += pel->runtime_effect;
operand_needed = FALSE;
break;
case LITERAL_OPERAND:
runtime_depth += pel->runtime_effect;
psrc -= strlen(pel->name);
if (pel->code == LITERAL_DOUBLE) {
double lit_d;
epicsInt32 lit_i;
if (epicsParseDouble(psrc, &lit_d, &pnext)) {
*perror = CALC_ERR_BAD_LITERAL;
goto bad;
}
psrc = pnext;
lit_i = (epicsInt32) lit_d;
if (lit_d != (double) lit_i) {
*pout++ = pel->code;
memcpy(pout, &lit_d, sizeof(double));
pout += sizeof(double);
} else {
*pout++ = LITERAL_INT;
memcpy(pout, &lit_i, sizeof(epicsInt32));
pout += sizeof(epicsInt32);
}
}
else {
epicsUInt32 lit_ui;
assert(pel->code == LITERAL_INT);
if (epicsParseUInt32(psrc, &lit_ui, 0, &pnext)) {
*perror = CALC_ERR_BAD_LITERAL;
goto bad;
}
psrc = pnext;
*pout++ = LITERAL_INT;
memcpy(pout, &lit_ui, sizeof(epicsUInt32));
pout += sizeof(epicsUInt32);
}
operand_needed = FALSE;
break;
case STORE_OPERATOR:
if (pout == pdest || pstacktop > stack ||
*--pout < FETCH_A || *pout > FETCH_L) {
*perror = CALC_ERR_BAD_ASSIGNMENT;
goto bad;
}
/* Convert fetch into a store on the stack */
*++pstacktop = *pel;
pstacktop->code = STORE_A + *pout - FETCH_A;
runtime_depth -= 1;
operand_needed = TRUE;
break;
case UNARY_OPERATOR:
case VARARG_OPERATOR:
/* Move operators of >= priority to the output */
while ((pstacktop > stack) &&
(pstacktop->in_stack_pri >= pel->in_coming_pri)) {
*pout++ = pstacktop->code;
if (pstacktop->type == VARARG_OPERATOR) {
*pout++ = 1 - pstacktop->runtime_effect;
}
runtime_depth += pstacktop->runtime_effect;
pstacktop--;
}
/* Push new operator onto stack */
pstacktop++;
*pstacktop = *pel;
break;
case BINARY_OPERATOR:
/* Move operators of >= priority to the output */
while ((pstacktop > stack) &&
(pstacktop->in_stack_pri >= pel->in_coming_pri)) {
*pout++ = pstacktop->code;
if (pstacktop->type == VARARG_OPERATOR) {
*pout++ = 1 - pstacktop->runtime_effect;
}
runtime_depth += pstacktop->runtime_effect;
pstacktop--;
}
/* Push new operator onto stack */
pstacktop++;
*pstacktop = *pel;
operand_needed = TRUE;
break;
case SEPERATOR:
/* Move operators to the output until open paren */
while (pstacktop->name[0] != '(') {
if (pstacktop <= stack+1) {
*perror = CALC_ERR_BAD_SEPERATOR;
goto bad;
}
*pout++ = pstacktop->code;
if (pstacktop->type == VARARG_OPERATOR) {
*pout++ = 1 - pstacktop->runtime_effect;
}
runtime_depth += pstacktop->runtime_effect;
pstacktop--;
}
operand_needed = TRUE;
pstacktop->runtime_effect -= 1;
break;
case CLOSE_PAREN:
/* Move operators to the output until matching paren */
while (pstacktop->name[0] != '(') {
if (pstacktop <= stack+1) {
*perror = CALC_ERR_PAREN_NOT_OPEN;
goto bad;
}
*pout++ = pstacktop->code;
if (pstacktop->type == VARARG_OPERATOR) {
*pout++ = 1 - pstacktop->runtime_effect;
}
runtime_depth += pstacktop->runtime_effect;
pstacktop--;
}
pstacktop--; /* remove ( from stack */
/* if there is a vararg operator before the opening paren,
it inherits the (opening) paren's stack effect */
if ((pstacktop > stack) &&
pstacktop->type == VARARG_OPERATOR) {
pstacktop->runtime_effect = (pstacktop+1)->runtime_effect;
/* check for no arguments */
if (pstacktop->runtime_effect > 0) {
*perror = CALC_ERR_INCOMPLETE;
goto bad;
}
}
break;
case CONDITIONAL:
/* Move operators of > priority to the output */
while ((pstacktop > stack) &&
(pstacktop->in_stack_pri > pel->in_coming_pri)) {
*pout++ = pstacktop->code;
if (pstacktop->type == VARARG_OPERATOR) {
*pout++ = 1 - pstacktop->runtime_effect;
}
runtime_depth += pstacktop->runtime_effect;
pstacktop--;
}
/* Add new element to the output */
*pout++ = pel->code;
runtime_depth += pel->runtime_effect;
/* For : operator, also push COND_END code to stack */
if (pel->name[0] == ':') {
if (--cond_count < 0) {
*perror = CALC_ERR_CONDITIONAL;
goto bad;
}
pstacktop++;
*pstacktop = *pel;
pstacktop->code = COND_END;
pstacktop->runtime_effect = 0;
} else {
cond_count++;
}
operand_needed = TRUE;
break;
case EXPR_TERMINATOR:
/* Move everything from stack to the output */
while (pstacktop > stack) {
if (pstacktop->name[0] == '(') {
*perror = CALC_ERR_PAREN_OPEN;
goto bad;
}
*pout++ = pstacktop->code;
if (pstacktop->type == VARARG_OPERATOR) {
*pout++ = 1 - pstacktop->runtime_effect;
}
runtime_depth += pstacktop->runtime_effect;
pstacktop--;
}
if (cond_count != 0) {
*perror = CALC_ERR_CONDITIONAL;
goto bad;
}
if (runtime_depth > 1) {
*perror = CALC_ERR_TOOMANY;
goto bad;
}
operand_needed = TRUE;
break;
default:
*perror = CALC_ERR_INTERNAL;
goto bad;
}
if (runtime_depth < 0) {
*perror = CALC_ERR_UNDERFLOW;
goto bad;
}
if (runtime_depth >= CALCPERFORM_STACK) {
*perror = CALC_ERR_OVERFLOW;
goto bad;
}
}
if (*psrc != '\0') {
*perror = CALC_ERR_SYNTAX;
goto bad;
}
/* Move everything from stack to the output */
while (pstacktop > stack) {
if (pstacktop->name[0] == '(') {
*perror = CALC_ERR_PAREN_OPEN;
goto bad;
}
*pout++ = pstacktop->code;
if (pstacktop->type == VARARG_OPERATOR) {
*pout++ = 1 - pstacktop->runtime_effect;
}
runtime_depth += pstacktop->runtime_effect;
pstacktop--;
}
*pout = END_EXPRESSION;
if (cond_count != 0) {
*perror = CALC_ERR_CONDITIONAL;
goto bad;
}
if (operand_needed || runtime_depth != 1) {
*perror = CALC_ERR_INCOMPLETE;
goto bad;
}
return 0;
bad:
*pdest = END_EXPRESSION;
return -1;
}
/* calcErrorStr
*
* Return a message string appropriate for the given error code
*/
epicsShareFunc const char *
calcErrorStr(short error)
{
static const char *errStrs[] = {
"No error",
"Too many results returned",
"Badly formed numeric literal",
"Bad assignment target",
"Comma without enclosing parentheses",
"Close parenthesis found without open",
"Parenthesis still open at end of expression",
"Unbalanced conditional ?: operators",
"Incomplete expression, operand missing",
"Not enough operands provided",
"Runtime stack overflow",
"Syntax error, unknown operator/operand",
"NULL or empty input argument to postfix()",
"Internal error, unknown element type",
};
if (error < CALC_ERR_NONE || error > CALC_ERR_INTERNAL)
return NULL;
return errStrs[error];
}
/* calcExprDump
*
* Disassemble the given postfix instructions to stdout
*/
epicsShareFunc void
calcExprDump(const char *pinst)
{
static const char *opcodes[] = {
"End Expression",
/* Operands */
"LITERAL_DOUBLE", "LITERAL_INT", "VAL",
"FETCH_A", "FETCH_B", "FETCH_C", "FETCH_D", "FETCH_E", "FETCH_F",
"FETCH_G", "FETCH_H", "FETCH_I", "FETCH_J", "FETCH_K", "FETCH_L",
/* Assignment */
"STORE_A", "STORE_B", "STORE_C", "STORE_D", "STORE_E", "STORE_F",
"STORE_G", "STORE_H", "STORE_I", "STORE_J", "STORE_K", "STORE_L",
/* Trigonometry Constants */
"CONST_PI",
"CONST_D2R",
"CONST_R2D",
/* Arithmetic */
"UNARY_NEG",
"ADD",
"SUB",
"MULT",
"DIV",
"MODULO",
"POWER",
/* Algebraic */
"ABS_VAL",
"EXP",
"LOG_10",
"LOG_E",
"MAX",
"MIN",
"SQU_RT",
/* Trigonometric */
"ACOS",
"ASIN",
"ATAN",
"ATAN2",
"COS",
"COSH",
"SIN",
"SINH",
"TAN",
"TANH",
/* Numeric */
"CEIL",
"FLOOR",
"FINITE",
"ISINF",
"ISNAN",
"NINT",
"RANDOM",
/* Boolean */
"REL_OR",
"REL_AND",
"REL_NOT",
/* Bitwise */
"BIT_OR",
"BIT_AND",
"BIT_EXCL_OR",
"BIT_NOT",
"RIGHT_SHIFT",
"LEFT_SHIFT",
/* Relationals */
"NOT_EQ",
"LESS_THAN",
"LESS_OR_EQ",
"EQUAL",
"GR_OR_EQ",
"GR_THAN",
/* Conditional */
"COND_IF",
"COND_ELSE",
"COND_END",
/* Misc */
"NOT_GENERATED"
};
char op;
double lit_d;
epicsInt32 lit_i;
while ((op = *pinst) != END_EXPRESSION) {
switch (op) {
case LITERAL_DOUBLE:
memcpy(&lit_d, ++pinst, sizeof(double));
printf("\tDouble %g\n", lit_d);
pinst += sizeof(double);
break;
case LITERAL_INT:
memcpy(&lit_i, ++pinst, sizeof(epicsInt32));
printf("\tInteger %d (0x%x)\n", lit_i, lit_i);
pinst += sizeof(epicsInt32);
break;
case MIN:
case MAX:
case FINITE:
case ISNAN:
printf("\t%s, %d arg(s)\n", opcodes[(int) op], *++pinst);
pinst++;
break;
default:
printf("\t%s\n", opcodes[(int) op]);
pinst++;
}
}
}

View File

@@ -1,89 +0,0 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* postfix.h
* Original Author: Bob Dalesio
* Date: 9-21-88
*/
#ifndef INCpostfixh
#define INCpostfixh
#include "shareLib.h"
#define CALCPERFORM_NARGS 12
#define CALCPERFORM_STACK 80
#define INFIX_TO_POSTFIX_SIZE(n) ((n)*21/6)
/* The above expression is an estimate of the maximum postfix buffer
* size needed for a given infix expression buffer (the argument must count
* the trailing nil byte in the input expression string). The actual size
* needed is never larger than this value, although it is actually a
* few bytes smaller for some sizes.
*
* The maximum expansion from infix to postfix is for the sub-expression
* .1?.1:
* which is 6 characters long and results in 21 bytes of postfix:
* .1 => LITERAL_DOUBLE + 8 byte value
* ? => COND_IF
* .1 => LITERAL_DOUBLE + 8 byte value
* : => COND_ELSE
* ...
* => COND_END
* For other short expressions the factor 21/6 always gives a big enough
* postfix buffer (proven by hand, look at '1+' and '.1+' as well).
*/
/* These are not hard limits, just default sizes for the database */
#define MAX_INFIX_SIZE 100
#define MAX_POSTFIX_SIZE INFIX_TO_POSTFIX_SIZE(MAX_INFIX_SIZE)
/* Error numbers from postfix */
#define CALC_ERR_NONE 0 /* No error */
#define CALC_ERR_TOOMANY 1 /* Too many results returned */
#define CALC_ERR_BAD_LITERAL 2 /* Bad numeric literal */
#define CALC_ERR_BAD_ASSIGNMENT 3 /* Bad assignment target */
#define CALC_ERR_BAD_SEPERATOR 4 /* Comma without parentheses */
#define CALC_ERR_PAREN_NOT_OPEN 5 /* Close parenthesis without open */
#define CALC_ERR_PAREN_OPEN 6 /* Open parenthesis at end of expression */
#define CALC_ERR_CONDITIONAL 7 /* Unbalanced conditional ?: operators */
#define CALC_ERR_INCOMPLETE 8 /* Incomplete expression, operand missing */
#define CALC_ERR_UNDERFLOW 9 /* Runtime stack would underflow */
#define CALC_ERR_OVERFLOW 10 /* Runtime stack would overflow */
#define CALC_ERR_SYNTAX 11 /* Syntax error */
#define CALC_ERR_NULL_ARG 12 /* NULL or empty input argument */
#define CALC_ERR_INTERNAL 13 /* Internal error, bad element type */
/* Changes in the above errors must also be made in calcErrorStr() */
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc long
postfix(const char *pinfix, char *ppostfix, short *perror);
epicsShareFunc long
calcPerform(double *parg, double *presult, const char *ppostfix);
epicsShareFunc long
calcArgUsage(const char *ppostfix, unsigned long *pinputs, unsigned long *pstores);
epicsShareFunc const char *
calcErrorStr(short error);
epicsShareFunc void
calcExprDump(const char *pinst);
#ifdef __cplusplus
}
#endif
#endif /* INCpostfixh */

View File

@@ -1,104 +0,0 @@
/*************************************************************************\
* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* postfixPvt.h
* Original Author: Bob Dalesio
* Date: 9-21-88
*/
/* Notes:
* 1. The FETCH_A through FETCH_L and STORE_A through STORE_L opcodes must
* be contiguous.
* 2. The LITERAL opcodes are followed by a binary representation of their
* values, but these are not aligned properly.
* 3. The var-arg functions MIN, MAX, FINITE and ISNAN are followed by
* a byte giving the number of arguments to process.
* 4. You can't use strlen() on an RPN buffer since the literal values
* can contain zero bytes.
*/
#ifndef INCpostfixPvth
#define INCpostfixPvth
/* RPN opcodes */
typedef enum {
END_EXPRESSION = 0,
/* Operands */
LITERAL_DOUBLE, LITERAL_INT, FETCH_VAL,
FETCH_A, FETCH_B, FETCH_C, FETCH_D, FETCH_E, FETCH_F,
FETCH_G, FETCH_H, FETCH_I, FETCH_J, FETCH_K, FETCH_L,
/* Assignment */
STORE_A, STORE_B, STORE_C, STORE_D, STORE_E, STORE_F,
STORE_G, STORE_H, STORE_I, STORE_J, STORE_K, STORE_L,
/* Trigonometry Constants */
CONST_PI,
CONST_D2R,
CONST_R2D,
/* Arithmetic */
UNARY_NEG,
ADD,
SUB,
MULT,
DIV,
MODULO,
POWER,
/* Algebraic */
ABS_VAL,
EXP,
LOG_10,
LOG_E,
MAX,
MIN,
SQU_RT,
/* Trigonometric */
ACOS,
ASIN,
ATAN,
ATAN2,
COS,
COSH,
SIN,
SINH,
TAN,
TANH,
/* Numeric */
CEIL,
FLOOR,
FINITE,
ISINF,
ISNAN,
NINT,
RANDOM,
/* Boolean */
REL_OR,
REL_AND,
REL_NOT,
/* Bitwise */
BIT_OR,
BIT_AND,
BIT_EXCL_OR,
BIT_NOT,
RIGHT_SHIFT,
LEFT_SHIFT,
/* Relationals */
NOT_EQ,
LESS_THAN,
LESS_OR_EQ,
EQUAL,
GR_OR_EQ,
GR_THAN,
/* Conditional */
COND_IF,
COND_ELSE,
COND_END,
/* Misc */
NOT_GENERATED
} rpn_opcode;
#endif /* INCpostfixPvth */

308
src/client/CASG.cpp Normal file
View File

@@ -0,0 +1,308 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Jeffrey O. Hill
*/
#include <string>
#include <stdexcept>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "errlog.h"
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "syncGroup.h"
#include "oldAccess.h"
#include "cac.h"
#include "sgAutoPtr.h"
CASG::CASG ( epicsGuard < epicsMutex > & guard, ca_client_context & cacIn ) :
client ( cacIn ), magic ( CASG_MAGIC )
{
client.installCASG ( guard, *this );
}
CASG::~CASG ()
{
}
void CASG::destructor (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
if ( this->verify ( guard ) ) {
this->reset ( cbGuard, guard );
this->client.uninstallCASG ( guard, *this );
this->magic = 0;
}
else {
this->printFormated ( "cac: attempt to destroy invalid sync group ignored\n" );
}
this->~CASG ();
}
bool CASG::verify ( epicsGuard < epicsMutex > & ) const
{
return ( this->magic == CASG_MAGIC );
}
/*
* CASG::block ()
*/
int CASG::block (
epicsGuard < epicsMutex > * pcbGuard,
epicsGuard < epicsMutex > & guard,
double timeout )
{
epicsTime cur_time;
epicsTime beg_time;
double delay;
double remaining;
int status;
guard.assertIdenticalMutex ( this->client.mutexRef() );
// prevent recursion nightmares by disabling blocking
// for IO from within a CA callback.
if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) {
return ECA_EVDISALLOW;
}
if ( timeout < 0.0 ) {
return ECA_TIMEOUT;
}
cur_time = epicsTime::getCurrent ();
this->client.flush ( guard );
beg_time = cur_time;
delay = 0.0;
while ( 1 ) {
if ( this->ioPendingList.count() == 0u ) {
status = ECA_NORMAL;
break;
}
remaining = timeout - delay;
if ( remaining <= CAC_SIGNIFICANT_DELAY ) {
/*
* Make sure that we take care of
* recv backlog at least once
*/
status = ECA_TIMEOUT;
break;
}
if ( pcbGuard ) {
epicsGuardRelease < epicsMutex > unguard ( guard );
{
epicsGuardRelease < epicsMutex > uncbGuard ( *pcbGuard );
this->sem.wait ( remaining );
}
}
else {
epicsGuardRelease < epicsMutex > unguard ( guard );
this->sem.wait ( remaining );
}
/*
* force a time update
*/
cur_time = epicsTime::getCurrent ();
delay = cur_time - beg_time;
}
return status;
}
void CASG::reset (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
this->destroyCompletedIO ( cbGuard, guard );
this->destroyPendingIO ( cbGuard, guard );
}
// lock must be applied
void CASG::destroyCompletedIO (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
syncGroupNotify * pNotify;
while ( ( pNotify = this->ioCompletedList.get () ) ) {
pNotify->destroy ( cbGuard, guard );
}
}
void CASG::destroyPendingIO (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
while ( syncGroupNotify * pNotify = this->ioPendingList.first () ) {
pNotify->cancel ( cbGuard, guard );
// cancel must release the guard while
// canceling put callbacks so we
// must double check list membership
if ( pNotify->ioPending ( guard ) ) {
this->ioPendingList.remove ( *pNotify );
}
else {
this->ioCompletedList.remove ( *pNotify );
}
pNotify->destroy ( cbGuard, guard );
}
}
void CASG::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->client.mutexRef () );
this->show ( guard, level );
}
void CASG::show (
epicsGuard < epicsMutex > & guard, unsigned level ) const
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
::printf ( "Sync Group: id=%u, magic=%u, opPend=%u\n",
this->getId (), this->magic, this->ioPendingList.count () );
if ( level ) {
::printf ( "\tPending" );
tsDLIterConst < syncGroupNotify > notifyPending =
this->ioPendingList.firstIter ();
while ( notifyPending.valid () ) {
notifyPending->show ( guard, level - 1u );
notifyPending++;
}
::printf ( "\tCompleted" );
tsDLIterConst < syncGroupNotify > notifyCompleted =
this->ioCompletedList.firstIter ();
while ( notifyCompleted.valid () ) {
notifyCompleted->show ( guard, level - 1u );
notifyCompleted++;
}
}
}
bool CASG::ioComplete (
CallbackGuard & cbGuard,
epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
this->destroyCompletedIO ( cbGuard, guard );
return this->ioPendingList.count () == 0u;
}
void CASG::put ( epicsGuard < epicsMutex > & guard, chid pChan,
unsigned type, arrayElementCount count, const void * pValue )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this );
pNotify = syncGroupWriteNotify::factory (
this->freeListWriteOP, *this, & CASG :: recycleWriteNotifyIO, pChan );
pNotify->begin ( guard, type, count, pValue );
pNotify.release ();
}
void CASG::get ( epicsGuard < epicsMutex > & guard, chid pChan,
unsigned type, arrayElementCount count, void *pValue )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this );
pNotify = syncGroupReadNotify::factory (
this->freeListReadOP, *this, & CASG :: recycleReadNotifyIO, pChan, pValue );
pNotify->begin ( guard, type, count );
pNotify.release ();
}
void CASG::completionNotify (
epicsGuard < epicsMutex > & guard, syncGroupNotify & notify )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
this->ioPendingList.remove ( notify );
this->ioCompletedList.add ( notify );
if ( this->ioPendingList.count () == 0u ) {
this->sem.signal ();
}
}
void CASG :: recycleReadNotifyIO ( epicsGuard < epicsMutex > & guard,
syncGroupReadNotify & io )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
this->freeListReadOP.release ( & io );
}
void CASG :: recycleWriteNotifyIO ( epicsGuard < epicsMutex > & guard,
syncGroupWriteNotify & io )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
this->freeListWriteOP.release ( & io );
}
int CASG :: printFormated ( const char *pformat, ... )
{
va_list theArgs;
int status;
va_start ( theArgs, pformat );
status = this->client.varArgsPrintFormated ( pformat, theArgs );
va_end ( theArgs );
return status;
}
void CASG::exception (
epicsGuard < epicsMutex > & guard,
int status, const char * pContext,
const char * pFileName, unsigned lineNo )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
if ( status != ECA_CHANDESTROY ) {
this->client.exception (
guard, status, pContext, pFileName, lineNo );
}
}
void CASG::exception (
epicsGuard < epicsMutex > & guard,
int status, const char * pContext,
const char * pFileName, unsigned lineNo, oldChannelNotify & chan,
unsigned type, arrayElementCount count, unsigned op )
{
guard.assertIdenticalMutex ( this->client.mutexRef() );
if ( status != ECA_CHANDESTROY ) {
this->client.exception (
guard, status, pContext, pFileName,
lineNo, chan, type, count, op );
}
}
void CASG::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
// placement operator delete is defined? I smell a ms rat
// because if I declare placement new and delete, but
// comment out the placement delete definition there are
// no undefined symbols.
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
__FILE__, __LINE__ );
}

4489
src/client/CAref.html Normal file

File diff suppressed because it is too large Load Diff

136
src/client/Makefile Normal file
View File

@@ -0,0 +1,136 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
TOP = ../..
include $(TOP)/configure/CONFIG
HTMLS += CAref.html
#
# includes to install from this subproject
#
INC += cadef.h
INC += caerr.h
INC += caeventmask.h
INC += caProto.h
INC += db_access.h
INC += addrList.h
INC += cacIO.h
INC += caDiagnostics.h
INC += net_convert.h
INC += caVersion.h
INC += caVersionNum.h
LIBSRCS += cac.cpp
LIBSRCS += cacChannel.cpp
LIBSRCS += cacChannelNotify.cpp
LIBSRCS += cacContextNotify.cpp
LIBSRCS += cacReadNotify.cpp
LIBSRCS += cacWriteNotify.cpp
LIBSRCS += cacStateNotify.cpp
LIBSRCS += access.cpp
LIBSRCS += iocinf.cpp
LIBSRCS += convert.cpp
LIBSRCS += test_event.cpp
LIBSRCS += repeater.cpp
LIBSRCS += searchTimer.cpp
LIBSRCS += disconnectGovernorTimer.cpp
LIBSRCS += repeaterSubscribeTimer.cpp
LIBSRCS += baseNMIU.cpp
LIBSRCS += nciu.cpp
LIBSRCS += netiiu.cpp
LIBSRCS += udpiiu.cpp
LIBSRCS += tcpiiu.cpp
LIBSRCS += noopiiu.cpp
LIBSRCS += netReadNotifyIO.cpp
LIBSRCS += netWriteNotifyIO.cpp
LIBSRCS += netSubscription.cpp
LIBSRCS += tcpSendWatchdog.cpp
LIBSRCS += tcpRecvWatchdog.cpp
LIBSRCS += bhe.cpp
LIBSRCS += ca_client_context.cpp
LIBSRCS += oldChannelNotify.cpp
LIBSRCS += oldSubscription.cpp
LIBSRCS += getCallback.cpp
LIBSRCS += getCopy.cpp
LIBSRCS += putCallback.cpp
LIBSRCS += syncgrp.cpp
LIBSRCS += CASG.cpp
LIBSRCS += syncGroupNotify.cpp
LIBSRCS += syncGroupReadNotify.cpp
LIBSRCS += syncGroupWriteNotify.cpp
LIBSRCS += localHostName.cpp
LIBSRCS += comQueRecv.cpp
LIBSRCS += comQueSend.cpp
LIBSRCS += comBuf.cpp
LIBSRCS += hostNameCache.cpp
LIBSRCS += msgForMultiplyDefinedPV.cpp
LIBRARY=ca
ca_RCS = ca.rc
ca_LIBS = Com
ca_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
# libs needed for PROD and TESTPRODUCT
PROD_LIBS = ca Com
# needed when its an object library build
PROD_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
PROD_DEFAULT += caRepeater catime acctst caConnTest casw caEventRate
PROD_vxWorks = -nil-
PROD_RTEMS = -nil-
PROD_iOS = -nil-
OBJS_vxWorks = catime acctst caConnTest casw caEventRate acctstRegister
caRepeater_SRCS = caRepeater.cpp
catime_SRCS = catimeMain.c catime.c
acctst_SRCS = acctstMain.c acctst.c
caEventRate_SRCS = caEventRateMain.cpp caEventRate.cpp
casw_SRCS = casw.cpp
caConnTest_SRCS = caConnTestMain.cpp caConnTest.cpp
casw_SYS_LIBS_solaris = socket
SCRIPTS_HOST = S99caRepeater
SCRIPTS_Linux = caRepeater.service
EXPAND += S99caRepeater@
EXPAND += caRepeater.service@
EXPAND_VARS = INSTALL_BIN=$(abspath $(INSTALL_BIN))
SRC_DIRS += $(TOP)/src/client/test
PROD_HOST += ca_test
ca_test_SRCS = ca_test_main.c ca_test.c
ca_test_LIBS = ca Com
ca_test_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
OBJS_vxWorks += ca_test
EXPANDVARS += EPICS_CA_MAJOR_VERSION
EXPANDVARS += EPICS_CA_MINOR_VERSION
EXPANDVARS += EPICS_CA_MAINTENANCE_VERSION
EXPANDVARS += EPICS_CA_DEVELOPMENT_FLAG
EXPANDFLAGS += $(foreach var,$(EXPANDVARS),-D$(var)="$(strip $($(var)))")
# shared library ABI version.
SHRLIB_VERSION = 4.13.1
include $(TOP)/configure/RULES
# Can't use EXPAND as generated headers must appear
# in O.Common, but EXPAND emits rules for O.$(T_A)
../O.Common/caVersionNum.h: ../caVersionNum.h@
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@

28
src/client/S99caRepeater@ Normal file
View File

@@ -0,0 +1,28 @@
#!/bin/sh
#
# System-V init script for the EPICS CA Repeater.
#
INSTALL_BIN=@INSTALL_BIN@
# To change the default values for the EPICS environment parameters,
# uncomment and modify the relevant lines below. These are the only
# EPICS environment variables that the CA Repeater makes use of.
# EPICS_CA_REPEATER_PORT="5065" export EPICS_CA_REPEATER_PORT
if [ $1 = "start" ]; then
if [ -x $INSTALL_BIN/caRepeater ]; then
echo "Starting EPICS CA Repeater "
$INSTALL_BIN/caRepeater &
fi
else
if [ $1 = "stop" ]; then
pid=`ps -e | sed -ne '/caRepeat/s/^ *\([1-9][0-9]*\).*$/\1/p'`
if [ "${pid}" != "" ]; then
echo "Stopping EPICS CA Repeater "
kill ${pid}
fi
fi
fi

39
src/client/SearchDest.h Normal file
View File

@@ -0,0 +1,39 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef SearchDest_h
#define SearchDest_h
#include <osiSock.h>
#include <epicsTime.h>
#include <tsDLList.h>
#include "caProto.h"
class channelNode;
class epicsMutex;
template < class T > class epicsGuard;
struct SearchDest :
public tsDLNode < SearchDest > {
virtual ~SearchDest () {};
struct Callback {
virtual ~Callback () {};
virtual void notify (
const caHdr & msg, const void * pPayload,
const osiSockAddr & addr, const epicsTime & ) = 0;
virtual void show (
epicsGuard < epicsMutex > &, unsigned level ) const = 0;
};
virtual void searchRequest ( epicsGuard < epicsMutex > &,
const char * pbuf, size_t len ) = 0;
virtual void show ( epicsGuard < epicsMutex > &, unsigned level ) const = 0;
};
#endif // SearchDest_h

1118
src/client/access.cpp Normal file

File diff suppressed because it is too large Load Diff

3555
src/client/acctst.c Normal file

File diff suppressed because it is too large Load Diff

70
src/client/acctstMain.c Normal file
View File

@@ -0,0 +1,70 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "cadef.h"
#include "caDiagnostics.h"
int main ( int argc, char **argv )
{
unsigned progressLoggingLevel;
unsigned channelCount;
unsigned repetitionCount;
enum ca_preemptive_callback_select preempt;
int aBoolean;
if ( argc < 2 || argc > 6 ) {
printf ("usage: %s <PV name> [progress logging level] [channel count] "
"[repetition count] [enable preemptive callback]\n",
argv[0] );
return 1;
}
if ( argc >= 3 ) {
progressLoggingLevel = atoi ( argv[2] );
}
else {
progressLoggingLevel = 0;
}
if ( argc >= 4 ) {
channelCount = atoi ( argv[3] );
}
else {
channelCount = 20000;
}
if ( argc >= 5 ) {
repetitionCount = atoi ( argv[4] );
}
else {
repetitionCount = 1;
}
if ( argc >= 6 ) {
aBoolean = atoi ( argv[5] );
}
else {
aBoolean = 0;
}
if ( aBoolean ) {
preempt = ca_enable_preemptive_callback;
}
else {
preempt = ca_disable_preemptive_callback;
}
acctst ( argv[1], progressLoggingLevel, channelCount, repetitionCount, preempt );
return 0;
}

View File

@@ -0,0 +1,69 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* CA client library diagnostics IOC shell registration
* Authors:
* Jeff Hill
*/
#include <iocsh.h>
#include "caDiagnostics.h"
/* Information needed by iocsh */
static const iocshArg acctstArg0 = { "channel name", iocshArgString };
static const iocshArg acctstArg1 = { "interest level", iocshArgInt };
static const iocshArg acctstArg2 = { "channel count", iocshArgInt };
static const iocshArg acctstArg3 = { "repetition count", iocshArgInt };
static const iocshArg acctstArg4 = { "preemptive callback select", iocshArgInt };
static const iocshArg *acctstArgs[] =
{
&acctstArg0,
&acctstArg1,
&acctstArg2,
&acctstArg3,
&acctstArg4
};
static const iocshFuncDef acctstFuncDef = {"acctst", 5, acctstArgs};
/* Wrapper called by iocsh, selects the argument types that print needs */
static void acctstCallFunc(const iocshArgBuf *args) {
if ( args[1].ival < 0 ) {
printf ( "negative interest level not allowed\n" );
return;
}
if ( args[2].ival < 0 ) {
printf ( "negative channel count not allowed\n" );
return;
}
if ( args[3].ival < 0 ) {
printf ( "negative repetition count not allowed\n" );
return;
}
acctst (
args[0].sval, /* channel name */
( unsigned ) args[1].ival, /* interest level */
( unsigned ) args[2].ival, /* channel count */
( unsigned ) args[3].ival, /* repetition count */
( ca_preemptive_callback_select ) args[4].ival ); /* preemptive callback select */
}
struct AutoInit {
AutoInit ();
};
AutoInit :: AutoInit ()
{
iocshRegister ( &acctstFuncDef, acctstCallFunc );
}
AutoInit autoInit;

40
src/client/addrList.h Normal file
View File

@@ -0,0 +1,40 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef addrListh
#define addrListh
#include "shareLib.h"
#include "envDefs.h"
#include "osiSock.h"
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc void epicsShareAPI configureChannelAccessAddressList
( struct ELLLIST *pList, SOCKET sock, unsigned short port );
epicsShareFunc int epicsShareAPI addAddrToChannelAccessAddressList
( struct ELLLIST *pList, const ENV_PARAM *pEnv,
unsigned short port, int ignoreNonDefaultPort );
epicsShareFunc void epicsShareAPI printChannelAccessAddressList
( const struct ELLLIST *pList );
epicsShareFunc void epicsShareAPI removeDuplicateAddresses
( struct ELLLIST *pDestList, ELLLIST *pSrcList, int silent);
#ifdef __cplusplus
}
#endif
#endif /* ifndef addrListh */

View File

@@ -0,0 +1,104 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef autoPtrFreeListh
#define autoPtrFreeListh
#ifdef epicsExportSharedSymbols
# define autoPtrFreeListh_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "tsFreeList.h"
#include "compilerDependencies.h"
#ifdef autoPtrFreeListh_epicsExportSharedSymbols
# define epicsExportSharedSymbols
#endif
template < class T, unsigned N = 0x400, class MUTEX = epicsMutex >
class autoPtrFreeList {
public:
autoPtrFreeList ( tsFreeList < T, N, MUTEX > &, T * );
~autoPtrFreeList ();
T & operator * () const;
T * operator -> () const;
T * get () const;
T * release ();
private:
T * p;
tsFreeList < T, N, MUTEX > & freeList;
// not implemented
autoPtrFreeList & operator = ( const autoPtrFreeList & );
autoPtrFreeList ( const autoPtrFreeList < T, N, MUTEX > & );
};
template < class T, unsigned N, class MUTEX >
inline autoPtrFreeList < T, N, MUTEX >::autoPtrFreeList (
tsFreeList < T, N, MUTEX > & freeListIn, T * pIn ) :
p ( pIn ), freeList ( freeListIn ) {}
template < class T, unsigned N, class MUTEX >
inline autoPtrFreeList < T, N, MUTEX >::~autoPtrFreeList ()
{
if ( this->p ) {
this->p->~T();
// its probably a good idea to require that the class has placement delete
// by calling it during cleanup if the compiler supports it
# if defined ( CXX_PLACEMENT_DELETE )
T::operator delete ( this->p, this->freeList );
# else
this->freeList.release ( this->p );
# endif
}
}
template < class T, unsigned N, class MUTEX >
inline T & autoPtrFreeList < T, N, MUTEX >::operator * () const
{
return * this->p;
}
template < class T, unsigned N, class MUTEX >
inline T * autoPtrFreeList < T, N, MUTEX >::operator -> () const
{
return this->p;
}
template < class T, unsigned N, class MUTEX >
inline T * autoPtrFreeList < T, N, MUTEX >::get () const
{
return this->p;
}
template < class T, unsigned N, class MUTEX >
inline T * autoPtrFreeList < T, N, MUTEX >::release ()
{
T *pTmp = this->p;
this->p = 0;
return pTmp;
}
#endif // #ifdef autoPtrFreeListh

View File

@@ -0,0 +1,92 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef autoPtrRecycleh
#define autoPtrRecycleh
template < class T >
class autoPtrRecycle {
public:
autoPtrRecycle (
epicsGuard < epicsMutex > &, chronIntIdResTable < baseNMIU > &,
cacRecycle &, T * );
~autoPtrRecycle ();
T & operator * () const;
T * operator -> () const;
T * get () const;
T * release ();
private:
T * p;
cacRecycle & r;
chronIntIdResTable < baseNMIU > & ioTable;
epicsGuard < epicsMutex > & guard;
// not implemented
autoPtrRecycle ( const autoPtrRecycle & );
autoPtrRecycle & operator = ( const autoPtrRecycle & );
};
template < class T >
inline autoPtrRecycle<T>::autoPtrRecycle (
epicsGuard < epicsMutex > & guardIn, chronIntIdResTable < baseNMIU > & tbl,
cacRecycle & rIn, T * pIn ) :
p ( pIn ), r ( rIn ), ioTable ( tbl ), guard ( guardIn ) {}
template < class T >
inline autoPtrRecycle<T>::~autoPtrRecycle ()
{
if ( this->p ) {
baseNMIU *pb = this->p;
this->ioTable.remove ( *pb );
pb->destroy ( this->guard, this->r );
}
}
template < class T >
inline T & autoPtrRecycle<T>::operator * () const
{
return * this->p;
}
template < class T >
inline T * autoPtrRecycle<T>::operator -> () const
{
return this->p;
}
template < class T >
inline T * autoPtrRecycle<T>::get () const
{
return this->p;
}
template < class T >
inline T * autoPtrRecycle<T>::release ()
{
T *pTmp = this->p;
this->p = 0;
return pTmp;
}
#endif // #ifdef autoPtrRecycleh

View File

@@ -8,24 +8,32 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
// simple type safe inline template functions to replace
// the min() and max() macros
//
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, the Regents of the University of California.
*
* Author: Jeff Hill
*/
#ifndef tsMinMaxh
#define tsMinMaxh
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
template <class T>
inline const T & tsMax ( const T & a, const T & b )
#include "iocinf.h"
#include "nciu.h"
#include "netIO.h"
baseNMIU::~baseNMIU ()
{
return ( a > b ) ? a : b;
}
template <class T>
inline const T & tsMin ( const T & a, const T & b )
{
return ( a < b ) ? a : b;
}
#endif // tsMinMaxh
void baseNMIU::forceSubscriptionUpdate (
epicsGuard < epicsMutex > &, nciu & )
{
}

358
src/client/bhe.cpp Normal file
View File

@@ -0,0 +1,358 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#include <string>
#include <stdexcept>
#include <limits.h>
#include <float.h>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "errlog.h"
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "virtualCircuit.h"
#include "bhe.h"
/*
* set average to -1.0 so that when the next beacon
* occurs we can distinguish between:
* o new server
* o existing server's beacon we are seeing
* for the first time shortly after program
* start up
*
* if creating this in response to a search reply
* and not in response to a beacon then
* we set the beacon time stamp to
* zero (so we can correctly compute the period
* between the 1st and 2nd beacons)
*/
bhe::bhe ( epicsMutex & mutexIn, const epicsTime & initialTimeStamp,
unsigned initialBeaconNumber, const inetAddrID & addr ) :
inetAddrID ( addr ), timeStamp ( initialTimeStamp ), averagePeriod ( - DBL_MAX ),
mutex ( mutexIn ), pIIU ( 0 ), lastBeaconNumber ( initialBeaconNumber )
{
# ifdef DEBUG
{
char name[64];
addr.name ( name, sizeof ( name ) );
::printf ( "created beacon entry for %s\n", name );
}
# endif
}
bhe::~bhe ()
{
}
void bhe::beaconAnomalyNotify ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->pIIU ) {
this->pIIU->beaconAnomalyNotify ( guard );
}
}
#ifdef DEBUG
void bhe::logBeacon ( const char * pDiagnostic,
const double & currentPeriod,
const epicsTime & currentTime )
{
if ( this->pIIU ) {
char name[64];
this->name ( name, sizeof ( name ) );
char date[64];
currentTime.strftime ( date, sizeof ( date ),
"%a %b %d %Y %H:%M:%S.%f");
::printf ( "%s cp=%g ap=%g %s %s\n",
pDiagnostic, currentPeriod,
this->averagePeriod, name, date );
}
}
#else
inline void bhe::logBeacon ( const char * /* pDiagnostic */,
const double & /* currentPeriod */,
const epicsTime & /* currentTime */ )
{
}
#endif
#ifdef DEBUG
void bhe::logBeaconDiscard ( unsigned beaconAdvance,
const epicsTime & currentTime )
{
if ( this->pIIU ) {
char name[64];
this->name ( name, sizeof ( name ) );
char date[64];
currentTime.strftime ( date, sizeof ( date ),
"%a %b %d %Y %H:%M:%S.%f");
::printf ( "bb %u %s %s\n",
beaconAdvance, name, date );
}
}
#else
void bhe::logBeaconDiscard ( unsigned /* beaconAdvance */,
const epicsTime & /* currentTime */ )
{
}
#endif
/*
* update beacon period
*
* updates beacon period, and looks for beacon anomalies
*/
bool bhe::updatePeriod (
epicsGuard < epicsMutex > & guard, const epicsTime & programBeginTime,
const epicsTime & currentTime, ca_uint32_t beaconNumber,
unsigned protocolRevision )
{
guard.assertIdenticalMutex ( this->mutex );
//
// this block is enetered if the beacon was created as a side effect of
// creating a connection and so we dont yet know the first beacon time
// and sequence number
//
if ( this->timeStamp == epicsTime () ) {
if ( CA_V410 ( protocolRevision ) ) {
this->lastBeaconNumber = beaconNumber;
}
this->beaconAnomalyNotify ( guard );
/*
* this is the 1st beacon seen - the beacon time stamp
* was not initialized during BHE create because
* a TCP/IP connection created the beacon.
* (nothing to do but set the beacon time stamp and return)
*/
this->timeStamp = currentTime;
logBeacon ( "fb", - DBL_MAX, currentTime );
return false;
}
// 1) detect beacon duplications due to redundant routes
// 2) detect lost beacons due to input queue overrun or damage
if ( CA_V410 ( protocolRevision ) ) {
unsigned beaconSeqAdvance;
if ( beaconNumber >= this->lastBeaconNumber ) {
beaconSeqAdvance = beaconNumber - this->lastBeaconNumber;
}
else {
beaconSeqAdvance = ( ca_uint32_max - this->lastBeaconNumber ) + beaconNumber;
}
this->lastBeaconNumber = beaconNumber;
// throw out sequence numbers just prior to, or the same as, the last one received
// (this situation is probably caused by a temporary duplicate route )
if ( beaconSeqAdvance == 0 || beaconSeqAdvance > ca_uint32_max - 256 ) {
logBeaconDiscard ( beaconSeqAdvance, currentTime );
return false;
}
// throw out sequence numbers that jump forward by only a few numbers
// (this situation is probably caused by a duplicate route
// or a beacon due to input queue overun)
if ( beaconSeqAdvance > 1 && beaconSeqAdvance < 4 ) {
logBeaconDiscard ( beaconSeqAdvance, currentTime );
return false;
}
}
// compute the beacon period (if we have seen at least two beacons)
bool netChange = false;
double currentPeriod = currentTime - this->timeStamp;
if ( this->averagePeriod < 0.0 ) {
double totalRunningTime;
this->beaconAnomalyNotify ( guard );
/*
* this is the 2nd beacon seen. We cant tell about
* the change in period at this point so we just
* initialize the average period and return.
*/
this->averagePeriod = currentPeriod;
logBeacon ( "fp", currentPeriod, currentTime );
/*
* ignore beacons seen for the first time shortly after
* init, but do not ignore beacons arriving with a short
* period because the IOC was rebooted soon after the
* client starts up.
*/
totalRunningTime = this->timeStamp - programBeginTime;
if ( currentPeriod <= totalRunningTime ) {
netChange = true;
}
}
else {
/*
* Is this an IOC seen because of a restored
* network segment?
*
* It may be possible to get false triggers here
* if the client is busy, but this does not cause
* problems because the echo response will tell us
* that the server is available
*/
if ( currentPeriod >= this->averagePeriod * 1.25 ) {
/*
* trigger on any missing beacon
* if connected to this server
*/
this->beaconAnomalyNotify ( guard );
if ( currentPeriod >= this->averagePeriod * 3.25 ) {
/*
* trigger on any 3 contiguous missing beacons
* if not connected to this server
*/
netChange = true;
}
logBeacon ( "bah", currentPeriod, currentTime );
}
/*
* Is this an IOC seen because of an IOC reboot
* (beacon come at a higher rate just after the
* IOC reboots). Lower tolarance here because we
* dont have to worry about lost beacons.
*
* It may be possible to get false triggers here
* if the client is busy, but this does not cause
* problems because the echo response will tell us
* that the server is available
*/
else if ( currentPeriod <= this->averagePeriod * 0.80 ) {
this->beaconAnomalyNotify ( guard );
netChange = true;
logBeacon ( "bal", currentPeriod, currentTime );
}
else if ( this->pIIU ) {
// update state of health for active virtual circuits
// if the beacon looks ok
this->pIIU->beaconArrivalNotify ( guard );
logBeacon ( "vb", currentPeriod, currentTime );
}
// update a running average period
this->averagePeriod = currentPeriod * 0.125 +
this->averagePeriod * 0.875;
}
this->timeStamp = currentTime;
return netChange;
}
void bhe::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->show ( guard, level );
}
void bhe::show ( epicsGuard < epicsMutex > &, unsigned level ) const
{
char host [64];
this->name ( host, sizeof ( host ) );
if ( this->averagePeriod == -DBL_MAX ) {
::printf ( "CA beacon hash entry for %s <no period estimate>\n",
host );
}
else {
::printf ( "CA beacon hash entry for %s with period estimate %f\n",
host, this->averagePeriod );
}
if ( level > 0u ) {
char date[64];
this->timeStamp.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
::printf ( "\tbeacon number %u, on %s\n",
this->lastBeaconNumber, date );
}
}
double bhe::period ( epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
return this->averagePeriod;
}
epicsTime bhe::updateTime ( epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
return this->timeStamp;
}
void bhe::registerIIU (
epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
{
guard.assertIdenticalMutex ( this->mutex );
this->pIIU = & iiu;
}
void bhe::unregisterIIU (
epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->pIIU == & iiu ) {
this->pIIU = 0;
this->timeStamp = epicsTime();
this->averagePeriod = - DBL_MAX;
logBeacon ( "ui", this->averagePeriod, epicsTime::getCurrent () );
}
}
void bhe::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
// placement operator delete is defined? I smell a ms rat
// because if I declare placement new and delete, but
// comment out the placement delete definition there are
// no undefined symbols.
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
__FILE__, __LINE__ );
}
void * bheFreeStore::allocate ( size_t size )
{
return freeList.allocate ( size );
}
void bheFreeStore::release ( void * pCadaver )
{
freeList.release ( pCadaver );
}
bheMemoryManager::~bheMemoryManager () {}

122
src/client/bhe.h Normal file
View File

@@ -0,0 +1,122 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#ifndef bheh
#define bheh
#ifdef epicsExportSharedSymbols
# define bhehEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "tsDLList.h"
#include "tsFreeList.h"
#include "epicsTime.h"
#include "compilerDependencies.h"
#ifdef bhehEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
#include "inetAddrID.h"
#include "caProto.h"
class tcpiiu;
class bheMemoryManager;
// using a pure abstract wrapper class around the free list avoids
// Tornado 2.0.1 GNU compiler bugs
class epicsShareClass bheMemoryManager {
public:
virtual ~bheMemoryManager ();
virtual void * allocate ( size_t ) = 0;
virtual void release ( void * ) = 0;
};
class bhe : public tsSLNode < bhe >, public inetAddrID {
public:
epicsShareFunc bhe (
epicsMutex &, const epicsTime & initialTimeStamp,
unsigned initialBeaconNumber, const inetAddrID & addr );
epicsShareFunc ~bhe ();
epicsShareFunc bool updatePeriod (
epicsGuard < epicsMutex > &,
const epicsTime & programBeginTime,
const epicsTime & currentTime, ca_uint32_t beaconNumber,
unsigned protocolRevision );
epicsShareFunc double period ( epicsGuard < epicsMutex > & ) const;
epicsShareFunc epicsTime updateTime ( epicsGuard < epicsMutex > & ) const;
epicsShareFunc void show ( unsigned level ) const;
epicsShareFunc void show ( epicsGuard < epicsMutex > &, unsigned /* level */ ) const;
epicsShareFunc void registerIIU ( epicsGuard < epicsMutex > &, tcpiiu & );
epicsShareFunc void unregisterIIU ( epicsGuard < epicsMutex > &, tcpiiu & );
epicsShareFunc void * operator new ( size_t size, bheMemoryManager & );
#ifdef CXX_PLACEMENT_DELETE
epicsShareFunc void operator delete ( void *, bheMemoryManager & );
#endif
private:
epicsTime timeStamp;
double averagePeriod;
epicsMutex & mutex;
tcpiiu * pIIU;
ca_uint32_t lastBeaconNumber;
void beaconAnomalyNotify ( epicsGuard < epicsMutex > & );
void logBeacon ( const char * pDiagnostic,
const double & currentPeriod,
const epicsTime & currentTime );
void logBeaconDiscard ( unsigned beaconAdvance,
const epicsTime & currentTime );
bhe ( const bhe & );
bhe & operator = ( const bhe & );
epicsShareFunc void operator delete ( void * );
};
// using a wrapper class around the free list avoids
// Tornado 2.0.1 GNU compiler bugs
class bheFreeStore : public bheMemoryManager {
public:
bheFreeStore () {}
void * allocate ( size_t );
void release ( void * );
private:
tsFreeList < bhe, 0x100 > freeList;
bheFreeStore ( const bheFreeStore & );
bheFreeStore & operator = ( const bheFreeStore & );
};
inline void * bhe::operator new ( size_t size,
bheMemoryManager & mgr )
{
return mgr.allocate ( size );
}
#ifdef CXX_PLACEMENT_DELETE
inline void bhe::operator delete ( void * pCadaver,
bheMemoryManager & mgr )
{
mgr.release ( pCadaver );
}
#endif
#endif // ifdef bheh

View File

@@ -18,13 +18,13 @@ BEGIN
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments","Common Library for EPICS\0"
VALUE "Comments","Channel Access Library for EPICS\0"
VALUE "CompanyName", "The EPICS collaboration\0"
VALUE "FileDescription", "Common Library\0"
VALUE "FileDescription", "Channel Access Library\0"
VALUE "FileVersion", EPICS_VERSION_STRING "\0"
VALUE "InternalName", "Com\0"
VALUE "InternalName", "ca\0"
VALUE "LegalCopyright", "Copyright (C) Univ. of California, Univ. of Chicago\0"
VALUE "OriginalFilename", "Com.dll\0"
VALUE "OriginalFilename", "ca.dll\0"
VALUE "ProductName", "Experimental Physics and Industrial Control System (EPICS)\0"
VALUE "ProductVersion", EPICS_VERSION_STRING "\0"
END

109
src/client/caConnTest.cpp Normal file
View File

@@ -0,0 +1,109 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "cadef.h"
#include "epicsTime.h"
static unsigned channelCount = 0u;
static unsigned connCount = 0u;
static bool subsequentConnect = false;
epicsTime begin;
extern "C" void caConnTestConnHandler ( struct connection_handler_args args )
{
if ( args.op == CA_OP_CONN_UP ) {
if ( connCount == 0u ) {
if ( subsequentConnect ) {
printf ("the first channel connected\n");
begin = epicsTime::getCurrent ();
}
}
connCount++;
// printf ( "." );
// fflush ( stdout );
if ( connCount == channelCount ) {
epicsTime current = epicsTime::getCurrent ();
double delay = current - begin;
printf ( "all channels connected after %f sec ( %f sec per channel)\n",
delay, delay / channelCount );
}
}
else if ( args.op == CA_OP_CONN_DOWN ) {
if ( connCount == channelCount ) {
printf ( "channels are disconnected\n" );
subsequentConnect = true;
}
connCount--;
if ( connCount == 0u ) {
printf ( "all channels are disconnected\n" );
}
}
else {
assert ( 0 );
}
}
void caConnTest ( const char *pNameIn, unsigned channelCountIn, double delayIn )
{
unsigned iteration = 0u;
int status;
unsigned i;
chid *pChans;
channelCount = channelCountIn;
pChans = new chid [channelCount];
while ( 1 ) {
connCount = 0u;
subsequentConnect = false;
begin = epicsTime::getCurrent ();
printf ( "initializing CA client library\n" );
status = ca_task_initialize();
SEVCHK ( status, "CA init failed" );
printf ( "creating channels\n" );
for ( i = 0u; i < channelCount; i++ ) {
status = ca_search_and_connect ( pNameIn,
&pChans[i], caConnTestConnHandler, 0 );
SEVCHK ( status, "CA search problems" );
}
printf ( "all channels were created\n" );
ca_pend_event ( delayIn );
if ( iteration & 1 ) {
for ( i = 0u; i < channelCount; i++ ) {
status = ca_clear_channel ( pChans[i] );
SEVCHK ( status, "ca_clear_channel() problems" );
}
printf ( "all channels were destroyed\n" );
}
printf ( "shutting down CA client library\n" );
status = ca_task_exit ();
SEVCHK ( status, "task exit problems" );
iteration++;
}
//delete [] pChans;
}

View File

@@ -0,0 +1,45 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stdio.h>
#include <epicsStdlib.h>
#include "caDiagnostics.h"
int main ( int argc, char **argv )
{
double delay = 60.0 * 5.0;
unsigned count = 2000;
if ( argc < 2 || argc > 4 ) {
printf ( "usage: %s < channel name > [ < count > ] [ < delay sec > ]\n", argv[0] );
return -1;
}
if ( argc >= 3 ) {
int nConverted = sscanf ( argv[2], "%u", &count );
if ( nConverted != 1 ) {
printf ( "conversion failed, changing channel count arg \"%s\" to %u\n",
argv[1], count );
}
}
if ( argc >= 4 ) {
int nConverted = epicsScanDouble( argv[3], &delay );
if ( nConverted != 1 ) {
printf ( "conversion failed, changing delay arg \"%s\" to %f\n",
argv[2], delay );
}
}
caConnTest ( argv[1], count, delay );
return 0;
}

View File

@@ -3,37 +3,36 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* Copyright (c) 2002 Berliner Elektronenspeicherringgesellschaft fuer
* Synchrotronstrahlung.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef _EPICS_GETOPT_H
#define _EPICS_GETOPT_H
#ifdef _MINGW
#ifndef caDiagnosticsh
#define caDiagnosticsh
#include <unistd.h>
#else /* _MINGW */
#include "shareLib.h"
#include "cadef.h"
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc int getopt(int argc, char * const argv[], const char *optstring);
enum appendNumberFlag {appendNumber, dontAppendNumber};
int catime ( const char *channelName, unsigned channelCount, enum appendNumberFlag appNF );
epicsShareExtern char *optarg;
int acctst ( const char *pname, unsigned logggingInterestLevel,
unsigned channelCount, unsigned repetitionCount,
enum ca_preemptive_callback_select select );
epicsShareExtern int optind, opterr, optopt;
#define CATIME_OK 0
#define CATIME_ERROR -1
#ifdef __cplusplus
}
#endif
#endif /* _MINGW */
void caConnTest ( const char *pNameIn, unsigned channelCountIn, double delayIn );
#endif /* caDiagnosticsh */
#endif /* _EPICS_GETOPT_H */

139
src/client/caEventRate.cpp Normal file
View File

@@ -0,0 +1,139 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stdio.h>
#include <limits.h>
#include <math.h>
#include "cadef.h"
#include "dbDefs.h"
#include "epicsTime.h"
#include "errlog.h"
/*
* event_handler()
*/
extern "C" void eventCallBack ( struct event_handler_args args )
{
unsigned *pCount = static_cast < unsigned * > ( args.usr );
(*pCount)++;
}
/*
* caEventRate ()
*/
void caEventRate ( const char *pName, unsigned count )
{
static const double initialSamplePeriod = 1.0;
static const double maxSamplePeriod = 60.0 * 5.0;
unsigned eventCount = 0u;
chid * pChidTable = new chid [ count ];
{
printf ( "Connecting to CA Channel \"%s\" %u times.",
pName, count );
fflush ( stdout );
epicsTime begin = epicsTime::getCurrent ();
for ( unsigned i = 0u; i < count; i++ ) {
int status = ca_search ( pName, & pChidTable[i] );
SEVCHK ( status, NULL );
}
int status = ca_pend_io ( 10000.0 );
if ( status != ECA_NORMAL ) {
fprintf ( stderr, " not found.\n" );
return;
}
epicsTime end = epicsTime::getCurrent ();
printf ( " done(%f sec).\n", end - begin );
}
{
printf ( "Subscribing %u times.", count );
fflush ( stdout );
epicsTime begin = epicsTime::getCurrent ();
for ( unsigned i = 0u; i < count; i++ ) {
int addEventStatus = ca_add_event ( DBR_FLOAT,
pChidTable[i], eventCallBack, &eventCount, NULL);
SEVCHK ( addEventStatus, __FILE__ );
}
int status = ca_flush_io ();
SEVCHK ( status, __FILE__ );
epicsTime end = epicsTime::getCurrent ();
printf ( " done(%f sec).\n", end - begin );
}
{
printf ( "Waiting for initial value events." );
fflush ( stdout );
// let the first one go by
epicsTime begin = epicsTime::getCurrent ();
while ( eventCount < count ) {
int status = ca_pend_event ( 0.01 );
if ( status != ECA_TIMEOUT ) {
SEVCHK ( status, NULL );
}
}
epicsTime end = epicsTime::getCurrent ();
printf ( " done(%f sec).\n", end - begin );
}
double samplePeriod = initialSamplePeriod;
double X = 0.0;
double XX = 0.0;
unsigned N = 0u;
while ( true ) {
unsigned nEvents, lastEventCount, curEventCount;
epicsTime beginPend = epicsTime::getCurrent ();
lastEventCount = eventCount;
int status = ca_pend_event ( samplePeriod );
curEventCount = eventCount;
epicsTime endPend = epicsTime::getCurrent ();
if ( status != ECA_TIMEOUT ) {
SEVCHK ( status, NULL );
}
if ( curEventCount >= lastEventCount ) {
nEvents = curEventCount - lastEventCount;
}
else {
nEvents = ( UINT_MAX - lastEventCount ) + curEventCount + 1u;
}
N++;
double period = endPend - beginPend;
double Hz = nEvents / period;
X += Hz;
XX += Hz * Hz;
double mean = X / N;
double stdDev = sqrt ( XX / N - mean * mean );
printf ( "CA Event Rate (Hz): current %g mean %g std dev %g\n",
Hz, mean, stdDev );
if ( samplePeriod < maxSamplePeriod ) {
samplePeriod += samplePeriod;
}
}
}

View File

@@ -8,30 +8,31 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define epicsExportSharedSymbols
#include "epicsTempFile.h"
void caEventRate ( const char *pName, unsigned count );
extern "C"
epicsShareFunc void epicsShareAPI epicsTempName (
char * pNameBuf, size_t nameBufLength )
int main ( int argc, char **argv )
{
if ( nameBufLength ) {
pNameBuf[0] = '\0';
char nameBuf[L_tmpnam];
if ( tmpnam ( nameBuf ) ) {
if ( nameBufLength > strlen ( nameBuf ) ) {
strncpy ( pNameBuf, nameBuf, nameBufLength );
}
if ( argc < 2 || argc > 3 ) {
fprintf ( stderr, "usage: %s < PV name > [subscription count]\n", argv[0] );
return 0;
}
unsigned count;
if ( argc == 3 ) {
int status = sscanf ( argv[2], " %u ", & count );
if ( status != 1 ) {
fprintf ( stderr, "expected unsigned integer 2nd argument\n" );
return 0;
}
}
else {
count = 1;
}
caEventRate ( argv[1], count );
return 0;
}
extern "C"
epicsShareFunc FILE * epicsShareAPI epicsTempFile ( void )
{
return tmpfile ();
}

187
src/client/caProto.h Normal file
View File

@@ -0,0 +1,187 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef __CAPROTO__
#define __CAPROTO__
#define capStrOf(A) #A
#define capStrOfX(A) capStrOf ( A )
/*
* CA protocol revision
* TCP/UDP port number (bumped each major protocol change)
*/
#define CA_MAJOR_PROTOCOL_REVISION 4
#define CA_VERSION_STRING( MINOR_REVISION ) \
( capStrOfX ( CA_MAJOR_PROTOCOL_REVISION ) "." capStrOfX ( MINOR_REVISION ) )
#define CA_UKN_MINOR_VERSION 0u /* unknown minor version */
#define CA_MINIMUM_SUPPORTED_VERSION 4u
# define CA_VSUPPORTED(MINOR) ((MINOR)>=CA_MINIMUM_SUPPORTED_VERSION)
# define CA_V41(MINOR) ((MINOR)>=1u)
# define CA_V42(MINOR) ((MINOR)>=2u)
# define CA_V43(MINOR) ((MINOR)>=3u)
# define CA_V44(MINOR) ((MINOR)>=4u)
# define CA_V45(MINOR) ((MINOR)>=5u)
# define CA_V46(MINOR) ((MINOR)>=6u)
# define CA_V47(MINOR) ((MINOR)>=7u)
# define CA_V48(MINOR) ((MINOR)>=8u)
# define CA_V49(MINOR) ((MINOR)>=9u) /* large arrays, dispatch priorities */
# define CA_V410(MINOR) ((MINOR)>=10u) /* beacon counter */
# define CA_V411(MINOR) ((MINOR)>=11u) /* sequence numbers in UDP version command */
# define CA_V412(MINOR) ((MINOR)>=12u) /* TCP-based search requests */
# define CA_V413(MINOR) ((MINOR)>=13u) /* Allow zero length in requests. */
/*
* These port numbers are only used if the CA repeater and
* CA server port numbers cant be obtained from the EPICS
* environment variables "EPICS_CA_REPEATER_PORT" and
* "EPICS_CA_SERVER_PORT"
*/
#define CA_PORT_BASE IPPORT_USERRESERVED + 56U
#define CA_SERVER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*2u)
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*2u+1u)
/*
* 1500 (max of ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP)
* (the MTU of Ethernet is currently independent of its speed varient)
*/
#define ETHERNET_MAX_UDP ( 1500u - 20u - 8u )
#define MAX_UDP_RECV ( 0xffff + 16u ) /* allow large frames to be received in the future */
#define MAX_UDP_SEND 1024u /* original MAX_UDP */
#define MAX_TCP ( 1024 * 16u ) /* so waveforms fit */
#define MAX_MSG_SIZE ( MAX_TCP ) /* the larger of tcp and udp max */
#define CA_PROTO_PRIORITY_MIN 0u
#define CA_PROTO_PRIORITY_MAX 99u
/*
* architecture independent types
*
* (so far this works on all archs we have ported to)
*/
typedef unsigned char ca_uint8_t;
typedef unsigned short ca_uint16_t;
typedef unsigned int ca_uint32_t;
typedef float ca_float32_t;
typedef ca_uint32_t caResId;
#define ca_uint32_max 0xffffffff
/* values for m_cmmd */
#define CA_PROTO_VERSION 0u /* set minor version and priority (used to be NOOP cmd) */
#define CA_PROTO_EVENT_ADD 1u /* add an event */
#define CA_PROTO_EVENT_CANCEL 2u /* cancel an event */
#define CA_PROTO_READ 3u /* read and return a channel value*/
#define CA_PROTO_WRITE 4u /* write a channel value */
#define CA_PROTO_SNAPSHOT 5u /* snapshot of the system */
#define CA_PROTO_SEARCH 6u /* IOC channel search */
#define CA_PROTO_BUILD 7u /* build - obsolete */
#define CA_PROTO_EVENTS_OFF 8u /* flow control */
#define CA_PROTO_EVENTS_ON 9u /* flow control */
#define CA_PROTO_READ_SYNC 10u /* purge old reads */
#define CA_PROTO_ERROR 11u /* an operation failed */
#define CA_PROTO_CLEAR_CHANNEL 12u /* free chan resources */
#define CA_PROTO_RSRV_IS_UP 13u /* CA server has joined the net */
#define CA_PROTO_NOT_FOUND 14u /* channel not found */
#define CA_PROTO_READ_NOTIFY 15u /* add a one shot event */
#define CA_PROTO_READ_BUILD 16u /* read and build - obsolete */
#define REPEATER_CONFIRM 17u /* registration confirmation */
#define CA_PROTO_CREATE_CHAN 18u /* client creates channel in server */
#define CA_PROTO_WRITE_NOTIFY 19u /* notify after write chan value */
#define CA_PROTO_CLIENT_NAME 20u /* CA V4.1 identify client */
#define CA_PROTO_HOST_NAME 21u /* CA V4.1 identify client */
#define CA_PROTO_ACCESS_RIGHTS 22u /* CA V4.2 asynch access rights chg */
#define CA_PROTO_ECHO 23u /* CA V4.3 connection verify */
#define REPEATER_REGISTER 24u /* register for repeater fan out */
#define CA_PROTO_SIGNAL 25u /* knock the server out of select */
#define CA_PROTO_CREATE_CH_FAIL 26u /* unable to create chan resource in server */
#define CA_PROTO_SERVER_DISCONN 27u /* server deletes PV (or channel) */
#define CA_PROTO_LAST_CMMD CA_PROTO_SERVER_DISCONN
/*
* for use with search and not_found (if search fails and
* its not a broadcast tell the client to look elesewhere)
*/
#define DOREPLY 10u
#define DONTREPLY 5u
/*
* for use with the m_dataType field in UDP messages emitted by servers
*/
#define sequenceNoIsValid 1
/* size of object in bytes rounded up to nearest oct word */
#define OCT_ROUND(A) (((A)+7)/8)
#define OCT_SIZEOF(A) (OCT_ROUND(sizeof(A)))
/* size of object in bytes rounded up to nearest long word */
#define QUAD_ROUND(A) ((A)+3)/4)
#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A)))
/* size of object in bytes rounded up to nearest short word */
#define BI_ROUND(A) (((A)+1)/2)
#define BI_SIZEOF(A) (BI_ROUND(sizeof(A)))
/*
* For communicating access rights to the clients
*
* (placed in m_available hdr field of CA_PROTO_ACCESS_RIGHTS cmmd
*/
#define CA_PROTO_ACCESS_RIGHT_READ (1u<<0u)
#define CA_PROTO_ACCESS_RIGHT_WRITE (1u<<1u)
/*
* All structures passed in the protocol must have individual
* fields aligned on natural boundaries.
*
* NOTE: all structures declared in this file must have a
* byte count which is evenly divisible by 8 matching
* the largest atomic data type in db_access.h.
*/
#define CA_MESSAGE_ALIGN(A) (OCT_ROUND(A)<<3u)
/*
* the common part of each message sent/recv by the
* CA server.
*/
typedef struct ca_hdr {
ca_uint16_t m_cmmd; /* operation to be performed */
ca_uint16_t m_postsize; /* size of payload */
ca_uint16_t m_dataType; /* operation data type */
ca_uint16_t m_count; /* operation data count */
ca_uint32_t m_cid; /* channel identifier */
ca_uint32_t m_available; /* protocol stub dependent */
} caHdr;
/*
* for monitor (event) message extension
*/
struct mon_info {
ca_float32_t m_lval; /* low delta */
ca_float32_t m_hval; /* high delta */
ca_float32_t m_toval; /* period btween samples */
ca_uint16_t m_mask; /* event select mask */
ca_uint16_t m_pad; /* extend to 32 bits */
};
/*
* PV names greater than this length assumed to be invalid
*/
#define unreasonablePVNameSize 500u
#endif /* __CAPROTO__ */

42
src/client/caRepeater.cpp Normal file
View File

@@ -0,0 +1,42 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* CA UDP repeater standalone executable
*
* Author: Jeff Hill
* Date: 3-27-90
*
* PURPOSE:
* Broadcasts fan out over the LAN, but old IP kernels do not allow
* two processes on the same machine to get the same broadcast
* (and modern IP kernels do not allow two processes on the same machine
* to receive the same unicast).
*
* This code fans out UDP messages sent to the CA repeater port
* to all CA client processes that have subscribed.
*
* NOTES:
*
* see repeater.c
*
*/
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "epicsAssert.h"
#include "udpiiu.h"
int main()
{
ca_repeater ();
return ( 0 );
}

View File

@@ -0,0 +1,25 @@
#
# Linux systemd service file for the EPICS CA Repeater
#
# To install this file, as root:
# cp caRepeater.service /etc/systemd/system
# chmod 664 /etc/systemd/system/caRepeater.service
# systemctl daemon-reload
# systemctl enable caRepeater
# systemctl start caRepeater
#
# To check the status:
# systemctl status caRepeater
[Unit]
Description=EPICS CA Repeater
Requires=network.target
After=network.target
[Service]
ExecStart=@INSTALL_BIN@/caRepeater
Restart=always
User=daemon
[Install]
WantedBy=multi-user.target

88
src/client/caServerID.h Normal file
View File

@@ -0,0 +1,88 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#ifndef caServerIDh
#define caServerIDh
#include "osiSock.h"
#include "resourceLib.h"
#include "caProto.h"
class caServerID {
public:
caServerID ( const struct sockaddr_in & addrIn, unsigned priority );
bool operator == ( const caServerID & ) const;
resTableIndex hash () const;
osiSockAddr address () const;
unsigned priority () const;
private:
struct sockaddr_in addr;
ca_uint8_t pri;
};
inline caServerID::caServerID (
const struct sockaddr_in & addrIn, unsigned priorityIn ) :
addr ( addrIn ), pri ( static_cast <ca_uint8_t> ( priorityIn ) )
{
assert ( priorityIn <= 0xff );
}
inline bool caServerID::operator == ( const caServerID & rhs ) const
{
if ( this->addr.sin_addr.s_addr == rhs.addr.sin_addr.s_addr &&
this->addr.sin_port == rhs.addr.sin_port &&
this->pri == rhs.pri ) {
return true;
}
return false;
}
inline resTableIndex caServerID::hash () const
{
// start with a very small server table to speed
// up the flush traverse for the frequent case -
// a small numbers of servers
const unsigned caServerMinIndexBitWidth = 2u;
const unsigned caServerMaxIndexBitWidth = 32u;
unsigned index;
index = this->addr.sin_addr.s_addr;
index ^= this->addr.sin_port;
index ^= this->addr.sin_port >> 8u;
index ^= this->pri;
return integerHash ( caServerMinIndexBitWidth,
caServerMaxIndexBitWidth, index );
}
inline osiSockAddr caServerID::address () const
{
osiSockAddr tmp;
tmp.ia = this->addr;
return tmp;
}
inline unsigned caServerID::priority () const
{
return this->pri;
}
#endif // ifdef caServerID

View File

@@ -5,8 +5,8 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef LIBCOMVERSION_H
#define LIBCOMVERSION_H
#ifndef CAVERSION_H
#define CAVERSION_H
#include <epicsVersion.h>
#include <shareLib.h>
@@ -16,13 +16,13 @@
#endif
/* include generated headers with:
* EPICS_LIBCOM_MAJOR_VERSION
* EPICS_LIBCOM_MINOR_VERSION
* EPICS_LIBCOM_MAINTENANCE_VERSION
* EPICS_LIBCOM_DEVELOPMENT_FLAG
* EPICS_CA_MAJOR_VERSION
* EPICS_CA_MINOR_VERSION
* EPICS_CA_MAINTENANCE_VERSION
* EPICS_CA_DEVELOPMENT_FLAG
*/
#include "libComVersionNum.h"
#include "caVersionNum.h"
#define LIBCOM_VERSION_INT VERSION_INT(EPICS_LIBCOM_MAJOR_VERSION, EPICS_LIBCOM_MINOR_VERSION, EPICS_LIBCOM_MAINTENANCE_VERSION, 0)
#define CA_VERSION_INT VERSION_INT(EPICS_CA_MAJOR_VERSION, EPICS_CA_MINOR_VERSION, EPICS_CA_MAINTENANCE_VERSION, 0)
#endif // LIBCOMVERSION_H
#endif // CAVERSION_H

View File

@@ -0,0 +1,7 @@
#ifndef CAVERSION_H
# error include caVersion.h, not this header
#endif
#define EPICS_CA_MAJOR_VERSION @EPICS_CA_MAJOR_VERSION@
#define EPICS_CA_MINOR_VERSION @EPICS_CA_MINOR_VERSION@
#define EPICS_CA_MAINTENANCE_VERSION @EPICS_CA_MAINTENANCE_VERSION@
#define EPICS_CA_DEVELOPMENT_FLAG @EPICS_CA_DEVELOPMENT_FLAG@

View File

@@ -0,0 +1,811 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifdef _MSC_VER
# pragma warning(disable:4355)
#endif
#include <stdexcept>
#include <string> // vxWorks 6.0 requires this include
#include <stdio.h>
#include "epicsExit.h"
#include "errlog.h"
#include "locationException.h"
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "oldAccess.h"
#include "cac.h"
epicsShareDef epicsThreadPrivateId caClientCallbackThreadId;
static epicsThreadOnceId cacOnce = EPICS_THREAD_ONCE_INIT;
const unsigned ca_client_context :: flushBlockThreshold = 0x58000;
extern "C" void cacExitHandler ( void *)
{
epicsThreadPrivateDelete ( caClientCallbackThreadId );
caClientCallbackThreadId = 0;
delete ca_client_context::pDefaultServiceInstallMutex;
}
// runs once only for each process
extern "C" void cacOnceFunc ( void * )
{
caClientCallbackThreadId = epicsThreadPrivateCreate ();
assert ( caClientCallbackThreadId );
ca_client_context::pDefaultServiceInstallMutex = newEpicsMutex;
epicsAtExit ( cacExitHandler,0 );
}
extern epicsThreadPrivateId caClientContextId;
cacService * ca_client_context::pDefaultService = 0;
epicsMutex * ca_client_context::pDefaultServiceInstallMutex;
ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
createdByThread ( epicsThreadGetIdSelf () ),
ca_exception_func ( 0 ), ca_exception_arg ( 0 ),
pVPrintfFunc ( errlogVprintf ), fdRegFunc ( 0 ), fdRegArg ( 0 ),
pndRecvCnt ( 0u ), ioSeqNo ( 0u ), callbackThreadsPending ( 0u ),
localPort ( 0 ), fdRegFuncNeedsToBeCalled ( false ),
noWakeupSincePend ( true )
{
static const unsigned short PORT_ANY = 0u;
if ( ! osiSockAttach () ) {
throwWithLocation ( noSocket () );
}
epicsThreadOnce ( & cacOnce, cacOnceFunc, 0 );
{
epicsGuard < epicsMutex > guard ( *ca_client_context::pDefaultServiceInstallMutex );
if ( ca_client_context::pDefaultService ) {
this->pServiceContext.reset (
& ca_client_context::pDefaultService->contextCreate (
this->mutex, this->cbMutex, *this ) );
}
else {
this->pServiceContext.reset ( new cac ( this->mutex, this->cbMutex, *this ) );
}
}
this->sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if ( this->sock == INVALID_SOCKET ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
this->printFormated (
"ca_client_context: unable to create "
"datagram socket because = \"%s\"\n",
sockErrBuf );
throwWithLocation ( noSocket () );
}
{
osiSockIoctl_t yes = true;
int status = socket_ioctl ( this->sock,
FIONBIO, & yes);
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
epicsSocketDestroy ( this->sock );
this->printFormated (
"%s: non blocking IO set fail because \"%s\"\n",
__FILE__, sockErrBuf );
throwWithLocation ( noSocket () );
}
}
// force a bind to an unconstrained address so we can obtain
// the local port number below
{
osiSockAddr addr;
memset ( (char *)&addr, 0 , sizeof ( addr ) );
addr.ia.sin_family = AF_INET;
addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
addr.ia.sin_port = htons ( PORT_ANY );
int status = bind (this->sock, &addr.sa, sizeof (addr) );
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
epicsSocketDestroy (this->sock);
this->printFormated (
"CAC: unable to bind to an unconstrained "
"address because = \"%s\"\n",
sockErrBuf );
throwWithLocation ( noSocket () );
}
}
{
osiSockAddr tmpAddr;
osiSocklen_t saddr_length = sizeof ( tmpAddr );
int status = getsockname ( this->sock, & tmpAddr.sa, & saddr_length );
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
epicsSocketDestroy ( this->sock );
this->printFormated ( "CAC: getsockname () error was \"%s\"\n", sockErrBuf );
throwWithLocation ( noSocket () );
}
if ( tmpAddr.sa.sa_family != AF_INET) {
epicsSocketDestroy ( this->sock );
this->printFormated ( "CAC: UDP socket was not inet addr family\n" );
throwWithLocation ( noSocket () );
}
this->localPort = htons ( tmpAddr.ia.sin_port );
}
std::auto_ptr < CallbackGuard > pCBGuard;
if ( ! enablePreemptiveCallback ) {
pCBGuard.reset ( new CallbackGuard ( this->cbMutex ) );
}
// multiple steps ensure exception safety
this->pCallbackGuard = pCBGuard;
}
ca_client_context::~ca_client_context ()
{
if ( this->fdRegFunc ) {
( *this->fdRegFunc )
( this->fdRegArg, this->sock, false );
}
epicsSocketDestroy ( this->sock );
osiSockRelease ();
// force a logical shutdown order
// so that the cac class does not hang its
// receive threads during their shutdown sequence
// and so that classes using this classes mutex
// are destroyed before the mutex is destroyed
if ( this->pCallbackGuard.get() ) {
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
this->pServiceContext.reset ( 0 );
}
else {
this->pServiceContext.reset ( 0 );
}
}
void ca_client_context::destroyGetCopy (
epicsGuard < epicsMutex > & guard, getCopy & gc )
{
guard.assertIdenticalMutex ( this->mutex );
gc.~getCopy ();
this->getCopyFreeList.release ( & gc );
}
void ca_client_context::destroyGetCallback (
epicsGuard < epicsMutex > & guard, getCallback & gcb )
{
guard.assertIdenticalMutex ( this->mutex );
gcb.~getCallback ();
this->getCallbackFreeList.release ( & gcb );
}
void ca_client_context::destroyPutCallback (
epicsGuard < epicsMutex > & guard, putCallback & pcb )
{
guard.assertIdenticalMutex ( this->mutex );
pcb.~putCallback ();
this->putCallbackFreeList.release ( & pcb );
}
void ca_client_context::destroySubscription (
epicsGuard < epicsMutex > & guard, oldSubscription & os )
{
guard.assertIdenticalMutex ( this->mutex );
os.~oldSubscription ();
this->subscriptionFreeList.release ( & os );
}
void ca_client_context::changeExceptionEvent (
caExceptionHandler * pfunc, void * arg )
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->ca_exception_func = pfunc;
this->ca_exception_arg = arg;
// should block here until releated callback in progress completes
}
void ca_client_context::replaceErrLogHandler (
caPrintfFunc * ca_printf_func )
{
epicsGuard < epicsMutex > guard ( this->mutex );
if ( ca_printf_func ) {
this->pVPrintfFunc = ca_printf_func;
}
else {
this->pVPrintfFunc = epicsVprintf;
}
// should block here until releated callback in progress completes
}
void ca_client_context::registerForFileDescriptorCallBack (
CAFDHANDLER *pFunc, void *pArg )
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->fdRegFunc = pFunc;
this->fdRegArg = pArg;
this->fdRegFuncNeedsToBeCalled = true;
if ( pFunc ) {
// the receive thread might already be blocking
// w/o having sent the wakeup message
this->_sendWakeupMsg ();
}
// should block here until releated callback in progress completes
}
int ca_client_context :: printFormated (
const char *pformat, ... ) const
{
va_list theArgs;
int status;
va_start ( theArgs, pformat );
status = this->ca_client_context :: varArgsPrintFormated ( pformat, theArgs );
va_end ( theArgs );
return status;
}
int ca_client_context :: varArgsPrintFormated (
const char *pformat, va_list args ) const
{
caPrintfFunc * pFunc;
{
epicsGuard < epicsMutex > guard ( this->mutex );
pFunc = this->pVPrintfFunc;
}
if ( pFunc ) {
return ( *pFunc ) ( pformat, args );
}
else {
return :: vfprintf ( stderr, pformat, args );
}
}
void ca_client_context::exception (
epicsGuard < epicsMutex > & guard, int stat, const char * pCtx,
const char * pFile, unsigned lineNo )
{
struct exception_handler_args args;
caExceptionHandler * pFunc = this->ca_exception_func;
void * pArg = this->ca_exception_arg;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
// NOOP if they disable exceptions
if ( pFunc ) {
args.chid = NULL;
args.type = TYPENOTCONN;
args.count = 0;
args.addr = NULL;
args.stat = stat;
args.op = CA_OP_OTHER;
args.ctx = pCtx;
args.pFile = pFile;
args.lineNo = lineNo;
args.usr = pArg;
( *pFunc ) ( args );
}
else {
this->signal ( stat, pFile, lineNo, pCtx );
}
}
}
void ca_client_context::exception (
epicsGuard < epicsMutex > & guard, int status, const char * pContext,
const char * pFileName, unsigned lineNo, oldChannelNotify & chan,
unsigned type, arrayElementCount count, unsigned op )
{
struct exception_handler_args args;
caExceptionHandler * pFunc = this->ca_exception_func;
void * pArg = this->ca_exception_arg;
{
epicsGuardRelease < epicsMutex > unguard ( guard );
// NOOP if they disable exceptions
if ( pFunc ) {
args.chid = &chan;
args.type = type;
args.count = count;
args.addr = NULL;
args.stat = status;
args.op = op;
args.ctx = pContext;
args.pFile = pFileName;
args.lineNo = lineNo;
args.usr = pArg;
( *pFunc ) ( args );
}
else {
this->signal ( status, pFileName, lineNo,
"op=%u, channel=%s, type=%s, count=%lu, ctx=\"%s\"",
op, ca_name ( &chan ),
dbr_type_to_text ( static_cast <int> ( type ) ),
count, pContext );
}
}
}
void ca_client_context::signal ( int ca_status, const char * pfilenm,
int lineno, const char * pFormat, ... )
{
va_list theArgs;
va_start ( theArgs, pFormat );
this->vSignal ( ca_status, pfilenm, lineno, pFormat, theArgs);
va_end ( theArgs );
}
void ca_client_context :: vSignal (
int ca_status, const char *pfilenm,
int lineno, const char *pFormat, va_list args )
{
static const char *severity[] =
{
"Warning",
"Success",
"Error",
"Info",
"Fatal",
"Fatal",
"Fatal",
"Fatal"
};
this->printFormated ( "CA.Client.Exception...............................................\n" );
this->printFormated ( " %s: \"%s\"\n",
severity[ CA_EXTRACT_SEVERITY ( ca_status ) ],
ca_message ( ca_status ) );
if ( pFormat ) {
this->printFormated ( " Context: \"" );
this->varArgsPrintFormated ( pFormat, args );
this->printFormated ( "\"\n" );
}
if ( pfilenm ) {
this->printFormated ( " Source File: %s line %d\n",
pfilenm, lineno );
}
epicsTime current = epicsTime::getCurrent ();
char date[64];
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
this->printFormated ( " Current Time: %s\n", date );
/*
* Terminate execution if unsuccessful
*/
if( ! ( ca_status & CA_M_SUCCESS ) &&
CA_EXTRACT_SEVERITY ( ca_status ) != CA_K_WARNING ){
errlogFlush ();
abort ();
}
this->printFormated ( "..................................................................\n" );
}
void ca_client_context::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
::printf ( "ca_client_context at %p pndRecvCnt=%u ioSeqNo=%u\n",
static_cast <const void *> ( this ),
this->pndRecvCnt, this->ioSeqNo );
if ( level > 0u ) {
this->pServiceContext->show ( guard, level - 1u );
::printf ( "\tpreemptive callback is %s\n",
this->pCallbackGuard.get() ? "disabled" : "enabled" );
::printf ( "\tthere are %u unsatisfied IO operations blocking ca_pend_io()\n",
this->pndRecvCnt );
::printf ( "\tthe current io sequence number is %u\n",
this->ioSeqNo );
::printf ( "IO done event:\n");
this->ioDone.show ( level - 1u );
::printf ( "Synchronous group identifier hash table:\n" );
this->sgTable.show ( level - 1u );
}
}
void ca_client_context::attachToClientCtx ()
{
assert ( ! epicsThreadPrivateGet ( caClientContextId ) );
epicsThreadPrivateSet ( caClientContextId, this );
}
void ca_client_context::incrementOutstandingIO (
epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->ioSeqNo == ioSeqNoIn ) {
assert ( this->pndRecvCnt < UINT_MAX );
this->pndRecvCnt++;
}
}
void ca_client_context::decrementOutstandingIO (
epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn )
{
guard.assertIdenticalMutex ( this->mutex );
if ( this->ioSeqNo == ioSeqNoIn ) {
assert ( this->pndRecvCnt > 0u );
this->pndRecvCnt--;
if ( this->pndRecvCnt == 0u ) {
this->ioDone.signal ();
}
}
}
// !!!! This routine is only visible in the old interface - or in a new ST interface.
// !!!! In the old interface we restrict thread attach so that calls from threads
// !!!! other than the initializing thread are not allowed if preemptive callback
// !!!! is disabled. This prevents the preemptive callback lock from being released
// !!!! by other threads than the one that locked it.
//
int ca_client_context::pendIO ( const double & timeout )
{
// prevent recursion nightmares by disabling calls to
// pendIO () from within a CA callback.
if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) {
return ECA_EVDISALLOW;
}
int status = ECA_NORMAL;
epicsTime beg_time = epicsTime::getCurrent ();
double remaining = timeout;
epicsGuard < epicsMutex > guard ( this->mutex );
this->flush ( guard );
while ( this->pndRecvCnt > 0 ) {
if ( remaining < CAC_SIGNIFICANT_DELAY ) {
status = ECA_TIMEOUT;
break;
}
{
epicsGuardRelease < epicsMutex > unguard ( guard );
this->blockForEventAndEnableCallbacks ( this->ioDone, remaining );
}
double delay = epicsTime::getCurrent () - beg_time;
if ( delay < timeout ) {
remaining = timeout - delay;
}
else {
remaining = 0.0;
}
}
this->ioSeqNo++;
this->pndRecvCnt = 0u;
return status;
}
// !!!! This routine is only visible in the old interface - or in a new ST interface.
// !!!! In the old interface we restrict thread attach so that calls from threads
// !!!! other than the initializing thread are not allowed if preemptive callback
// !!!! is disabled. This prevents the preemptive callback lock from being released
// !!!! by other threads than the one that locked it.
//
int ca_client_context::pendEvent ( const double & timeout )
{
// prevent recursion nightmares by disabling calls to
// pendIO () from within a CA callback.
if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) {
return ECA_EVDISALLOW;
}
epicsTime current = epicsTime::getCurrent ();
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->flush ( guard );
}
// process at least once if preemptive callback is disabled
if ( this->pCallbackGuard.get() ) {
epicsGuardRelease < epicsMutex > cbUnguard ( *this->pCallbackGuard );
epicsGuard < epicsMutex > guard ( this->mutex );
//
// This is needed because in non-preemptive callback mode
// legacy applications that use file descriptor managers
// will register for ca receive thread activity and keep
// calling ca_pend_event until all of the socket data has
// been read. We must guarantee that other threads get a
// chance to run if there is data in any of the sockets.
//
if ( this->fdRegFunc ) {
epicsGuardRelease < epicsMutex > unguard ( guard );
// remove short udp message sent to wake
// up a file descriptor manager
osiSockAddr tmpAddr;
osiSocklen_t addrSize = sizeof ( tmpAddr.sa );
char buf = 0;
int status = 0;
do {
status = recvfrom ( this->sock, & buf, sizeof ( buf ),
0, & tmpAddr.sa, & addrSize );
} while ( status > 0 );
}
while ( this->callbackThreadsPending > 0 ) {
epicsGuardRelease < epicsMutex > unguard ( guard );
this->callbackThreadActivityComplete.wait ( 30.0 );
}
this->noWakeupSincePend = true;
}
double elapsed = epicsTime::getCurrent() - current;
double delay;
if ( timeout > elapsed ) {
delay = timeout - elapsed;
}
else {
delay = 0.0;
}
if ( delay >= CAC_SIGNIFICANT_DELAY ) {
if ( this->pCallbackGuard.get() ) {
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
epicsThreadSleep ( delay );
}
else {
epicsThreadSleep ( delay );
}
}
return ECA_TIMEOUT;
}
void ca_client_context::blockForEventAndEnableCallbacks (
epicsEvent & event, const double & timeout )
{
if ( this->pCallbackGuard.get() ) {
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
event.wait ( timeout );
}
else {
event.wait ( timeout );
}
}
void ca_client_context::callbackProcessingInitiateNotify ()
{
// if preemptive callback is enabled then this is a noop
if ( this->pCallbackGuard.get() ) {
bool sendNeeded = false;
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->callbackThreadsPending++;
if ( this->fdRegFunc && this->noWakeupSincePend ) {
this->noWakeupSincePend = false;
sendNeeded = true;
}
}
if ( sendNeeded ) {
_sendWakeupMsg ();
}
}
}
void ca_client_context :: _sendWakeupMsg ()
{
// send short udp message to wake up a file descriptor manager
// when a message arrives
osiSockAddr tmpAddr;
tmpAddr.ia.sin_family = AF_INET;
tmpAddr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
tmpAddr.ia.sin_port = htons ( this->localPort );
char buf = 0;
sendto ( this->sock, & buf, sizeof ( buf ),
0, & tmpAddr.sa, sizeof ( tmpAddr.sa ) );
}
void ca_client_context::callbackProcessingCompleteNotify ()
{
// if preemptive callback is enabled then this is a noop
if ( this->pCallbackGuard.get() ) {
bool signalNeeded = false;
{
epicsGuard < epicsMutex > guard ( this->mutex );
if ( this->callbackThreadsPending <= 1 ) {
if ( this->callbackThreadsPending == 1 ) {
this->callbackThreadsPending = 0;
signalNeeded = true;
}
}
else {
this->callbackThreadsPending--;
}
}
if ( signalNeeded ) {
this->callbackThreadActivityComplete.signal ();
}
}
}
cacChannel & ca_client_context::createChannel (
epicsGuard < epicsMutex > & guard, const char * pChannelName,
cacChannelNotify & chan, cacChannel::priLev pri )
{
guard.assertIdenticalMutex ( this->mutex );
return this->pServiceContext->createChannel (
guard, pChannelName, chan, pri );
}
void ca_client_context::flush ( epicsGuard < epicsMutex > & guard )
{
this->pServiceContext->flush ( guard );
}
unsigned ca_client_context::circuitCount () const
{
epicsGuard < epicsMutex > guard ( this->mutex );
return this->pServiceContext->circuitCount ( guard );
}
unsigned ca_client_context::beaconAnomaliesSinceProgramStart () const
{
epicsGuard < epicsMutex > guard ( this->mutex );
return this->pServiceContext->beaconAnomaliesSinceProgramStart ( guard );
}
void ca_client_context::installCASG (
epicsGuard < epicsMutex > & guard, CASG & sg )
{
guard.assertIdenticalMutex ( this->mutex );
this->sgTable.idAssignAdd ( sg );
}
void ca_client_context::uninstallCASG (
epicsGuard < epicsMutex > & guard, CASG & sg )
{
guard.assertIdenticalMutex ( this->mutex );
this->sgTable.remove ( sg );
}
CASG * ca_client_context::lookupCASG (
epicsGuard < epicsMutex > & guard, unsigned idIn )
{
guard.assertIdenticalMutex ( this->mutex );
CASG * psg = this->sgTable.lookup ( idIn );
if ( psg ) {
if ( ! psg->verify ( guard ) ) {
psg = 0;
}
}
return psg;
}
void ca_client_context::selfTest () const
{
epicsGuard < epicsMutex > guard ( this->mutex );
this->sgTable.verify ();
this->pServiceContext->selfTest ( guard );
}
epicsMutex & ca_client_context::mutexRef () const
{
return this->mutex;
}
cacContext & ca_client_context::createNetworkContext (
epicsMutex & mutexIn, epicsMutex & cbMutexIn )
{
return * new cac ( mutexIn, cbMutexIn, *this );
}
void ca_client_context::installDefaultService ( cacService & service )
{
epicsThreadOnce ( & cacOnce, cacOnceFunc, 0 );
epicsGuard < epicsMutex > guard ( *ca_client_context::pDefaultServiceInstallMutex );
if ( ca_client_context::pDefaultService ) {
throw std::logic_error
( "CA in-memory service already installed and can't be replaced");
}
ca_client_context::pDefaultService = & service;
}
void epicsShareAPI caInstallDefaultService ( cacService & service )
{
ca_client_context::installDefaultService ( service );
}
epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon )
{
oldChannelNotify & chan = pMon->channel ();
ca_client_context & cac = chan.getClientCtx ();
// !!!! the order in which we take the mutex here prevents deadlocks
{
epicsGuard < epicsMutex > guard ( cac.mutex );
try {
// if this stalls out on a live circuit then an exception
// can be forthcoming which we must ignore as the clear
// request must always be successful
chan.eliminateExcessiveSendBacklog ( guard );
}
catch ( cacChannel::notConnected & ) {
// intentionally ignored
}
}
if ( cac.pCallbackGuard.get() &&
cac.createdByThread == epicsThreadGetIdSelf () ) {
epicsGuard < epicsMutex > guard ( cac.mutex );
pMon->cancel ( *cac.pCallbackGuard.get(), guard );
}
else {
//
// we will definately stall out here if all of the
// following are true
//
// o user creates non-preemtive mode client library context
// o user doesnt periodically call a ca function
// o user calls this function from an auxiillary thread
//
CallbackGuard cbGuard ( cac.cbMutex );
epicsGuard < epicsMutex > guard ( cac.mutex );
pMon->cancel ( cbGuard, guard );
}
return ECA_NORMAL;
}
void ca_client_context :: eliminateExcessiveSendBacklog (
epicsGuard < epicsMutex > & guard, cacChannel & chan )
{
if ( chan.requestMessageBytesPending ( guard ) >
ca_client_context :: flushBlockThreshold ) {
if ( this->pCallbackGuard.get() &&
this->createdByThread == epicsThreadGetIdSelf () ) {
// we need to be very careful about lock hierarchy
// inversion in this situation
epicsGuardRelease < epicsMutex > unguard ( guard );
{
epicsGuardRelease < epicsMutex > cbunguard (
* this->pCallbackGuard.get() );
{
epicsGuard < epicsMutex > nestedGuard ( this->mutex );
chan.flush ( nestedGuard );
}
}
}
else {
chan.flush ( guard );
}
}
}

1336
src/client/cac.cpp Normal file

File diff suppressed because it is too large Load Diff

435
src/client/cac.h Normal file
View File

@@ -0,0 +1,435 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author: Jeff Hill
*
*/
#ifndef cach
#define cach
#ifdef epicsExportSharedSymbols
# define cach_restore_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "compilerDependencies.h"
#include "ipAddrToAsciiAsynchronous.h"
#include "msgForMultiplyDefinedPV.h"
#include "epicsTimer.h"
#include "epicsEvent.h"
#include "freeList.h"
#include "localHostName.h"
#ifdef cach_restore_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
#include "nciu.h"
#include "comBuf.h"
#include "bhe.h"
#include "cacIO.h"
#include "netIO.h"
#include "localHostName.h"
#include "virtualCircuit.h"
class netWriteNotifyIO;
class netReadNotifyIO;
class netSubscription;
class tcpiiu;
// used to control access to cac's recycle routines which
// should only be indirectly invoked by CAC when its lock
// is applied
class cacRecycle {
public:
virtual void recycleReadNotifyIO (
epicsGuard < epicsMutex > &, netReadNotifyIO &io ) = 0;
virtual void recycleWriteNotifyIO (
epicsGuard < epicsMutex > &, netWriteNotifyIO &io ) = 0;
virtual void recycleSubscription (
epicsGuard < epicsMutex > &, netSubscription &io ) = 0;
protected:
virtual ~cacRecycle() {}
};
struct CASG;
class inetAddrID;
class caServerID;
struct caHdrLargeArray;
class cacComBufMemoryManager : public comBufMemoryManager
{
public:
cacComBufMemoryManager () {}
void * allocate ( size_t );
void release ( void * );
private:
tsFreeList < comBuf, 0x20 > freeList;
cacComBufMemoryManager ( const cacComBufMemoryManager & );
cacComBufMemoryManager & operator = ( const cacComBufMemoryManager & );
};
class notifyGuard {
public:
notifyGuard ( cacContextNotify & );
~notifyGuard ();
private:
cacContextNotify & notify;
notifyGuard ( const notifyGuard & );
notifyGuard & operator = ( const notifyGuard & );
};
class callbackManager : public notifyGuard {
public:
callbackManager (
cacContextNotify &,
epicsMutex & callbackControl );
epicsGuard < epicsMutex > cbGuard;
};
class cac :
public cacContext,
private cacRecycle,
private callbackForMultiplyDefinedPV
{
public:
cac (
epicsMutex & mutualExclusion,
epicsMutex & callbackControl,
cacContextNotify & );
virtual ~cac ();
// beacon management
void beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime,
ca_uint32_t beaconNumber, unsigned protocolRevision );
unsigned beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & ) const;
// IO management
void flush ( epicsGuard < epicsMutex > & guard );
bool executeResponse ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, caHdrLargeArray &, char *pMsgBody );
// channel routines
void transferChanToVirtCircuit (
unsigned cid, unsigned sid,
ca_uint16_t typeCode, arrayElementCount count,
unsigned minorVersionNumber, const osiSockAddr &,
const epicsTime & currentTime );
cacChannel & createChannel (
epicsGuard < epicsMutex > & guard, const char * pChannelName,
cacChannelNotify &, cacChannel::priLev );
void destroyChannel (
epicsGuard < epicsMutex > &, nciu & );
void initiateConnect (
epicsGuard < epicsMutex > &, nciu &, netiiu * & );
nciu * lookupChannel (
epicsGuard < epicsMutex > &, const cacChannel::ioid & );
// IO requests
netWriteNotifyIO & writeNotifyRequest (
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
unsigned type, arrayElementCount nElem, const void * pValue,
cacWriteNotify & );
netReadNotifyIO & readNotifyRequest (
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
unsigned type, arrayElementCount nElem,
cacReadNotify & );
netSubscription & subscriptionRequest (
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
unsigned type, arrayElementCount nElem, unsigned mask,
cacStateNotify &, bool channelIsInstalled );
bool destroyIO (
CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard,
const cacChannel::ioid & idIn,
nciu & chan );
void disconnectAllIO (
epicsGuard < epicsMutex > & cbGuard,
epicsGuard < epicsMutex > & guard,
nciu &, tsDLList < baseNMIU > & ioList );
void ioShow (
epicsGuard < epicsMutex > & guard,
const cacChannel::ioid &id, unsigned level ) const;
// exception generation
void exception (
epicsGuard < epicsMutex > & cbGuard,
epicsGuard < epicsMutex > & guard,
int status, const char * pContext,
const char * pFileName, unsigned lineNo );
// search destination management
void registerSearchDest (
epicsGuard < epicsMutex > &, SearchDest & req );
bool findOrCreateVirtCircuit (
epicsGuard < epicsMutex > &, const osiSockAddr &,
unsigned, tcpiiu *&, unsigned, SearchDestTCP * pSearchDest = NULL );
// diagnostics
unsigned circuitCount ( epicsGuard < epicsMutex > & ) const;
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
int printFormated (
epicsGuard < epicsMutex > & callbackControl,
const char *pformat, ... ) const;
int varArgsPrintFormated (
epicsGuard < epicsMutex > & callbackControl,
const char *pformat, va_list args ) const;
double connectionTimeout ( epicsGuard < epicsMutex > & );
unsigned maxContiguousFrames ( epicsGuard < epicsMutex > & ) const;
// misc
const char * userNamePointer () const;
unsigned getInitializingThreadsPriority () const;
epicsMutex & mutexRef ();
void attachToClientCtx ();
void selfTest (
epicsGuard < epicsMutex > & ) const;
double beaconPeriod (
epicsGuard < epicsMutex > &,
const nciu & chan ) const;
static unsigned lowestPriorityLevelAbove ( unsigned priority );
static unsigned highestPriorityLevelBelow ( unsigned priority );
void destroyIIU ( tcpiiu & iiu );
const char * pLocalHostName ();
private:
epicsSingleton < localHostName > :: reference _refLocalHostName;
chronIntIdResTable < nciu > chanTable;
//
// !!!! There is at this point no good reason
// !!!! to maintain one IO table for all types of
// !!!! IO. It would probably be better to maintain
// !!!! an independent table for each IO type. The
// !!!! new adaptive sized hash table will not
// !!!! waste memory. Making this change will
// !!!! avoid virtual function overhead when
// !!!! accessing the different types of IO. This
// !!!! approach would also probably be safer in
// !!!! terms of detecting damaged protocol.
//
chronIntIdResTable < baseNMIU > ioTable;
resTable < bhe, inetAddrID > beaconTable;
resTable < tcpiiu, caServerID > serverTable;
tsDLList < tcpiiu > circuitList;
tsDLList < SearchDest > searchDestList;
tsDLList < msgForMultiplyDefinedPV > msgMultiPVList;
tsFreeList
< class tcpiiu, 32, epicsMutexNOOP >
freeListVirtualCircuit;
tsFreeList
< class netReadNotifyIO, 1024, epicsMutexNOOP >
freeListReadNotifyIO;
tsFreeList
< class netWriteNotifyIO, 1024, epicsMutexNOOP >
freeListWriteNotifyIO;
tsFreeList
< class netSubscription, 1024, epicsMutexNOOP >
freeListSubscription;
tsFreeList
< class nciu, 1024, epicsMutexNOOP >
channelFreeList;
tsFreeList
< class msgForMultiplyDefinedPV, 16 >
mdpvFreeList;
cacComBufMemoryManager comBufMemMgr;
bheFreeStore bheFreeList;
epicsTime programBeginTime;
double connTMO;
// **** lock hierarchy ****
// 1) callback lock must always be acquired before
// the primary mutex if both locks are needed
epicsMutex & mutex;
epicsMutex & cbMutex;
epicsEvent iiuUninstall;
ipAddrToAsciiEngine & ipToAEngine;
epicsTimerQueueActive & timerQueue;
char * pUserName;
class udpiiu * pudpiiu;
void * tcpSmallRecvBufFreeList;
void * tcpLargeRecvBufFreeList;
cacContextNotify & notify;
epicsThreadId initializingThreadsId;
unsigned initializingThreadsPriority;
unsigned maxRecvBytesTCP;
unsigned maxContigFrames;
unsigned beaconAnomalyCount;
unsigned short _serverPort;
unsigned iiuExistenceCount;
bool cacShutdownInProgress;
void recycleReadNotifyIO (
epicsGuard < epicsMutex > &, netReadNotifyIO &io );
void recycleWriteNotifyIO (
epicsGuard < epicsMutex > &, netWriteNotifyIO &io );
void recycleSubscription (
epicsGuard < epicsMutex > &, netSubscription &io );
void disconnectChannel (
epicsGuard < epicsMutex > & cbGuard,
epicsGuard < epicsMutex > & guard, nciu & chan );
void ioExceptionNotify ( unsigned id, int status,
const char * pContext, unsigned type, arrayElementCount count );
void ioExceptionNotifyAndUninstall ( unsigned id, int status,
const char * pContext, unsigned type, arrayElementCount count );
void pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
const char * pChannelName, const char * pAcc, const char * pRej );
// recv protocol stubs
bool versionAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool echoRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool writeNotifyRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool searchRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool readNotifyRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool eventRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool readRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool clearChannelRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool exceptionRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool accessRightsRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool createChannelRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool verifyAndDisconnectChan ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
bool badTCPRespAction ( callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
typedef bool ( cac::*pProtoStubTCP ) (
callbackManager &, tcpiiu &,
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
static const pProtoStubTCP tcpJumpTableCAC [];
bool defaultExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool eventAddExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool readExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool writeExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool clearChanExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool readNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
bool writeNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
typedef bool ( cac::*pExcepProtoStubTCP ) (
callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
const char *pCtx, unsigned status );
static const pExcepProtoStubTCP tcpExcepJumpTableCAC [];
cac ( const cac & );
cac & operator = ( const cac & );
friend class tcpiiu;
};
inline const char * cac::userNamePointer () const
{
return this->pUserName;
}
inline unsigned cac::getInitializingThreadsPriority () const
{
return this->initializingThreadsPriority;
}
inline epicsMutex & cac::mutexRef ()
{
return this->mutex;
}
inline int cac :: varArgsPrintFormated (
epicsGuard < epicsMutex > & callbackControl,
const char *pformat, va_list args ) const
{
callbackControl.assertIdenticalMutex ( this->cbMutex );
return this->notify.varArgsPrintFormated ( pformat, args );
}
inline void cac::attachToClientCtx ()
{
this->notify.attachToClientCtx ();
}
inline unsigned cac::beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & guard ) const
{
guard.assertIdenticalMutex ( this->mutex );
return this->beaconAnomalyCount;
}
inline notifyGuard::notifyGuard ( cacContextNotify & notifyIn ) :
notify ( notifyIn )
{
this->notify.callbackProcessingInitiateNotify ();
}
inline notifyGuard::~notifyGuard ()
{
this->notify.callbackProcessingCompleteNotify ();
}
inline callbackManager::callbackManager (
cacContextNotify & notify, epicsMutex & callbackControl ) :
notifyGuard ( notify ), cbGuard ( callbackControl )
{
}
inline nciu * cac::lookupChannel (
epicsGuard < epicsMutex > & guard,
const cacChannel::ioid & idIn )
{
guard.assertIdenticalMutex ( this->mutex );
return this->chanTable.lookup ( idIn );
}
inline const char * cac :: pLocalHostName ()
{
return _refLocalHostName->pointer ();
}
inline unsigned cac ::
maxContiguousFrames ( epicsGuard < epicsMutex > & ) const
{
return maxContigFrames;
}
inline double cac ::
connectionTimeout ( epicsGuard < epicsMutex > & guard )
{
guard.assertIdenticalMutex ( this->mutex );
return this->connTMO;
}
#endif // ifdef cach

145
src/client/cacChannel.cpp Normal file
View File

@@ -0,0 +1,145 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#include <stdexcept>
#include <float.h>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "errlog.h"
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "localHostName.h"
#include "cacIO.h"
class CACChannelPrivate {
public:
CACChannelPrivate ();
unsigned getHostName ( char * pBuf, unsigned bufLength );
const char * pHostName ();
private:
epicsSingleton < localHostName > :: reference
_refLocalHostName;
};
static epicsThreadOnceId cacChannelIdOnce = EPICS_THREAD_ONCE_INIT;
const cacChannel::priLev cacChannel::priorityMax = 99u;
const cacChannel::priLev cacChannel::priorityMin = 0u;
const cacChannel::priLev cacChannel::priorityDefault = priorityMin;
const cacChannel::priLev cacChannel::priorityLinksDB = priorityMax;
const cacChannel::priLev cacChannel::priorityArchive = ( priorityMax - priorityMin ) / 2;
const cacChannel::priLev cacChannel::priorityOPI = priorityMin;
cacChannel::~cacChannel ()
{
}
caAccessRights cacChannel::accessRights (
epicsGuard < epicsMutex > & ) const
{
static caAccessRights ar ( true, true );
return ar;
}
unsigned cacChannel::searchAttempts (
epicsGuard < epicsMutex > & ) const
{
return 0u;
}
double cacChannel::beaconPeriod (
epicsGuard < epicsMutex > & ) const
{
return - DBL_MAX;
}
double cacChannel::receiveWatchdogDelay (
epicsGuard < epicsMutex > & ) const
{
return - DBL_MAX;
}
bool cacChannel::ca_v42_ok (
epicsGuard < epicsMutex > & ) const
{
return true;
}
bool cacChannel::connected (
epicsGuard < epicsMutex > & ) const
{
return true;
}
CACChannelPrivate ::
CACChannelPrivate() :
_refLocalHostName ( localHostNameCache.getReference () )
{
}
inline unsigned CACChannelPrivate ::
getHostName ( char * pBuf, unsigned bufLength )
{
return _refLocalHostName->getName ( pBuf, bufLength );
}
inline const char * CACChannelPrivate ::
pHostName ()
{
return _refLocalHostName->pointer ();
}
static CACChannelPrivate * pCACChannelPrivate = 0;
// runs once only for each process
extern "C" void cacChannelSetup ( void * )
{
pCACChannelPrivate = new CACChannelPrivate ();
}
// the default is to assume that it is a locally hosted channel
unsigned cacChannel::getHostName (
epicsGuard < epicsMutex > &,
char * pBuf, unsigned bufLength ) const throw ()
{
if ( bufLength ) {
epicsThreadOnce ( & cacChannelIdOnce, cacChannelSetup, 0);
return pCACChannelPrivate->getHostName ( pBuf, bufLength );
}
return 0u;
}
// the default is to assume that it is a locally hosted channel
const char * cacChannel::pHostName (
epicsGuard < epicsMutex > & ) const throw ()
{
epicsThreadOnce ( & cacChannelIdOnce, cacChannelSetup, 0);
return pCACChannelPrivate->pHostName ();
}
cacContext::~cacContext () {}
cacService::~cacService () {}

View File

@@ -8,16 +8,27 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#include <unistd.h>
#include "iocinf.h"
#define epicsExportSharedSymbols
#include "cacIO.h"
#undef epicsExportSharedSymbols
cacChannelNotify::~cacChannelNotify ()
{
}
/*
* Some systems fail to provide prototypes of these functions.
* Others provide different prototypes.
* There seems to be no way to handle this automatically, so
* if you get compile errors, just make the appropriate changes here.
*/

View File

@@ -8,24 +8,36 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <osiUnistd.h>
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#include <stdlib.h>
#include "iocinf.h"
#define epicsExportSharedSymbols
#include <epicsStdio.h>
#include "cacIO.h"
#undef epicsExportSharedSymbols
epicsShareFunc int epicsShareAPI epicsSnprintf(
char *str, size_t size, const char *format, ...)
cacContextNotify::~cacContextNotify ()
{
int nchars;
va_list pvar;
va_start(pvar,format);
nchars = epicsVsnprintf(str,size,format,pvar);
va_end (pvar);
return(nchars);
}
epicsShareFunc int epicsShareAPI epicsVsnprintf(
char *str, size_t size, const char *format, va_list ap)
void cacContextNotify::callbackProcessingInitiateNotify ()
{
return vsnprintf ( str, size, format, ap );
}
void cacContextNotify::callbackProcessingCompleteNotify ()
{
}

392
src/client/cacIO.h Normal file
View File

@@ -0,0 +1,392 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef cacIOh
#define cacIOh
//
// Open Issues
// -----------
//
// 1) A status code from the old client side interface is passed
// to the exception notify callback. Should we just pass a string?
// If so, then how do they detect the type of error and recover.
// Perhaps we should call a different vf for each type of exception.
//
// 2) Some exception types are present here but there is no common
// exception base class in use.
//
// 3) Should I be passing the channel reference in cacChannelNotify?
//
// 4) Should the code for caAccessRights not be inline so that this
// interface is version independent.
//
//
#include <new>
#include <stdarg.h>
#ifdef epicsExportSharedSymbols
# define cacIOh_restore_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "tsDLList.h"
#include "epicsMutex.h"
#include "epicsGuard.h"
#include "epicsThread.h"
#ifdef cacIOh_restore_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
class cacChannel;
typedef unsigned long arrayElementCount;
// 1) this should not be passing caerr.h status to the exception callback
// 2) needless-to-say the data should be passed here using the new data access API
class epicsShareClass cacWriteNotify {
public:
virtual ~cacWriteNotify () = 0;
virtual void completion ( epicsGuard < epicsMutex > & ) = 0;
// we should probably have a different vf for each type of exception ????
virtual void exception (
epicsGuard < epicsMutex > &,
int status, const char * pContext,
unsigned type, arrayElementCount count ) = 0;
};
// 1) this should not be passing caerr.h status to the exception callback
// 2) needless-to-say the data should be passed here using the new data access API
class epicsShareClass cacReadNotify {
public:
virtual ~cacReadNotify () = 0;
virtual void completion (
epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, const void * pData ) = 0;
// we should probably have a different vf for each type of exception ????
virtual void exception (
epicsGuard < epicsMutex > &, int status,
const char * pContext, unsigned type,
arrayElementCount count ) = 0;
};
// 1) this should not be passing caerr.h status to the exception callback
// 2) needless-to-say the data should be passed here using the new data access API
class epicsShareClass cacStateNotify {
public:
virtual ~cacStateNotify () = 0;
virtual void current (
epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, const void * pData ) = 0;
// we should probably have a different vf for each type of exception ????
virtual void exception (
epicsGuard < epicsMutex > &, int status,
const char *pContext, unsigned type,
arrayElementCount count ) = 0;
};
class caAccessRights {
public:
caAccessRights (
bool readPermit = false,
bool writePermit = false,
bool operatorConfirmationRequest = false);
void setReadPermit ();
void setWritePermit ();
void setOperatorConfirmationRequest ();
void clrReadPermit ();
void clrWritePermit ();
void clrOperatorConfirmationRequest ();
bool readPermit () const;
bool writePermit () const;
bool operatorConfirmationRequest () const;
private:
bool f_readPermit:1;
bool f_writePermit:1;
bool f_operatorConfirmationRequest:1;
};
class epicsShareClass cacChannelNotify {
public:
virtual ~cacChannelNotify () = 0;
virtual void connectNotify ( epicsGuard < epicsMutex > & ) = 0;
virtual void disconnectNotify ( epicsGuard < epicsMutex > & ) = 0;
virtual void serviceShutdownNotify (
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
virtual void accessRightsNotify (
epicsGuard < epicsMutex > &, const caAccessRights & ) = 0;
virtual void exception (
epicsGuard < epicsMutex > &, int status, const char *pContext ) = 0;
// we should probably have a different vf for each type of exception ????
virtual void readException (
epicsGuard < epicsMutex > &, int status, const char *pContext,
unsigned type, arrayElementCount count, void *pValue ) = 0;
// we should probably have a different vf for each type of exception ????
virtual void writeException (
epicsGuard < epicsMutex > &, int status, const char * pContext,
unsigned type, arrayElementCount count ) = 0;
};
class CallbackGuard :
public epicsGuard < epicsMutex > {
public:
CallbackGuard ( epicsMutex & mutex ) :
epicsGuard < epicsMutex > ( mutex ) {}
private:
CallbackGuard ( const CallbackGuard & );
CallbackGuard & operator = ( const CallbackGuard & );
};
//
// Notes
// 1) This interface assumes that when a channel is deleted then all
// attached IO is deleted. This is left over from the old interface,
// but perhaps is a bad practice that should be eliminated? If so,
// then the IO should not store or use a pointer to the channel.
//
class epicsShareClass cacChannel {
public:
typedef unsigned priLev;
static const priLev priorityMax;
static const priLev priorityMin;
static const priLev priorityDefault;
static const priLev priorityLinksDB;
static const priLev priorityArchive;
static const priLev priorityOPI;
typedef unsigned ioid;
enum ioStatus { iosSynch, iosAsynch };
cacChannel ( cacChannelNotify & );
virtual void destroy (
CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
cacChannelNotify & notify () const; // required ?????
virtual unsigned getName (
epicsGuard < epicsMutex > &,
char * pBuf, unsigned bufLen ) const throw () = 0;
// !! deprecated, avoid use !!
virtual const char * pName (
epicsGuard < epicsMutex > & guard ) const throw () = 0;
virtual void show (
epicsGuard < epicsMutex > &,
unsigned level ) const = 0;
virtual void initiateConnect (
epicsGuard < epicsMutex > & ) = 0;
virtual unsigned requestMessageBytesPending (
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
virtual void flush (
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
virtual ioStatus read (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
cacReadNotify &, ioid * = 0 ) = 0;
virtual void write (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
const void *pValue ) = 0;
virtual ioStatus write (
epicsGuard < epicsMutex > &,
unsigned type, arrayElementCount count,
const void *pValue, cacWriteNotify &, ioid * = 0 ) = 0;
virtual void subscribe (
epicsGuard < epicsMutex > &, unsigned type,
arrayElementCount count, unsigned mask, cacStateNotify &,
ioid * = 0 ) = 0;
// The primary mutex must be released when calling the user's
// callback, and therefore a finite interval exists when we are
// moving forward with the intent to call the users callback
// but the users IO could be deleted during this interval.
// To prevent the user's callback from being called after
// destroying his IO we must past a guard for the callback
// mutex here.
virtual void ioCancel (
CallbackGuard & callbackGuard,
epicsGuard < epicsMutex > & mutualExclusionGuard,
const ioid & ) = 0;
virtual void ioShow (
epicsGuard < epicsMutex > &,
const ioid &, unsigned level ) const = 0;
virtual short nativeType (
epicsGuard < epicsMutex > & ) const = 0;
virtual arrayElementCount nativeElementCount (
epicsGuard < epicsMutex > & ) const = 0;
virtual caAccessRights accessRights (
epicsGuard < epicsMutex > & ) const;
virtual unsigned searchAttempts (
epicsGuard < epicsMutex > & ) const;
virtual double beaconPeriod (
epicsGuard < epicsMutex > & ) const; // negative DBL_MAX if UKN
virtual double receiveWatchdogDelay (
epicsGuard < epicsMutex > & ) const; // negative DBL_MAX if UKN
virtual bool ca_v42_ok (
epicsGuard < epicsMutex > & ) const;
virtual bool connected (
epicsGuard < epicsMutex > & ) const;
virtual unsigned getHostName (
epicsGuard < epicsMutex > &,
char * pBuf, unsigned bufLength ) const throw ();
// !! deprecated, avoid use !!
virtual const char * pHostName (
epicsGuard < epicsMutex > & guard ) const throw ();
// exceptions
class badString {};
class badType {};
class badPriority {};
class outOfBounds {};
class badEventSelection {};
class noWriteAccess {};
class noReadAccess {};
class notConnected {};
class unsupportedByService {};
class msgBodyCacheTooSmall {}; // hopefully this one goes away in the future
class requestTimedOut {};
protected:
virtual ~cacChannel () = 0;
private:
cacChannelNotify & callback;
cacChannel ( const cacChannel & );
cacChannel & operator = ( const cacChannel & );
};
class epicsShareClass cacContext {
public:
virtual ~cacContext ();
virtual cacChannel & createChannel (
epicsGuard < epicsMutex > &,
const char * pChannelName, cacChannelNotify &,
cacChannel::priLev = cacChannel::priorityDefault ) = 0;
virtual void flush (
epicsGuard < epicsMutex > & ) = 0;
virtual unsigned circuitCount (
epicsGuard < epicsMutex > & ) const = 0;
virtual void selfTest (
epicsGuard < epicsMutex > & ) const = 0;
virtual unsigned beaconAnomaliesSinceProgramStart (
epicsGuard < epicsMutex > & ) const = 0;
virtual void show (
epicsGuard < epicsMutex > &, unsigned level ) const = 0;
};
class epicsShareClass cacContextNotify {
public:
virtual ~cacContextNotify () = 0;
virtual cacContext & createNetworkContext (
epicsMutex & mutualExclusion, epicsMutex & callbackControl ) = 0;
// we should probably have a different vf for each type of exception ????
virtual void exception (
epicsGuard < epicsMutex > &, int status, const char * pContext,
const char * pFileName, unsigned lineNo ) = 0;
// perhaps this should be phased out in deference to the exception mechanism
virtual int varArgsPrintFormated ( const char * pformat, va_list args ) const = 0;
// backwards compatibility (from here down)
virtual void attachToClientCtx () = 0;
virtual void callbackProcessingInitiateNotify () = 0;
virtual void callbackProcessingCompleteNotify () = 0;
};
// **** Lock Hierarchy ****
// callbackControl must be taken before mutualExclusion if both are held at
// the same time
class epicsShareClass cacService {
public:
virtual ~cacService () = 0;
virtual cacContext & contextCreate (
epicsMutex & mutualExclusion,
epicsMutex & callbackControl,
cacContextNotify & ) = 0;
};
epicsShareFunc void epicsShareAPI caInstallDefaultService ( cacService & service );
epicsShareExtern epicsThreadPrivateId caClientCallbackThreadId;
inline cacChannel::cacChannel ( cacChannelNotify & notify ) :
callback ( notify )
{
}
inline cacChannelNotify & cacChannel::notify () const
{
return this->callback;
}
inline caAccessRights::caAccessRights (
bool readPermit, bool writePermit, bool operatorConfirmationRequest) :
f_readPermit ( readPermit ), f_writePermit ( writePermit ),
f_operatorConfirmationRequest ( operatorConfirmationRequest ) {}
inline void caAccessRights::setReadPermit ()
{
this->f_readPermit = true;
}
inline void caAccessRights::setWritePermit ()
{
this->f_writePermit = true;
}
inline void caAccessRights::setOperatorConfirmationRequest ()
{
this->f_operatorConfirmationRequest = true;
}
inline void caAccessRights::clrReadPermit ()
{
this->f_readPermit = false;
}
inline void caAccessRights::clrWritePermit ()
{
this->f_writePermit = false;
}
inline void caAccessRights::clrOperatorConfirmationRequest ()
{
this->f_operatorConfirmationRequest = false;
}
inline bool caAccessRights::readPermit () const
{
return this->f_readPermit;
}
inline bool caAccessRights::writePermit () const
{
return this->f_writePermit;
}
inline bool caAccessRights::operatorConfirmationRequest () const
{
return this->f_operatorConfirmationRequest;
}
#endif // ifndef cacIOh

View File

@@ -8,16 +8,23 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define epicsExportSharedSymbols
#include "osiPoolStatus.h"
/*
* osiSufficentSpaceInPool ()
/*
*
* @@@@@ not implemented @@@@@
* 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
*/
epicsShareFunc int epicsShareAPI osiSufficentSpaceInPool ( size_t contiguousBlockSize )
#include "iocinf.h"
#define epicsExportSharedSymbols
#include "cacIO.h"
#undef epicsExportSharedSymbols
cacReadNotify::~cacReadNotify ()
{
return 1;
}

View File

@@ -8,16 +8,23 @@
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#define epicsExportSharedSymbols
#include "osiPoolStatus.h"
/*
* osiSufficentSpaceInPool ()
/*
*
* @@@@@ not implemented @@@@@
* 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
*/
epicsShareFunc int epicsShareAPI osiSufficentSpaceInPool ( size_t contiguousBlockSize )
#include "iocinf.h"
#define epicsExportSharedSymbols
#include "cacIO.h"
#undef epicsExportSharedSymbols
cacStateNotify::~cacStateNotify ()
{
return 1;
}

View File

@@ -1,4 +1,3 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
@@ -8,15 +7,24 @@
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Jeff Hill
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#define epicsExportSharedSymbols
#include "osiSock.h"
#include "iocinf.h"
enum epicsSocketSystemCallInterruptMechanismQueryInfo
epicsSocketSystemCallInterruptMechanismQuery ()
#define epicsExportSharedSymbols
#include "cacIO.h"
#undef epicsExportSharedSymbols
cacWriteNotify::~cacWriteNotify ()
{
return esscimqi_socketBothShutdownRequired;
}

904
src/client/cadef.h Normal file
View File

@@ -0,0 +1,904 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
*/
#ifndef INCLcadefh
#define INCLcadefh
/*
* done in two ifdef steps so that we will remain compatible with
* traditional C
*/
#ifndef CA_DONT_INCLUDE_STDARGH
# include <stdarg.h>
#endif
#ifdef epicsExportSharedSymbols
# define INCLcadefh_accessh_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "epicsThread.h"
#ifdef INCLcadefh_accessh_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
#include "caerr.h"
#include "db_access.h"
#include "caeventmask.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct oldChannelNotify *chid;
typedef chid chanId; /* for when the structures field name is "chid" */
typedef long chtype;
typedef struct oldSubscription *evid;
typedef double ca_real;
/* arguments passed to user connection handlers */
struct connection_handler_args {
chanId chid; /* channel id */
long op; /* one of CA_OP_CONN_UP or CA_OP_CONN_DOWN */
};
typedef void caCh (struct connection_handler_args args);
typedef struct ca_access_rights {
unsigned read_access:1;
unsigned write_access:1;
} caar;
/* arguments passed to user access rights handlers */
struct access_rights_handler_args {
chanId chid; /* channel id */
caar ar; /* new access rights state */
};
typedef void caArh (struct access_rights_handler_args args);
/* The conversion routine to call for each type */
#define VALID_TYPE(TYPE) (((unsigned short)TYPE)<=LAST_BUFFER_TYPE)
/*
* Arguments passed to event handlers and get/put call back handlers.
*
* The status field below is the CA ECA_XXX status of the requested
* operation which is saved from when the operation was attempted in the
* server and copied back to the clients call back routine.
* If the status is not ECA_NORMAL then the dbr pointer will be NULL
* and the requested operation can not be assumed to be successful.
*/
typedef struct event_handler_args {
void *usr; /* user argument supplied with request */
chanId chid; /* channel id */
long type; /* the type of the item returned */
long count; /* the element count of the item returned */
const void *dbr; /* a pointer to the item returned */
int status; /* ECA_XXX status of the requested op from the server */
} evargs;
typedef void caEventCallBackFunc (struct event_handler_args);
epicsShareFunc void epicsShareAPI ca_test_event
(
struct event_handler_args
);
/* arguments passed to user exception handlers */
struct exception_handler_args {
void *usr; /* user argument supplied when installed */
chanId chid; /* channel id (may be nill) */
long type; /* type requested */
long count; /* count requested */
void *addr; /* user's address to write results of CA_OP_GET */
long stat; /* channel access ECA_XXXX status code */
long op; /* CA_OP_GET, CA_OP_PUT, ..., CA_OP_OTHER */
const char *ctx; /* a character string containing context info */
const char *pFile; /* source file name (may be NULL) */
unsigned lineNo; /* source file line number (may be zero) */
};
typedef unsigned CA_SYNC_GID;
/*
* External OP codes for CA operations
*/
#define CA_OP_GET 0
#define CA_OP_PUT 1
#define CA_OP_CREATE_CHANNEL 2
#define CA_OP_ADD_EVENT 3
#define CA_OP_CLEAR_EVENT 4
#define CA_OP_OTHER 5
/*
* used with connection_handler_args
*/
#define CA_OP_CONN_UP 6
#define CA_OP_CONN_DOWN 7
/* depricated */
#define CA_OP_SEARCH 2
/*
* provides efficient test and display of channel access errors
*/
#define SEVCHK(CA_ERROR_CODE, MESSAGE_STRING) \
{ \
int ca_unique_status_name = (CA_ERROR_CODE); \
if(!(ca_unique_status_name & CA_M_SUCCESS)) \
ca_signal_with_file_and_lineno( \
ca_unique_status_name, \
(MESSAGE_STRING), \
__FILE__, \
__LINE__); \
}
#define TYPENOTCONN (-1) /* the channel's native type when disconnected */
epicsShareFunc short epicsShareAPI ca_field_type (chid chan);
epicsShareFunc unsigned long epicsShareAPI ca_element_count (chid chan);
epicsShareFunc const char * epicsShareAPI ca_name (chid chan);
epicsShareFunc void epicsShareAPI ca_set_puser (chid chan, void *puser);
epicsShareFunc void * epicsShareAPI ca_puser (chid chan);
epicsShareFunc unsigned epicsShareAPI ca_read_access (chid chan);
epicsShareFunc unsigned epicsShareAPI ca_write_access (chid chan);
/*
* cs_ - `channel state'
*
* cs_never_conn valid chid, IOC not found
* cs_prev_conn valid chid, IOC was found, but unavailable
* cs_conn valid chid, IOC was found, still available
* cs_closed channel deleted by user
*/
enum channel_state {cs_never_conn, cs_prev_conn, cs_conn, cs_closed};
epicsShareFunc enum channel_state epicsShareAPI ca_state (chid chan);
/************************************************************************/
/* Perform Library Initialization */
/* */
/* Must be called once before calling any of the other routines */
/************************************************************************/
epicsShareFunc int epicsShareAPI ca_task_initialize (void);
enum ca_preemptive_callback_select
{ ca_disable_preemptive_callback, ca_enable_preemptive_callback };
epicsShareFunc int epicsShareAPI
ca_context_create (enum ca_preemptive_callback_select select);
epicsShareFunc void epicsShareAPI ca_detach_context ();
/************************************************************************/
/* Remove CA facility from your task */
/* */
/* Normally called automatically at task exit */
/************************************************************************/
epicsShareFunc int epicsShareAPI ca_task_exit (void);
epicsShareFunc void epicsShareAPI ca_context_destroy (void);
typedef unsigned capri;
#define CA_PRIORITY_MAX 99
#define CA_PRIORITY_MIN 0
#define CA_PRIORITY_DEFAULT CA_PRIORITY_MIN
#define CA_PRIORITY_DB_LINKS 80
#define CA_PRIORITY_ARCHIVE 20
#define CA_PRIORITY_OPI 0
/*
* ca_create_channel ()
*
* pChanName R channel name string
* pConnStateCallback R address of connection state change
* callback function
* pUserPrivate R placed in the channel's user private field
* o can be fetched later by ca_puser(CHID)
* o passed as void * arg to *pConnectCallback above
* priority R priority level in the server 0 - 100
* pChanID RW channel id written here
*/
epicsShareFunc int epicsShareAPI ca_create_channel
(
const char *pChanName,
caCh *pConnStateCallback,
void *pUserPrivate,
capri priority,
chid *pChanID
);
/*
* ca_change_connection_event()
*
* chan R channel identifier
* pfunc R address of connection call-back function
*/
epicsShareFunc int epicsShareAPI ca_change_connection_event
(
chid chan,
caCh * pfunc
);
/*
* ca_replace_access_rights_event ()
*
* chan R channel identifier
* pfunc R address of access rights call-back function
*/
epicsShareFunc int epicsShareAPI ca_replace_access_rights_event (
chid chan,
caArh *pfunc
);
/*
* ca_add_exception_event ()
*
* replace the default exception handler
*
* pfunc R address of exception call-back function
* pArg R copy of this pointer passed to exception
* call-back function
*/
typedef void caExceptionHandler (struct exception_handler_args);
epicsShareFunc int epicsShareAPI ca_add_exception_event
(
caExceptionHandler *pfunc,
void *pArg
);
/*
* ca_clear_channel()
* - deallocate resources reserved for a channel
*
* chanId R channel ID
*/
epicsShareFunc int epicsShareAPI ca_clear_channel
(
chid chanId
);
/************************************************************************/
/* Write a value to a channel */
/************************************************************************/
/*
* ca_bput()
*
* WARNING: this copies the new value from a string (dbr_string_t)
* (and not as an integer)
*
* chan R channel identifier
* pValue R new channel value string copied from this location
*/
#define ca_bput(chan, pValue) \
ca_array_put(DBR_STRING, 1u, chan, (const dbr_string_t *) (pValue))
/*
* ca_rput()
*
* WARNING: this copies the new value from a dbr_float_t
*
* chan R channel identifier
* pValue R new channel value copied from this location
*/
#define ca_rput(chan,pValue) \
ca_array_put(DBR_FLOAT, 1u, chan, (const dbr_float_t *) pValue)
/*
* ca_put()
*
* type R data type from db_access.h
* chan R channel identifier
* pValue R new channel value copied from this location
*/
#define ca_put(type, chan, pValue) ca_array_put (type, 1u, chan, pValue)
/*
* ca_array_put()
*
* type R data type from db_access.h
* count R array element count
* chan R channel identifier
* pValue R new channel value copied from this location
*/
epicsShareFunc int epicsShareAPI ca_array_put
(
chtype type,
unsigned long count,
chid chanId,
const void * pValue
);
/*
* ca_array_put_callback()
*
* This routine functions identically to the original ca put request
* with the addition of a callback to the user supplied function
* after recod processing completes in the IOC. The arguments
* to the user supplied callback function are declared in
* the structure event_handler_args and include the pointer
* sized user argument supplied when ca_array_put_callback() is called.
*
* type R data type from db_access.h
* count R array element count
* chan R channel identifier
* pValue R new channel value copied from this location
* pFunc R pointer to call-back function
* pArg R copy of this pointer passed to pFunc
*/
epicsShareFunc int epicsShareAPI ca_array_put_callback
(
chtype type,
unsigned long count,
chid chanId,
const void * pValue,
caEventCallBackFunc * pFunc,
void * pArg
);
#define ca_put_callback(type, chan, pValue, pFunc, pArg) \
ca_array_put_callback(type, 1u, chan, pValue, pFunc, pArg)
/************************************************************************/
/* Read a value from a channel */
/************************************************************************/
/*
* ca_bget()
*
* WARNING: this copies the new value into a string (dbr_string_t)
* (and not into an integer)
*
* chan R channel identifier
* pValue W channel value copied to this location
*/
#define ca_bget(chan, pValue) \
ca_array_get(DBR_STRING, 1u, chan, (dbr_string_t *)(pValue))
/*
* ca_rget()
*
* WARNING: this copies the new value into a 32 bit float (dbr_float_t)
*
* chan R channel identifier
* pValue W channel value copied to this location
*/
#define ca_rget(chan, pValue) \
ca_array_get(DBR_FLOAT, 1u, chan, (dbr_float_t *)(pValue))
/*
* ca_rget()
*
* type R data type from db_access.h
* chan R channel identifier
* pValue W channel value copied to this location
*/
#define ca_get(type, chan, pValue) ca_array_get(type, 1u, chan, pValue)
/*
* ca_array_get()
*
* type R data type from db_access.h
* count R array element count
* chan R channel identifier
* pValue W channel value copied to this location
*/
epicsShareFunc int epicsShareAPI ca_array_get
(
chtype type,
unsigned long count,
chid chanId,
void * pValue
);
/************************************************************************/
/* Read a value from a channel and run a callback when the value */
/* returns */
/* */
/* */
/************************************************************************/
/*
* ca_bget_callback()
*
* WARNING: this returns the new value as a string (dbr_string_t)
* (and not as an integer)
*
* chan R channel identifier
* pFunc R pointer to call-back function
* pArg R copy of this pointer passed to pFunc
*/
#define ca_bget_callback(chan, pFunc, pArg)\
ca_array_get_callback (DBR_STRING, 1u, chan, pFunc, pArg)
/*
* ca_rget_callback()
*
* WARNING: this returns the new value as a float (dbr_float_t)
*
* chan R channel identifier
* pFunc R pointer to call-back function
* pArg R copy of this pointer passed to pFunc
*/
#define ca_rget_callback(chan, pFunc, pArg)\
ca_array_get_callback (DBR_FLOAT, 1u, chan, pFunc, pArg)
/*
* ca_get_callback()
*
* type R data type from db_access.h
* chan R channel identifier
* pFunc R pointer to call-back function
* pArg R copy of this pointer passed to pFunc
*/
#define ca_get_callback(type, chan, pFunc, pArg)\
ca_array_get_callback (type, 1u, chan, pFunc, pArg)
/*
* ca_array_get_callback()
*
* type R data type from db_access.h
* count R array element count
* chan R channel identifier
* pFunc R pointer to call-back function
* pArg R copy of this pointer passed to pFunc
*/
epicsShareFunc int epicsShareAPI ca_array_get_callback
(
chtype type,
unsigned long count,
chid chanId,
caEventCallBackFunc * pFunc,
void * pArg
);
/************************************************************************/
/* Specify a function to be executed whenever significant changes */
/* occur to a channel. */
/* NOTES: */
/* 1) Evid may be omited by passing a NULL pointer */
/* */
/* 2) An array count of zero specifies the native db count */
/* */
/************************************************************************/
/*
* ca_create_subscription ()
*
* type R data type from db_access.h
* count R array element count
* chan R channel identifier
* mask R event mask - one of {DBE_VALUE, DBE_ALARM, DBE_LOG}
* pFunc R pointer to call-back function
* pArg R copy of this pointer passed to pFunc
* pEventID W event id written at specified address
*/
epicsShareFunc int epicsShareAPI ca_create_subscription
(
chtype type,
unsigned long count,
chid chanId,
long mask,
caEventCallBackFunc * pFunc,
void * pArg,
evid * pEventID
);
/************************************************************************/
/* Remove a function from a list of those specified to run */
/* whenever significant changes occur to a channel */
/* */
/************************************************************************/
/*
* ca_clear_subscription()
*
* eventID R event id
*/
epicsShareFunc int epicsShareAPI ca_clear_subscription
(
evid eventID
);
epicsShareFunc chid epicsShareAPI ca_evid_to_chid ( evid id );
/************************************************************************/
/* */
/* Requested data is not necessarily stable prior to */
/* return from called subroutine. Call ca_pend_io() */
/* to guarantee that requested data is stable. Call the routine */
/* ca_flush_io() to force all outstanding requests to be */
/* sent out over the network. Significant increases in */
/* performance have been measured when batching several remote */
/* requests together into one message. Additional */
/* improvements can be obtained by performing local processing */
/* in parallel with outstanding remote processing. */
/* */
/* FLOW OF TYPICAL APPLICATION */
/* */
/* search() ! Obtain Channel ids */
/* . ! " */
/* . ! " */
/* pend_io ! wait for channels to connect */
/* */
/* get() ! several requests for remote info */
/* get() ! " */
/* add_event() ! " */
/* get() ! " */
/* . */
/* . */
/* . */
/* flush_io() ! send get requests */
/* ! optional parallel processing */
/* . ! " */
/* . ! " */
/* pend_io() ! wait for replies from get requests */
/* . ! access to requested data */
/* . ! " */
/* pend_event() ! wait for requested events */
/* */
/************************************************************************/
/************************************************************************/
/* These routines wait for channel subscription events and call the */
/* functions specified with add_event when events occur. If the */
/* timeout is specified as 0 an infinite timeout is assumed. */
/* ca_flush_io() is called by this routine. If ca_pend_io () */
/* is called when no IO is outstanding then it will return immediately */
/* without processing. */
/************************************************************************/
/*
* ca_pend_event()
*
* timeOut R wait for this delay in seconds
*/
epicsShareFunc int epicsShareAPI ca_pend_event (ca_real timeOut);
#define ca_poll() ca_pend_event(1e-12)
/*
* ca_pend_io()
*
* timeOut R wait for this delay in seconds but return early
* if all get requests (or search requests with null
* connection handler pointer have completed)
*/
epicsShareFunc int epicsShareAPI ca_pend_io (ca_real timeOut);
/* calls ca_pend_io() if early is true otherwise ca_pend_event() is called */
epicsShareFunc int epicsShareAPI ca_pend (ca_real timeout, int early);
/*
* ca_test_io()
*
* returns TRUE when get requests (or search requests with null
* connection handler pointer) are outstanding
*/
epicsShareFunc int epicsShareAPI ca_test_io (void);
/************************************************************************/
/* Send out all outstanding messages in the send queue */
/************************************************************************/
/*
* ca_flush_io()
*/
epicsShareFunc int epicsShareAPI ca_flush_io (void);
/*
* ca_signal()
*
* errorCode R status returned from channel access function
* pCtxStr R context string included with error print out
*/
epicsShareFunc void epicsShareAPI ca_signal
(
long errorCode,
const char *pCtxStr
);
/*
* ca_signal_with_file_and_lineno()
* errorCode R status returned from channel access function
* pCtxStr R context string included with error print out
* pFileStr R file name string included with error print out
* lineNo R line number included with error print out
*
*/
epicsShareFunc void epicsShareAPI ca_signal_with_file_and_lineno
(
long errorCode,
const char *pCtxStr,
const char *pFileStr,
int lineNo
);
/*
* ca_signal_formated()
* errorCode R status returned from channel access function
* pFileStr R file name string included with error print out
* lineNo R line number included with error print out
* pFormat R printf dtyle format string (and optional arguments)
*
*/
epicsShareFunc void epicsShareAPI ca_signal_formated (long ca_status, const char *pfilenm,
int lineno, const char *pFormat, ...);
/*
* ca_host_name_function()
*
* channel R channel identifier
*
* !!!! this function is _not_ thread safe !!!!
*/
epicsShareFunc const char * epicsShareAPI ca_host_name (chid channel);
/* thread safe version */
epicsShareFunc unsigned epicsShareAPI ca_get_host_name ( chid pChan,
char *pBuf, unsigned bufLength );
/*
* CA_ADD_FD_REGISTRATION
*
* call their function with their argument whenever
* a new fd is added or removed
* (for use with a manager of the select system call under UNIX)
*
* if (opened) then fd was created
* if (!opened) then fd was deleted
*
*/
typedef void CAFDHANDLER (void *parg, int fd, int opened);
/*
* ca_add_fd_registration()
*
* pHandler R pointer to function which is to be called
* when an fd is created or deleted
* pArg R argument passed to above function
*/
epicsShareFunc int epicsShareAPI ca_add_fd_registration
(
CAFDHANDLER *pHandler,
void *pArg
);
/*
* CA synch groups
*
* This facility will allow the programmer to create
* any number of synchronization groups. The programmer might then
* interleave IO requests within any of the groups. Once The
* IO operations are initiated then the programmer is free to
* block for IO completion within any one of the groups as needed.
*/
/*
* ca_sg_create()
*
* create a sync group
*
* pgid W pointer to sync group id that will be written
*/
epicsShareFunc int epicsShareAPI ca_sg_create (CA_SYNC_GID * pgid);
/*
* ca_sg_delete()
*
* delete a sync group
*
* gid R sync group id
*/
epicsShareFunc int epicsShareAPI ca_sg_delete (const CA_SYNC_GID gid);
/*
* ca_sg_block()
*
* block for IO performed within a sync group to complete
*
* gid R sync group id
* timeout R wait for this duration prior to timing out
* and returning ECA_TIMEOUT
*/
epicsShareFunc int epicsShareAPI ca_sg_block (const CA_SYNC_GID gid, ca_real timeout);
/*
* ca_sg_test()
*
* test for sync group IO operations in progress
*
* gid R sync group id
*
* returns one of ECA_BADSYNCGRP, ECA_IOINPROGRESS, ECA_IODONE
*/
epicsShareFunc int epicsShareAPI ca_sg_test (const CA_SYNC_GID gid);
/*
* ca_sg_reset
*
* gid R sync group id
*/
epicsShareFunc int epicsShareAPI ca_sg_reset(const CA_SYNC_GID gid);
/*
* ca_sg_array_get()
*
* initiate a get within a sync group
* (essentially a ca_array_get() with a sync group specified)
*
* gid R sync group id
* type R data type from db_access.h
* count R array element count
* chan R channel identifier
* pValue W channel value copied to this location
*/
epicsShareFunc int epicsShareAPI ca_sg_array_get
(
const CA_SYNC_GID gid,
chtype type,
unsigned long count,
chid chan,
void *pValue
);
#define ca_sg_get(gid, type, chan, pValue) \
ca_sg_array_get (gid, type, 1u, chan, pValue)
/*
* ca_sg_array_put()
*
* initiate a put within a sync group
* (essentially a ca_array_put() with a sync group specified)
*
* gid R sync group id
* type R data type from db_access.h
* count R array element count
* chan R channel identifier
* pValue R new channel value copied from this location
*/
epicsShareFunc int epicsShareAPI ca_sg_array_put
(
const CA_SYNC_GID gid,
chtype type,
unsigned long count,
chid chan,
const void *pValue
);
#define ca_sg_put(gid, type, chan, pValue) \
ca_sg_array_put (gid, type, 1u, chan, pValue)
/*
* ca_sg_stat()
*
* print status of a sync group
*
* gid R sync group id
*/
epicsShareFunc int epicsShareAPI ca_sg_stat (CA_SYNC_GID gid);
epicsShareFunc void epicsShareAPI ca_dump_dbr (chtype type, unsigned count, const void * pbuffer);
/*
* ca_v42_ok()
*
* Put call back is available if the CA server is on version is 4.2
* or higher.
*
* chan R channel identifier
*
* (returns true or false)
*/
epicsShareFunc int epicsShareAPI ca_v42_ok (chid chan);
/*
* ca_version()
*
* returns the CA version string
*/
epicsShareFunc const char * epicsShareAPI ca_version (void);
/*
* ca_replace_printf_handler ()
*
* for apps that want to change where ca formatted
* text output goes
*
* use two ifdef's for trad C compatibility
*
* ca_printf_func R pointer to new function called when
* CA prints an error message
*/
#ifndef CA_DONT_INCLUDE_STDARGH
typedef int caPrintfFunc (const char *pformat, va_list args);
epicsShareFunc int epicsShareAPI ca_replace_printf_handler (
caPrintfFunc *ca_printf_func
);
#endif /*CA_DONT_INCLUDE_STDARGH*/
/*
* (for testing purposes only)
*/
epicsShareFunc unsigned epicsShareAPI ca_get_ioc_connection_count (void);
epicsShareFunc int epicsShareAPI ca_preemtive_callback_is_enabled (void);
epicsShareFunc void epicsShareAPI ca_self_test (void);
epicsShareFunc unsigned epicsShareAPI ca_beacon_anomaly_count (void);
epicsShareFunc unsigned epicsShareAPI ca_search_attempts (chid chan);
epicsShareFunc double epicsShareAPI ca_beacon_period (chid chan);
epicsShareFunc double epicsShareAPI ca_receive_watchdog_delay (chid chan);
/*
* used when an auxillary thread needs to join a CA client context started
* by another thread
*/
epicsShareFunc struct ca_client_context * epicsShareAPI ca_current_context ();
epicsShareFunc int epicsShareAPI ca_attach_context ( struct ca_client_context * context );
epicsShareFunc int epicsShareAPI ca_client_status ( unsigned level );
epicsShareFunc int epicsShareAPI ca_context_status ( struct ca_client_context *, unsigned level );
/*
* deprecated
*/
#define ca_build_channel(NAME,XXXXX,CHIDPTR,YYYYY)\
ca_build_and_connect(NAME, XXXXX, 1, CHIDPTR, YYYYY, 0, 0)
#define ca_array_build(NAME,XXXXX, ZZZZZZ, CHIDPTR,YYYYY)\
ca_build_and_connect(NAME, XXXXX, ZZZZZZ, CHIDPTR, YYYYY, 0, 0)
epicsShareFunc int epicsShareAPI ca_build_and_connect
( const char *pChanName, chtype, unsigned long,
chid * pChanID, void *, caCh * pFunc, void * pArg );
#define ca_search(pChanName, pChanID)\
ca_search_and_connect (pChanName, pChanID, 0, 0)
epicsShareFunc int epicsShareAPI ca_search_and_connect
( const char * pChanName, chid * pChanID,
caCh *pFunc, void * pArg );
epicsShareFunc int epicsShareAPI ca_channel_status (epicsThreadId tid);
epicsShareFunc int epicsShareAPI ca_clear_event ( evid eventID );
#define ca_add_event(type,chan,pFunc,pArg,pEventID)\
ca_add_array_event(type,1u,chan,pFunc,pArg,0.0,0.0,0.0,pEventID)
#define ca_add_delta_event(TYPE,CHID,ENTRY,ARG,DELTA,EVID)\
ca_add_array_event(TYPE,1,CHID,ENTRY,ARG,DELTA,DELTA,0.0,EVID)
#define ca_add_general_event(TYPE,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)\
ca_add_array_event(TYPE,1,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)
#define ca_add_array_event(TYPE,COUNT,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)\
ca_add_masked_array_event(TYPE,COUNT,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID, DBE_VALUE | DBE_ALARM)
epicsShareFunc int epicsShareAPI ca_add_masked_array_event
( chtype type, unsigned long count, chid chanId, caEventCallBackFunc * pFunc,
void * pArg, ca_real p_delta, ca_real n_delta, ca_real timeout,
evid * pEventID, long mask );
/*
* defunct
*/
epicsShareFunc int epicsShareAPI ca_modify_user_name ( const char *pUserName );
epicsShareFunc int epicsShareAPI ca_modify_host_name ( const char *pHostName );
#ifdef __cplusplus
}
#endif
/*
* no additions below this endif
*/
#endif /* ifndef INCLcadefh */

160
src/client/caerr.h Normal file
View File

@@ -0,0 +1,160 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeffrey O. Hill
*
*/
#ifndef INCLcaerrh
#define INCLcaerrh
#ifdef epicsExportSharedSymbols
# define INCLcaerrh_accessh_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
# include "epicsTypes.h"
#ifdef INCLcaerrh_accessh_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
/* CA Status Code Definitions */
#define CA_K_INFO 3 /* successful */
#define CA_K_ERROR 2 /* failed- continue */
#define CA_K_SUCCESS 1 /* successful */
#define CA_K_WARNING 0 /* unsuccessful */
#define CA_K_SEVERE 4 /* failed- quit */
#define CA_K_FATAL CA_K_ERROR | CA_K_SEVERE
#define CA_M_MSG_NO 0x0000FFF8
#define CA_M_SEVERITY 0x00000007
#define CA_M_LEVEL 0x00000003
#define CA_M_SUCCESS 0x00000001
#define CA_M_ERROR 0x00000002
#define CA_M_SEVERE 0x00000004
#define CA_S_MSG_NO 0x0D
#define CA_S_SEVERITY 0x03
#define CA_V_MSG_NO 0x03
#define CA_V_SEVERITY 0x00
#define CA_V_SUCCESS 0x00
/* Define MACROS to extract/insert individual fields from a status value */
#define CA_EXTRACT_MSG_NO(code)\
( ( (code) & CA_M_MSG_NO ) >> CA_V_MSG_NO )
#define CA_EXTRACT_SEVERITY(code)\
( ( (code) & CA_M_SEVERITY ) >> CA_V_SEVERITY )
#define CA_EXTRACT_SUCCESS(code)\
( ( (code) & CA_M_SUCCESS ) >> CA_V_SUCCESS )
#define CA_INSERT_MSG_NO(code)\
( ((code)<< CA_V_MSG_NO) & CA_M_MSG_NO )
#define CA_INSERT_SEVERITY(code)\
( ((code)<< CA_V_SEVERITY)& CA_M_SEVERITY )
#define CA_INSERT_SUCCESS(code)\
( ((code)<< CA_V_SUCCESS) & CA_M_SUCCESS )
#define DEFMSG(SEVERITY,NUMBER)\
(CA_INSERT_MSG_NO(NUMBER) | CA_INSERT_SEVERITY(SEVERITY))
/*
* In the lines below "defunct" indicates that current release
* servers and client library will not return this error code, but
* servers on earlier releases that communicate with current clients
* might still generate exceptions with these error constants
*/
#define ECA_NORMAL DEFMSG(CA_K_SUCCESS, 0) /* success */
#define ECA_MAXIOC DEFMSG(CA_K_ERROR, 1) /* defunct */
#define ECA_UKNHOST DEFMSG(CA_K_ERROR, 2) /* defunct */
#define ECA_UKNSERV DEFMSG(CA_K_ERROR, 3) /* defunct */
#define ECA_SOCK DEFMSG(CA_K_ERROR, 4) /* defunct */
#define ECA_CONN DEFMSG(CA_K_WARNING, 5) /* defunct */
#define ECA_ALLOCMEM DEFMSG(CA_K_WARNING, 6)
#define ECA_UKNCHAN DEFMSG(CA_K_WARNING, 7) /* defunct */
#define ECA_UKNFIELD DEFMSG(CA_K_WARNING, 8) /* defunct */
#define ECA_TOLARGE DEFMSG(CA_K_WARNING, 9)
#define ECA_TIMEOUT DEFMSG(CA_K_WARNING, 10)
#define ECA_NOSUPPORT DEFMSG(CA_K_WARNING, 11) /* defunct */
#define ECA_STRTOBIG DEFMSG(CA_K_WARNING, 12) /* defunct */
#define ECA_DISCONNCHID DEFMSG(CA_K_ERROR, 13) /* defunct */
#define ECA_BADTYPE DEFMSG(CA_K_ERROR, 14)
#define ECA_CHIDNOTFND DEFMSG(CA_K_INFO, 15) /* defunct */
#define ECA_CHIDRETRY DEFMSG(CA_K_INFO, 16) /* defunct */
#define ECA_INTERNAL DEFMSG(CA_K_FATAL, 17)
#define ECA_DBLCLFAIL DEFMSG(CA_K_WARNING, 18) /* defunct */
#define ECA_GETFAIL DEFMSG(CA_K_WARNING, 19)
#define ECA_PUTFAIL DEFMSG(CA_K_WARNING, 20)
#define ECA_ADDFAIL DEFMSG(CA_K_WARNING, 21) /* defunct */
#define ECA_BADCOUNT DEFMSG(CA_K_WARNING, 22)
#define ECA_BADSTR DEFMSG(CA_K_ERROR, 23)
#define ECA_DISCONN DEFMSG(CA_K_WARNING, 24)
#define ECA_DBLCHNL DEFMSG(CA_K_WARNING, 25)
#define ECA_EVDISALLOW DEFMSG(CA_K_ERROR, 26)
#define ECA_BUILDGET DEFMSG(CA_K_WARNING, 27) /* defunct */
#define ECA_NEEDSFP DEFMSG(CA_K_WARNING, 28) /* defunct */
#define ECA_OVEVFAIL DEFMSG(CA_K_WARNING, 29) /* defunct */
#define ECA_BADMONID DEFMSG(CA_K_ERROR, 30)
#define ECA_NEWADDR DEFMSG(CA_K_WARNING, 31) /* defunct */
#define ECA_NEWCONN DEFMSG(CA_K_INFO, 32) /* defunct */
#define ECA_NOCACTX DEFMSG(CA_K_WARNING, 33) /* defunct */
#define ECA_DEFUNCT DEFMSG(CA_K_FATAL, 34) /* defunct */
#define ECA_EMPTYSTR DEFMSG(CA_K_WARNING, 35) /* defunct */
#define ECA_NOREPEATER DEFMSG(CA_K_WARNING, 36) /* defunct */
#define ECA_NOCHANMSG DEFMSG(CA_K_WARNING, 37) /* defunct */
#define ECA_DLCKREST DEFMSG(CA_K_WARNING, 38) /* defunct */
#define ECA_SERVBEHIND DEFMSG(CA_K_WARNING, 39) /* defunct */
#define ECA_NOCAST DEFMSG(CA_K_WARNING, 40) /* defunct */
#define ECA_BADMASK DEFMSG(CA_K_ERROR, 41)
#define ECA_IODONE DEFMSG(CA_K_INFO, 42)
#define ECA_IOINPROGRESS DEFMSG(CA_K_INFO, 43)
#define ECA_BADSYNCGRP DEFMSG(CA_K_ERROR, 44)
#define ECA_PUTCBINPROG DEFMSG(CA_K_ERROR, 45)
#define ECA_NORDACCESS DEFMSG(CA_K_WARNING, 46)
#define ECA_NOWTACCESS DEFMSG(CA_K_WARNING, 47)
#define ECA_ANACHRONISM DEFMSG(CA_K_ERROR, 48)
#define ECA_NOSEARCHADDR DEFMSG(CA_K_WARNING, 49)
#define ECA_NOCONVERT DEFMSG(CA_K_WARNING, 50)
#define ECA_BADCHID DEFMSG(CA_K_ERROR, 51)
#define ECA_BADFUNCPTR DEFMSG(CA_K_ERROR, 52)
#define ECA_ISATTACHED DEFMSG(CA_K_WARNING, 53)
#define ECA_UNAVAILINSERV DEFMSG(CA_K_WARNING, 54)
#define ECA_CHANDESTROY DEFMSG(CA_K_WARNING, 55)
#define ECA_BADPRIORITY DEFMSG(CA_K_ERROR, 56)
#define ECA_NOTTHREADED DEFMSG(CA_K_ERROR, 57)
#define ECA_16KARRAYCLIENT DEFMSG(CA_K_WARNING, 58)
#define ECA_CONNSEQTMO DEFMSG(CA_K_WARNING, 59)
#define ECA_UNRESPTMO DEFMSG(CA_K_WARNING, 60)
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc const char * epicsShareAPI ca_message(long ca_status);
epicsShareExtern const char * ca_message_text [];
#ifdef __cplusplus
}
#endif
#endif

44
src/client/caeventmask.h Normal file
View File

@@ -0,0 +1,44 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef INCLcaeventmaskh
#define INCLcaeventmaskh
/*
event selections
(If any more than 8 of these are needed then update the
select field in the event_block struct in db_event.c from
unsigned char to unsigned short)
DBE_VALUE
Trigger an event when a significant change in the channel's value
occurs. Relies on the monitor deadband field under DCT.
DBE_ARCHIVE (DBE_LOG)
Trigger an event when an archive significant change in the channel's
value occurs. Relies on the archiver monitor deadband field under DCT.
DBE_ALARM
Trigger an event when the alarm state changes
DBE_PROPERTY
Trigger an event when a property change (control limit, graphical
limit, status string, enum string ...) occurs.
*/
#define DBE_VALUE (1<<0)
#define DBE_ARCHIVE (1<<1)
#define DBE_LOG DBE_ARCHIVE
#define DBE_ALARM (1<<2)
#define DBE_PROPERTY (1<<3)
#endif

306
src/client/casw.cpp Normal file
View File

@@ -0,0 +1,306 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#include <stdio.h>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "envDefs.h"
#include "errlog.h"
#include "osiWireFormat.h"
#include "bhe.h"
#include "udpiiu.h"
#include "inetAddrID.h"
// using a wrapper class around the free list avoids
// Tornado 2.0.1 GNU compiler bugs
class bheFreeStoreMgr : public bheMemoryManager {
public:
bheFreeStoreMgr () {}
void * allocate ( size_t );
void release ( void * );
private:
tsFreeList < class bhe, 0x100 > freeList;
bheFreeStoreMgr ( const bheFreeStoreMgr & );
bheFreeStoreMgr & operator = ( const bheFreeStoreMgr & );
};
void * bheFreeStoreMgr::allocate ( size_t size )
{
return freeList.allocate ( size );
}
void bheFreeStoreMgr::release ( void * pCadaver )
{
freeList.release ( pCadaver );
}
int main ( int argc, char ** argv )
{
epicsMutex mutex;
epicsGuard < epicsMutex > guard ( mutex );
bheFreeStoreMgr bheFreeList;
epicsTime programBeginTime = epicsTime::getCurrent ();
bool validCommandLine = false;
unsigned interest = 0u;
SOCKET sock;
osiSockAddr addr;
osiSocklen_t addrSize;
char buf [0x4000];
const char *pCurBuf;
const caHdr *pCurMsg;
ca_uint16_t serverPort;
ca_uint16_t repeaterPort;
int status;
if ( argc == 1 ) {
validCommandLine = true;
}
else if ( argc == 2 ) {
status = sscanf ( argv[1], " -i%u ", & interest );
if ( status == 1 ) {
validCommandLine = true;
}
}
else if ( argc == 3 ) {
if ( strcmp ( argv[1], "-i" ) == 0 ) {
status = sscanf ( argv[2], " %u ", & interest );
if ( status == 1 ) {
validCommandLine = true;
}
}
}
if ( ! validCommandLine ) {
printf ( "usage: casw <-i interestLevel>\n" );
return 0;
}
serverPort =
envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT,
static_cast <unsigned short> (CA_SERVER_PORT) );
repeaterPort =
envGetInetPortConfigParam ( &EPICS_CA_REPEATER_PORT,
static_cast <unsigned short> (CA_REPEATER_PORT) );
caStartRepeaterIfNotInstalled ( repeaterPort );
sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
if ( sock == INVALID_SOCKET ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ("casw: unable to create datagram socket because = \"%s\"\n",
sockErrBuf );
return -1;
}
memset ( (char *) &addr, 0 , sizeof (addr) );
addr.ia.sin_family = AF_INET;
addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
addr.ia.sin_port = htons ( 0 ); // any port
status = bind ( sock, &addr.sa, sizeof (addr) );
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
epicsSocketDestroy ( sock );
errlogPrintf ( "casw: unable to bind to an unconstrained address because = \"%s\"\n",
sockErrBuf );
return -1;
}
osiSockIoctl_t yes = true;
status = socket_ioctl ( sock, FIONBIO, &yes );
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
epicsSocketDestroy ( sock );
errlogPrintf ( "casw: unable to set socket to nonblocking state because \"%s\"\n",
sockErrBuf );
return -1;
}
unsigned attemptNumber = 0u;
while ( true ) {
caRepeaterRegistrationMessage ( sock, repeaterPort, attemptNumber );
epicsThreadSleep ( 0.1 );
addrSize = ( osiSocklen_t ) sizeof ( addr );
status = recvfrom ( sock, buf, sizeof ( buf ), 0,
&addr.sa, &addrSize );
if ( status >= static_cast <int> ( sizeof ( *pCurMsg ) ) ) {
pCurMsg = reinterpret_cast < caHdr * > ( buf );
epicsUInt16 cmmd = AlignedWireRef < const epicsUInt16 > ( pCurMsg->m_cmmd );
if ( cmmd == REPEATER_CONFIRM ) {
break;
}
}
attemptNumber++;
if ( attemptNumber > 100 ) {
epicsSocketDestroy ( sock );
errlogPrintf ( "casw: unable to register with the CA repeater\n" );
return -1;
}
}
osiSockIoctl_t no = false;
status = socket_ioctl ( sock, FIONBIO, &no );
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
epicsSocketDestroy ( sock );
errlogPrintf ( "casw: unable to set socket to blocking state because \"%s\"\n",
sockErrBuf );
return -1;
}
resTable < bhe, inetAddrID > beaconTable;
while ( true ) {
addrSize = ( osiSocklen_t ) sizeof ( addr );
status = recvfrom ( sock, buf, sizeof ( buf ), 0,
&addr.sa, &addrSize );
if ( status <= 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
epicsSocketDestroy ( sock );
errlogPrintf ("casw: error from recv was = \"%s\"\n",
sockErrBuf );
return -1;
}
if ( addr.sa.sa_family != AF_INET ) {
continue;
}
unsigned byteCount = static_cast <unsigned> ( status );
pCurMsg = reinterpret_cast < const caHdr * > ( ( pCurBuf = buf ) );
while ( byteCount ) {
AlignedWireRef < const epicsUInt16 > pstSize ( pCurMsg->m_postsize );
size_t msgSize = pstSize + sizeof ( *pCurMsg ) ;
if ( msgSize > byteCount ) {
errlogPrintf ( "CASW: udp input protocol violation\n" );
break;
}
epicsUInt16 cmmd = AlignedWireRef < const epicsUInt16 > ( pCurMsg->m_cmmd );
if ( cmmd == CA_PROTO_RSRV_IS_UP ) {
bool anomaly = false;
epicsTime previousTime;
struct sockaddr_in ina;
/*
* this allows a fan-out server to potentially
* insert the true address of the CA server
*
* old servers:
* 1) set this field to one of the ip addresses of the host _or_
* 2) set this field to INADDR_ANY
* new servers:
* always set this field to INADDR_ANY
*
* clients always assume that if this
* field is set to something that isnt INADDR_ANY
* then it is the overriding IP address of the server.
*/
ina.sin_family = AF_INET;
ina.sin_addr.s_addr = pCurMsg->m_available;
if ( pCurMsg->m_count != 0 ) {
ina.sin_port = pCurMsg->m_count;
}
else {
/*
* old servers dont supply this and the
* default port must be assumed
*/
ina.sin_port = htons ( serverPort );
}
ca_uint32_t beaconNumber = ntohl ( pCurMsg->m_cid );
unsigned protocolRevision = ntohs ( pCurMsg->m_dataType );
epicsTime currentTime = epicsTime::getCurrent();
/*
* look for it in the hash table
*/
bhe *pBHE = beaconTable.lookup ( ina );
if ( pBHE ) {
previousTime = pBHE->updateTime ( guard );
anomaly = pBHE->updatePeriod (
guard, programBeginTime,
currentTime, beaconNumber, protocolRevision );
}
else {
/*
* This is the first beacon seen from this server.
* Wait until 2nd beacon is seen before deciding
* if it is a new server (or just the first
* time that we have seen a server's beacon
* shortly after the program started up)
*/
pBHE = new ( bheFreeList )
bhe ( mutex, currentTime, beaconNumber, ina );
if ( pBHE ) {
if ( beaconTable.add ( *pBHE ) < 0 ) {
pBHE->~bhe ();
bheFreeList.release ( pBHE );
}
}
}
if ( anomaly || interest > 1 ) {
char date[64];
currentTime.strftime ( date, sizeof ( date ),
"%Y-%m-%d %H:%M:%S.%09f");
char host[64];
ipAddrToA ( &ina, host, sizeof ( host ) );
const char * pPrefix = "";
if ( interest > 1 ) {
if ( anomaly ) {
pPrefix = "* ";
}
else {
pPrefix = " ";
}
}
printf ( "%s%-40s %s\n",
pPrefix, host, date );
if ( anomaly && interest > 0 ) {
printf ( "\testimate=%f current=%f\n",
pBHE->period ( guard ),
currentTime - previousTime );
}
fflush(stdout);
}
}
pCurBuf += msgSize;
pCurMsg = reinterpret_cast < const caHdr * > ( pCurBuf );
byteCount -= msgSize;
}
}
}

685
src/client/catime.c Normal file
View File

@@ -0,0 +1,685 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* CA performance test
*
* History
* joh 09-12-89 Initial release
* joh 12-20-94 portability
*
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "epicsAssert.h"
#include "epicsTime.h"
#include "cadef.h"
#include "caProto.h"
#include "caDiagnostics.h"
#ifndef NULL
#define NULL 0
#endif
#define WAIT_FOR_ACK
typedef struct testItem {
chid chix;
char name[128];
int type;
int count;
void * pValue;
} ti;
typedef void tf ( ti *pItems, unsigned iterations, unsigned *pInlineIter );
/*
* test_pend()
*/
static void test_pend(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
unsigned i;
int status;
for (i=0; i<iterations; i++) {
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
status = ca_pend_event(1e-9);
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
SEVCHK(status, NULL);
}
}
*pInlineIter = 5;
}
/*
* test_search ()
*/
static void test_search (
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
unsigned i;
int status;
for ( i = 0u; i < iterations; i++ ) {
status = ca_search ( pItems[i].name, &pItems[i].chix );
SEVCHK (status, NULL);
}
status = ca_pend_io ( 0.0 );
SEVCHK ( status, NULL );
*pInlineIter = 1;
}
/*
* test_sync_search()
*/
#if 0
static void test_sync_search(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
unsigned i;
int status;
for (i=0u; i<iterations; i++) {
status = ca_search (pItems[i].name, &pItems[i].chix);
SEVCHK (status, NULL);
status = ca_pend_io(0.0);
SEVCHK (status, NULL);
}
*pInlineIter = 1;
}
#endif
/*
* test_free ()
*/
static void test_free(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
int status;
unsigned i;
for (i=0u; i<iterations; i++) {
status = ca_clear_channel (pItems[i].chix);
SEVCHK (status, NULL);
}
status = ca_flush_io();
SEVCHK (status, NULL);
*pInlineIter = 1;
}
/*
* test_put ()
*/
static void test_put(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
ti *pi;
int status;
dbr_int_t val;
for (pi=pItems; pi < &pItems[iterations]; pi++) {
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_put(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
}
#ifdef WAIT_FOR_ACK
status = ca_array_get (DBR_INT, 1, pItems[0].chix, &val);
SEVCHK (status, NULL);
ca_pend_io(100.0);
#endif
status = ca_array_put(
pItems[0].type,
pItems[0].count,
pItems[0].chix,
pItems[0].pValue);
SEVCHK (status, NULL);
status = ca_flush_io();
SEVCHK (status, NULL);
*pInlineIter = 10;
}
/*
* test_get ()
*/
static void test_get(
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
ti *pi;
int status;
for (pi=pItems; pi<&pItems[iterations]; pi++) {
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
}
status = ca_pend_io(1e20);
SEVCHK (status, NULL);
*pInlineIter = 10;
}
/*
* test_wait ()
*/
static void test_wait (
ti *pItems,
unsigned iterations,
unsigned *pInlineIter
)
{
ti *pi;
int status;
for (pi=pItems; pi<&pItems[iterations]; pi++) {
status = ca_array_get(
pi->type,
pi->count,
pi->chix,
pi->pValue);
SEVCHK (status, NULL);
status = ca_pend_io(100.0);
SEVCHK (status, NULL);
}
*pInlineIter = 1;
}
/*
* measure_get_latency
*/
static void measure_get_latency (ti *pItems, unsigned iterations)
{
epicsTimeStamp end_time;
epicsTimeStamp start_time;
double delay;
double X = 0u;
double XX = 0u;
double max = DBL_MIN;
double min = DBL_MAX;
double mean;
double stdDev;
ti *pi;
int status;
for ( pi = pItems; pi < &pItems[iterations]; pi++ ) {
epicsTimeGetCurrent ( &start_time );
status = ca_array_get ( pi->type, pi->count,
pi->chix, pi->pValue );
SEVCHK ( status, NULL );
status = ca_pend_io ( 100.0 );
SEVCHK ( status, NULL );
epicsTimeGetCurrent ( &end_time );
delay = epicsTimeDiffInSeconds ( &end_time,&start_time );
X += delay;
XX += delay*delay;
if ( delay > max ) {
max = delay;
}
if ( delay < min ) {
min = delay;
}
}
mean = X/iterations;
stdDev = sqrt ( XX/iterations - mean*mean );
printf (
"Get Latency - "
"mean = %3.1f uS, "
"std dev = %3.1f uS, "
"min = %3.1f uS "
"max = %3.1f uS\n",
mean * 1e6, stdDev * 1e6,
min * 1e6, max * 1e6 );
}
/*
* printSearchStat()
*/
static void printSearchStat ( const ti * pi, unsigned iterations )
{
unsigned i;
double X = 0u;
double XX = 0u;
double max = DBL_MIN;
double min = DBL_MAX;
double mean;
double stdDev;
for ( i = 0; i < iterations; i++ ) {
double retry = ca_search_attempts ( pi[i].chix );
X += retry;
XX += retry * retry;
if ( retry > max ) {
max = retry;
}
if ( retry < min ) {
min = retry;
}
}
mean = X / iterations;
stdDev = sqrt( XX / iterations - mean * mean );
printf (
"Search tries per chan - "
"mean = %3.1f "
"std dev = %3.1f "
"min = %3.1f "
"max = %3.1f\n",
mean, stdDev, min, max);
}
/*
* timeIt ()
*/
void timeIt ( tf *pfunc, ti *pItems, unsigned iterations,
unsigned nBytesSent, unsigned nBytesRecv )
{
epicsTimeStamp end_time;
epicsTimeStamp start_time;
double delay;
unsigned inlineIter;
epicsTimeGetCurrent ( &start_time );
(*pfunc) ( pItems, iterations, &inlineIter );
epicsTimeGetCurrent ( &end_time );
delay = epicsTimeDiffInSeconds ( &end_time, &start_time );
if ( delay > 0.0 ) {
double freq = ( iterations * inlineIter ) / delay;
printf ( "Per Op, %8.4f uS ( %8.4f MHz )",
1e6 / freq, freq / 1e6 );
if ( pItems != NULL ) {
printf(", %8.4f snd Mbps, %8.4f rcv Mbps\n",
(inlineIter*nBytesSent*CHAR_BIT)/(delay*1e6),
(inlineIter*nBytesRecv*CHAR_BIT)/(delay*1e6) );
}
else {
printf ("\n");
}
}
}
/*
* test ()
*/
static void test ( ti *pItems, unsigned iterations )
{
unsigned payloadSize, dblPayloadSize;
unsigned nBytesSent, nBytesRecv;
payloadSize =
dbr_size_n ( pItems[0].type, pItems[0].count );
payloadSize = CA_MESSAGE_ALIGN ( payloadSize );
dblPayloadSize = dbr_size [ DBR_DOUBLE ];
dblPayloadSize = CA_MESSAGE_ALIGN ( dblPayloadSize );
if ( payloadSize > dblPayloadSize ) {
unsigned factor = payloadSize / dblPayloadSize;
while ( factor ) {
if ( iterations > 10 * factor ) {
iterations /= factor;
break;
}
factor /= 2;
}
}
printf ( "\t### async put test ###\n");
nBytesSent = sizeof ( caHdr ) + CA_MESSAGE_ALIGN( payloadSize );
nBytesRecv = 0u;
timeIt ( test_put, pItems, iterations,
nBytesSent * iterations,
nBytesRecv * iterations );
printf ( "\t### async get test ###\n");
nBytesSent = sizeof ( caHdr );
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
timeIt ( test_get, pItems, iterations,
nBytesSent * ( iterations ),
nBytesRecv * ( iterations ) );
printf ("\t### synch get test ###\n");
nBytesSent = sizeof ( caHdr );
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
if ( iterations > 100 ) {
iterations /= 100;
}
else if ( iterations > 10 ) {
iterations /= 10;
}
timeIt ( test_wait, pItems, iterations,
nBytesSent * iterations,
nBytesRecv * iterations );
}
/*
* catime ()
*/
int catime ( const char * channelName,
unsigned channelCount, enum appendNumberFlag appNF )
{
unsigned i;
int j;
unsigned strsize;
unsigned nBytesSent, nBytesRecv;
ti *pItemList;
if ( channelCount == 0 ) {
printf ( "channel count was zero\n" );
return 0;
}
pItemList = calloc ( channelCount, sizeof (ti) );
if ( ! pItemList ) {
return -1;
}
SEVCHK ( ca_context_create ( ca_disable_preemptive_callback ),
"Unable to initialize" );
if ( appNF == appendNumber ) {
printf ( "Testing with %u channels named %snnn\n",
channelCount, channelName );
}
else {
printf ( "Testing with %u channels named %s\n",
channelCount, channelName );
}
strsize = sizeof ( pItemList[0].name ) - 1;
nBytesSent = 0;
nBytesRecv = 0;
for ( i=0; i < channelCount; i++ ) {
if ( appNF == appendNumber ) {
sprintf ( pItemList[i].name,"%.*s%.6u",
(int) (strsize - 15u), channelName, i );
}
else {
strncpy ( pItemList[i].name, channelName, strsize);
}
pItemList[i].name[strsize]= '\0';
pItemList[i].count = 0;
pItemList[i].pValue = 0;
nBytesSent += 2 * ( CA_MESSAGE_ALIGN ( strlen ( pItemList[i].name ) )
+ sizeof (caHdr) );
nBytesRecv += 2 * sizeof (caHdr);
}
printf ( "Channel Connect Test\n" );
printf ( "--------------------\n" );
timeIt ( test_search, pItemList, channelCount, nBytesSent, nBytesRecv );
printSearchStat ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
size_t count = ca_element_count ( pItemList[i].chix );
size_t size = sizeof ( dbr_string_t ) * count;
pItemList[i].count = count;
pItemList[i].pValue = malloc ( size );
assert ( pItemList[i].pValue );
}
printf (
"channel name=%s, native type=%d, native count=%u\n",
ca_name (pItemList[0].chix),
ca_field_type (pItemList[0].chix),
pItemList[0].count );
printf ("Pend Event Test\n");
printf ( "----------------\n" );
timeIt ( test_pend, NULL, 100, 0, 0 );
for ( i = 0; i < channelCount; i++ ) {
dbr_float_t * pFltVal = ( dbr_float_t * ) pItemList[i].pValue;
double val = i;
val /= channelCount;
for ( j = 0; j < pItemList[i].count; j++ ) {
pFltVal[j] = (dbr_float_t) val;
}
pItemList[i].type = DBR_FLOAT;
}
printf ( "DBR_FLOAT Test\n" );
printf ( "--------------\n" );
test ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
double val = i;
val /= channelCount;
for ( j = 0; j < pItemList[i].count; j++ ) {
pDblVal[j] = (dbr_double_t) val;
}
pItemList[i].type = DBR_DOUBLE;
}
printf ( "DBR_DOUBLE Test\n" );
printf ( "---------------\n" );
test ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
dbr_string_t * pStrVal = ( dbr_string_t * ) pItemList[i].pValue;
double val = i;
val /= channelCount;
for ( j = 0; j < pItemList[i].count; j++ ) {
sprintf ( pStrVal[j], "%f", val );
}
pItemList[i].type = DBR_STRING;
}
printf ( "DBR_STRING Test\n" );
printf ( "---------------\n" );
test ( pItemList, channelCount );
for ( i = 0; i < channelCount; i++ ) {
dbr_int_t * pIntVal = ( dbr_int_t * ) pItemList[i].pValue;
double val = i;
val /= channelCount;
for ( j = 0; j < pItemList[i].count; j++ ) {
pIntVal[j] = (dbr_int_t) val;
}
pItemList[i].type = DBR_INT;
}
printf ( "DBR_INT Test\n" );
printf ( "------------\n" );
test ( pItemList, channelCount );
printf ( "Get Latency Test\n" );
printf ( "----------------\n" );
for ( i = 0; i < channelCount; i++ ) {
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
for ( j = 0; j < pItemList[i].count; j++ ) {
pDblVal[j] = 0;
}
pItemList[i].type = DBR_DOUBLE;
}
measure_get_latency ( pItemList, channelCount );
printf ( "Free Channel Test\n" );
printf ( "-----------------\n" );
timeIt ( test_free, pItemList, channelCount, 0, 0 );
SEVCHK ( ca_task_exit (), "Unable to free resources at exit" );
for ( i = 0; i < channelCount; i++ ) {
free ( pItemList[i].pValue );
}
free ( pItemList );
return CATIME_OK;
}

53
src/client/catimeMain.c Normal file
View File

@@ -0,0 +1,53 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "caDiagnostics.h"
static const unsigned defaultIterations = 10000u;
int main ( int argc, char **argv )
{
const char *pUsage = "<PV name> [<channel count> [<append number to pv name if true>]]";
if ( argc > 1 ) {
char *pname = argv[1];
if ( argc > 2 ) {
int iterations = atoi (argv[2]);
if ( iterations > 0) {
if ( argc > 3 ) {
if ( argc == 4 ) {
int status;
unsigned appendNumberBool;
status = sscanf ( argv[3], " %u ", &appendNumberBool );
if ( status == 1 ) {
if ( appendNumberBool ) {
return catime ( pname, (unsigned) iterations, appendNumber );
}
else {
return catime ( pname, (unsigned) iterations, dontAppendNumber );
}
}
}
}
else {
return catime ( pname, (unsigned) iterations, dontAppendNumber );
}
}
}
else {
return catime ( pname, defaultIterations, dontAppendNumber );
}
}
printf ( "usage: %s %s\n", argv[0], pUsage);
return -1;
}

66
src/client/comBuf.cpp Normal file
View File

@@ -0,0 +1,66 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
#include <stdexcept>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "comBuf.h"
#include "errlog.h"
bool comBuf::flushToWire ( wireSendAdapter & wire, const epicsTime & currentTime )
{
unsigned index = this->nextReadIndex;
unsigned finalIndex = this->commitIndex;
while ( index < finalIndex ) {
unsigned nBytes = wire.sendBytes (
&this->buf[index], finalIndex - index, currentTime );
if ( nBytes == 0u ) {
this->nextReadIndex = index;
return false;
}
index += nBytes;
}
this->nextReadIndex = index;
return true;
}
// throwing the exception from a function that isnt inline
// shrinks the GNU compiled object code
void comBuf::throwInsufficentBytesException ()
{
throw comBuf::insufficentBytesAvailable ();
}
void comBuf::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
// placement operator delete is defined? I smell a ms rat
// because if I declare placement new and delete, but
// comment out the placement delete definition there are
// no undefined symbols.
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
__FILE__, __LINE__ );
}
comBufMemoryManager::~comBufMemoryManager () {}

335
src/client/comBuf.h Normal file
View File

@@ -0,0 +1,335 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
#ifndef comBufh
#define comBufh
#include <new>
#include <cstring>
#include "epicsAssert.h"
#include "epicsTypes.h"
#include "tsFreeList.h"
#include "tsDLList.h"
#include "osiWireFormat.h"
#include "compilerDependencies.h"
static const unsigned comBufSize = 0x4000;
// this wrapper avoids Tornado 2.0.1 compiler bugs
class comBufMemoryManager {
public:
virtual ~comBufMemoryManager ();
virtual void * allocate ( size_t ) = 0;
virtual void release ( void * ) = 0;
};
class wireSendAdapter {
public:
virtual unsigned sendBytes ( const void * pBuf,
unsigned nBytesInBuf,
const class epicsTime & currentTime ) = 0;
protected:
virtual ~wireSendAdapter() {}
};
enum swioCircuitState {
swioConnected,
swioPeerHangup,
swioPeerAbort,
swioLinkFailure,
swioLocalAbort
};
struct statusWireIO {
unsigned bytesCopied;
swioCircuitState circuitState;
};
class wireRecvAdapter {
public:
virtual void recvBytes ( void * pBuf,
unsigned nBytesInBuf, statusWireIO & ) = 0;
protected:
virtual ~wireRecvAdapter() {}
};
class comBuf : public tsDLNode < comBuf > {
public:
class insufficentBytesAvailable {};
comBuf ();
unsigned unoccupiedBytes () const;
unsigned occupiedBytes () const;
unsigned uncommittedBytes () const;
static unsigned capacityBytes ();
void clear ();
unsigned copyInBytes ( const void *pBuf, unsigned nBytes );
unsigned push ( comBuf & );
template < class T >
bool push ( const T & value );
template < class T >
unsigned push ( const T * pValue, unsigned nElem );
unsigned push ( const epicsInt8 * pValue, unsigned nElem );
unsigned push ( const epicsUInt8 * pValue, unsigned nElem );
unsigned push ( const epicsOldString * pValue, unsigned nElem );
void commitIncomming ();
void clearUncommittedIncomming ();
bool copyInAllBytes ( const void *pBuf, unsigned nBytes );
unsigned copyOutBytes ( void *pBuf, unsigned nBytes );
bool copyOutAllBytes ( void *pBuf, unsigned nBytes );
unsigned removeBytes ( unsigned nBytes );
bool flushToWire ( wireSendAdapter &, const epicsTime & currentTime );
void fillFromWire ( wireRecvAdapter &, statusWireIO & );
struct popStatus {
bool success;
bool nowEmpty;
};
template < class T >
popStatus pop ( T & );
static void throwInsufficentBytesException ();
void * operator new ( size_t size,
comBufMemoryManager & );
epicsPlacementDeleteOperator (( void *, comBufMemoryManager & ))
private:
unsigned commitIndex;
unsigned nextWriteIndex;
unsigned nextReadIndex;
epicsUInt8 buf [ comBufSize ];
void operator delete ( void * );
template < class T >
bool push ( const T * ); // disabled
};
inline void * comBuf::operator new ( size_t size,
comBufMemoryManager & mgr )
{
return mgr.allocate ( size );
}
#ifdef CXX_PLACEMENT_DELETE
inline void comBuf::operator delete ( void * pCadaver,
comBufMemoryManager & mgr )
{
mgr.release ( pCadaver );
}
#endif
inline comBuf::comBuf () : commitIndex ( 0u ),
nextWriteIndex ( 0u ), nextReadIndex ( 0u )
{
}
inline void comBuf :: clear ()
{
this->commitIndex = 0u;
this->nextWriteIndex = 0u;
this->nextReadIndex = 0u;
}
inline unsigned comBuf :: unoccupiedBytes () const
{
return sizeof ( this->buf ) - this->nextWriteIndex;
}
inline unsigned comBuf :: occupiedBytes () const
{
return this->commitIndex - this->nextReadIndex;
}
inline unsigned comBuf :: uncommittedBytes () const
{
return this->nextWriteIndex - this->commitIndex;
}
inline unsigned comBuf :: push ( comBuf & bufIn )
{
unsigned nBytes = this->copyInBytes (
& bufIn.buf[ bufIn.nextReadIndex ],
bufIn.commitIndex - bufIn.nextReadIndex );
bufIn.nextReadIndex += nBytes;
return nBytes;
}
inline unsigned comBuf :: capacityBytes ()
{
return comBufSize;
}
inline void comBuf :: fillFromWire (
wireRecvAdapter & wire, statusWireIO & stat )
{
wire.recvBytes (
& this->buf[this->nextWriteIndex],
sizeof ( this->buf ) - this->nextWriteIndex, stat );
if ( stat.circuitState == swioConnected ) {
this->nextWriteIndex += stat.bytesCopied;
}
}
template < class T >
inline bool comBuf :: push ( const T & value )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
if ( sizeof ( value ) > available ) {
return false;
}
WireSet ( value, & this->buf[index] );
this->nextWriteIndex = index + sizeof ( value );
return true;
}
inline unsigned comBuf :: push ( const epicsInt8 *pValue, unsigned nElem )
{
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf :: push ( const epicsUInt8 *pValue, unsigned nElem )
{
return copyInBytes ( pValue, nElem );
}
inline unsigned comBuf :: push ( const epicsOldString * pValue, unsigned nElem )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
unsigned nBytes = sizeof ( *pValue ) * nElem;
if ( nBytes > available ) {
nElem = available / sizeof ( *pValue );
nBytes = nElem * sizeof ( *pValue );
}
memcpy ( &this->buf[ index ], pValue, nBytes );
this->nextWriteIndex = index + nBytes;
return nElem;
}
template < class T >
unsigned comBuf :: push ( const T * pValue, unsigned nElem )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
unsigned nBytes = sizeof ( *pValue ) * nElem;
if ( nBytes > available ) {
nElem = available / sizeof ( *pValue );
}
for ( unsigned i = 0u; i < nElem; i++ ) {
// allow native floating point formats to be converted to IEEE
WireSet( pValue[i], &this->buf[index] );
index += sizeof ( *pValue );
}
this->nextWriteIndex = index;
return nElem;
}
inline void comBuf :: commitIncomming ()
{
this->commitIndex = this->nextWriteIndex;
}
inline void comBuf :: clearUncommittedIncomming ()
{
this->nextWriteIndex = this->commitIndex;
}
inline bool comBuf :: copyInAllBytes ( const void *pBuf, unsigned nBytes )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
if ( nBytes <= available ) {
memcpy ( & this->buf[index], pBuf, nBytes );
this->nextWriteIndex = index + nBytes;
return true;
}
return false;
}
inline unsigned comBuf :: copyInBytes ( const void * pBuf, unsigned nBytes )
{
unsigned index = this->nextWriteIndex;
unsigned available = sizeof ( this->buf ) - index;
if ( nBytes > available ) {
nBytes = available;
}
memcpy ( & this->buf[index], pBuf, nBytes );
this->nextWriteIndex = index + nBytes;
return nBytes;
}
inline bool comBuf :: copyOutAllBytes ( void * pBuf, unsigned nBytes )
{
unsigned index = this->nextReadIndex;
unsigned occupied = this->commitIndex - index;
if ( nBytes <= occupied ) {
memcpy ( pBuf, &this->buf[index], nBytes);
this->nextReadIndex = index + nBytes;
return true;
}
return false;
}
inline unsigned comBuf :: copyOutBytes ( void *pBuf, unsigned nBytes )
{
unsigned index = this->nextReadIndex;
unsigned occupied = this->commitIndex - index;
if ( nBytes > occupied ) {
nBytes = occupied;
}
memcpy ( pBuf, &this->buf[index], nBytes);
this->nextReadIndex = index + nBytes;
return nBytes;
}
inline unsigned comBuf :: removeBytes ( unsigned nBytes )
{
unsigned index = this->nextReadIndex;
unsigned occupied = this->commitIndex - index;
if ( nBytes > occupied ) {
nBytes = occupied;
}
this->nextReadIndex = index + nBytes;
return nBytes;
}
template < class T >
comBuf :: popStatus comBuf :: pop ( T & returnVal )
{
unsigned nrIndex = this->nextReadIndex;
unsigned popIndex = nrIndex + sizeof ( returnVal );
unsigned cIndex = this->commitIndex;
popStatus status;
status.success = true;
status.nowEmpty = false;
if ( popIndex >= cIndex ) {
if ( popIndex == cIndex ) {
status.nowEmpty = true;
}
else {
status.success = false;
return status;
}
}
WireGet ( & this->buf[ nrIndex ], returnVal );
this->nextReadIndex = popIndex;
return status;
}
#endif // ifndef comBufh

269
src/client/comQueRecv.cpp Normal file
View File

@@ -0,0 +1,269 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "iocinf.h"
#include "virtualCircuit.h"
comQueRecv::comQueRecv ( comBufMemoryManager & comBufMemoryManagerIn ):
comBufMemMgr ( comBufMemoryManagerIn ), nBytesPending ( 0u )
{
}
comQueRecv::~comQueRecv ()
{
this->clear ();
}
void comQueRecv::clear ()
{
comBuf *pBuf;
while ( ( pBuf = this->bufs.get () ) ) {
pBuf->~comBuf ();
this->comBufMemMgr.release ( pBuf );
}
this->nBytesPending = 0u;
}
unsigned comQueRecv::copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes )
{
unsigned totalBytes = 0u;
do {
comBuf * pComBuf = this->bufs.first ();
if ( ! pComBuf ) {
this->nBytesPending -= totalBytes;
return totalBytes;
}
totalBytes += pComBuf->copyOutBytes ( &pBuf[totalBytes], nBytes - totalBytes );
if ( pComBuf->occupiedBytes () == 0u ) {
this->bufs.remove ( *pComBuf );
pComBuf->~comBuf ();
this->comBufMemMgr.release ( pComBuf );
}
}
while ( totalBytes < nBytes );
this->nBytesPending -= totalBytes;
return totalBytes;
}
unsigned comQueRecv::removeBytes ( unsigned nBytes )
{
unsigned totalBytes = 0u;
unsigned bytesLeft = nBytes;
while ( bytesLeft ) {
comBuf * pComBuf = this->bufs.first ();
if ( ! pComBuf ) {
this->nBytesPending -= totalBytes;
return totalBytes;
}
unsigned nBytesThisTime = pComBuf->removeBytes ( bytesLeft );
if ( pComBuf->occupiedBytes () == 0u ) {
this->bufs.remove ( *pComBuf );
pComBuf->~comBuf ();
this->comBufMemMgr.release ( pComBuf );
}
if ( nBytesThisTime == 0u) {
break;
}
totalBytes += nBytesThisTime;
bytesLeft = nBytes - totalBytes;
}
this->nBytesPending -= totalBytes;
return totalBytes;
}
void comQueRecv::popString ( epicsOldString *pStr )
{
for ( unsigned i = 0u; i < sizeof ( *pStr ); i++ ) {
pStr[0][i] = this->popInt8 ();
}
}
void comQueRecv::pushLastComBufReceived ( comBuf & bufIn )
{
bufIn.commitIncomming ();
comBuf * pComBuf = this->bufs.last ();
if ( pComBuf ) {
if ( pComBuf->unoccupiedBytes() ) {
this->nBytesPending += pComBuf->push ( bufIn );
pComBuf->commitIncomming ();
}
}
unsigned bufBytes = bufIn.occupiedBytes();
if ( bufBytes ) {
this->nBytesPending += bufBytes;
this->bufs.add ( bufIn );
}
else {
bufIn.~comBuf ();
this->comBufMemMgr.release ( & bufIn );
}
}
// 1) split between buffers expected to run slower
// 2) using canonical unsigned tmp avoids ANSI C conversions to int
// 3) cast required because sizeof(unsigned) >= sizeof(epicsUInt32)
epicsUInt16 comQueRecv::multiBufferPopUInt16 ()
{
epicsUInt16 tmp;
if ( this->occupiedBytes() >= sizeof (tmp) ) {
unsigned byte1 = this->popUInt8 ();
unsigned byte2 = this->popUInt8 ();
tmp = static_cast <epicsUInt16> ( ( byte1 << 8u ) | byte2 );
}
else {
comBuf::throwInsufficentBytesException ();
tmp = 0u;
}
return tmp;
}
// 1) split between buffers expected to run slower
// 2) using canonical unsigned temporary avoids ANSI C conversions to int
// 3) cast required because sizeof(unsigned) >= sizeof(epicsUInt32)
epicsUInt32 comQueRecv::multiBufferPopUInt32 ()
{
epicsUInt32 tmp;
if ( this->occupiedBytes() >= sizeof (tmp) ) {
// 1) split between buffers expected to run slower
// 2) using canonical unsigned temporary avoids ANSI C conversions to int
// 3) cast required because sizeof(unsigned) >= sizeof(epicsUInt32)
unsigned byte1 = this->popUInt8();
unsigned byte2 = this->popUInt8();
unsigned byte3 = this->popUInt8();
unsigned byte4 = this->popUInt8();
tmp = static_cast <epicsUInt32>
( ( byte1 << 24u ) | ( byte2 << 16u ) |
( byte3 << 8u ) | byte4 );
}
else {
comBuf::throwInsufficentBytesException ();
tmp = 0u; // avoid compiler warnings
}
return tmp;
}
void comQueRecv::removeAndDestroyBuf ( comBuf & buf )
{
this->bufs.remove ( buf );
buf.~comBuf ();
this->comBufMemMgr.release ( & buf );
}
epicsUInt8 comQueRecv::popUInt8 ()
{
comBuf * pComBuf = this->bufs.first ();
if ( ! pComBuf ) {
comBuf::throwInsufficentBytesException ();
}
epicsUInt8 tmp = '\0';
comBuf::popStatus status = pComBuf->pop ( tmp );
if ( ! status.success ) {
comBuf::throwInsufficentBytesException ();
}
if ( status.nowEmpty ) {
this->removeAndDestroyBuf ( *pComBuf );
}
this->nBytesPending--;
return tmp;
}
epicsUInt16 comQueRecv::popUInt16 ()
{
comBuf * pComBuf = this->bufs.first ();
if ( ! pComBuf ) {
comBuf::throwInsufficentBytesException ();
}
// try first for all in one buffer efficent version
epicsUInt16 tmp = 0;
comBuf::popStatus status = pComBuf->pop ( tmp );
if ( status.success ) {
this->nBytesPending -= sizeof ( epicsUInt16 );
if ( status.nowEmpty ) {
this->removeAndDestroyBuf ( *pComBuf );
}
return tmp;
}
return this->multiBufferPopUInt16 ();
}
epicsUInt32 comQueRecv::popUInt32 ()
{
comBuf *pComBuf = this->bufs.first ();
if ( ! pComBuf ) {
comBuf::throwInsufficentBytesException ();
}
// try first for all in one buffer efficent version
epicsUInt32 tmp = 0;
comBuf::popStatus status = pComBuf->pop ( tmp );
if ( status.success ) {
this->nBytesPending -= sizeof ( epicsUInt32 );
if ( status.nowEmpty ) {
this->removeAndDestroyBuf ( *pComBuf );
}
return tmp;
}
return this->multiBufferPopUInt32 ();
}
bool comQueRecv::popOldMsgHeader ( caHdrLargeArray & msg )
{
// try first for all in one buffer efficent version
comBuf * pComBuf = this->bufs.first ();
if ( ! pComBuf ) {
return false;
}
unsigned avail = pComBuf->occupiedBytes ();
if ( avail >= sizeof ( caHdr ) ) {
pComBuf->pop ( msg.m_cmmd );
ca_uint16_t smallPostsize = 0;
pComBuf->pop ( smallPostsize );
msg.m_postsize = smallPostsize;
pComBuf->pop ( msg.m_dataType );
ca_uint16_t smallCount = 0;
pComBuf->pop ( smallCount );
msg.m_count = smallCount;
pComBuf->pop ( msg.m_cid );
pComBuf->pop ( msg.m_available );
this->nBytesPending -= sizeof ( caHdr );
if ( avail == sizeof ( caHdr ) ) {
this->removeAndDestroyBuf ( *pComBuf );
}
return true;
}
else if ( this->occupiedBytes () >= sizeof ( caHdr ) ) {
msg.m_cmmd = this->popUInt16 ();
msg.m_postsize = this->popUInt16 ();
msg.m_dataType = this->popUInt16 ();
msg.m_count = this->popUInt16 ();
msg.m_cid = this->popUInt32 ();
msg.m_available = this->popUInt32 ();
return true;
}
else {
return false;
}
}

111
src/client/comQueRecv.h Normal file
View File

@@ -0,0 +1,111 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef comQueRecvh
#define comQueRecvh
#include "comBuf.h"
class comQueRecv {
public:
comQueRecv ( comBufMemoryManager & );
~comQueRecv ();
unsigned occupiedBytes () const;
unsigned copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes );
unsigned removeBytes ( unsigned nBytes );
void pushLastComBufReceived ( comBuf & );
void clear ();
bool popOldMsgHeader ( struct caHdrLargeArray & );
epicsInt8 popInt8 ();
epicsUInt8 popUInt8 ();
epicsInt16 popInt16 ();
epicsUInt16 popUInt16 ();
epicsInt32 popInt32 ();
epicsUInt32 popUInt32 ();
epicsFloat32 popFloat32 ();
epicsFloat64 popFloat64 ();
void popString ( epicsOldString * );
private:
tsDLList < comBuf > bufs;
comBufMemoryManager & comBufMemMgr;
unsigned nBytesPending;
epicsUInt16 multiBufferPopUInt16 ();
epicsUInt32 multiBufferPopUInt32 ();
void removeAndDestroyBuf ( comBuf & );
comQueRecv ( const comQueRecv & );
comQueRecv & operator = ( const comQueRecv & );
};
inline unsigned comQueRecv::occupiedBytes () const
{
return this->nBytesPending;
}
inline epicsInt8 comQueRecv::popInt8 ()
{
return static_cast < epicsInt8 > ( this->popUInt8() );
}
inline epicsInt16 comQueRecv::popInt16 ()
{
return static_cast < epicsInt16 > ( this->popUInt16() );
}
inline epicsInt32 comQueRecv::popInt32 ()
{
return static_cast < epicsInt32 > ( this->popUInt32() );
}
// this has been optimized to aligned convert, maybe more could be done,
// but since it is currently not used ...
inline epicsFloat32 comQueRecv::popFloat32 ()
{
union {
epicsUInt8 _wire[ sizeof ( epicsFloat32 ) ];
epicsFloat32 _fp;
} tmp;
// optimizer will unroll this loop
for ( unsigned i = 0u; i < sizeof ( tmp._wire ); i++ ) {
tmp._wire[i] = this->popUInt8 ();
}
return AlignedWireRef < epicsFloat32 > ( tmp._fp );
}
// this has been optimized to aligned convert, maybe more could be done,
// but since it is currently not used ...
inline epicsFloat64 comQueRecv::popFloat64 ()
{
union {
epicsUInt8 _wire[ sizeof ( epicsFloat64 ) ];
epicsFloat64 _fp;
} tmp;
// optimizer will unroll this loop
for ( unsigned i = 0u; i < sizeof ( tmp._wire ); i++ ) {
tmp._wire[i] = this->popUInt8 ();
}
return AlignedWireRef < epicsFloat64 > ( tmp._fp );
}
#endif // ifndef comQueRecvh

411
src/client/comQueSend.cpp Normal file
View File

@@ -0,0 +1,411 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
//
// Requirements:
// 1) Allow sufficent headroom so that users will be able to perform
// a reasonable amount of IO within CA callbacks without experiencing
// a push/pull deadlock. If a potential push/pull deadlock situation
// occurs then detect and avoid it and provide diagnotic to the user
// via special status.
// 2) Return status to the user when there is insufficent memory to
// queue a complete message.
// 3) return status to the user when a message cant be flushed because
// a connection dropped.
// 4) Do not allocate too much memory in exception situatons (such as
// after a circuit disconnect).
// 5) Avoid allocating more memory than is absolutely necessary to meet
// the above requirements.
// 6) Message fragments must never be sent to the IOC when there isnt
// enough memory to queue part of a message (we also must not force
// a disconnect because the client is starved for memory).
// 7) avoid the need to check status for each byte pushed into the
// protocol stream.
//
// Implementation:
// 1) When queuing a complete message, first test to see if a flush is
// required. If it is a receive thread scheduals the flush with the
// send thread, and otherwise directly execute the system call. The
// send thread must run at a higher priority than the receive thread
// if we are to minimize memory consumption.
// 2) Preallocate space for the entire message prior to copying in the
// message so that message fragments are not flushed out just prior
// to detecting that memory is unavailable.
// 3) Return a special error constant when the following situations
// are detected when the user is attempting to queue a request
// from within a user callback executed by a receive thread:
// a) A user is queuing more requests that demand a response from a
// callback than are removed by the response that initiated the
// callback, and this situation persists for many callbacks until
// all buffering in the system is exausted.
// b) A user is queuing many requests that demand a response from one
// callback until all buffering in the system is exausted.
// c) Some combination of both (a) nad (b).
//
//
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "virtualCircuit.h"
#include "db_access.h" // for dbr_short_t etc
// nill message alignment pad bytes
const char cacNillBytes [] =
{
0, 0, 0, 0,
0, 0, 0, 0
};
comQueSend::comQueSend ( wireSendAdapter & wireIn,
comBufMemoryManager & comBufMemMgrIn ):
comBufMemMgr ( comBufMemMgrIn ), wire ( wireIn ),
nBytesPending ( 0u )
{
}
comQueSend::~comQueSend ()
{
this->clear ();
}
void comQueSend::clear ()
{
comBuf *pBuf;
while ( ( pBuf = this->bufs.get () ) ) {
this->nBytesPending -= pBuf->occupiedBytes ();
pBuf->~comBuf ();
this->comBufMemMgr.release ( pBuf );
}
this->pFirstUncommited = tsDLIter < comBuf > ();
assert ( this->nBytesPending == 0 );
}
void comQueSend::copy_dbr_string ( const void * pValue )
{
this->push ( static_cast < const char * > ( pValue ), MAX_STRING_SIZE );
}
void comQueSend::copy_dbr_short ( const void * pValue )
{
this->push ( * static_cast <const dbr_short_t *> ( pValue ) );
}
void comQueSend::copy_dbr_float ( const void * pValue )
{
this->push ( * static_cast <const dbr_float_t *> ( pValue ) );
}
void comQueSend::copy_dbr_char ( const void * pValue )
{
this->push ( * static_cast <const dbr_char_t *> ( pValue ) );
}
void comQueSend::copy_dbr_long ( const void * pValue )
{
this->push ( * static_cast <const dbr_long_t *> ( pValue ) );
}
void comQueSend::copy_dbr_double ( const void * pValue )
{
this->push ( * static_cast <const dbr_double_t *> ( pValue ) );
}
void comQueSend::copy_dbr_invalid ( const void * )
{
throw cacChannel::badType ();
}
const comQueSend::copyScalarFunc_t comQueSend::dbrCopyScalar [39] = {
&comQueSend::copy_dbr_string,
&comQueSend::copy_dbr_short,
&comQueSend::copy_dbr_float,
&comQueSend::copy_dbr_short, // DBR_ENUM
&comQueSend::copy_dbr_char,
&comQueSend::copy_dbr_long,
&comQueSend::copy_dbr_double,
&comQueSend::copy_dbr_invalid, // DBR_STS_SHORT
&comQueSend::copy_dbr_invalid, // DBR_STS_FLOAT
&comQueSend::copy_dbr_invalid, // DBR_STS_ENUM
&comQueSend::copy_dbr_invalid, // DBR_STS_CHAR
&comQueSend::copy_dbr_invalid, // DBR_STS_LONG
&comQueSend::copy_dbr_invalid, // DBR_STS_DOUBLE
&comQueSend::copy_dbr_invalid, // DBR_TIME_STRING
&comQueSend::copy_dbr_invalid, // DBR_TIME_INT
&comQueSend::copy_dbr_invalid, // DBR_TIME_SHORT
&comQueSend::copy_dbr_invalid, // DBR_TIME_FLOAT
&comQueSend::copy_dbr_invalid, // DBR_TIME_ENUM
&comQueSend::copy_dbr_invalid, // DBR_TIME_CHAR
&comQueSend::copy_dbr_invalid, // DBR_TIME_LONG
&comQueSend::copy_dbr_invalid, // DBR_TIME_DOUBLE
&comQueSend::copy_dbr_invalid, // DBR_GR_STRING
&comQueSend::copy_dbr_invalid, // DBR_GR_SHORT
&comQueSend::copy_dbr_invalid, // DBR_GR_FLOAT
&comQueSend::copy_dbr_invalid, // DBR_GR_ENUM
&comQueSend::copy_dbr_invalid, // DBR_GR_CHAR
&comQueSend::copy_dbr_invalid, // DBR_GR_LONG
&comQueSend::copy_dbr_invalid, // DBR_GR_DOUBLE
&comQueSend::copy_dbr_invalid, // DBR_CTRL_STRING
&comQueSend::copy_dbr_invalid, // DBR_CTRL_SHORT
&comQueSend::copy_dbr_invalid, // DBR_CTRL_FLOAT
&comQueSend::copy_dbr_invalid, // DBR_CTRL_ENUM
&comQueSend::copy_dbr_invalid, // DBR_CTRL_CHAR
&comQueSend::copy_dbr_invalid, // DBR_CTRL_LONG
&comQueSend::copy_dbr_invalid, // DBR_CTRL_DOUBLE
&comQueSend::copy_dbr_short, // DBR_PUT_ACKT
&comQueSend::copy_dbr_short, // DBR_PUT_ACKS
&comQueSend::copy_dbr_invalid, // DBR_STSACK_STRING
&comQueSend::copy_dbr_invalid // DBR_CLASS_NAME
};
void comQueSend::copy_dbr_string ( const void *pValue, unsigned nElem )
{
this->push ( static_cast < const char * > ( pValue ), nElem * MAX_STRING_SIZE );
}
void comQueSend::copy_dbr_short ( const void *pValue, unsigned nElem )
{
this->push ( static_cast <const dbr_short_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_float ( const void *pValue, unsigned nElem )
{
this->push ( static_cast <const dbr_float_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_char ( const void *pValue, unsigned nElem )
{
this->push ( static_cast <const dbr_char_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_long ( const void *pValue, unsigned nElem )
{
this->push ( static_cast <const dbr_long_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_double ( const void *pValue, unsigned nElem )
{
this->push ( static_cast <const dbr_double_t *> ( pValue ), nElem );
}
void comQueSend::copy_dbr_invalid ( const void *, unsigned )
{
throw cacChannel::badType ();
}
const comQueSend::copyVectorFunc_t comQueSend::dbrCopyVector [39] = {
&comQueSend::copy_dbr_string,
&comQueSend::copy_dbr_short,
&comQueSend::copy_dbr_float,
&comQueSend::copy_dbr_short, // DBR_ENUM
&comQueSend::copy_dbr_char,
&comQueSend::copy_dbr_long,
&comQueSend::copy_dbr_double,
&comQueSend::copy_dbr_invalid, // DBR_STS_SHORT
&comQueSend::copy_dbr_invalid, // DBR_STS_FLOAT
&comQueSend::copy_dbr_invalid, // DBR_STS_ENUM
&comQueSend::copy_dbr_invalid, // DBR_STS_CHAR
&comQueSend::copy_dbr_invalid, // DBR_STS_LONG
&comQueSend::copy_dbr_invalid, // DBR_STS_DOUBLE
&comQueSend::copy_dbr_invalid, // DBR_TIME_STRING
&comQueSend::copy_dbr_invalid, // DBR_TIME_INT
&comQueSend::copy_dbr_invalid, // DBR_TIME_SHORT
&comQueSend::copy_dbr_invalid, // DBR_TIME_FLOAT
&comQueSend::copy_dbr_invalid, // DBR_TIME_ENUM
&comQueSend::copy_dbr_invalid, // DBR_TIME_CHAR
&comQueSend::copy_dbr_invalid, // DBR_TIME_LONG
&comQueSend::copy_dbr_invalid, // DBR_TIME_DOUBLE
&comQueSend::copy_dbr_invalid, // DBR_GR_STRING
&comQueSend::copy_dbr_invalid, // DBR_GR_SHORT
&comQueSend::copy_dbr_invalid, // DBR_GR_FLOAT
&comQueSend::copy_dbr_invalid, // DBR_GR_ENUM
&comQueSend::copy_dbr_invalid, // DBR_GR_CHAR
&comQueSend::copy_dbr_invalid, // DBR_GR_LONG
&comQueSend::copy_dbr_invalid, // DBR_GR_DOUBLE
&comQueSend::copy_dbr_invalid, // DBR_CTRL_STRING
&comQueSend::copy_dbr_invalid, // DBR_CTRL_SHORT
&comQueSend::copy_dbr_invalid, // DBR_CTRL_FLOAT
&comQueSend::copy_dbr_invalid, // DBR_CTRL_ENUM
&comQueSend::copy_dbr_invalid, // DBR_CTRL_CHAR
&comQueSend::copy_dbr_invalid, // DBR_CTRL_LONG
&comQueSend::copy_dbr_invalid, // DBR_CTRL_DOUBLE
&comQueSend::copy_dbr_short, // DBR_PUT_ACKT
&comQueSend::copy_dbr_short, // DBR_PUT_ACKS
&comQueSend::copy_dbr_invalid, // DBR_STSACK_STRING
&comQueSend::copy_dbr_invalid // DBR_CLASS_NAME
};
comBuf * comQueSend::popNextComBufToSend ()
{
comBuf *pBuf = this->bufs.get ();
if ( pBuf ) {
unsigned nBytesThisBuf = pBuf->occupiedBytes ();
if ( nBytesThisBuf ) {
assert ( this->nBytesPending >= nBytesThisBuf );
this->nBytesPending -= nBytesThisBuf;
}
else {
this->bufs.push ( *pBuf );
pBuf = 0;
}
}
else {
assert ( this->nBytesPending == 0u );
}
return pBuf;
}
void comQueSend::insertRequestHeader (
ca_uint16_t request, ca_uint32_t payloadSize,
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
ca_uint32_t requestDependent, bool v49Ok )
{
if ( payloadSize < 0xffff && nElem < 0xffff ) {
comBuf * pComBuf = this->bufs.last ();
if ( ! pComBuf || pComBuf->unoccupiedBytes() < 16u ) {
pComBuf = newComBuf ();
this->pushComBuf ( *pComBuf );
}
pComBuf->push ( request );
pComBuf->push ( static_cast < ca_uint16_t > ( payloadSize ) );
pComBuf->push ( dataType );
pComBuf->push ( static_cast < ca_uint16_t > ( nElem ) );
pComBuf->push ( cid );
pComBuf->push ( requestDependent );
}
else if ( v49Ok ) {
comBuf * pComBuf = this->bufs.last ();
if ( ! pComBuf || pComBuf->unoccupiedBytes() < 24u ) {
pComBuf = newComBuf ();
this->pushComBuf ( *pComBuf );
}
pComBuf->push ( request );
pComBuf->push ( static_cast < ca_uint16_t > ( 0xffff ) );
pComBuf->push ( dataType );
pComBuf->push ( static_cast < ca_uint16_t > ( 0u ) );
pComBuf->push ( cid );
pComBuf->push ( requestDependent );
pComBuf->push ( payloadSize );
pComBuf->push ( nElem );
}
else {
throw cacChannel::outOfBounds ();
}
}
void comQueSend::insertRequestWithPayLoad (
ca_uint16_t request, unsigned dataType, arrayElementCount nElem,
ca_uint32_t cid, ca_uint32_t requestDependent,
const void * pPayload, bool v49Ok )
{
if ( INVALID_DB_REQ ( dataType ) ) {
throw cacChannel::badType ();
}
if ( dataType >= comQueSendCopyDispatchSize ) {
throw cacChannel::badType();
}
ca_uint32_t size = 0u;
ca_uint32_t payloadSize = 0u;
if ( nElem == 1 ) {
if ( dataType == DBR_STRING ) {
const char * pStr = static_cast < const char * > ( pPayload );
size = strlen ( pStr ) + 1u;
if ( size > MAX_STRING_SIZE ) {
throw cacChannel::outOfBounds();
}
payloadSize = CA_MESSAGE_ALIGN ( size );
this->insertRequestHeader ( request, payloadSize,
static_cast <ca_uint16_t> ( dataType ),
nElem, cid, requestDependent, v49Ok );
this->pushString ( pStr, size );
}
else {
size = dbr_size[dataType];
payloadSize = CA_MESSAGE_ALIGN ( size );
this->insertRequestHeader ( request, payloadSize,
static_cast <ca_uint16_t> ( dataType ),
nElem, cid, requestDependent, v49Ok );
( this->*dbrCopyScalar [dataType] ) ( pPayload );
}
}
else {
arrayElementCount maxBytes;
if ( v49Ok ) {
maxBytes = 0xffffffff;
}
else {
maxBytes = MAX_TCP - sizeof ( caHdr );
}
arrayElementCount maxElem =
( maxBytes - sizeof (dbr_double_t) - dbr_size[dataType] ) /
dbr_value_size[dataType];
if ( nElem >= maxElem ) {
throw cacChannel::outOfBounds();
}
// the above checks verify that the total size
// is lest that 0xffffffff
size = static_cast < ca_uint32_t >
( dbr_size_n ( dataType, nElem ) );
payloadSize = CA_MESSAGE_ALIGN ( size );
this->insertRequestHeader ( request, payloadSize,
static_cast <ca_uint16_t> ( dataType ),
static_cast < ca_uint32_t > ( nElem ),
cid, requestDependent, v49Ok );
( this->*dbrCopyVector [dataType] ) ( pPayload, nElem );
}
// set pad bytes to nill
unsigned padSize = payloadSize - size;
if ( padSize ) {
this->pushString ( cacNillBytes, payloadSize - size );
}
}
void comQueSend::commitMsg ()
{
while ( this->pFirstUncommited.valid() ) {
this->nBytesPending += this->pFirstUncommited->uncommittedBytes ();
this->pFirstUncommited->commitIncomming ();
this->pFirstUncommited++;
}
// printf ( "NBP: %u\n", this->nBytesPending );
}
void comQueSend::clearUncommitedMsg ()
{
while ( this->pFirstUncommited.valid() ) {
tsDLIter < comBuf > next = this->pFirstUncommited;
next++;
this->pFirstUncommited->clearUncommittedIncomming ();
if ( this->pFirstUncommited->occupiedBytes() == 0u ) {
this->bufs.remove ( *this->pFirstUncommited );
this->pFirstUncommited->~comBuf ();
this->comBufMemMgr.release ( this->pFirstUncommited.pointer() );
}
this->pFirstUncommited = next;
}
}

238
src/client/comQueSend.h Normal file
View File

@@ -0,0 +1,238 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef comQueSendh
#define comQueSendh
#include <new>
#include "tsDLList.h"
#include "comBuf.h"
#define comQueSendCopyDispatchSize 39
class epicsMutex;
template < class T > class epicsGuard;
class comQueSendMsgMinder {
public:
comQueSendMsgMinder (
class comQueSend &, epicsGuard < epicsMutex > & );
~comQueSendMsgMinder ();
void commit ();
private:
class comQueSend * pSendQue;
};
//
// Notes.
// o calling popNextComBufToSend() will clear any uncommitted bytes
//
class comQueSend {
public:
comQueSend ( wireSendAdapter &, comBufMemoryManager & );
~comQueSend ();
void clear ();
unsigned occupiedBytes () const;
bool flushEarlyThreshold ( unsigned nBytesThisMsg ) const;
bool flushBlockThreshold () const;
void pushUInt16 ( const ca_uint16_t value );
void pushUInt32 ( const ca_uint32_t value );
void pushFloat32 ( const ca_float32_t value );
void pushString ( const char *pVal, unsigned nChar );
void insertRequestHeader (
ca_uint16_t request, ca_uint32_t payloadSize,
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
ca_uint32_t requestDependent, bool v49Ok );
void insertRequestWithPayLoad (
ca_uint16_t request, unsigned dataType, arrayElementCount nElem,
ca_uint32_t cid, ca_uint32_t requestDependent,
const void * pPayload, bool v49Ok );
comBuf * popNextComBufToSend ();
private:
comBufMemoryManager & comBufMemMgr;
tsDLList < comBuf > bufs;
tsDLIter < comBuf > pFirstUncommited;
wireSendAdapter & wire;
unsigned nBytesPending;
typedef void ( comQueSend::*copyScalarFunc_t ) (
const void * pValue );
static const copyScalarFunc_t dbrCopyScalar [comQueSendCopyDispatchSize];
void copy_dbr_string ( const void * pValue );
void copy_dbr_short ( const void * pValue );
void copy_dbr_float ( const void * pValue );
void copy_dbr_char ( const void * pValue );
void copy_dbr_long ( const void * pValue );
void copy_dbr_double ( const void * pValue );
void copy_dbr_invalid ( const void * pValue );
typedef void ( comQueSend::*copyVectorFunc_t ) (
const void * pValue, unsigned nElem );
static const copyVectorFunc_t dbrCopyVector [comQueSendCopyDispatchSize];
void copy_dbr_string ( const void *pValue, unsigned nElem );
void copy_dbr_short ( const void *pValue, unsigned nElem );
void copy_dbr_float ( const void *pValue, unsigned nElem );
void copy_dbr_char ( const void *pValue, unsigned nElem );
void copy_dbr_long ( const void *pValue, unsigned nElem );
void copy_dbr_double ( const void *pValue, unsigned nElem );
void copy_dbr_invalid ( const void * pValue, unsigned nElem );
void pushComBuf ( comBuf & );
comBuf * newComBuf ();
void beginMsg ();
void commitMsg ();
void clearUncommitedMsg ();
friend class comQueSendMsgMinder;
//
// visual C++ versions 6 & 7 do not allow out of
// class member template function definition
//
template < class T >
inline void push ( const T *pVal, const unsigned nElem )
{
comBuf * pLastBuf = this->bufs.last ();
unsigned nCopied;
if ( pLastBuf ) {
nCopied = pLastBuf->push ( pVal, nElem );
}
else {
nCopied = 0u;
}
while ( nElem > nCopied ) {
comBuf * pComBuf = newComBuf ();
nCopied += pComBuf->push
( &pVal[nCopied], nElem - nCopied );
this->pushComBuf ( *pComBuf );
}
}
//
// visual C++ versions 6 and 7 do not allow out of
// class member template function definition
//
template < class T >
inline void push ( const T & val )
{
comBuf * pComBuf = this->bufs.last ();
if ( pComBuf && pComBuf->push ( val ) ) {
return;
}
pComBuf = newComBuf ();
bool success = pComBuf->push ( val );
assert ( success );
this->pushComBuf ( *pComBuf );
}
template < class T >
inline void push ( const T * ); // disabled
comQueSend ( const comQueSend & );
comQueSend & operator = ( const comQueSend & );
};
extern const char cacNillBytes[];
inline comQueSendMsgMinder::comQueSendMsgMinder (
class comQueSend & sendQueIn, epicsGuard < epicsMutex > & ) :
pSendQue ( & sendQueIn )
{
sendQueIn.beginMsg ();
}
inline comQueSendMsgMinder::~comQueSendMsgMinder ()
{
if ( this->pSendQue ) {
this->pSendQue->clearUncommitedMsg ();
}
}
inline void comQueSendMsgMinder::commit ()
{
if ( this->pSendQue ) {
this->pSendQue->commitMsg ();
this->pSendQue = 0;
}
}
inline void comQueSend::beginMsg ()
{
this->pFirstUncommited = this->bufs.lastIter ();
}
inline void comQueSend::pushUInt16 ( const ca_uint16_t value )
{
this->push ( value );
}
inline void comQueSend::pushUInt32 ( const ca_uint32_t value )
{
this->push ( value );
}
inline void comQueSend::pushFloat32 ( const ca_float32_t value )
{
this->push ( value );
}
inline void comQueSend::pushString ( const char *pVal, unsigned nChar )
{
this->push ( pVal, nChar );
}
inline void comQueSend::pushComBuf ( comBuf & cb )
{
this->bufs.add ( cb );
if ( ! this->pFirstUncommited.valid() ) {
this->pFirstUncommited = this->bufs.lastIter ();
}
}
inline unsigned comQueSend::occupiedBytes () const
{
return this->nBytesPending;
}
inline bool comQueSend::flushBlockThreshold () const
{
return ( this->nBytesPending > 16 * comBuf::capacityBytes () );
}
inline bool comQueSend::flushEarlyThreshold ( unsigned nBytesThisMsg ) const
{
return ( this->nBytesPending + nBytesThisMsg > 4 * comBuf::capacityBytes () );
}
// wrapping this with a function avoids WRS T2.2 Cygnus GNU compiler bugs
inline comBuf * comQueSend::newComBuf ()
{
return new ( this->comBufMemMgr ) comBuf;
}
#endif // ifndef comQueSendh

1440
src/client/convert.cpp Normal file

File diff suppressed because it is too large Load Diff

740
src/client/db_access.h Normal file
View File

@@ -0,0 +1,740 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* base/include/db_access.h */
/* Author: Bob Dalesio
* Date: 4-4-88
*/
#ifndef INCLdb_accessh
#define INCLdb_accessh
#include <stddef.h>
#ifdef epicsExportSharedSymbols
# define INCLdb_accessh_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "epicsTypes.h"
#include "epicsTime.h"
#ifdef INCLdb_accessh_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_UNITS_SIZE 8
#define MAX_ENUM_STRING_SIZE 26
#define MAX_ENUM_STATES 16
/*
* architecture independent types
*
* (so far this is sufficient for all archs we have ported to)
*/
typedef epicsOldString dbr_string_t;
typedef epicsUInt8 dbr_char_t;
typedef epicsInt16 dbr_short_t;
typedef epicsUInt16 dbr_ushort_t;
typedef epicsInt16 dbr_int_t;
typedef epicsUInt16 dbr_enum_t;
typedef epicsInt32 dbr_long_t;
typedef epicsUInt32 dbr_ulong_t;
typedef epicsFloat32 dbr_float_t;
typedef epicsFloat64 dbr_double_t;
typedef epicsUInt16 dbr_put_ackt_t;
typedef epicsUInt16 dbr_put_acks_t;
typedef epicsOldString dbr_stsack_string_t;
typedef epicsOldString dbr_class_name_t;
#ifndef db_accessHFORdb_accessC
/* database field types */
#define DBF_STRING 0
#define DBF_INT 1
#define DBF_SHORT 1
#define DBF_FLOAT 2
#define DBF_ENUM 3
#define DBF_CHAR 4
#define DBF_LONG 5
#define DBF_DOUBLE 6
#define DBF_NO_ACCESS 7
#define LAST_TYPE DBF_DOUBLE
#define VALID_DB_FIELD(x) ((x >= 0) && (x <= LAST_TYPE))
#define INVALID_DB_FIELD(x) ((x < 0) || (x > LAST_TYPE))
/* data request buffer types */
#define DBR_STRING DBF_STRING
#define DBR_INT DBF_INT
#define DBR_SHORT DBF_INT
#define DBR_FLOAT DBF_FLOAT
#define DBR_ENUM DBF_ENUM
#define DBR_CHAR DBF_CHAR
#define DBR_LONG DBF_LONG
#define DBR_DOUBLE DBF_DOUBLE
#define DBR_STS_STRING 7
#define DBR_STS_SHORT 8
#define DBR_STS_INT DBR_STS_SHORT
#define DBR_STS_FLOAT 9
#define DBR_STS_ENUM 10
#define DBR_STS_CHAR 11
#define DBR_STS_LONG 12
#define DBR_STS_DOUBLE 13
#define DBR_TIME_STRING 14
#define DBR_TIME_INT 15
#define DBR_TIME_SHORT 15
#define DBR_TIME_FLOAT 16
#define DBR_TIME_ENUM 17
#define DBR_TIME_CHAR 18
#define DBR_TIME_LONG 19
#define DBR_TIME_DOUBLE 20
#define DBR_GR_STRING 21
#define DBR_GR_SHORT 22
#define DBR_GR_INT DBR_GR_SHORT
#define DBR_GR_FLOAT 23
#define DBR_GR_ENUM 24
#define DBR_GR_CHAR 25
#define DBR_GR_LONG 26
#define DBR_GR_DOUBLE 27
#define DBR_CTRL_STRING 28
#define DBR_CTRL_SHORT 29
#define DBR_CTRL_INT DBR_CTRL_SHORT
#define DBR_CTRL_FLOAT 30
#define DBR_CTRL_ENUM 31
#define DBR_CTRL_CHAR 32
#define DBR_CTRL_LONG 33
#define DBR_CTRL_DOUBLE 34
#define DBR_PUT_ACKT DBR_CTRL_DOUBLE + 1
#define DBR_PUT_ACKS DBR_PUT_ACKT + 1
#define DBR_STSACK_STRING DBR_PUT_ACKS + 1
#define DBR_CLASS_NAME DBR_STSACK_STRING + 1
#define LAST_BUFFER_TYPE DBR_CLASS_NAME
#define VALID_DB_REQ(x) ((x >= 0) && (x <= LAST_BUFFER_TYPE))
#define INVALID_DB_REQ(x) ((x < 0) || (x > LAST_BUFFER_TYPE))
/*
* The enumeration "epicsType" is an index to this array
* of type DBR types. In some cases we select the a
* larger type to avoid loss of information
*/
epicsShareExtern const int epicsTypeToDBR_XXXX [lastEpicsType+1];
/*
* The DBR_XXXX types are indicies into this array
*/
epicsShareExtern const epicsType DBR_XXXXToEpicsType [LAST_BUFFER_TYPE+1];
/* values returned for each field type
* DBR_STRING returns a NULL terminated string
* DBR_SHORT returns an unsigned short
* DBR_INT returns an unsigned short
* DBR_FLOAT returns an IEEE floating point value
* DBR_ENUM returns an unsigned short which is the enum item
* DBR_CHAR returns an unsigned char
* DBR_LONG returns an unsigned long
* DBR_DOUBLE returns a double precision floating point number
* DBR_STS_STRING returns a string status structure (dbr_sts_string)
* DBR_STS_SHORT returns a short status structure (dbr_sts_short)
* DBR_STS_INT returns a short status structure (dbr_sts_int)
* DBR_STS_FLOAT returns a float status structure (dbr_sts_float)
* DBR_STS_ENUM returns an enum status structure (dbr_sts_enum)
* DBR_STS_CHAR returns a char status structure (dbr_sts_char)
* DBR_STS_LONG returns a long status structure (dbr_sts_long)
* DBR_STS_DOUBLE returns a double status structure (dbr_sts_double)
* DBR_TIME_STRING returns a string time structure (dbr_time_string)
* DBR_TIME_SHORT returns a short time structure (dbr_time_short)
* DBR_TIME_INT returns a short time structure (dbr_time_short)
* DBR_TIME_FLOAT returns a float time structure (dbr_time_float)
* DBR_TIME_ENUM returns an enum time structure (dbr_time_enum)
* DBR_TIME_CHAR returns a char time structure (dbr_time_char)
* DBR_TIME_LONG returns a long time structure (dbr_time_long)
* DBR_TIME_DOUBLE returns a double time structure (dbr_time_double)
* DBR_GR_STRING returns a graphic string structure (dbr_gr_string)
* DBR_GR_SHORT returns a graphic short structure (dbr_gr_short)
* DBR_GR_INT returns a graphic short structure (dbr_gr_int)
* DBR_GR_FLOAT returns a graphic float structure (dbr_gr_float)
* DBR_GR_ENUM returns a graphic enum structure (dbr_gr_enum)
* DBR_GR_CHAR returns a graphic char structure (dbr_gr_char)
* DBR_GR_LONG returns a graphic long structure (dbr_gr_long)
* DBR_GR_DOUBLE returns a graphic double structure (dbr_gr_double)
* DBR_CTRL_STRING returns a control string structure (dbr_ctrl_int)
* DBR_CTRL_SHORT returns a control short structure (dbr_ctrl_short)
* DBR_CTRL_INT returns a control short structure (dbr_ctrl_int)
* DBR_CTRL_FLOAT returns a control float structure (dbr_ctrl_float)
* DBR_CTRL_ENUM returns a control enum structure (dbr_ctrl_enum)
* DBR_CTRL_CHAR returns a control char structure (dbr_ctrl_char)
* DBR_CTRL_LONG returns a control long structure (dbr_ctrl_long)
* DBR_CTRL_DOUBLE returns a control double structure (dbr_ctrl_double)
*/
#endif /*db_accessHFORdb_accessC*/
/* VALUES WITH STATUS STRUCTURES */
/* structure for a string status field */
struct dbr_sts_string {
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_string_t value; /* current value */
};
/* structure for a string status and ack field */
struct dbr_stsack_string{
dbr_ushort_t status; /* status of value */
dbr_ushort_t severity; /* severity of alarm */
dbr_ushort_t ackt; /* ack transient? */
dbr_ushort_t acks; /* ack severity */
dbr_string_t value; /* current value */
};
/* structure for an short status field */
struct dbr_sts_int{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_short_t value; /* current value */
};
struct dbr_sts_short{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_short_t value; /* current value */
};
/* structure for a float status field */
struct dbr_sts_float{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_float_t value; /* current value */
};
/* structure for a enum status field */
struct dbr_sts_enum{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_enum_t value; /* current value */
};
/* structure for a char status field */
struct dbr_sts_char{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_char_t RISC_pad; /* RISC alignment */
dbr_char_t value; /* current value */
};
/* structure for a long status field */
struct dbr_sts_long{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_long_t value; /* current value */
};
/* structure for a double status field */
struct dbr_sts_double{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_long_t RISC_pad; /* RISC alignment */
dbr_double_t value; /* current value */
};
/* VALUES WITH STATUS AND TIME STRUCTURES */
/* structure for a string time field */
struct dbr_time_string{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
epicsTimeStamp stamp; /* time stamp */
dbr_string_t value; /* current value */
};
/* structure for an short time field */
struct dbr_time_short{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
epicsTimeStamp stamp; /* time stamp */
dbr_short_t RISC_pad; /* RISC alignment */
dbr_short_t value; /* current value */
};
/* structure for a float time field */
struct dbr_time_float{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
epicsTimeStamp stamp; /* time stamp */
dbr_float_t value; /* current value */
};
/* structure for a enum time field */
struct dbr_time_enum{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
epicsTimeStamp stamp; /* time stamp */
dbr_short_t RISC_pad; /* RISC alignment */
dbr_enum_t value; /* current value */
};
/* structure for a char time field */
struct dbr_time_char{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
epicsTimeStamp stamp; /* time stamp */
dbr_short_t RISC_pad0; /* RISC alignment */
dbr_char_t RISC_pad1; /* RISC alignment */
dbr_char_t value; /* current value */
};
/* structure for a long time field */
struct dbr_time_long{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
epicsTimeStamp stamp; /* time stamp */
dbr_long_t value; /* current value */
};
/* structure for a double time field */
struct dbr_time_double{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
epicsTimeStamp stamp; /* time stamp */
dbr_long_t RISC_pad; /* RISC alignment */
dbr_double_t value; /* current value */
};
/* VALUES WITH STATUS AND GRAPHIC STRUCTURES */
/* structure for a graphic string */
/* not implemented; use struct_dbr_sts_string */
/* structure for a graphic short field */
struct dbr_gr_int{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_short_t upper_disp_limit; /* upper limit of graph */
dbr_short_t lower_disp_limit; /* lower limit of graph */
dbr_short_t upper_alarm_limit;
dbr_short_t upper_warning_limit;
dbr_short_t lower_warning_limit;
dbr_short_t lower_alarm_limit;
dbr_short_t value; /* current value */
};
struct dbr_gr_short{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_short_t upper_disp_limit; /* upper limit of graph */
dbr_short_t lower_disp_limit; /* lower limit of graph */
dbr_short_t upper_alarm_limit;
dbr_short_t upper_warning_limit;
dbr_short_t lower_warning_limit;
dbr_short_t lower_alarm_limit;
dbr_short_t value; /* current value */
};
/* structure for a graphic floating point field */
struct dbr_gr_float{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_short_t precision; /* number of decimal places */
dbr_short_t RISC_pad0; /* RISC alignment */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_float_t upper_disp_limit; /* upper limit of graph */
dbr_float_t lower_disp_limit; /* lower limit of graph */
dbr_float_t upper_alarm_limit;
dbr_float_t upper_warning_limit;
dbr_float_t lower_warning_limit;
dbr_float_t lower_alarm_limit;
dbr_float_t value; /* current value */
};
/* structure for a graphic enumeration field */
struct dbr_gr_enum{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_short_t no_str; /* number of strings */
char strs[MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];
/* state strings */
dbr_enum_t value; /* current value */
};
/* structure for a graphic char field */
struct dbr_gr_char{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_char_t upper_disp_limit; /* upper limit of graph */
dbr_char_t lower_disp_limit; /* lower limit of graph */
dbr_char_t upper_alarm_limit;
dbr_char_t upper_warning_limit;
dbr_char_t lower_warning_limit;
dbr_char_t lower_alarm_limit;
dbr_char_t RISC_pad; /* RISC alignment */
dbr_char_t value; /* current value */
};
/* structure for a graphic long field */
struct dbr_gr_long{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_long_t upper_disp_limit; /* upper limit of graph */
dbr_long_t lower_disp_limit; /* lower limit of graph */
dbr_long_t upper_alarm_limit;
dbr_long_t upper_warning_limit;
dbr_long_t lower_warning_limit;
dbr_long_t lower_alarm_limit;
dbr_long_t value; /* current value */
};
/* structure for a graphic double field */
struct dbr_gr_double{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_short_t precision; /* number of decimal places */
dbr_short_t RISC_pad0; /* RISC alignment */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_double_t upper_disp_limit; /* upper limit of graph */
dbr_double_t lower_disp_limit; /* lower limit of graph */
dbr_double_t upper_alarm_limit;
dbr_double_t upper_warning_limit;
dbr_double_t lower_warning_limit;
dbr_double_t lower_alarm_limit;
dbr_double_t value; /* current value */
};
/* VALUES WITH STATUS, GRAPHIC and CONTROL STRUCTURES */
/* structure for a control string */
/* not implemented; use struct_dbr_sts_string */
/* structure for a control integer */
struct dbr_ctrl_int{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_short_t upper_disp_limit; /* upper limit of graph */
dbr_short_t lower_disp_limit; /* lower limit of graph */
dbr_short_t upper_alarm_limit;
dbr_short_t upper_warning_limit;
dbr_short_t lower_warning_limit;
dbr_short_t lower_alarm_limit;
dbr_short_t upper_ctrl_limit; /* upper control limit */
dbr_short_t lower_ctrl_limit; /* lower control limit */
dbr_short_t value; /* current value */
};
struct dbr_ctrl_short{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_short_t upper_disp_limit; /* upper limit of graph */
dbr_short_t lower_disp_limit; /* lower limit of graph */
dbr_short_t upper_alarm_limit;
dbr_short_t upper_warning_limit;
dbr_short_t lower_warning_limit;
dbr_short_t lower_alarm_limit;
dbr_short_t upper_ctrl_limit; /* upper control limit */
dbr_short_t lower_ctrl_limit; /* lower control limit */
dbr_short_t value; /* current value */
};
/* structure for a control floating point field */
struct dbr_ctrl_float{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_short_t precision; /* number of decimal places */
dbr_short_t RISC_pad; /* RISC alignment */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_float_t upper_disp_limit; /* upper limit of graph */
dbr_float_t lower_disp_limit; /* lower limit of graph */
dbr_float_t upper_alarm_limit;
dbr_float_t upper_warning_limit;
dbr_float_t lower_warning_limit;
dbr_float_t lower_alarm_limit;
dbr_float_t upper_ctrl_limit; /* upper control limit */
dbr_float_t lower_ctrl_limit; /* lower control limit */
dbr_float_t value; /* current value */
};
/* structure for a control enumeration field */
struct dbr_ctrl_enum{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_short_t no_str; /* number of strings */
char strs[MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];
/* state strings */
dbr_enum_t value; /* current value */
};
/* structure for a control char field */
struct dbr_ctrl_char{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_char_t upper_disp_limit; /* upper limit of graph */
dbr_char_t lower_disp_limit; /* lower limit of graph */
dbr_char_t upper_alarm_limit;
dbr_char_t upper_warning_limit;
dbr_char_t lower_warning_limit;
dbr_char_t lower_alarm_limit;
dbr_char_t upper_ctrl_limit; /* upper control limit */
dbr_char_t lower_ctrl_limit; /* lower control limit */
dbr_char_t RISC_pad; /* RISC alignment */
dbr_char_t value; /* current value */
};
/* structure for a control long field */
struct dbr_ctrl_long{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_long_t upper_disp_limit; /* upper limit of graph */
dbr_long_t lower_disp_limit; /* lower limit of graph */
dbr_long_t upper_alarm_limit;
dbr_long_t upper_warning_limit;
dbr_long_t lower_warning_limit;
dbr_long_t lower_alarm_limit;
dbr_long_t upper_ctrl_limit; /* upper control limit */
dbr_long_t lower_ctrl_limit; /* lower control limit */
dbr_long_t value; /* current value */
};
/* structure for a control double field */
struct dbr_ctrl_double{
dbr_short_t status; /* status of value */
dbr_short_t severity; /* severity of alarm */
dbr_short_t precision; /* number of decimal places */
dbr_short_t RISC_pad0; /* RISC alignment */
char units[MAX_UNITS_SIZE]; /* units of value */
dbr_double_t upper_disp_limit; /* upper limit of graph */
dbr_double_t lower_disp_limit; /* lower limit of graph */
dbr_double_t upper_alarm_limit;
dbr_double_t upper_warning_limit;
dbr_double_t lower_warning_limit;
dbr_double_t lower_alarm_limit;
dbr_double_t upper_ctrl_limit; /* upper control limit */
dbr_double_t lower_ctrl_limit; /* lower control limit */
dbr_double_t value; /* current value */
};
#define dbr_size_n(TYPE,COUNT)\
((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
/* size for each type - array indexed by the DBR_ type code */
epicsShareExtern const unsigned short dbr_size[];
/* size for each type's value - array indexed by the DBR_ type code */
epicsShareExtern const unsigned short dbr_value_size[];
#ifndef db_accessHFORdb_accessC
/* class for each type's value */
enum dbr_value_class {
dbr_class_int,
dbr_class_float,
dbr_class_string,
dbr_class_max};
epicsShareExtern const enum dbr_value_class dbr_value_class[LAST_BUFFER_TYPE+1];
/*
* ptr to value given a pointer to the structure and the DBR type
*/
#define dbr_value_ptr(PDBR, DBR_TYPE) \
((void *)(((char *)PDBR)+dbr_value_offset[DBR_TYPE]))
/*
* ptr to value given a pointer to the structure and the structure declaration
*/
#define dbr_value_ptr_from_structure(PDBR, STRUCTURE)\
((void *)(((char *)PDBR)+BYTE_OS(STRUCTURE, value)))
epicsShareExtern const unsigned short dbr_value_offset[LAST_BUFFER_TYPE+1];
/* union for each fetch buffers */
union db_access_val{
dbr_string_t strval; /* string max size */
dbr_short_t shrtval; /* short */
dbr_short_t intval; /* short */
dbr_float_t fltval; /* IEEE Float */
dbr_enum_t enmval; /* item number */
dbr_char_t charval; /* character */
dbr_long_t longval; /* long */
dbr_double_t doubleval; /* double */
struct dbr_sts_string sstrval; /* string field with status */
struct dbr_sts_short sshrtval; /* short field with status */
struct dbr_sts_float sfltval; /* float field with status */
struct dbr_sts_enum senmval; /* item number with status */
struct dbr_sts_char schrval; /* char field with status */
struct dbr_sts_long slngval; /* long field with status */
struct dbr_sts_double sdblval; /* double field with time */
struct dbr_time_string tstrval; /* string field with time */
struct dbr_time_short tshrtval; /* short field with time */
struct dbr_time_float tfltval; /* float field with time */
struct dbr_time_enum tenmval; /* item number with time */
struct dbr_time_char tchrval; /* char field with time */
struct dbr_time_long tlngval; /* long field with time */
struct dbr_time_double tdblval; /* double field with time */
struct dbr_sts_string gstrval; /* graphic string info */
struct dbr_gr_short gshrtval; /* graphic short info */
struct dbr_gr_float gfltval; /* graphic float info */
struct dbr_gr_enum genmval; /* graphic item info */
struct dbr_gr_char gchrval; /* graphic char info */
struct dbr_gr_long glngval; /* graphic long info */
struct dbr_gr_double gdblval; /* graphic double info */
struct dbr_sts_string cstrval; /* control string info */
struct dbr_ctrl_short cshrtval; /* control short info */
struct dbr_ctrl_float cfltval; /* control float info */
struct dbr_ctrl_enum cenmval; /* control item info */
struct dbr_ctrl_char cchrval; /* control char info */
struct dbr_ctrl_long clngval; /* control long info */
struct dbr_ctrl_double cdblval; /* control double info */
dbr_put_ackt_t putackt; /* item number */
dbr_put_acks_t putacks; /* item number */
struct dbr_sts_string sastrval; /* string field with status */
dbr_string_t classname; /* string max size */
};
/*----------------------------------------------------------------------------
* repository for some useful PV database constants and utilities
*
* item dimensions
* db_strval_dim dimension for string values
* db_units_dim dimension for record units text
* db_desc_dim dimension for record description text
* db_name_dim dimension for channel names (record.field\0)
* db_state_dim number of states possible in a state table
* db_state_text_dim dimension for a state text string
* usage: char state_table[db_state_dim][db_state_text_dim]
*
* type checking macros -- return non-zero if condition is true, zero otherwise
*
* int dbf_type_is_valid(type) type is a valid DBF_xxx
* int dbr_type_is_valid(type) type is a valid DBR_xxx
* int dbr_type_is_plain(type) type is a valid plain DBR_xxx
* int dbr_type_is_STS(type) type is a valid DBR_STS_xxx
* int dbr_type_is_TIME(type) type is a valid DBR_TIME_xxx
* int dbr_type_is_GR(type) type is a valid DBR_GR_xxx
* int dbr_type_is_CTRL(type) type is a valid DBR_CTRL_xxx
* int dbr_type_is_STRING(type) type is a valid DBR_STRING_xxx
* int dbr_type_is_SHORT(type) type is a valid DBR_SHORT_xxx
* int dbr_type_is_FLOAT(type) type is a valid DBR_FLOAT_xxx
* int dbr_type_is_ENUM(type) type is a valid DBR_ENUM_xxx
* int dbr_type_is_CHAR(type) type is a valid DBR_CHAR_xxx
* int dbr_type_is_LONG(type) type is a valid DBR_LONG_xxx
* int dbr_type_is_DOUBLE(type) type is a valid DBR_DOUBLE_xxx
*
* type conversion macros
*
* char *dbf_type_to_text(type) returns text matching DBF_xxx
* void dbf_text_to_type(text, type) finds DBF_xxx matching text
* int dbf_type_to_DBR(type) returns DBR_xxx matching DBF_xxx
* int dbf_type_to_DBR_TIME(type) returns DBR_TIME_xxx matching DBF_xxx
* int dbf_type_to_DBR_GR(type) returns DBR_GR_xxx matching DBF_xxx
* int dbf_type_to_DBR_CTRL(type) returns DBR_CTRL_xxx matching DBF_xxx
* char *dbr_type_to_text(type) returns text matching DBR_xxx
* void dbr_text_to_type(text, type) finds DBR_xxx matching text
*---------------------------------------------------------------------------*/
#define db_strval_dim MAX_STRING_SIZE
#define db_units_dim MAX_UNITS_SIZE
#define db_desc_dim 24
#define db_name_dim 36
#define db_state_dim MAX_ENUM_STATES
#define db_state_text_dim MAX_ENUM_STRING_SIZE
#define dbf_type_is_valid(type) ((type) >= 0 && (type) <= LAST_TYPE)
#define dbr_type_is_valid(type) ((type) >= 0 && (type) <= LAST_BUFFER_TYPE)
#define dbr_type_is_plain(type) \
((type) >= DBR_STRING && (type) <= DBR_DOUBLE)
#define dbr_type_is_STS(type) \
((type) >= DBR_STS_STRING && (type) <= DBR_STS_DOUBLE)
#define dbr_type_is_TIME(type) \
((type) >= DBR_TIME_STRING && (type) <= DBR_TIME_DOUBLE)
#define dbr_type_is_GR(type) \
((type) >= DBR_GR_STRING && (type) <= DBR_GR_DOUBLE)
#define dbr_type_is_CTRL(type) \
((type) >= DBR_CTRL_STRING && (type) <= DBR_CTRL_DOUBLE)
#define dbr_type_is_STRING(type) \
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
(type)%(LAST_TYPE+1) == DBR_STRING)
#define dbr_type_is_SHORT(type) \
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
(type)%(LAST_TYPE+1) == DBR_SHORT)
#define dbr_type_is_FLOAT(type) \
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
(type)%(LAST_TYPE+1) == DBR_FLOAT)
#define dbr_type_is_ENUM(type) \
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
(type)%(LAST_TYPE+1) == DBR_ENUM)
#define dbr_type_is_CHAR(type) \
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
(type)%(LAST_TYPE+1) == DBR_CHAR)
#define dbr_type_is_LONG(type) \
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
(type)%(LAST_TYPE+1) == DBR_LONG)
#define dbr_type_is_DOUBLE(type) \
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
(type)%(LAST_TYPE+1) == DBR_DOUBLE)
#define dbf_type_to_text(type) \
( ((type) >= -1 && (type) < dbf_text_dim-2) ? \
dbf_text[type+1] : dbf_text_invalid )
#define dbf_text_to_type(text, type) \
for (type=dbf_text_dim-3; type>=0; type--) { \
if (strcmp(text, dbf_text[type+1]) == 0) \
break; \
}
#define dbr_type_to_text(type) \
( ((type) >= 0 && (type) < dbr_text_dim) ? \
dbr_text[(type)] : dbr_text_invalid )
#define dbr_text_to_type(text, type) \
for (type=dbr_text_dim-2; type>=0; type--) { \
if (strcmp(text, dbr_text[type]) == 0) \
break; \
}
#define dbf_type_to_DBR(type) \
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
(type) : -1 )
#define dbf_type_to_DBR_STS(type) \
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
(type) + (dbf_text_dim-2) : -1 )
#define dbf_type_to_DBR_TIME(type) \
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
(type) + 2*(dbf_text_dim-2) : -1 )
#define dbf_type_to_DBR_GR(type) \
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
(type) + 3*(dbf_text_dim-2) : -1 )
#define dbf_type_to_DBR_CTRL(type) \
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
(type) + 4*(dbf_text_dim-2) : -1 )
epicsShareExtern const char *dbf_text[LAST_TYPE+3];
epicsShareExtern const short dbf_text_dim;
epicsShareExtern const char *dbf_text_invalid;
epicsShareExtern const char *dbr_text[LAST_BUFFER_TYPE+1];
epicsShareExtern const short dbr_text_dim;
epicsShareExtern const char *dbr_text_invalid;
#endif /*db_accessHFORdb_accessC*/
#ifdef __cplusplus
}
#endif
#endif /* INCLdb_accessh */

View File

@@ -0,0 +1,110 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
//
// L O S A L A M O S
// Los Alamos National Laboratory
// Los Alamos, New Mexico 87545
//
// Copyright, 1986, The Regents of the University of California.
//
// Author: Jeff Hill
//
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#define epicsExportSharedSymbols
#include "disconnectGovernorTimer.h"
#include "udpiiu.h"
#include "nciu.h"
static const double disconnectGovernorPeriod = 10.0; // sec
disconnectGovernorTimer::disconnectGovernorTimer (
disconnectGovernorNotify & iiuIn,
epicsTimerQueue & queueIn,
epicsMutex & mutexIn ) :
mutex ( mutexIn ), timer ( queueIn.createTimer () ),
iiu ( iiuIn )
{
}
disconnectGovernorTimer::~disconnectGovernorTimer ()
{
this->timer.destroy ();
}
void disconnectGovernorTimer:: start ()
{
this->timer.start ( *this, disconnectGovernorPeriod );
}
void disconnectGovernorTimer::shutdown (
epicsGuard < epicsMutex > & cbGuard,
epicsGuard < epicsMutex > & guard )
{
{
epicsGuardRelease < epicsMutex > unguard ( guard );
{
epicsGuardRelease < epicsMutex > cbUnguard ( cbGuard );
this->timer.cancel ();
}
}
while ( nciu * pChan = this->chanList.get () ) {
pChan->channelNode::listMember =
channelNode::cs_none;
pChan->serviceShutdownNotify ( cbGuard, guard );
}
}
epicsTimerNotify::expireStatus disconnectGovernorTimer::expire (
const epicsTime & /* currentTime */ )
{
epicsGuard < epicsMutex > guard ( this->mutex );
while ( nciu * pChan = chanList.get () ) {
pChan->channelNode::listMember =
channelNode::cs_none;
this->iiu.govExpireNotify ( guard, *pChan );
}
return expireStatus ( restart, disconnectGovernorPeriod );
}
void disconnectGovernorTimer::show ( unsigned level ) const
{
epicsGuard < epicsMutex > guard ( this->mutex );
::printf ( "disconnect governor timer: with %u channels pending\n",
this->chanList.count () );
if ( level > 0u ) {
tsDLIterConst < nciu > pChan = this->chanList.firstIter ();
while ( pChan.valid () ) {
pChan->show ( level - 1u );
pChan++;
}
}
}
void disconnectGovernorTimer::installChan (
epicsGuard < epicsMutex > & guard, nciu & chan )
{
guard.assertIdenticalMutex ( this->mutex );
this->chanList.add ( chan );
chan.channelNode::listMember = channelNode::cs_disconnGov;
}
void disconnectGovernorTimer::uninstallChan (
epicsGuard < epicsMutex > & guard, nciu & chan )
{
guard.assertIdenticalMutex ( this->mutex );
this->chanList.remove ( chan );
chan.channelNode::listMember = channelNode::cs_none;
}
disconnectGovernorNotify::~disconnectGovernorNotify () {}

View File

@@ -0,0 +1,77 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
//
//
// L O S A L A M O S
// Los Alamos National Laboratory
// Los Alamos, New Mexico 87545
//
// Copyright, 1986, The Regents of the University of California.
//
//
// Author Jeffrey O. Hill
// johill@lanl.gov
// 505 665 1831
//
#ifndef disconnectGovernorTimerh
#define disconnectGovernorTimerh
#ifdef epicsExportSharedSymbols
# define searchTimerh_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "epicsMutex.h"
#include "epicsGuard.h"
#include "epicsTimer.h"
#ifdef searchTimerh_epicsExportSharedSymbols
# define epicsExportSharedSymbols
# include "shareLib.h"
#endif
#include "caProto.h"
#include "netiiu.h"
class disconnectGovernorNotify {
public:
virtual ~disconnectGovernorNotify () = 0;
virtual void govExpireNotify (
epicsGuard < epicsMutex > &, nciu & ) = 0;
};
class disconnectGovernorTimer : private epicsTimerNotify {
public:
disconnectGovernorTimer (
class disconnectGovernorNotify &, epicsTimerQueue &, epicsMutex & );
virtual ~disconnectGovernorTimer ();
void start ();
void shutdown (
epicsGuard < epicsMutex > & cbGuard,
epicsGuard < epicsMutex > & guard );
void installChan (
epicsGuard < epicsMutex > &, nciu & );
void uninstallChan (
epicsGuard < epicsMutex > &, nciu & );
void show ( unsigned level ) const;
private:
tsDLList < nciu > chanList;
epicsMutex & mutex;
epicsTimer & timer;
class disconnectGovernorNotify & iiu;
epicsTimerNotify::expireStatus expire ( const epicsTime & currentTime );
disconnectGovernorTimer ( const disconnectGovernorTimer & );
disconnectGovernorTimer & operator = ( const disconnectGovernorTimer & );
};
#endif // ifdef disconnectGovernorTimerh

95
src/client/evtime.c Normal file
View File

@@ -0,0 +1,95 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stdio.h>
#include "dbDefs.h"
#include "epicsTime.h"
#include "cadef.h"
void event_handler (struct event_handler_args args);
int evtime (char *pname);
static unsigned iteration_count;
static epicsUInt32 last_time;
#ifndef iocCore
int main(int argc, char **argv)
{
char *pname;
if(argc == 2){
pname = argv[1];
evtime(pname);
}
else{
printf("usage: %s <channel name>", argv[0]);
}
return(0);
}
#endif
/*
* evtime()
*/
int evtime(char *pname)
{
chid chan;
int status;
status = ca_search(pname, &chan);
SEVCHK(status, NULL);
status = ca_pend_io(10.0);
if(status != ECA_NORMAL){
printf("%s not found\n", pname);
return 0;
}
status = ca_add_event(
DBR_FLOAT,
chan,
event_handler,
NULL,
NULL);
SEVCHK(status, __FILE__);
status = ca_pend_event(0.0);
SEVCHK(status, NULL);
}
/*
* event_handler()
*
*/
void event_handler(struct event_handler_args args)
{
epicsUInt32 current_time;
# define COUNT 0x8000
double interval;
double delay;
epicsTimeStamp ts;
if(iteration_count%COUNT == 0){
epicsTimeGetCurrent(&ts);
current_time = ts.secPastEpoch;
if(last_time != 0){
interval = current_time - last_time;
delay = interval/COUNT;
printf("Delay = %f sec per event\n",
delay);
}
last_time = current_time;
}
iteration_count++;
}

View File

@@ -0,0 +1,38 @@
Potential upgrades to Channel Access
o generalized access to abstract data
o use multicast for broadcasting and ax the repeater
o improve client API
o improve security
o name service (wildcard queries)
o PV name prefix (for all PVs)
o client access to process passive and for maximize severity
o detect name conflicts at boot time
o multi priority connections (quality of service)
o reduce protocol overhead
o compressed protocol
o If there is a beacon anomaly then this indicates that
the server is _not_ available. Perhaps we should only
reset the search timer interval when we see a beacon
anomaly transition into a sure steady beacon.
o make certain that a monitor callback canceling itself
does not deadlock.
o the free list library does not now cause exceptions to
occur (it uses new ( nothrow )), and therefore we should
change the new handlers to be nothrow also if this is
the design goal.
o test the library when an IOC is running low on memory.
o The new CA interface should be multi-threaded by default.
We should continue to support a single-threaded interface,
but this would should be restricted so that it always
runs with preemptive callback disable and no threads
may join in. Alternatively, the new CA interface could
be 100% preemptive multi-threaded and the old interface
could be layered on this.

104
src/client/getCallback.cpp Normal file
View File

@@ -0,0 +1,104 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#include <string>
#include <stdexcept>
#include "errlog.h"
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "oldAccess.h"
getCallback::getCallback ( oldChannelNotify & chanIn,
caEventCallBackFunc *pFuncIn, void *pPrivateIn ) :
chan ( chanIn ), pFunc ( pFuncIn ), pPrivate ( pPrivateIn )
{
}
getCallback::~getCallback ()
{
}
void getCallback::completion (
epicsGuard < epicsMutex > & guard,
unsigned type, arrayElementCount count, const void *pData )
{
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = & this->chan;
args.type = type;
args.count = count;
args.status = ECA_NORMAL;
args.dbr = pData;
caEventCallBackFunc * pFuncTmp = this->pFunc;
// fetch client context and destroy prior to releasing
// the lock and calling cb in case they destroy channel there
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
if ( pFuncTmp ) {
epicsGuardRelease < epicsMutex > unguard ( guard );
pFuncTmp ( args );
}
}
void getCallback::exception (
epicsGuard < epicsMutex > & guard,
int status, const char * /* pContext */,
unsigned type, arrayElementCount count )
{
if ( status != ECA_CHANDESTROY ) {
struct event_handler_args args;
args.usr = this->pPrivate;
args.chid = & this->chan;
args.type = type;
args.count = count;
args.status = status;
args.dbr = 0;
caEventCallBackFunc * pFuncTmp = this->pFunc;
// fetch client context and destroy prior to releasing
// the lock and calling cb in case they destroy channel there
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
{
epicsGuardRelease < epicsMutex > unguard ( guard );
( *pFuncTmp ) ( args );
}
}
else {
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
}
}
void getCallback::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
// placement operator delete is defined? I smell a ms rat
// because if I declare placement new and delete, but
// comment out the placement delete definition there are
// no undefined symbols.
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
__FILE__, __LINE__ );
}

118
src/client/getCopy.cpp Normal file
View File

@@ -0,0 +1,118 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#include <string>
#include <stdexcept>
#include "errlog.h"
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#define epicsExportSharedSymbols
#include "iocinf.h"
#include "oldAccess.h"
#include "cac.h"
getCopy::getCopy (
epicsGuard < epicsMutex > & guard, ca_client_context & cacCtxIn,
oldChannelNotify & chanIn, unsigned typeIn,
arrayElementCount countIn, void * pValueIn ) :
count ( countIn ), cacCtx ( cacCtxIn ), chan ( chanIn ), pValue ( pValueIn ),
ioSeqNo ( 0 ), type ( typeIn )
{
this->ioSeqNo = cacCtxIn.sequenceNumberOfOutstandingIO ( guard );
cacCtxIn.incrementOutstandingIO ( guard, this->ioSeqNo );
}
getCopy::~getCopy ()
{
}
void getCopy::cancel ()
{
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef () );
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
}
void getCopy::completion (
epicsGuard < epicsMutex > & guard, unsigned typeIn,
arrayElementCount countIn, const void *pDataIn )
{
if ( this->type == typeIn ) {
unsigned size = dbr_size_n ( typeIn, countIn );
memcpy ( this->pValue, pDataIn, size );
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
this->cacCtx.destroyGetCopy ( guard, *this );
// this object destroyed by preceding function call
}
else {
this->exception ( guard, ECA_INTERNAL,
"bad data type match in get copy back response",
typeIn, countIn);
// this object destroyed by preceding function call
}
}
void getCopy::exception (
epicsGuard < epicsMutex > & guard,
int status, const char *pContext,
unsigned /* typeIn */, arrayElementCount /* countIn */ )
{
oldChannelNotify & chanTmp ( this->chan );
unsigned typeTmp ( this->type );
arrayElementCount countTmp ( this->count );
ca_client_context & caClientCtx ( this->cacCtx );
// fetch client context and destroy prior to releasing
// the lock and calling cb in case they destroy channel there
this->cacCtx.destroyGetCopy ( guard, *this );
if ( status != ECA_CHANDESTROY ) {
caClientCtx.exception ( guard, status, pContext,
__FILE__, __LINE__, chanTmp, typeTmp,
countTmp, CA_OP_GET );
}
}
void getCopy::show ( unsigned level ) const
{
int tmpType = static_cast <int> ( this->type );
::printf ( "read copy IO at %p, type %s, element count %lu\n",
static_cast <const void *> ( this ), dbf_type_to_text ( tmpType ), this->count );
if ( level > 0u ) {
::printf ( "\tIO sequence number %u, user's storage %p\n",
this->ioSeqNo, static_cast <const void *> ( this->pValue ) );
}
}
void getCopy::operator delete ( void * )
{
// Visual C++ .net appears to require operator delete if
// placement operator delete is defined? I smell a ms rat
// because if I declare placement new and delete, but
// comment out the placement delete definition there are
// no undefined symbols.
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
__FILE__, __LINE__ );
}

View File

@@ -0,0 +1,92 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
*/
#include <algorithm>
#include <cstring>
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include "hostNameCache.h"
#include "epicsGuard.h"
hostNameCache::hostNameCache (
const osiSockAddr & addr, ipAddrToAsciiEngine & engine ) :
dnsTransaction ( engine.createTransaction() ), nameLength ( 0 )
{
sockAddrToDottedIP ( &addr.sa, hostNameBuf, sizeof ( hostNameBuf ) );
hostNameBuf[ sizeof ( hostNameBuf ) - 1 ] = '\0';
nameLength = strlen ( hostNameBuf );
this->dnsTransaction.ipAddrToAscii ( addr, *this );
}
void hostNameCache::destroy ()
{
delete this;
}
hostNameCache::~hostNameCache ()
{
this->dnsTransaction.release ();
}
void hostNameCache::transactionComplete ( const char * pHostNameIn )
{
epicsGuard < epicsMutex > guard ( this->mutex );
// a few legacy clients have a direct pointer to this buffer so we
// set the entrire string to nill terminators before we start copying
// in the name (this reduces the chance that another thread will see
// garbage characters).
size_t newNameLen = strlen ( pHostNameIn );
if ( newNameLen > sizeof ( this->hostNameBuf ) - 1u ) {
newNameLen = sizeof ( this->hostNameBuf ) - 1u;
}
strncpy ( this->hostNameBuf, "", sizeof ( this->hostNameBuf ) );
strncpy ( this->hostNameBuf, pHostNameIn, sizeof ( this->hostNameBuf ) - 1 );
this->nameLength = newNameLen;
}
unsigned hostNameCache::getName (
char * pBuf, unsigned bufSize ) const
{
if ( bufSize == 0u ) {
return 0u;
}
epicsGuard < epicsMutex > guard ( this->mutex );
if ( this->nameLength > 0u ) {
if ( this->nameLength < bufSize ) {
strcpy ( pBuf, this->hostNameBuf );
return this->nameLength;
}
else {
unsigned reducedSize = bufSize - 1u;
strncpy ( pBuf, this->hostNameBuf, reducedSize );
pBuf [ reducedSize ] = '\0';
return reducedSize;
}
}
else {
osiSockAddr tmpAddr = this->dnsTransaction.address ();
return sockAddrToDottedIP ( &tmpAddr.sa, pBuf, bufSize );
}
}

View File

@@ -0,0 +1,61 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef hostNameCacheh
#define hostNameCacheh
#ifdef epicsExportSharedSymbols
# define hostNameCache_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "ipAddrToAsciiAsynchronous.h"
#include "epicsMutex.h"
#ifdef hostNameCache_epicsExportSharedSymbols
# define epicsExportSharedSymbols
#endif
class hostNameCache : public ipAddrToAsciiCallBack {
public:
hostNameCache ( const osiSockAddr & addr, ipAddrToAsciiEngine & engine );
~hostNameCache ();
void destroy ();
void transactionComplete ( const char * pHostName );
unsigned getName ( char *pBuf, unsigned bufLength ) const;
const char * pointer () const;
private:
char hostNameBuf [128];
mutable epicsMutex mutex;
ipAddrToAsciiTransaction & dnsTransaction;
unsigned nameLength;
};
inline const char * hostNameCache::pointer () const
{
return this->hostNameBuf;
}
#endif // #ifndef hostNameCacheh

72
src/client/inetAddrID.h Normal file
View File

@@ -0,0 +1,72 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#ifndef inetAddrIDh
#define inetAddrIDh
#include "osiSock.h"
#include "resourceLib.h"
class inetAddrID {
public:
inetAddrID ( const struct sockaddr_in & addrIn );
bool operator == ( const inetAddrID & ) const;
resTableIndex hash () const;
void name ( char *pBuf, unsigned bufSize ) const;
private:
struct sockaddr_in addr;
};
inline inetAddrID::inetAddrID ( const struct sockaddr_in & addrIn ) :
addr ( addrIn )
{
}
inline bool inetAddrID::operator == ( const inetAddrID &rhs ) const
{
if ( this->addr.sin_addr.s_addr == rhs.addr.sin_addr.s_addr ) {
if ( this->addr.sin_port == rhs.addr.sin_port ) {
return true;
}
}
return false;
}
inline resTableIndex inetAddrID::hash () const
{
const unsigned inetAddrMinIndexBitWidth = 8u;
const unsigned inetAddrMaxIndexBitWidth = 32u;
unsigned index;
index = this->addr.sin_addr.s_addr;
index ^= this->addr.sin_port;
index ^= this->addr.sin_port >> 8u;
return integerHash ( inetAddrMinIndexBitWidth,
inetAddrMaxIndexBitWidth, index );
}
inline void inetAddrID::name ( char *pBuf, unsigned bufSize ) const
{
ipAddrToDottedIP ( &this->addr, pBuf, bufSize );
}
#endif // ifdef inetAddrID

265
src/client/iocinf.cpp Normal file
View File

@@ -0,0 +1,265 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include "envDefs.h"
#include "epicsAssert.h"
#include "epicsStdioRedirect.h"
#include "errlog.h"
#include "osiWireFormat.h"
#define epicsExportSharedSymbols
#include "addrList.h"
#undef epicsExportSharedSymbols
#include "iocinf.h"
/*
* getToken()
*/
static char *getToken ( const char **ppString, char *pBuf, unsigned bufSIze )
{
bool tokenFound = false;
const char *pToken;
unsigned i;
pToken = *ppString;
while ( isspace (*pToken) && *pToken ){
pToken++;
}
for ( i=0u; i<bufSIze; i++ ) {
if ( isspace (pToken[i]) || pToken[i]=='\0' ) {
pBuf[i] = '\0';
*ppString = &pToken[i];
if ( i != 0 ) {
tokenFound = true;
}
break;
}
pBuf[i] = pToken[i];
}
if ( tokenFound ) {
pBuf[bufSIze-1] = '\0';
return pBuf;
}
return NULL;
}
/*
* addAddrToChannelAccessAddressList ()
*/
extern "C" int epicsShareAPI addAddrToChannelAccessAddressList
( ELLLIST *pList, const ENV_PARAM *pEnv,
unsigned short port, int ignoreNonDefaultPort )
{
osiSockAddrNode *pNewNode;
const char *pStr;
const char *pToken;
struct sockaddr_in addr;
char buf[32u]; /* large enough to hold an IP address */
int status, ret = -1;
pStr = envGetConfigParamPtr (pEnv);
if (!pStr) {
return ret;
}
while ( ( pToken = getToken (&pStr, buf, sizeof (buf) ) ) ) {
status = aToIPAddr ( pToken, port, &addr );
if (status<0) {
fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name);
fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken);
continue;
}
if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) {
continue;
}
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
if (pNewNode==NULL) {
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
break;
}
pNewNode->addr.ia = addr;
/*
* LOCK applied externally
*/
ellAdd (pList, &pNewNode->node);
ret = 0; /* success if anything is added to the list */
}
return ret;
}
/*
* removeDuplicateAddresses ()
*/
extern "C" void epicsShareAPI removeDuplicateAddresses
( ELLLIST *pDestList, ELLLIST *pSrcList, int silent )
{
ELLNODE *pRawNode;
while ( (pRawNode = ellGet ( pSrcList ) ) ) {
STATIC_ASSERT ( offsetof (osiSockAddrNode, node) == 0 );
osiSockAddrNode *pNode = reinterpret_cast <osiSockAddrNode *> ( pRawNode );
osiSockAddrNode *pTmpNode;
if ( pNode->addr.sa.sa_family == AF_INET ) {
pTmpNode = (osiSockAddrNode *) ellFirst (pDestList);
while ( pTmpNode ) {
if (pTmpNode->addr.sa.sa_family == AF_INET) {
if ( pNode->addr.ia.sin_addr.s_addr == pTmpNode->addr.ia.sin_addr.s_addr &&
pNode->addr.ia.sin_port == pTmpNode->addr.ia.sin_port ) {
if ( ! silent ) {
char buf[64];
ipAddrToDottedIP ( &pNode->addr.ia, buf, sizeof (buf) );
fprintf ( stderr,
"Warning: Duplicate EPICS CA Address list entry \"%s\" discarded\n", buf );
}
free (pNode);
pNode = NULL;
break;
}
}
pTmpNode = (osiSockAddrNode *) ellNext (&pTmpNode->node);
}
if (pNode) {
ellAdd (pDestList, &pNode->node);
}
}
else {
ellAdd (pDestList, &pNode->node);
}
}
}
/*
* forcePort ()
*/
static void forcePort ( ELLLIST *pList, unsigned short port )
{
osiSockAddrNode *pNode;
pNode = ( osiSockAddrNode * ) ellFirst ( pList );
while ( pNode ) {
if ( pNode->addr.sa.sa_family == AF_INET ) {
pNode->addr.ia.sin_port = htons ( port );
}
pNode = ( osiSockAddrNode * ) ellNext ( &pNode->node );
}
}
/*
* configureChannelAccessAddressList ()
*/
extern "C" void epicsShareAPI configureChannelAccessAddressList
( ELLLIST *pList, SOCKET sock, unsigned short port )
{
ELLLIST tmpList;
char *pstr;
char yesno[32u];
int yes;
/*
* dont load the list twice
*/
assert ( ellCount (pList) == 0 );
ellInit ( &tmpList );
/*
* Check to see if the user has disabled
* initializing the search b-cast list
* from the interfaces found.
*/
yes = true;
pstr = envGetConfigParam ( &EPICS_CA_AUTO_ADDR_LIST,
sizeof (yesno), yesno );
if ( pstr ) {
if ( strstr ( pstr, "no" ) || strstr ( pstr, "NO" ) ) {
yes = false;
}
}
/*
* LOCK is for piiu->destAddr list
* (lock outside because this is used by the server also)
*/
if (yes) {
ELLLIST bcastList;
osiSockAddr addr;
ellInit ( &bcastList );
addr.ia.sin_family = AF_UNSPEC;
osiSockDiscoverBroadcastAddresses ( &bcastList, sock, &addr );
forcePort ( &bcastList, port );
removeDuplicateAddresses ( &tmpList, &bcastList, 1 );
if ( ellCount ( &tmpList ) == 0 ) {
osiSockAddrNode *pNewNode;
pNewNode = (osiSockAddrNode *) calloc ( 1, sizeof (*pNewNode) );
if ( pNewNode ) {
/*
* if no interfaces found then look for local channels
* with the loop back interface
*/
pNewNode->addr.ia.sin_family = AF_INET;
pNewNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
pNewNode->addr.ia.sin_port = htons ( port );
ellAdd ( &tmpList, &pNewNode->node );
}
else {
errlogPrintf ( "configureChannelAccessAddressList(): no memory available for configuration\n" );
}
}
}
addAddrToChannelAccessAddressList ( &tmpList, &EPICS_CA_ADDR_LIST, port, false );
removeDuplicateAddresses ( pList, &tmpList, 0 );
}
/*
* printChannelAccessAddressList ()
*/
extern "C" void epicsShareAPI printChannelAccessAddressList ( const ELLLIST *pList )
{
osiSockAddrNode *pNode;
::printf ( "Channel Access Address List\n" );
pNode = (osiSockAddrNode *) ellFirst ( pList );
while (pNode) {
char buf[64];
ipAddrToA ( &pNode->addr.ia, buf, sizeof ( buf ) );
::printf ( "%s\n", buf );
pNode = (osiSockAddrNode *) ellNext ( &pNode->node );
}
}

70
src/client/iocinf.h Normal file
View File

@@ -0,0 +1,70 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*/
#ifndef INCiocinfh
#define INCiocinfh
#ifdef DEBUG
# define debugPrintf(argsInParen) ::printf argsInParen
#else
# define debugPrintf(argsInParen)
#endif
#if defined ( CLOCKS_PER_SEC )
# define CAC_SIGNIFICANT_DELAY ( 1.0 / CLOCKS_PER_SEC )
#else
# define CAC_SIGNIFICANT_DELAY (1.0 / 1000000u)
#endif
/*
* these two control the period of connection verifies
* (echo requests) - CA_CONN_VERIFY_PERIOD - and how
* long we will wait for an echo reply before we
* give up and flag the connection for disconnect
* - CA_ECHO_TIMEOUT.
*
* CA_CONN_VERIFY_PERIOD is normally obtained from an
* EPICS environment variable.
*/
static const double CA_ECHO_TIMEOUT = 5.0; /* (sec) disconn no echo reply tmo */
static const double CA_CONN_VERIFY_PERIOD = 30.0; /* (sec) how often to request echo */
/*
* this determines the number of messages received
* without a delay in between before we go into
* monitor flow control
*
* turning this down effects maximum throughput
* because we dont get an optimal number of bytes
* per network frame
*/
static const unsigned contiguousMsgCountWhichTriggersFlowControl = 10u;
/*
* CA internal functions
*/
#define genLocalExcep( CBGUARD, GUARD, CAC, STAT, PCTX ) \
(CAC).exception ( CBGUARD, GUARD, STAT, PCTX, __FILE__, __LINE__ )
#endif // ifdef INCiocinfh

View File

@@ -0,0 +1,66 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#include "osiSock.h"
#include "localHostName.h"
epicsSingleton < localHostName > localHostNameCache;
localHostName::localHostName () :
attachedToSockLib ( osiSockAttach () != 0 ), length ( 0u )
{
const char * pErrStr = "<unknown host>";
int status = -1;
if ( this->attachedToSockLib ) {
status = gethostname (
this->cache, sizeof ( this->cache ) );
}
if ( status ) {
strncpy ( this->cache, pErrStr, sizeof ( this->cache ) );
}
this->cache [ sizeof ( this->cache ) - 1u ] = '\0';
this->length = strlen ( this->cache );
}
localHostName::~localHostName ()
{
if ( this->attachedToSockLib ) {
osiSockRelease ();
}
}
unsigned localHostName::getName (
char * pBuf, unsigned bufLength ) const
{
if ( bufLength ) {
strncpy ( pBuf, this->cache, bufLength );
if ( this->length < bufLength ) {
return this->length;
}
else {
unsigned reducedSize = bufLength - 1;
pBuf [ reducedSize ] = '\0';
return reducedSize;
}
}
return 0u;
}

View File

@@ -0,0 +1,65 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
*
* L O S A L A M O S
* Los Alamos National Laboratory
* Los Alamos, New Mexico 87545
*
* Copyright, 1986, The Regents of the University of California.
*
* Author: Jeff Hill
*/
#ifndef localHostNameh
#define localHostNameh
#include <string.h>
#ifdef epicsExportSharedSymbols
# define localHostNameh_restore_epicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include "epicsSingleton.h"
#ifdef localHostNameh_restore_epicsExportSharedSymbols
# define epicsExportSharedSymbols
#endif
class localHostName {
public:
localHostName ();
~localHostName ();
const char * pointer () const;
unsigned getName ( char * pBuf, unsigned bufLength ) const;
unsigned nameLength () const;
private:
bool attachedToSockLib;
unsigned length;
char cache [128];
};
extern epicsSingleton < localHostName > localHostNameCache;
inline unsigned localHostName::nameLength () const
{
return this->length;
}
inline const char * localHostName::pointer () const
{
return this->cache;
}
#endif // ifndef localHostNameh

Some files were not shown because too many files have changed in this diff Show More