Compare commits
18 Commits
end-of-lib
...
ca-4.13.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
524ceee2c8 | ||
|
|
37e6c875ba | ||
|
|
796279cc0d | ||
|
|
ee10014a62 | ||
|
|
7a6fff0334 | ||
|
|
5dfd1fc0f0 | ||
|
|
c3a6cfcf0d | ||
|
|
9ac5f7fbc1 | ||
|
|
2ebd193681 | ||
|
|
b6c78adaaa | ||
|
|
ed7798ba08 | ||
|
|
abb8136817 | ||
|
|
33f503722e | ||
|
|
79739f3eec | ||
|
|
7458569f10 | ||
|
|
701309fc4a | ||
|
|
765b53e3fd | ||
|
|
c55fb421ce |
@@ -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`
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
11
Makefile
11
Makefile
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
4
configure/CONFIG_CA_VERSION
Normal file
4
configure/CONFIG_CA_VERSION
Normal file
@@ -0,0 +1,4 @@
|
||||
EPICS_CA_MAJOR_VERSION = 4
|
||||
EPICS_CA_MINOR_VERSION = 13
|
||||
EPICS_CA_MAINTENANCE_VERSION = 1
|
||||
EPICS_CA_DEVELOPMENT_FLAG = 0
|
||||
@@ -1,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))
|
||||
@@ -1,4 +0,0 @@
|
||||
EPICS_LIBCOM_MAJOR_VERSION = 3
|
||||
EPICS_LIBCOM_MINOR_VERSION = 17
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
|
||||
EPICS_LIBCOM_DEVELOPMENT_FLAG = 1
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
79
src/Makefile
79
src/Makefile
@@ -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
|
||||
|
||||
@@ -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
|
||||
21
src/as/RULES
21
src/as/RULES
@@ -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
|
||||
244
src/as/asLib.h
244
src/as/asLib.h
@@ -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*/
|
||||
230
src/as/asLib.y
230
src/as/asLib.y
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
%%
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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*/
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
308
src/client/CASG.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Jeffrey O. Hill
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "syncGroup.h"
|
||||
#include "oldAccess.h"
|
||||
#include "cac.h"
|
||||
#include "sgAutoPtr.h"
|
||||
|
||||
CASG::CASG ( epicsGuard < epicsMutex > & guard, ca_client_context & cacIn ) :
|
||||
client ( cacIn ), magic ( CASG_MAGIC )
|
||||
{
|
||||
client.installCASG ( guard, *this );
|
||||
}
|
||||
|
||||
CASG::~CASG ()
|
||||
{
|
||||
}
|
||||
|
||||
void CASG::destructor (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
|
||||
if ( this->verify ( guard ) ) {
|
||||
this->reset ( cbGuard, guard );
|
||||
this->client.uninstallCASG ( guard, *this );
|
||||
this->magic = 0;
|
||||
}
|
||||
else {
|
||||
this->printFormated ( "cac: attempt to destroy invalid sync group ignored\n" );
|
||||
}
|
||||
this->~CASG ();
|
||||
}
|
||||
|
||||
bool CASG::verify ( epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return ( this->magic == CASG_MAGIC );
|
||||
}
|
||||
|
||||
/*
|
||||
* CASG::block ()
|
||||
*/
|
||||
int CASG::block (
|
||||
epicsGuard < epicsMutex > * pcbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
double timeout )
|
||||
{
|
||||
epicsTime cur_time;
|
||||
epicsTime beg_time;
|
||||
double delay;
|
||||
double remaining;
|
||||
int status;
|
||||
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
|
||||
// prevent recursion nightmares by disabling blocking
|
||||
// for IO from within a CA callback.
|
||||
if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) {
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
|
||||
if ( timeout < 0.0 ) {
|
||||
return ECA_TIMEOUT;
|
||||
}
|
||||
|
||||
cur_time = epicsTime::getCurrent ();
|
||||
|
||||
this->client.flush ( guard );
|
||||
|
||||
beg_time = cur_time;
|
||||
delay = 0.0;
|
||||
|
||||
while ( 1 ) {
|
||||
if ( this->ioPendingList.count() == 0u ) {
|
||||
status = ECA_NORMAL;
|
||||
break;
|
||||
}
|
||||
|
||||
remaining = timeout - delay;
|
||||
if ( remaining <= CAC_SIGNIFICANT_DELAY ) {
|
||||
/*
|
||||
* Make sure that we take care of
|
||||
* recv backlog at least once
|
||||
*/
|
||||
status = ECA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( pcbGuard ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > uncbGuard ( *pcbGuard );
|
||||
this->sem.wait ( remaining );
|
||||
}
|
||||
}
|
||||
else {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
this->sem.wait ( remaining );
|
||||
}
|
||||
|
||||
/*
|
||||
* force a time update
|
||||
*/
|
||||
cur_time = epicsTime::getCurrent ();
|
||||
|
||||
delay = cur_time - beg_time;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void CASG::reset (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->destroyCompletedIO ( cbGuard, guard );
|
||||
this->destroyPendingIO ( cbGuard, guard );
|
||||
}
|
||||
|
||||
// lock must be applied
|
||||
void CASG::destroyCompletedIO (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
syncGroupNotify * pNotify;
|
||||
while ( ( pNotify = this->ioCompletedList.get () ) ) {
|
||||
pNotify->destroy ( cbGuard, guard );
|
||||
}
|
||||
}
|
||||
|
||||
void CASG::destroyPendingIO (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
while ( syncGroupNotify * pNotify = this->ioPendingList.first () ) {
|
||||
pNotify->cancel ( cbGuard, guard );
|
||||
// cancel must release the guard while
|
||||
// canceling put callbacks so we
|
||||
// must double check list membership
|
||||
if ( pNotify->ioPending ( guard ) ) {
|
||||
this->ioPendingList.remove ( *pNotify );
|
||||
}
|
||||
else {
|
||||
this->ioCompletedList.remove ( *pNotify );
|
||||
}
|
||||
pNotify->destroy ( cbGuard, guard );
|
||||
}
|
||||
}
|
||||
|
||||
void CASG::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->client.mutexRef () );
|
||||
this->show ( guard, level );
|
||||
}
|
||||
|
||||
void CASG::show (
|
||||
epicsGuard < epicsMutex > & guard, unsigned level ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
::printf ( "Sync Group: id=%u, magic=%u, opPend=%u\n",
|
||||
this->getId (), this->magic, this->ioPendingList.count () );
|
||||
if ( level ) {
|
||||
::printf ( "\tPending" );
|
||||
tsDLIterConst < syncGroupNotify > notifyPending =
|
||||
this->ioPendingList.firstIter ();
|
||||
while ( notifyPending.valid () ) {
|
||||
notifyPending->show ( guard, level - 1u );
|
||||
notifyPending++;
|
||||
}
|
||||
::printf ( "\tCompleted" );
|
||||
tsDLIterConst < syncGroupNotify > notifyCompleted =
|
||||
this->ioCompletedList.firstIter ();
|
||||
while ( notifyCompleted.valid () ) {
|
||||
notifyCompleted->show ( guard, level - 1u );
|
||||
notifyCompleted++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CASG::ioComplete (
|
||||
CallbackGuard & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->destroyCompletedIO ( cbGuard, guard );
|
||||
return this->ioPendingList.count () == 0u;
|
||||
}
|
||||
|
||||
void CASG::put ( epicsGuard < epicsMutex > & guard, chid pChan,
|
||||
unsigned type, arrayElementCount count, const void * pValue )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
sgAutoPtr < syncGroupWriteNotify > pNotify ( guard, *this );
|
||||
pNotify = syncGroupWriteNotify::factory (
|
||||
this->freeListWriteOP, *this, & CASG :: recycleWriteNotifyIO, pChan );
|
||||
pNotify->begin ( guard, type, count, pValue );
|
||||
pNotify.release ();
|
||||
}
|
||||
|
||||
void CASG::get ( epicsGuard < epicsMutex > & guard, chid pChan,
|
||||
unsigned type, arrayElementCount count, void *pValue )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
sgAutoPtr < syncGroupReadNotify > pNotify ( guard, *this );
|
||||
pNotify = syncGroupReadNotify::factory (
|
||||
this->freeListReadOP, *this, & CASG :: recycleReadNotifyIO, pChan, pValue );
|
||||
pNotify->begin ( guard, type, count );
|
||||
pNotify.release ();
|
||||
}
|
||||
|
||||
void CASG::completionNotify (
|
||||
epicsGuard < epicsMutex > & guard, syncGroupNotify & notify )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->ioPendingList.remove ( notify );
|
||||
this->ioCompletedList.add ( notify );
|
||||
if ( this->ioPendingList.count () == 0u ) {
|
||||
this->sem.signal ();
|
||||
}
|
||||
}
|
||||
|
||||
void CASG :: recycleReadNotifyIO ( epicsGuard < epicsMutex > & guard,
|
||||
syncGroupReadNotify & io )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->freeListReadOP.release ( & io );
|
||||
}
|
||||
|
||||
void CASG :: recycleWriteNotifyIO ( epicsGuard < epicsMutex > & guard,
|
||||
syncGroupWriteNotify & io )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
this->freeListWriteOP.release ( & io );
|
||||
}
|
||||
|
||||
int CASG :: printFormated ( const char *pformat, ... )
|
||||
{
|
||||
va_list theArgs;
|
||||
int status;
|
||||
|
||||
va_start ( theArgs, pformat );
|
||||
|
||||
status = this->client.varArgsPrintFormated ( pformat, theArgs );
|
||||
|
||||
va_end ( theArgs );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void CASG::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
this->client.exception (
|
||||
guard, status, pContext, pFileName, lineNo );
|
||||
}
|
||||
}
|
||||
|
||||
void CASG::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo, oldChannelNotify & chan,
|
||||
unsigned type, arrayElementCount count, unsigned op )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->client.mutexRef() );
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
this->client.exception (
|
||||
guard, status, pContext, pFileName,
|
||||
lineNo, chan, type, count, op );
|
||||
}
|
||||
}
|
||||
|
||||
void CASG::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
4489
src/client/CAref.html
Normal file
4489
src/client/CAref.html
Normal file
File diff suppressed because it is too large
Load Diff
136
src/client/Makefile
Normal file
136
src/client/Makefile
Normal file
@@ -0,0 +1,136 @@
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# Copyright (c) 2002 The Regents of the University of California, as
|
||||
# Operator of Los Alamos National Laboratory.
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
TOP = ../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
HTMLS += CAref.html
|
||||
|
||||
#
|
||||
# includes to install from this subproject
|
||||
#
|
||||
INC += cadef.h
|
||||
INC += caerr.h
|
||||
INC += caeventmask.h
|
||||
INC += caProto.h
|
||||
INC += db_access.h
|
||||
INC += addrList.h
|
||||
INC += cacIO.h
|
||||
INC += caDiagnostics.h
|
||||
INC += net_convert.h
|
||||
INC += caVersion.h
|
||||
INC += caVersionNum.h
|
||||
|
||||
LIBSRCS += cac.cpp
|
||||
LIBSRCS += cacChannel.cpp
|
||||
LIBSRCS += cacChannelNotify.cpp
|
||||
LIBSRCS += cacContextNotify.cpp
|
||||
LIBSRCS += cacReadNotify.cpp
|
||||
LIBSRCS += cacWriteNotify.cpp
|
||||
LIBSRCS += cacStateNotify.cpp
|
||||
LIBSRCS += access.cpp
|
||||
LIBSRCS += iocinf.cpp
|
||||
LIBSRCS += convert.cpp
|
||||
LIBSRCS += test_event.cpp
|
||||
LIBSRCS += repeater.cpp
|
||||
LIBSRCS += searchTimer.cpp
|
||||
LIBSRCS += disconnectGovernorTimer.cpp
|
||||
LIBSRCS += repeaterSubscribeTimer.cpp
|
||||
LIBSRCS += baseNMIU.cpp
|
||||
LIBSRCS += nciu.cpp
|
||||
LIBSRCS += netiiu.cpp
|
||||
LIBSRCS += udpiiu.cpp
|
||||
LIBSRCS += tcpiiu.cpp
|
||||
LIBSRCS += noopiiu.cpp
|
||||
LIBSRCS += netReadNotifyIO.cpp
|
||||
LIBSRCS += netWriteNotifyIO.cpp
|
||||
LIBSRCS += netSubscription.cpp
|
||||
LIBSRCS += tcpSendWatchdog.cpp
|
||||
LIBSRCS += tcpRecvWatchdog.cpp
|
||||
LIBSRCS += bhe.cpp
|
||||
LIBSRCS += ca_client_context.cpp
|
||||
LIBSRCS += oldChannelNotify.cpp
|
||||
LIBSRCS += oldSubscription.cpp
|
||||
LIBSRCS += getCallback.cpp
|
||||
LIBSRCS += getCopy.cpp
|
||||
LIBSRCS += putCallback.cpp
|
||||
LIBSRCS += syncgrp.cpp
|
||||
LIBSRCS += CASG.cpp
|
||||
LIBSRCS += syncGroupNotify.cpp
|
||||
LIBSRCS += syncGroupReadNotify.cpp
|
||||
LIBSRCS += syncGroupWriteNotify.cpp
|
||||
LIBSRCS += localHostName.cpp
|
||||
LIBSRCS += comQueRecv.cpp
|
||||
LIBSRCS += comQueSend.cpp
|
||||
LIBSRCS += comBuf.cpp
|
||||
LIBSRCS += hostNameCache.cpp
|
||||
LIBSRCS += msgForMultiplyDefinedPV.cpp
|
||||
|
||||
LIBRARY=ca
|
||||
|
||||
ca_RCS = ca.rc
|
||||
|
||||
ca_LIBS = Com
|
||||
|
||||
ca_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
# libs needed for PROD and TESTPRODUCT
|
||||
PROD_LIBS = ca Com
|
||||
# needed when its an object library build
|
||||
PROD_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
PROD_DEFAULT += caRepeater catime acctst caConnTest casw caEventRate
|
||||
PROD_vxWorks = -nil-
|
||||
PROD_RTEMS = -nil-
|
||||
PROD_iOS = -nil-
|
||||
|
||||
OBJS_vxWorks = catime acctst caConnTest casw caEventRate acctstRegister
|
||||
|
||||
caRepeater_SRCS = caRepeater.cpp
|
||||
catime_SRCS = catimeMain.c catime.c
|
||||
acctst_SRCS = acctstMain.c acctst.c
|
||||
caEventRate_SRCS = caEventRateMain.cpp caEventRate.cpp
|
||||
casw_SRCS = casw.cpp
|
||||
caConnTest_SRCS = caConnTestMain.cpp caConnTest.cpp
|
||||
|
||||
casw_SYS_LIBS_solaris = socket
|
||||
|
||||
SCRIPTS_HOST = S99caRepeater
|
||||
SCRIPTS_Linux = caRepeater.service
|
||||
|
||||
EXPAND += S99caRepeater@
|
||||
EXPAND += caRepeater.service@
|
||||
EXPAND_VARS = INSTALL_BIN=$(abspath $(INSTALL_BIN))
|
||||
|
||||
SRC_DIRS += $(TOP)/src/client/test
|
||||
PROD_HOST += ca_test
|
||||
ca_test_SRCS = ca_test_main.c ca_test.c
|
||||
ca_test_LIBS = ca Com
|
||||
ca_test_SYS_LIBS_WIN32 = ws2_32 advapi32 user32
|
||||
|
||||
OBJS_vxWorks += ca_test
|
||||
|
||||
EXPANDVARS += EPICS_CA_MAJOR_VERSION
|
||||
EXPANDVARS += EPICS_CA_MINOR_VERSION
|
||||
EXPANDVARS += EPICS_CA_MAINTENANCE_VERSION
|
||||
EXPANDVARS += EPICS_CA_DEVELOPMENT_FLAG
|
||||
|
||||
EXPANDFLAGS += $(foreach var,$(EXPANDVARS),-D$(var)="$(strip $($(var)))")
|
||||
|
||||
# shared library ABI version.
|
||||
SHRLIB_VERSION = 4.13.1
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
||||
# Can't use EXPAND as generated headers must appear
|
||||
# in O.Common, but EXPAND emits rules for O.$(T_A)
|
||||
../O.Common/caVersionNum.h: ../caVersionNum.h@
|
||||
$(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@
|
||||
28
src/client/S99caRepeater@
Normal file
28
src/client/S99caRepeater@
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# System-V init script for the EPICS CA Repeater.
|
||||
#
|
||||
|
||||
INSTALL_BIN=@INSTALL_BIN@
|
||||
|
||||
# To change the default values for the EPICS environment parameters,
|
||||
# uncomment and modify the relevant lines below. These are the only
|
||||
# EPICS environment variables that the CA Repeater makes use of.
|
||||
|
||||
# EPICS_CA_REPEATER_PORT="5065" export EPICS_CA_REPEATER_PORT
|
||||
|
||||
if [ $1 = "start" ]; then
|
||||
if [ -x $INSTALL_BIN/caRepeater ]; then
|
||||
echo "Starting EPICS CA Repeater "
|
||||
$INSTALL_BIN/caRepeater &
|
||||
fi
|
||||
else
|
||||
if [ $1 = "stop" ]; then
|
||||
pid=`ps -e | sed -ne '/caRepeat/s/^ *\([1-9][0-9]*\).*$/\1/p'`
|
||||
if [ "${pid}" != "" ]; then
|
||||
echo "Stopping EPICS CA Repeater "
|
||||
kill ${pid}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
39
src/client/SearchDest.h
Normal file
39
src/client/SearchDest.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef SearchDest_h
|
||||
#define SearchDest_h
|
||||
|
||||
#include <osiSock.h>
|
||||
#include <epicsTime.h>
|
||||
#include <tsDLList.h>
|
||||
#include "caProto.h"
|
||||
|
||||
class channelNode;
|
||||
class epicsMutex;
|
||||
template < class T > class epicsGuard;
|
||||
|
||||
struct SearchDest :
|
||||
public tsDLNode < SearchDest > {
|
||||
virtual ~SearchDest () {};
|
||||
struct Callback {
|
||||
virtual ~Callback () {};
|
||||
virtual void notify (
|
||||
const caHdr & msg, const void * pPayload,
|
||||
const osiSockAddr & addr, const epicsTime & ) = 0;
|
||||
virtual void show (
|
||||
epicsGuard < epicsMutex > &, unsigned level ) const = 0;
|
||||
};
|
||||
virtual void searchRequest ( epicsGuard < epicsMutex > &,
|
||||
const char * pbuf, size_t len ) = 0;
|
||||
virtual void show ( epicsGuard < epicsMutex > &, unsigned level ) const = 0;
|
||||
};
|
||||
|
||||
#endif // SearchDest_h
|
||||
1118
src/client/access.cpp
Normal file
1118
src/client/access.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3555
src/client/acctst.c
Normal file
3555
src/client/acctst.c
Normal file
File diff suppressed because it is too large
Load Diff
70
src/client/acctstMain.c
Normal file
70
src/client/acctstMain.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cadef.h"
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
int main ( int argc, char **argv )
|
||||
{
|
||||
unsigned progressLoggingLevel;
|
||||
unsigned channelCount;
|
||||
unsigned repetitionCount;
|
||||
enum ca_preemptive_callback_select preempt;
|
||||
int aBoolean;
|
||||
|
||||
|
||||
if ( argc < 2 || argc > 6 ) {
|
||||
printf ("usage: %s <PV name> [progress logging level] [channel count] "
|
||||
"[repetition count] [enable preemptive callback]\n",
|
||||
argv[0] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( argc >= 3 ) {
|
||||
progressLoggingLevel = atoi ( argv[2] );
|
||||
}
|
||||
else {
|
||||
progressLoggingLevel = 0;
|
||||
}
|
||||
|
||||
if ( argc >= 4 ) {
|
||||
channelCount = atoi ( argv[3] );
|
||||
}
|
||||
else {
|
||||
channelCount = 20000;
|
||||
}
|
||||
|
||||
if ( argc >= 5 ) {
|
||||
repetitionCount = atoi ( argv[4] );
|
||||
}
|
||||
else {
|
||||
repetitionCount = 1;
|
||||
}
|
||||
|
||||
if ( argc >= 6 ) {
|
||||
aBoolean = atoi ( argv[5] );
|
||||
}
|
||||
else {
|
||||
aBoolean = 0;
|
||||
}
|
||||
if ( aBoolean ) {
|
||||
preempt = ca_enable_preemptive_callback;
|
||||
}
|
||||
else {
|
||||
preempt = ca_disable_preemptive_callback;
|
||||
}
|
||||
|
||||
acctst ( argv[1], progressLoggingLevel, channelCount, repetitionCount, preempt );
|
||||
|
||||
return 0;
|
||||
}
|
||||
69
src/client/acctstRegister.cpp
Normal file
69
src/client/acctstRegister.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* CA client library diagnostics IOC shell registration
|
||||
* Authors:
|
||||
* Jeff Hill
|
||||
*/
|
||||
|
||||
#include <iocsh.h>
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
/* Information needed by iocsh */
|
||||
static const iocshArg acctstArg0 = { "channel name", iocshArgString };
|
||||
static const iocshArg acctstArg1 = { "interest level", iocshArgInt };
|
||||
static const iocshArg acctstArg2 = { "channel count", iocshArgInt };
|
||||
static const iocshArg acctstArg3 = { "repetition count", iocshArgInt };
|
||||
static const iocshArg acctstArg4 = { "preemptive callback select", iocshArgInt };
|
||||
|
||||
static const iocshArg *acctstArgs[] =
|
||||
{
|
||||
&acctstArg0,
|
||||
&acctstArg1,
|
||||
&acctstArg2,
|
||||
&acctstArg3,
|
||||
&acctstArg4
|
||||
};
|
||||
static const iocshFuncDef acctstFuncDef = {"acctst", 5, acctstArgs};
|
||||
|
||||
|
||||
/* Wrapper called by iocsh, selects the argument types that print needs */
|
||||
static void acctstCallFunc(const iocshArgBuf *args) {
|
||||
if ( args[1].ival < 0 ) {
|
||||
printf ( "negative interest level not allowed\n" );
|
||||
return;
|
||||
}
|
||||
if ( args[2].ival < 0 ) {
|
||||
printf ( "negative channel count not allowed\n" );
|
||||
return;
|
||||
}
|
||||
if ( args[3].ival < 0 ) {
|
||||
printf ( "negative repetition count not allowed\n" );
|
||||
return;
|
||||
}
|
||||
acctst (
|
||||
args[0].sval, /* channel name */
|
||||
( unsigned ) args[1].ival, /* interest level */
|
||||
( unsigned ) args[2].ival, /* channel count */
|
||||
( unsigned ) args[3].ival, /* repetition count */
|
||||
( ca_preemptive_callback_select ) args[4].ival ); /* preemptive callback select */
|
||||
}
|
||||
|
||||
struct AutoInit {
|
||||
AutoInit ();
|
||||
};
|
||||
|
||||
AutoInit :: AutoInit ()
|
||||
{
|
||||
iocshRegister ( &acctstFuncDef, acctstCallFunc );
|
||||
}
|
||||
|
||||
AutoInit autoInit;
|
||||
|
||||
40
src/client/addrList.h
Normal file
40
src/client/addrList.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef addrListh
|
||||
#define addrListh
|
||||
|
||||
#include "shareLib.h"
|
||||
#include "envDefs.h"
|
||||
#include "osiSock.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareFunc void epicsShareAPI configureChannelAccessAddressList
|
||||
( struct ELLLIST *pList, SOCKET sock, unsigned short port );
|
||||
|
||||
epicsShareFunc int epicsShareAPI addAddrToChannelAccessAddressList
|
||||
( struct ELLLIST *pList, const ENV_PARAM *pEnv,
|
||||
unsigned short port, int ignoreNonDefaultPort );
|
||||
|
||||
epicsShareFunc void epicsShareAPI printChannelAccessAddressList
|
||||
( const struct ELLLIST *pList );
|
||||
|
||||
epicsShareFunc void epicsShareAPI removeDuplicateAddresses
|
||||
( struct ELLLIST *pDestList, ELLLIST *pSrcList, int silent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ifndef addrListh */
|
||||
|
||||
104
src/client/autoPtrFreeList.h
Normal file
104
src/client/autoPtrFreeList.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef autoPtrFreeListh
|
||||
#define autoPtrFreeListh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define autoPtrFreeListh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "tsFreeList.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef autoPtrFreeListh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
template < class T, unsigned N = 0x400, class MUTEX = epicsMutex >
|
||||
class autoPtrFreeList {
|
||||
public:
|
||||
autoPtrFreeList ( tsFreeList < T, N, MUTEX > &, T * );
|
||||
~autoPtrFreeList ();
|
||||
T & operator * () const;
|
||||
T * operator -> () const;
|
||||
T * get () const;
|
||||
T * release ();
|
||||
private:
|
||||
T * p;
|
||||
tsFreeList < T, N, MUTEX > & freeList;
|
||||
// not implemented
|
||||
autoPtrFreeList & operator = ( const autoPtrFreeList & );
|
||||
autoPtrFreeList ( const autoPtrFreeList < T, N, MUTEX > & );
|
||||
};
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline autoPtrFreeList < T, N, MUTEX >::autoPtrFreeList (
|
||||
tsFreeList < T, N, MUTEX > & freeListIn, T * pIn ) :
|
||||
p ( pIn ), freeList ( freeListIn ) {}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline autoPtrFreeList < T, N, MUTEX >::~autoPtrFreeList ()
|
||||
{
|
||||
if ( this->p ) {
|
||||
this->p->~T();
|
||||
// its probably a good idea to require that the class has placement delete
|
||||
// by calling it during cleanup if the compiler supports it
|
||||
# if defined ( CXX_PLACEMENT_DELETE )
|
||||
T::operator delete ( this->p, this->freeList );
|
||||
# else
|
||||
this->freeList.release ( this->p );
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline T & autoPtrFreeList < T, N, MUTEX >::operator * () const
|
||||
{
|
||||
return * this->p;
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline T * autoPtrFreeList < T, N, MUTEX >::operator -> () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline T * autoPtrFreeList < T, N, MUTEX >::get () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T, unsigned N, class MUTEX >
|
||||
inline T * autoPtrFreeList < T, N, MUTEX >::release ()
|
||||
{
|
||||
T *pTmp = this->p;
|
||||
this->p = 0;
|
||||
return pTmp;
|
||||
}
|
||||
|
||||
#endif // #ifdef autoPtrFreeListh
|
||||
92
src/client/autoPtrRecycle.h
Normal file
92
src/client/autoPtrRecycle.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef autoPtrRecycleh
|
||||
#define autoPtrRecycleh
|
||||
|
||||
template < class T >
|
||||
class autoPtrRecycle {
|
||||
public:
|
||||
autoPtrRecycle (
|
||||
epicsGuard < epicsMutex > &, chronIntIdResTable < baseNMIU > &,
|
||||
cacRecycle &, T * );
|
||||
~autoPtrRecycle ();
|
||||
T & operator * () const;
|
||||
T * operator -> () const;
|
||||
T * get () const;
|
||||
T * release ();
|
||||
private:
|
||||
T * p;
|
||||
cacRecycle & r;
|
||||
chronIntIdResTable < baseNMIU > & ioTable;
|
||||
epicsGuard < epicsMutex > & guard;
|
||||
// not implemented
|
||||
autoPtrRecycle ( const autoPtrRecycle & );
|
||||
autoPtrRecycle & operator = ( const autoPtrRecycle & );
|
||||
};
|
||||
|
||||
template < class T >
|
||||
inline autoPtrRecycle<T>::autoPtrRecycle (
|
||||
epicsGuard < epicsMutex > & guardIn, chronIntIdResTable < baseNMIU > & tbl,
|
||||
cacRecycle & rIn, T * pIn ) :
|
||||
p ( pIn ), r ( rIn ), ioTable ( tbl ), guard ( guardIn ) {}
|
||||
|
||||
template < class T >
|
||||
inline autoPtrRecycle<T>::~autoPtrRecycle ()
|
||||
{
|
||||
if ( this->p ) {
|
||||
baseNMIU *pb = this->p;
|
||||
this->ioTable.remove ( *pb );
|
||||
pb->destroy ( this->guard, this->r );
|
||||
}
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T & autoPtrRecycle<T>::operator * () const
|
||||
{
|
||||
return * this->p;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * autoPtrRecycle<T>::operator -> () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * autoPtrRecycle<T>::get () const
|
||||
{
|
||||
return this->p;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline T * autoPtrRecycle<T>::release ()
|
||||
{
|
||||
T *pTmp = this->p;
|
||||
this->p = 0;
|
||||
return pTmp;
|
||||
}
|
||||
|
||||
#endif // #ifdef autoPtrRecycleh
|
||||
@@ -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
358
src/client/bhe.cpp
Normal file
@@ -0,0 +1,358 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "virtualCircuit.h"
|
||||
#include "bhe.h"
|
||||
|
||||
/*
|
||||
* set average to -1.0 so that when the next beacon
|
||||
* occurs we can distinguish between:
|
||||
* o new server
|
||||
* o existing server's beacon we are seeing
|
||||
* for the first time shortly after program
|
||||
* start up
|
||||
*
|
||||
* if creating this in response to a search reply
|
||||
* and not in response to a beacon then
|
||||
* we set the beacon time stamp to
|
||||
* zero (so we can correctly compute the period
|
||||
* between the 1st and 2nd beacons)
|
||||
*/
|
||||
bhe::bhe ( epicsMutex & mutexIn, const epicsTime & initialTimeStamp,
|
||||
unsigned initialBeaconNumber, const inetAddrID & addr ) :
|
||||
inetAddrID ( addr ), timeStamp ( initialTimeStamp ), averagePeriod ( - DBL_MAX ),
|
||||
mutex ( mutexIn ), pIIU ( 0 ), lastBeaconNumber ( initialBeaconNumber )
|
||||
{
|
||||
# ifdef DEBUG
|
||||
{
|
||||
char name[64];
|
||||
addr.name ( name, sizeof ( name ) );
|
||||
::printf ( "created beacon entry for %s\n", name );
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
bhe::~bhe ()
|
||||
{
|
||||
}
|
||||
|
||||
void bhe::beaconAnomalyNotify ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->pIIU ) {
|
||||
this->pIIU->beaconAnomalyNotify ( guard );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void bhe::logBeacon ( const char * pDiagnostic,
|
||||
const double & currentPeriod,
|
||||
const epicsTime & currentTime )
|
||||
{
|
||||
if ( this->pIIU ) {
|
||||
char name[64];
|
||||
this->name ( name, sizeof ( name ) );
|
||||
char date[64];
|
||||
currentTime.strftime ( date, sizeof ( date ),
|
||||
"%a %b %d %Y %H:%M:%S.%f");
|
||||
::printf ( "%s cp=%g ap=%g %s %s\n",
|
||||
pDiagnostic, currentPeriod,
|
||||
this->averagePeriod, name, date );
|
||||
}
|
||||
}
|
||||
#else
|
||||
inline void bhe::logBeacon ( const char * /* pDiagnostic */,
|
||||
const double & /* currentPeriod */,
|
||||
const epicsTime & /* currentTime */ )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
void bhe::logBeaconDiscard ( unsigned beaconAdvance,
|
||||
const epicsTime & currentTime )
|
||||
{
|
||||
if ( this->pIIU ) {
|
||||
char name[64];
|
||||
this->name ( name, sizeof ( name ) );
|
||||
char date[64];
|
||||
currentTime.strftime ( date, sizeof ( date ),
|
||||
"%a %b %d %Y %H:%M:%S.%f");
|
||||
::printf ( "bb %u %s %s\n",
|
||||
beaconAdvance, name, date );
|
||||
}
|
||||
}
|
||||
#else
|
||||
void bhe::logBeaconDiscard ( unsigned /* beaconAdvance */,
|
||||
const epicsTime & /* currentTime */ )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* update beacon period
|
||||
*
|
||||
* updates beacon period, and looks for beacon anomalies
|
||||
*/
|
||||
bool bhe::updatePeriod (
|
||||
epicsGuard < epicsMutex > & guard, const epicsTime & programBeginTime,
|
||||
const epicsTime & currentTime, ca_uint32_t beaconNumber,
|
||||
unsigned protocolRevision )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
|
||||
//
|
||||
// this block is enetered if the beacon was created as a side effect of
|
||||
// creating a connection and so we dont yet know the first beacon time
|
||||
// and sequence number
|
||||
//
|
||||
if ( this->timeStamp == epicsTime () ) {
|
||||
if ( CA_V410 ( protocolRevision ) ) {
|
||||
this->lastBeaconNumber = beaconNumber;
|
||||
}
|
||||
|
||||
this->beaconAnomalyNotify ( guard );
|
||||
|
||||
/*
|
||||
* this is the 1st beacon seen - the beacon time stamp
|
||||
* was not initialized during BHE create because
|
||||
* a TCP/IP connection created the beacon.
|
||||
* (nothing to do but set the beacon time stamp and return)
|
||||
*/
|
||||
this->timeStamp = currentTime;
|
||||
|
||||
logBeacon ( "fb", - DBL_MAX, currentTime );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1) detect beacon duplications due to redundant routes
|
||||
// 2) detect lost beacons due to input queue overrun or damage
|
||||
if ( CA_V410 ( protocolRevision ) ) {
|
||||
unsigned beaconSeqAdvance;
|
||||
if ( beaconNumber >= this->lastBeaconNumber ) {
|
||||
beaconSeqAdvance = beaconNumber - this->lastBeaconNumber;
|
||||
}
|
||||
else {
|
||||
beaconSeqAdvance = ( ca_uint32_max - this->lastBeaconNumber ) + beaconNumber;
|
||||
}
|
||||
this->lastBeaconNumber = beaconNumber;
|
||||
|
||||
// throw out sequence numbers just prior to, or the same as, the last one received
|
||||
// (this situation is probably caused by a temporary duplicate route )
|
||||
if ( beaconSeqAdvance == 0 || beaconSeqAdvance > ca_uint32_max - 256 ) {
|
||||
logBeaconDiscard ( beaconSeqAdvance, currentTime );
|
||||
return false;
|
||||
}
|
||||
|
||||
// throw out sequence numbers that jump forward by only a few numbers
|
||||
// (this situation is probably caused by a duplicate route
|
||||
// or a beacon due to input queue overun)
|
||||
if ( beaconSeqAdvance > 1 && beaconSeqAdvance < 4 ) {
|
||||
logBeaconDiscard ( beaconSeqAdvance, currentTime );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// compute the beacon period (if we have seen at least two beacons)
|
||||
bool netChange = false;
|
||||
double currentPeriod = currentTime - this->timeStamp;
|
||||
|
||||
if ( this->averagePeriod < 0.0 ) {
|
||||
double totalRunningTime;
|
||||
|
||||
this->beaconAnomalyNotify ( guard );
|
||||
|
||||
/*
|
||||
* this is the 2nd beacon seen. We cant tell about
|
||||
* the change in period at this point so we just
|
||||
* initialize the average period and return.
|
||||
*/
|
||||
this->averagePeriod = currentPeriod;
|
||||
|
||||
logBeacon ( "fp", currentPeriod, currentTime );
|
||||
|
||||
|
||||
/*
|
||||
* ignore beacons seen for the first time shortly after
|
||||
* init, but do not ignore beacons arriving with a short
|
||||
* period because the IOC was rebooted soon after the
|
||||
* client starts up.
|
||||
*/
|
||||
totalRunningTime = this->timeStamp - programBeginTime;
|
||||
if ( currentPeriod <= totalRunningTime ) {
|
||||
netChange = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
/*
|
||||
* Is this an IOC seen because of a restored
|
||||
* network segment?
|
||||
*
|
||||
* It may be possible to get false triggers here
|
||||
* if the client is busy, but this does not cause
|
||||
* problems because the echo response will tell us
|
||||
* that the server is available
|
||||
*/
|
||||
if ( currentPeriod >= this->averagePeriod * 1.25 ) {
|
||||
|
||||
/*
|
||||
* trigger on any missing beacon
|
||||
* if connected to this server
|
||||
*/
|
||||
this->beaconAnomalyNotify ( guard );
|
||||
|
||||
if ( currentPeriod >= this->averagePeriod * 3.25 ) {
|
||||
/*
|
||||
* trigger on any 3 contiguous missing beacons
|
||||
* if not connected to this server
|
||||
*/
|
||||
netChange = true;
|
||||
}
|
||||
logBeacon ( "bah", currentPeriod, currentTime );
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this an IOC seen because of an IOC reboot
|
||||
* (beacon come at a higher rate just after the
|
||||
* IOC reboots). Lower tolarance here because we
|
||||
* dont have to worry about lost beacons.
|
||||
*
|
||||
* It may be possible to get false triggers here
|
||||
* if the client is busy, but this does not cause
|
||||
* problems because the echo response will tell us
|
||||
* that the server is available
|
||||
*/
|
||||
else if ( currentPeriod <= this->averagePeriod * 0.80 ) {
|
||||
this->beaconAnomalyNotify ( guard );
|
||||
netChange = true;
|
||||
logBeacon ( "bal", currentPeriod, currentTime );
|
||||
}
|
||||
else if ( this->pIIU ) {
|
||||
// update state of health for active virtual circuits
|
||||
// if the beacon looks ok
|
||||
this->pIIU->beaconArrivalNotify ( guard );
|
||||
logBeacon ( "vb", currentPeriod, currentTime );
|
||||
}
|
||||
|
||||
// update a running average period
|
||||
this->averagePeriod = currentPeriod * 0.125 +
|
||||
this->averagePeriod * 0.875;
|
||||
}
|
||||
|
||||
this->timeStamp = currentTime;
|
||||
|
||||
return netChange;
|
||||
}
|
||||
|
||||
void bhe::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->show ( guard, level );
|
||||
}
|
||||
|
||||
void bhe::show ( epicsGuard < epicsMutex > &, unsigned level ) const
|
||||
{
|
||||
char host [64];
|
||||
this->name ( host, sizeof ( host ) );
|
||||
if ( this->averagePeriod == -DBL_MAX ) {
|
||||
::printf ( "CA beacon hash entry for %s <no period estimate>\n",
|
||||
host );
|
||||
}
|
||||
else {
|
||||
::printf ( "CA beacon hash entry for %s with period estimate %f\n",
|
||||
host, this->averagePeriod );
|
||||
}
|
||||
if ( level > 0u ) {
|
||||
char date[64];
|
||||
this->timeStamp.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S");
|
||||
::printf ( "\tbeacon number %u, on %s\n",
|
||||
this->lastBeaconNumber, date );
|
||||
}
|
||||
}
|
||||
|
||||
double bhe::period ( epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->averagePeriod;
|
||||
}
|
||||
|
||||
epicsTime bhe::updateTime ( epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->timeStamp;
|
||||
}
|
||||
|
||||
void bhe::registerIIU (
|
||||
epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->pIIU = & iiu;
|
||||
}
|
||||
|
||||
void bhe::unregisterIIU (
|
||||
epicsGuard < epicsMutex > & guard, tcpiiu & iiu )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->pIIU == & iiu ) {
|
||||
this->pIIU = 0;
|
||||
this->timeStamp = epicsTime();
|
||||
this->averagePeriod = - DBL_MAX;
|
||||
logBeacon ( "ui", this->averagePeriod, epicsTime::getCurrent () );
|
||||
}
|
||||
}
|
||||
|
||||
void bhe::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
void * bheFreeStore::allocate ( size_t size )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
void bheFreeStore::release ( void * pCadaver )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
|
||||
bheMemoryManager::~bheMemoryManager () {}
|
||||
|
||||
|
||||
122
src/client/bhe.h
Normal file
122
src/client/bhe.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#ifndef bheh
|
||||
#define bheh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define bhehEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "epicsTime.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
#ifdef bhehEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
#include "inetAddrID.h"
|
||||
#include "caProto.h"
|
||||
|
||||
class tcpiiu;
|
||||
class bheMemoryManager;
|
||||
|
||||
// using a pure abstract wrapper class around the free list avoids
|
||||
// Tornado 2.0.1 GNU compiler bugs
|
||||
class epicsShareClass bheMemoryManager {
|
||||
public:
|
||||
virtual ~bheMemoryManager ();
|
||||
virtual void * allocate ( size_t ) = 0;
|
||||
virtual void release ( void * ) = 0;
|
||||
};
|
||||
|
||||
class bhe : public tsSLNode < bhe >, public inetAddrID {
|
||||
public:
|
||||
epicsShareFunc bhe (
|
||||
epicsMutex &, const epicsTime & initialTimeStamp,
|
||||
unsigned initialBeaconNumber, const inetAddrID & addr );
|
||||
epicsShareFunc ~bhe ();
|
||||
epicsShareFunc bool updatePeriod (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const epicsTime & programBeginTime,
|
||||
const epicsTime & currentTime, ca_uint32_t beaconNumber,
|
||||
unsigned protocolRevision );
|
||||
epicsShareFunc double period ( epicsGuard < epicsMutex > & ) const;
|
||||
epicsShareFunc epicsTime updateTime ( epicsGuard < epicsMutex > & ) const;
|
||||
epicsShareFunc void show ( unsigned level ) const;
|
||||
epicsShareFunc void show ( epicsGuard < epicsMutex > &, unsigned /* level */ ) const;
|
||||
epicsShareFunc void registerIIU ( epicsGuard < epicsMutex > &, tcpiiu & );
|
||||
epicsShareFunc void unregisterIIU ( epicsGuard < epicsMutex > &, tcpiiu & );
|
||||
epicsShareFunc void * operator new ( size_t size, bheMemoryManager & );
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
epicsShareFunc void operator delete ( void *, bheMemoryManager & );
|
||||
#endif
|
||||
private:
|
||||
epicsTime timeStamp;
|
||||
double averagePeriod;
|
||||
epicsMutex & mutex;
|
||||
tcpiiu * pIIU;
|
||||
ca_uint32_t lastBeaconNumber;
|
||||
void beaconAnomalyNotify ( epicsGuard < epicsMutex > & );
|
||||
void logBeacon ( const char * pDiagnostic,
|
||||
const double & currentPeriod,
|
||||
const epicsTime & currentTime );
|
||||
void logBeaconDiscard ( unsigned beaconAdvance,
|
||||
const epicsTime & currentTime );
|
||||
bhe ( const bhe & );
|
||||
bhe & operator = ( const bhe & );
|
||||
epicsShareFunc void operator delete ( void * );
|
||||
};
|
||||
|
||||
// using a wrapper class around the free list avoids
|
||||
// Tornado 2.0.1 GNU compiler bugs
|
||||
class bheFreeStore : public bheMemoryManager {
|
||||
public:
|
||||
bheFreeStore () {}
|
||||
void * allocate ( size_t );
|
||||
void release ( void * );
|
||||
private:
|
||||
tsFreeList < bhe, 0x100 > freeList;
|
||||
bheFreeStore ( const bheFreeStore & );
|
||||
bheFreeStore & operator = ( const bheFreeStore & );
|
||||
};
|
||||
|
||||
inline void * bhe::operator new ( size_t size,
|
||||
bheMemoryManager & mgr )
|
||||
{
|
||||
return mgr.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void bhe::operator delete ( void * pCadaver,
|
||||
bheMemoryManager & mgr )
|
||||
{
|
||||
mgr.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ifdef bheh
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ BEGIN
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "Comments","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
109
src/client/caConnTest.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "cadef.h"
|
||||
#include "epicsTime.h"
|
||||
|
||||
static unsigned channelCount = 0u;
|
||||
static unsigned connCount = 0u;
|
||||
static bool subsequentConnect = false;
|
||||
|
||||
epicsTime begin;
|
||||
|
||||
extern "C" void caConnTestConnHandler ( struct connection_handler_args args )
|
||||
{
|
||||
if ( args.op == CA_OP_CONN_UP ) {
|
||||
if ( connCount == 0u ) {
|
||||
if ( subsequentConnect ) {
|
||||
printf ("the first channel connected\n");
|
||||
begin = epicsTime::getCurrent ();
|
||||
}
|
||||
}
|
||||
connCount++;
|
||||
// printf ( "." );
|
||||
// fflush ( stdout );
|
||||
if ( connCount == channelCount ) {
|
||||
epicsTime current = epicsTime::getCurrent ();
|
||||
double delay = current - begin;
|
||||
printf ( "all channels connected after %f sec ( %f sec per channel)\n",
|
||||
delay, delay / channelCount );
|
||||
}
|
||||
}
|
||||
else if ( args.op == CA_OP_CONN_DOWN ) {
|
||||
if ( connCount == channelCount ) {
|
||||
printf ( "channels are disconnected\n" );
|
||||
subsequentConnect = true;
|
||||
}
|
||||
connCount--;
|
||||
if ( connCount == 0u ) {
|
||||
printf ( "all channels are disconnected\n" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert ( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void caConnTest ( const char *pNameIn, unsigned channelCountIn, double delayIn )
|
||||
{
|
||||
unsigned iteration = 0u;
|
||||
int status;
|
||||
unsigned i;
|
||||
chid *pChans;
|
||||
|
||||
channelCount = channelCountIn;
|
||||
|
||||
pChans = new chid [channelCount];
|
||||
|
||||
while ( 1 ) {
|
||||
connCount = 0u;
|
||||
subsequentConnect = false;
|
||||
begin = epicsTime::getCurrent ();
|
||||
|
||||
printf ( "initializing CA client library\n" );
|
||||
|
||||
status = ca_task_initialize();
|
||||
SEVCHK ( status, "CA init failed" );
|
||||
|
||||
printf ( "creating channels\n" );
|
||||
|
||||
for ( i = 0u; i < channelCount; i++ ) {
|
||||
status = ca_search_and_connect ( pNameIn,
|
||||
&pChans[i], caConnTestConnHandler, 0 );
|
||||
SEVCHK ( status, "CA search problems" );
|
||||
}
|
||||
|
||||
printf ( "all channels were created\n" );
|
||||
|
||||
ca_pend_event ( delayIn );
|
||||
|
||||
if ( iteration & 1 ) {
|
||||
for ( i = 0u; i < channelCount; i++ ) {
|
||||
status = ca_clear_channel ( pChans[i] );
|
||||
SEVCHK ( status, "ca_clear_channel() problems" );
|
||||
}
|
||||
printf ( "all channels were destroyed\n" );
|
||||
}
|
||||
|
||||
printf ( "shutting down CA client library\n" );
|
||||
|
||||
status = ca_task_exit ();
|
||||
SEVCHK ( status, "task exit problems" );
|
||||
|
||||
iteration++;
|
||||
}
|
||||
|
||||
//delete [] pChans;
|
||||
}
|
||||
45
src/client/caConnTestMain.cpp
Normal file
45
src/client/caConnTestMain.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <epicsStdlib.h>
|
||||
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
int main ( int argc, char **argv )
|
||||
{
|
||||
double delay = 60.0 * 5.0;
|
||||
unsigned count = 2000;
|
||||
|
||||
if ( argc < 2 || argc > 4 ) {
|
||||
printf ( "usage: %s < channel name > [ < count > ] [ < delay sec > ]\n", argv[0] );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( argc >= 3 ) {
|
||||
int nConverted = sscanf ( argv[2], "%u", &count );
|
||||
if ( nConverted != 1 ) {
|
||||
printf ( "conversion failed, changing channel count arg \"%s\" to %u\n",
|
||||
argv[1], count );
|
||||
}
|
||||
}
|
||||
|
||||
if ( argc >= 4 ) {
|
||||
int nConverted = epicsScanDouble( argv[3], &delay );
|
||||
if ( nConverted != 1 ) {
|
||||
printf ( "conversion failed, changing delay arg \"%s\" to %f\n",
|
||||
argv[2], delay );
|
||||
}
|
||||
}
|
||||
|
||||
caConnTest ( argv[1], count, delay );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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
139
src/client/caEventRate.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "cadef.h"
|
||||
#include "dbDefs.h"
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
|
||||
/*
|
||||
* event_handler()
|
||||
*/
|
||||
extern "C" void eventCallBack ( struct event_handler_args args )
|
||||
{
|
||||
unsigned *pCount = static_cast < unsigned * > ( args.usr );
|
||||
(*pCount)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* caEventRate ()
|
||||
*/
|
||||
void caEventRate ( const char *pName, unsigned count )
|
||||
{
|
||||
static const double initialSamplePeriod = 1.0;
|
||||
static const double maxSamplePeriod = 60.0 * 5.0;
|
||||
unsigned eventCount = 0u;
|
||||
|
||||
chid * pChidTable = new chid [ count ];
|
||||
|
||||
{
|
||||
printf ( "Connecting to CA Channel \"%s\" %u times.",
|
||||
pName, count );
|
||||
fflush ( stdout );
|
||||
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
for ( unsigned i = 0u; i < count; i++ ) {
|
||||
int status = ca_search ( pName, & pChidTable[i] );
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
|
||||
int status = ca_pend_io ( 10000.0 );
|
||||
if ( status != ECA_NORMAL ) {
|
||||
fprintf ( stderr, " not found.\n" );
|
||||
return;
|
||||
}
|
||||
epicsTime end = epicsTime::getCurrent ();
|
||||
|
||||
printf ( " done(%f sec).\n", end - begin );
|
||||
}
|
||||
|
||||
{
|
||||
printf ( "Subscribing %u times.", count );
|
||||
fflush ( stdout );
|
||||
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
for ( unsigned i = 0u; i < count; i++ ) {
|
||||
int addEventStatus = ca_add_event ( DBR_FLOAT,
|
||||
pChidTable[i], eventCallBack, &eventCount, NULL);
|
||||
SEVCHK ( addEventStatus, __FILE__ );
|
||||
}
|
||||
|
||||
int status = ca_flush_io ();
|
||||
SEVCHK ( status, __FILE__ );
|
||||
|
||||
epicsTime end = epicsTime::getCurrent ();
|
||||
|
||||
printf ( " done(%f sec).\n", end - begin );
|
||||
}
|
||||
|
||||
{
|
||||
printf ( "Waiting for initial value events." );
|
||||
fflush ( stdout );
|
||||
|
||||
// let the first one go by
|
||||
epicsTime begin = epicsTime::getCurrent ();
|
||||
while ( eventCount < count ) {
|
||||
int status = ca_pend_event ( 0.01 );
|
||||
if ( status != ECA_TIMEOUT ) {
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
}
|
||||
epicsTime end = epicsTime::getCurrent ();
|
||||
|
||||
printf ( " done(%f sec).\n", end - begin );
|
||||
}
|
||||
|
||||
double samplePeriod = initialSamplePeriod;
|
||||
double X = 0.0;
|
||||
double XX = 0.0;
|
||||
unsigned N = 0u;
|
||||
while ( true ) {
|
||||
unsigned nEvents, lastEventCount, curEventCount;
|
||||
|
||||
epicsTime beginPend = epicsTime::getCurrent ();
|
||||
lastEventCount = eventCount;
|
||||
int status = ca_pend_event ( samplePeriod );
|
||||
curEventCount = eventCount;
|
||||
epicsTime endPend = epicsTime::getCurrent ();
|
||||
if ( status != ECA_TIMEOUT ) {
|
||||
SEVCHK ( status, NULL );
|
||||
}
|
||||
|
||||
if ( curEventCount >= lastEventCount ) {
|
||||
nEvents = curEventCount - lastEventCount;
|
||||
}
|
||||
else {
|
||||
nEvents = ( UINT_MAX - lastEventCount ) + curEventCount + 1u;
|
||||
}
|
||||
|
||||
N++;
|
||||
|
||||
double period = endPend - beginPend;
|
||||
double Hz = nEvents / period;
|
||||
|
||||
X += Hz;
|
||||
XX += Hz * Hz;
|
||||
|
||||
double mean = X / N;
|
||||
double stdDev = sqrt ( XX / N - mean * mean );
|
||||
|
||||
printf ( "CA Event Rate (Hz): current %g mean %g std dev %g\n",
|
||||
Hz, mean, stdDev );
|
||||
|
||||
if ( samplePeriod < maxSamplePeriod ) {
|
||||
samplePeriod += samplePeriod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
187
src/client/caProto.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef __CAPROTO__
|
||||
#define __CAPROTO__
|
||||
|
||||
#define capStrOf(A) #A
|
||||
#define capStrOfX(A) capStrOf ( A )
|
||||
|
||||
/*
|
||||
* CA protocol revision
|
||||
* TCP/UDP port number (bumped each major protocol change)
|
||||
*/
|
||||
#define CA_MAJOR_PROTOCOL_REVISION 4
|
||||
#define CA_VERSION_STRING( MINOR_REVISION ) \
|
||||
( capStrOfX ( CA_MAJOR_PROTOCOL_REVISION ) "." capStrOfX ( MINOR_REVISION ) )
|
||||
#define CA_UKN_MINOR_VERSION 0u /* unknown minor version */
|
||||
#define CA_MINIMUM_SUPPORTED_VERSION 4u
|
||||
# define CA_VSUPPORTED(MINOR) ((MINOR)>=CA_MINIMUM_SUPPORTED_VERSION)
|
||||
# define CA_V41(MINOR) ((MINOR)>=1u)
|
||||
# define CA_V42(MINOR) ((MINOR)>=2u)
|
||||
# define CA_V43(MINOR) ((MINOR)>=3u)
|
||||
# define CA_V44(MINOR) ((MINOR)>=4u)
|
||||
# define CA_V45(MINOR) ((MINOR)>=5u)
|
||||
# define CA_V46(MINOR) ((MINOR)>=6u)
|
||||
# define CA_V47(MINOR) ((MINOR)>=7u)
|
||||
# define CA_V48(MINOR) ((MINOR)>=8u)
|
||||
# define CA_V49(MINOR) ((MINOR)>=9u) /* large arrays, dispatch priorities */
|
||||
# define CA_V410(MINOR) ((MINOR)>=10u) /* beacon counter */
|
||||
# define CA_V411(MINOR) ((MINOR)>=11u) /* sequence numbers in UDP version command */
|
||||
# define CA_V412(MINOR) ((MINOR)>=12u) /* TCP-based search requests */
|
||||
# define CA_V413(MINOR) ((MINOR)>=13u) /* Allow zero length in requests. */
|
||||
|
||||
/*
|
||||
* These port numbers are only used if the CA repeater and
|
||||
* CA server port numbers cant be obtained from the EPICS
|
||||
* environment variables "EPICS_CA_REPEATER_PORT" and
|
||||
* "EPICS_CA_SERVER_PORT"
|
||||
*/
|
||||
#define CA_PORT_BASE IPPORT_USERRESERVED + 56U
|
||||
#define CA_SERVER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*2u)
|
||||
#define CA_REPEATER_PORT (CA_PORT_BASE+CA_MAJOR_PROTOCOL_REVISION*2u+1u)
|
||||
|
||||
/*
|
||||
* 1500 (max of ethernet and 802.{2,3} MTU) - 20(IP) - 8(UDP)
|
||||
* (the MTU of Ethernet is currently independent of its speed varient)
|
||||
*/
|
||||
#define ETHERNET_MAX_UDP ( 1500u - 20u - 8u )
|
||||
#define MAX_UDP_RECV ( 0xffff + 16u ) /* allow large frames to be received in the future */
|
||||
#define MAX_UDP_SEND 1024u /* original MAX_UDP */
|
||||
#define MAX_TCP ( 1024 * 16u ) /* so waveforms fit */
|
||||
#define MAX_MSG_SIZE ( MAX_TCP ) /* the larger of tcp and udp max */
|
||||
|
||||
#define CA_PROTO_PRIORITY_MIN 0u
|
||||
#define CA_PROTO_PRIORITY_MAX 99u
|
||||
|
||||
/*
|
||||
* architecture independent types
|
||||
*
|
||||
* (so far this works on all archs we have ported to)
|
||||
*/
|
||||
typedef unsigned char ca_uint8_t;
|
||||
typedef unsigned short ca_uint16_t;
|
||||
typedef unsigned int ca_uint32_t;
|
||||
typedef float ca_float32_t;
|
||||
typedef ca_uint32_t caResId;
|
||||
|
||||
#define ca_uint32_max 0xffffffff
|
||||
|
||||
/* values for m_cmmd */
|
||||
#define CA_PROTO_VERSION 0u /* set minor version and priority (used to be NOOP cmd) */
|
||||
#define CA_PROTO_EVENT_ADD 1u /* add an event */
|
||||
#define CA_PROTO_EVENT_CANCEL 2u /* cancel an event */
|
||||
#define CA_PROTO_READ 3u /* read and return a channel value*/
|
||||
#define CA_PROTO_WRITE 4u /* write a channel value */
|
||||
#define CA_PROTO_SNAPSHOT 5u /* snapshot of the system */
|
||||
#define CA_PROTO_SEARCH 6u /* IOC channel search */
|
||||
#define CA_PROTO_BUILD 7u /* build - obsolete */
|
||||
#define CA_PROTO_EVENTS_OFF 8u /* flow control */
|
||||
#define CA_PROTO_EVENTS_ON 9u /* flow control */
|
||||
#define CA_PROTO_READ_SYNC 10u /* purge old reads */
|
||||
#define CA_PROTO_ERROR 11u /* an operation failed */
|
||||
#define CA_PROTO_CLEAR_CHANNEL 12u /* free chan resources */
|
||||
#define CA_PROTO_RSRV_IS_UP 13u /* CA server has joined the net */
|
||||
#define CA_PROTO_NOT_FOUND 14u /* channel not found */
|
||||
#define CA_PROTO_READ_NOTIFY 15u /* add a one shot event */
|
||||
#define CA_PROTO_READ_BUILD 16u /* read and build - obsolete */
|
||||
#define REPEATER_CONFIRM 17u /* registration confirmation */
|
||||
#define CA_PROTO_CREATE_CHAN 18u /* client creates channel in server */
|
||||
#define CA_PROTO_WRITE_NOTIFY 19u /* notify after write chan value */
|
||||
#define CA_PROTO_CLIENT_NAME 20u /* CA V4.1 identify client */
|
||||
#define CA_PROTO_HOST_NAME 21u /* CA V4.1 identify client */
|
||||
#define CA_PROTO_ACCESS_RIGHTS 22u /* CA V4.2 asynch access rights chg */
|
||||
#define CA_PROTO_ECHO 23u /* CA V4.3 connection verify */
|
||||
#define REPEATER_REGISTER 24u /* register for repeater fan out */
|
||||
#define CA_PROTO_SIGNAL 25u /* knock the server out of select */
|
||||
#define CA_PROTO_CREATE_CH_FAIL 26u /* unable to create chan resource in server */
|
||||
#define CA_PROTO_SERVER_DISCONN 27u /* server deletes PV (or channel) */
|
||||
|
||||
#define CA_PROTO_LAST_CMMD CA_PROTO_SERVER_DISCONN
|
||||
|
||||
/*
|
||||
* for use with search and not_found (if search fails and
|
||||
* its not a broadcast tell the client to look elesewhere)
|
||||
*/
|
||||
#define DOREPLY 10u
|
||||
#define DONTREPLY 5u
|
||||
|
||||
/*
|
||||
* for use with the m_dataType field in UDP messages emitted by servers
|
||||
*/
|
||||
#define sequenceNoIsValid 1
|
||||
|
||||
/* size of object in bytes rounded up to nearest oct word */
|
||||
#define OCT_ROUND(A) (((A)+7)/8)
|
||||
#define OCT_SIZEOF(A) (OCT_ROUND(sizeof(A)))
|
||||
|
||||
/* size of object in bytes rounded up to nearest long word */
|
||||
#define QUAD_ROUND(A) ((A)+3)/4)
|
||||
#define QUAD_SIZEOF(A) (QUAD_ROUND(sizeof(A)))
|
||||
|
||||
/* size of object in bytes rounded up to nearest short word */
|
||||
#define BI_ROUND(A) (((A)+1)/2)
|
||||
#define BI_SIZEOF(A) (BI_ROUND(sizeof(A)))
|
||||
|
||||
/*
|
||||
* For communicating access rights to the clients
|
||||
*
|
||||
* (placed in m_available hdr field of CA_PROTO_ACCESS_RIGHTS cmmd
|
||||
*/
|
||||
#define CA_PROTO_ACCESS_RIGHT_READ (1u<<0u)
|
||||
#define CA_PROTO_ACCESS_RIGHT_WRITE (1u<<1u)
|
||||
|
||||
/*
|
||||
* All structures passed in the protocol must have individual
|
||||
* fields aligned on natural boundaries.
|
||||
*
|
||||
* NOTE: all structures declared in this file must have a
|
||||
* byte count which is evenly divisible by 8 matching
|
||||
* the largest atomic data type in db_access.h.
|
||||
*/
|
||||
#define CA_MESSAGE_ALIGN(A) (OCT_ROUND(A)<<3u)
|
||||
|
||||
/*
|
||||
* the common part of each message sent/recv by the
|
||||
* CA server.
|
||||
*/
|
||||
typedef struct ca_hdr {
|
||||
ca_uint16_t m_cmmd; /* operation to be performed */
|
||||
ca_uint16_t m_postsize; /* size of payload */
|
||||
ca_uint16_t m_dataType; /* operation data type */
|
||||
ca_uint16_t m_count; /* operation data count */
|
||||
ca_uint32_t m_cid; /* channel identifier */
|
||||
ca_uint32_t m_available; /* protocol stub dependent */
|
||||
} caHdr;
|
||||
|
||||
/*
|
||||
* for monitor (event) message extension
|
||||
*/
|
||||
struct mon_info {
|
||||
ca_float32_t m_lval; /* low delta */
|
||||
ca_float32_t m_hval; /* high delta */
|
||||
ca_float32_t m_toval; /* period btween samples */
|
||||
ca_uint16_t m_mask; /* event select mask */
|
||||
ca_uint16_t m_pad; /* extend to 32 bits */
|
||||
};
|
||||
|
||||
/*
|
||||
* PV names greater than this length assumed to be invalid
|
||||
*/
|
||||
#define unreasonablePVNameSize 500u
|
||||
|
||||
#endif /* __CAPROTO__ */
|
||||
|
||||
42
src/client/caRepeater.cpp
Normal file
42
src/client/caRepeater.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* CA UDP repeater standalone executable
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
* Date: 3-27-90
|
||||
*
|
||||
* PURPOSE:
|
||||
* Broadcasts fan out over the LAN, but old IP kernels do not allow
|
||||
* two processes on the same machine to get the same broadcast
|
||||
* (and modern IP kernels do not allow two processes on the same machine
|
||||
* to receive the same unicast).
|
||||
*
|
||||
* This code fans out UDP messages sent to the CA repeater port
|
||||
* to all CA client processes that have subscribed.
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
* see repeater.c
|
||||
*
|
||||
*/
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "udpiiu.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
ca_repeater ();
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
25
src/client/caRepeater.service@
Normal file
25
src/client/caRepeater.service@
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# Linux systemd service file for the EPICS CA Repeater
|
||||
#
|
||||
# To install this file, as root:
|
||||
# cp caRepeater.service /etc/systemd/system
|
||||
# chmod 664 /etc/systemd/system/caRepeater.service
|
||||
# systemctl daemon-reload
|
||||
# systemctl enable caRepeater
|
||||
# systemctl start caRepeater
|
||||
#
|
||||
# To check the status:
|
||||
# systemctl status caRepeater
|
||||
|
||||
[Unit]
|
||||
Description=EPICS CA Repeater
|
||||
Requires=network.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@INSTALL_BIN@/caRepeater
|
||||
Restart=always
|
||||
User=daemon
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
88
src/client/caServerID.h
Normal file
88
src/client/caServerID.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#ifndef caServerIDh
|
||||
#define caServerIDh
|
||||
|
||||
#include "osiSock.h"
|
||||
#include "resourceLib.h"
|
||||
#include "caProto.h"
|
||||
|
||||
class caServerID {
|
||||
public:
|
||||
caServerID ( const struct sockaddr_in & addrIn, unsigned priority );
|
||||
bool operator == ( const caServerID & ) const;
|
||||
resTableIndex hash () const;
|
||||
osiSockAddr address () const;
|
||||
unsigned priority () const;
|
||||
private:
|
||||
struct sockaddr_in addr;
|
||||
ca_uint8_t pri;
|
||||
};
|
||||
|
||||
inline caServerID::caServerID (
|
||||
const struct sockaddr_in & addrIn, unsigned priorityIn ) :
|
||||
addr ( addrIn ), pri ( static_cast <ca_uint8_t> ( priorityIn ) )
|
||||
{
|
||||
assert ( priorityIn <= 0xff );
|
||||
}
|
||||
|
||||
inline bool caServerID::operator == ( const caServerID & rhs ) const
|
||||
{
|
||||
if ( this->addr.sin_addr.s_addr == rhs.addr.sin_addr.s_addr &&
|
||||
this->addr.sin_port == rhs.addr.sin_port &&
|
||||
this->pri == rhs.pri ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline resTableIndex caServerID::hash () const
|
||||
{
|
||||
// start with a very small server table to speed
|
||||
// up the flush traverse for the frequent case -
|
||||
// a small numbers of servers
|
||||
const unsigned caServerMinIndexBitWidth = 2u;
|
||||
const unsigned caServerMaxIndexBitWidth = 32u;
|
||||
|
||||
unsigned index;
|
||||
index = this->addr.sin_addr.s_addr;
|
||||
index ^= this->addr.sin_port;
|
||||
index ^= this->addr.sin_port >> 8u;
|
||||
index ^= this->pri;
|
||||
return integerHash ( caServerMinIndexBitWidth,
|
||||
caServerMaxIndexBitWidth, index );
|
||||
}
|
||||
|
||||
inline osiSockAddr caServerID::address () const
|
||||
{
|
||||
osiSockAddr tmp;
|
||||
tmp.ia = this->addr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline unsigned caServerID::priority () const
|
||||
{
|
||||
return this->pri;
|
||||
}
|
||||
|
||||
#endif // ifdef caServerID
|
||||
|
||||
|
||||
@@ -5,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
|
||||
7
src/client/caVersionNum.h@
Normal file
7
src/client/caVersionNum.h@
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef CAVERSION_H
|
||||
# error include caVersion.h, not this header
|
||||
#endif
|
||||
#define EPICS_CA_MAJOR_VERSION @EPICS_CA_MAJOR_VERSION@
|
||||
#define EPICS_CA_MINOR_VERSION @EPICS_CA_MINOR_VERSION@
|
||||
#define EPICS_CA_MAINTENANCE_VERSION @EPICS_CA_MAINTENANCE_VERSION@
|
||||
#define EPICS_CA_DEVELOPMENT_FLAG @EPICS_CA_DEVELOPMENT_FLAG@
|
||||
811
src/client/ca_client_context.cpp
Normal file
811
src/client/ca_client_context.cpp
Normal file
@@ -0,0 +1,811 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable:4355)
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string> // vxWorks 6.0 requires this include
|
||||
#include <stdio.h>
|
||||
|
||||
#include "epicsExit.h"
|
||||
#include "errlog.h"
|
||||
#include "locationException.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "oldAccess.h"
|
||||
#include "cac.h"
|
||||
|
||||
epicsShareDef epicsThreadPrivateId caClientCallbackThreadId;
|
||||
|
||||
static epicsThreadOnceId cacOnce = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
const unsigned ca_client_context :: flushBlockThreshold = 0x58000;
|
||||
|
||||
extern "C" void cacExitHandler ( void *)
|
||||
{
|
||||
epicsThreadPrivateDelete ( caClientCallbackThreadId );
|
||||
caClientCallbackThreadId = 0;
|
||||
delete ca_client_context::pDefaultServiceInstallMutex;
|
||||
}
|
||||
|
||||
// runs once only for each process
|
||||
extern "C" void cacOnceFunc ( void * )
|
||||
{
|
||||
caClientCallbackThreadId = epicsThreadPrivateCreate ();
|
||||
assert ( caClientCallbackThreadId );
|
||||
ca_client_context::pDefaultServiceInstallMutex = newEpicsMutex;
|
||||
epicsAtExit ( cacExitHandler,0 );
|
||||
}
|
||||
|
||||
extern epicsThreadPrivateId caClientContextId;
|
||||
|
||||
cacService * ca_client_context::pDefaultService = 0;
|
||||
epicsMutex * ca_client_context::pDefaultServiceInstallMutex;
|
||||
|
||||
ca_client_context::ca_client_context ( bool enablePreemptiveCallback ) :
|
||||
createdByThread ( epicsThreadGetIdSelf () ),
|
||||
ca_exception_func ( 0 ), ca_exception_arg ( 0 ),
|
||||
pVPrintfFunc ( errlogVprintf ), fdRegFunc ( 0 ), fdRegArg ( 0 ),
|
||||
pndRecvCnt ( 0u ), ioSeqNo ( 0u ), callbackThreadsPending ( 0u ),
|
||||
localPort ( 0 ), fdRegFuncNeedsToBeCalled ( false ),
|
||||
noWakeupSincePend ( true )
|
||||
{
|
||||
static const unsigned short PORT_ANY = 0u;
|
||||
|
||||
if ( ! osiSockAttach () ) {
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
|
||||
epicsThreadOnce ( & cacOnce, cacOnceFunc, 0 );
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( *ca_client_context::pDefaultServiceInstallMutex );
|
||||
if ( ca_client_context::pDefaultService ) {
|
||||
this->pServiceContext.reset (
|
||||
& ca_client_context::pDefaultService->contextCreate (
|
||||
this->mutex, this->cbMutex, *this ) );
|
||||
}
|
||||
else {
|
||||
this->pServiceContext.reset ( new cac ( this->mutex, this->cbMutex, *this ) );
|
||||
}
|
||||
}
|
||||
|
||||
this->sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
||||
if ( this->sock == INVALID_SOCKET ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
this->printFormated (
|
||||
"ca_client_context: unable to create "
|
||||
"datagram socket because = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
|
||||
{
|
||||
osiSockIoctl_t yes = true;
|
||||
int status = socket_ioctl ( this->sock,
|
||||
FIONBIO, & yes);
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( this->sock );
|
||||
this->printFormated (
|
||||
"%s: non blocking IO set fail because \"%s\"\n",
|
||||
__FILE__, sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
}
|
||||
|
||||
// force a bind to an unconstrained address so we can obtain
|
||||
// the local port number below
|
||||
{
|
||||
osiSockAddr addr;
|
||||
memset ( (char *)&addr, 0 , sizeof ( addr ) );
|
||||
addr.ia.sin_family = AF_INET;
|
||||
addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
|
||||
addr.ia.sin_port = htons ( PORT_ANY );
|
||||
int status = bind (this->sock, &addr.sa, sizeof (addr) );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy (this->sock);
|
||||
this->printFormated (
|
||||
"CAC: unable to bind to an unconstrained "
|
||||
"address because = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
osiSockAddr tmpAddr;
|
||||
osiSocklen_t saddr_length = sizeof ( tmpAddr );
|
||||
int status = getsockname ( this->sock, & tmpAddr.sa, & saddr_length );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( this->sock );
|
||||
this->printFormated ( "CAC: getsockname () error was \"%s\"\n", sockErrBuf );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
if ( tmpAddr.sa.sa_family != AF_INET) {
|
||||
epicsSocketDestroy ( this->sock );
|
||||
this->printFormated ( "CAC: UDP socket was not inet addr family\n" );
|
||||
throwWithLocation ( noSocket () );
|
||||
}
|
||||
this->localPort = htons ( tmpAddr.ia.sin_port );
|
||||
}
|
||||
|
||||
std::auto_ptr < CallbackGuard > pCBGuard;
|
||||
if ( ! enablePreemptiveCallback ) {
|
||||
pCBGuard.reset ( new CallbackGuard ( this->cbMutex ) );
|
||||
}
|
||||
|
||||
// multiple steps ensure exception safety
|
||||
this->pCallbackGuard = pCBGuard;
|
||||
}
|
||||
|
||||
ca_client_context::~ca_client_context ()
|
||||
{
|
||||
if ( this->fdRegFunc ) {
|
||||
( *this->fdRegFunc )
|
||||
( this->fdRegArg, this->sock, false );
|
||||
}
|
||||
epicsSocketDestroy ( this->sock );
|
||||
|
||||
osiSockRelease ();
|
||||
|
||||
// force a logical shutdown order
|
||||
// so that the cac class does not hang its
|
||||
// receive threads during their shutdown sequence
|
||||
// and so that classes using this classes mutex
|
||||
// are destroyed before the mutex is destroyed
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
|
||||
this->pServiceContext.reset ( 0 );
|
||||
}
|
||||
else {
|
||||
this->pServiceContext.reset ( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::destroyGetCopy (
|
||||
epicsGuard < epicsMutex > & guard, getCopy & gc )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
gc.~getCopy ();
|
||||
this->getCopyFreeList.release ( & gc );
|
||||
}
|
||||
|
||||
void ca_client_context::destroyGetCallback (
|
||||
epicsGuard < epicsMutex > & guard, getCallback & gcb )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
gcb.~getCallback ();
|
||||
this->getCallbackFreeList.release ( & gcb );
|
||||
}
|
||||
|
||||
void ca_client_context::destroyPutCallback (
|
||||
epicsGuard < epicsMutex > & guard, putCallback & pcb )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
pcb.~putCallback ();
|
||||
this->putCallbackFreeList.release ( & pcb );
|
||||
}
|
||||
|
||||
void ca_client_context::destroySubscription (
|
||||
epicsGuard < epicsMutex > & guard, oldSubscription & os )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
os.~oldSubscription ();
|
||||
this->subscriptionFreeList.release ( & os );
|
||||
}
|
||||
|
||||
void ca_client_context::changeExceptionEvent (
|
||||
caExceptionHandler * pfunc, void * arg )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->ca_exception_func = pfunc;
|
||||
this->ca_exception_arg = arg;
|
||||
// should block here until releated callback in progress completes
|
||||
}
|
||||
|
||||
void ca_client_context::replaceErrLogHandler (
|
||||
caPrintfFunc * ca_printf_func )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( ca_printf_func ) {
|
||||
this->pVPrintfFunc = ca_printf_func;
|
||||
}
|
||||
else {
|
||||
this->pVPrintfFunc = epicsVprintf;
|
||||
}
|
||||
// should block here until releated callback in progress completes
|
||||
}
|
||||
|
||||
void ca_client_context::registerForFileDescriptorCallBack (
|
||||
CAFDHANDLER *pFunc, void *pArg )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->fdRegFunc = pFunc;
|
||||
this->fdRegArg = pArg;
|
||||
this->fdRegFuncNeedsToBeCalled = true;
|
||||
if ( pFunc ) {
|
||||
// the receive thread might already be blocking
|
||||
// w/o having sent the wakeup message
|
||||
this->_sendWakeupMsg ();
|
||||
}
|
||||
// should block here until releated callback in progress completes
|
||||
}
|
||||
|
||||
int ca_client_context :: printFormated (
|
||||
const char *pformat, ... ) const
|
||||
{
|
||||
va_list theArgs;
|
||||
int status;
|
||||
|
||||
va_start ( theArgs, pformat );
|
||||
|
||||
status = this->ca_client_context :: varArgsPrintFormated ( pformat, theArgs );
|
||||
|
||||
va_end ( theArgs );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int ca_client_context :: varArgsPrintFormated (
|
||||
const char *pformat, va_list args ) const
|
||||
{
|
||||
caPrintfFunc * pFunc;
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
pFunc = this->pVPrintfFunc;
|
||||
}
|
||||
if ( pFunc ) {
|
||||
return ( *pFunc ) ( pformat, args );
|
||||
}
|
||||
else {
|
||||
return :: vfprintf ( stderr, pformat, args );
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::exception (
|
||||
epicsGuard < epicsMutex > & guard, int stat, const char * pCtx,
|
||||
const char * pFile, unsigned lineNo )
|
||||
{
|
||||
struct exception_handler_args args;
|
||||
caExceptionHandler * pFunc = this->ca_exception_func;
|
||||
void * pArg = this->ca_exception_arg;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
// NOOP if they disable exceptions
|
||||
if ( pFunc ) {
|
||||
args.chid = NULL;
|
||||
args.type = TYPENOTCONN;
|
||||
args.count = 0;
|
||||
args.addr = NULL;
|
||||
args.stat = stat;
|
||||
args.op = CA_OP_OTHER;
|
||||
args.ctx = pCtx;
|
||||
args.pFile = pFile;
|
||||
args.lineNo = lineNo;
|
||||
args.usr = pArg;
|
||||
( *pFunc ) ( args );
|
||||
}
|
||||
else {
|
||||
this->signal ( stat, pFile, lineNo, pCtx );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::exception (
|
||||
epicsGuard < epicsMutex > & guard, int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo, oldChannelNotify & chan,
|
||||
unsigned type, arrayElementCount count, unsigned op )
|
||||
{
|
||||
struct exception_handler_args args;
|
||||
caExceptionHandler * pFunc = this->ca_exception_func;
|
||||
void * pArg = this->ca_exception_arg;
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
// NOOP if they disable exceptions
|
||||
if ( pFunc ) {
|
||||
args.chid = &chan;
|
||||
args.type = type;
|
||||
args.count = count;
|
||||
args.addr = NULL;
|
||||
args.stat = status;
|
||||
args.op = op;
|
||||
args.ctx = pContext;
|
||||
args.pFile = pFileName;
|
||||
args.lineNo = lineNo;
|
||||
args.usr = pArg;
|
||||
( *pFunc ) ( args );
|
||||
}
|
||||
else {
|
||||
this->signal ( status, pFileName, lineNo,
|
||||
"op=%u, channel=%s, type=%s, count=%lu, ctx=\"%s\"",
|
||||
op, ca_name ( &chan ),
|
||||
dbr_type_to_text ( static_cast <int> ( type ) ),
|
||||
count, pContext );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::signal ( int ca_status, const char * pfilenm,
|
||||
int lineno, const char * pFormat, ... )
|
||||
{
|
||||
va_list theArgs;
|
||||
va_start ( theArgs, pFormat );
|
||||
this->vSignal ( ca_status, pfilenm, lineno, pFormat, theArgs);
|
||||
va_end ( theArgs );
|
||||
}
|
||||
|
||||
void ca_client_context :: vSignal (
|
||||
int ca_status, const char *pfilenm,
|
||||
int lineno, const char *pFormat, va_list args )
|
||||
{
|
||||
static const char *severity[] =
|
||||
{
|
||||
"Warning",
|
||||
"Success",
|
||||
"Error",
|
||||
"Info",
|
||||
"Fatal",
|
||||
"Fatal",
|
||||
"Fatal",
|
||||
"Fatal"
|
||||
};
|
||||
|
||||
this->printFormated ( "CA.Client.Exception...............................................\n" );
|
||||
|
||||
this->printFormated ( " %s: \"%s\"\n",
|
||||
severity[ CA_EXTRACT_SEVERITY ( ca_status ) ],
|
||||
ca_message ( ca_status ) );
|
||||
|
||||
if ( pFormat ) {
|
||||
this->printFormated ( " Context: \"" );
|
||||
this->varArgsPrintFormated ( pFormat, args );
|
||||
this->printFormated ( "\"\n" );
|
||||
}
|
||||
|
||||
if ( pfilenm ) {
|
||||
this->printFormated ( " Source File: %s line %d\n",
|
||||
pfilenm, lineno );
|
||||
}
|
||||
|
||||
epicsTime current = epicsTime::getCurrent ();
|
||||
char date[64];
|
||||
current.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f");
|
||||
this->printFormated ( " Current Time: %s\n", date );
|
||||
|
||||
/*
|
||||
* Terminate execution if unsuccessful
|
||||
*/
|
||||
if( ! ( ca_status & CA_M_SUCCESS ) &&
|
||||
CA_EXTRACT_SEVERITY ( ca_status ) != CA_K_WARNING ){
|
||||
errlogFlush ();
|
||||
abort ();
|
||||
}
|
||||
|
||||
this->printFormated ( "..................................................................\n" );
|
||||
}
|
||||
|
||||
void ca_client_context::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
::printf ( "ca_client_context at %p pndRecvCnt=%u ioSeqNo=%u\n",
|
||||
static_cast <const void *> ( this ),
|
||||
this->pndRecvCnt, this->ioSeqNo );
|
||||
|
||||
if ( level > 0u ) {
|
||||
this->pServiceContext->show ( guard, level - 1u );
|
||||
::printf ( "\tpreemptive callback is %s\n",
|
||||
this->pCallbackGuard.get() ? "disabled" : "enabled" );
|
||||
::printf ( "\tthere are %u unsatisfied IO operations blocking ca_pend_io()\n",
|
||||
this->pndRecvCnt );
|
||||
::printf ( "\tthe current io sequence number is %u\n",
|
||||
this->ioSeqNo );
|
||||
::printf ( "IO done event:\n");
|
||||
this->ioDone.show ( level - 1u );
|
||||
::printf ( "Synchronous group identifier hash table:\n" );
|
||||
this->sgTable.show ( level - 1u );
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::attachToClientCtx ()
|
||||
{
|
||||
assert ( ! epicsThreadPrivateGet ( caClientContextId ) );
|
||||
epicsThreadPrivateSet ( caClientContextId, this );
|
||||
}
|
||||
|
||||
void ca_client_context::incrementOutstandingIO (
|
||||
epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->ioSeqNo == ioSeqNoIn ) {
|
||||
assert ( this->pndRecvCnt < UINT_MAX );
|
||||
this->pndRecvCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::decrementOutstandingIO (
|
||||
epicsGuard < epicsMutex > & guard, unsigned ioSeqNoIn )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
if ( this->ioSeqNo == ioSeqNoIn ) {
|
||||
assert ( this->pndRecvCnt > 0u );
|
||||
this->pndRecvCnt--;
|
||||
if ( this->pndRecvCnt == 0u ) {
|
||||
this->ioDone.signal ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// !!!! This routine is only visible in the old interface - or in a new ST interface.
|
||||
// !!!! In the old interface we restrict thread attach so that calls from threads
|
||||
// !!!! other than the initializing thread are not allowed if preemptive callback
|
||||
// !!!! is disabled. This prevents the preemptive callback lock from being released
|
||||
// !!!! by other threads than the one that locked it.
|
||||
//
|
||||
int ca_client_context::pendIO ( const double & timeout )
|
||||
{
|
||||
// prevent recursion nightmares by disabling calls to
|
||||
// pendIO () from within a CA callback.
|
||||
if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) {
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
|
||||
int status = ECA_NORMAL;
|
||||
epicsTime beg_time = epicsTime::getCurrent ();
|
||||
double remaining = timeout;
|
||||
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
this->flush ( guard );
|
||||
|
||||
while ( this->pndRecvCnt > 0 ) {
|
||||
if ( remaining < CAC_SIGNIFICANT_DELAY ) {
|
||||
status = ECA_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
this->blockForEventAndEnableCallbacks ( this->ioDone, remaining );
|
||||
}
|
||||
|
||||
double delay = epicsTime::getCurrent () - beg_time;
|
||||
if ( delay < timeout ) {
|
||||
remaining = timeout - delay;
|
||||
}
|
||||
else {
|
||||
remaining = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
this->ioSeqNo++;
|
||||
this->pndRecvCnt = 0u;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// !!!! This routine is only visible in the old interface - or in a new ST interface.
|
||||
// !!!! In the old interface we restrict thread attach so that calls from threads
|
||||
// !!!! other than the initializing thread are not allowed if preemptive callback
|
||||
// !!!! is disabled. This prevents the preemptive callback lock from being released
|
||||
// !!!! by other threads than the one that locked it.
|
||||
//
|
||||
int ca_client_context::pendEvent ( const double & timeout )
|
||||
{
|
||||
// prevent recursion nightmares by disabling calls to
|
||||
// pendIO () from within a CA callback.
|
||||
if ( epicsThreadPrivateGet ( caClientCallbackThreadId ) ) {
|
||||
return ECA_EVDISALLOW;
|
||||
}
|
||||
|
||||
epicsTime current = epicsTime::getCurrent ();
|
||||
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->flush ( guard );
|
||||
}
|
||||
|
||||
// process at least once if preemptive callback is disabled
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
epicsGuardRelease < epicsMutex > cbUnguard ( *this->pCallbackGuard );
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
|
||||
//
|
||||
// This is needed because in non-preemptive callback mode
|
||||
// legacy applications that use file descriptor managers
|
||||
// will register for ca receive thread activity and keep
|
||||
// calling ca_pend_event until all of the socket data has
|
||||
// been read. We must guarantee that other threads get a
|
||||
// chance to run if there is data in any of the sockets.
|
||||
//
|
||||
if ( this->fdRegFunc ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
|
||||
// remove short udp message sent to wake
|
||||
// up a file descriptor manager
|
||||
osiSockAddr tmpAddr;
|
||||
osiSocklen_t addrSize = sizeof ( tmpAddr.sa );
|
||||
char buf = 0;
|
||||
int status = 0;
|
||||
do {
|
||||
status = recvfrom ( this->sock, & buf, sizeof ( buf ),
|
||||
0, & tmpAddr.sa, & addrSize );
|
||||
} while ( status > 0 );
|
||||
}
|
||||
while ( this->callbackThreadsPending > 0 ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
this->callbackThreadActivityComplete.wait ( 30.0 );
|
||||
}
|
||||
this->noWakeupSincePend = true;
|
||||
}
|
||||
|
||||
double elapsed = epicsTime::getCurrent() - current;
|
||||
double delay;
|
||||
|
||||
if ( timeout > elapsed ) {
|
||||
delay = timeout - elapsed;
|
||||
}
|
||||
else {
|
||||
delay = 0.0;
|
||||
}
|
||||
|
||||
if ( delay >= CAC_SIGNIFICANT_DELAY ) {
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
|
||||
epicsThreadSleep ( delay );
|
||||
}
|
||||
else {
|
||||
epicsThreadSleep ( delay );
|
||||
}
|
||||
}
|
||||
|
||||
return ECA_TIMEOUT;
|
||||
}
|
||||
|
||||
void ca_client_context::blockForEventAndEnableCallbacks (
|
||||
epicsEvent & event, const double & timeout )
|
||||
{
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( *this->pCallbackGuard );
|
||||
event.wait ( timeout );
|
||||
}
|
||||
else {
|
||||
event.wait ( timeout );
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context::callbackProcessingInitiateNotify ()
|
||||
{
|
||||
// if preemptive callback is enabled then this is a noop
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
bool sendNeeded = false;
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->callbackThreadsPending++;
|
||||
if ( this->fdRegFunc && this->noWakeupSincePend ) {
|
||||
this->noWakeupSincePend = false;
|
||||
sendNeeded = true;
|
||||
}
|
||||
}
|
||||
if ( sendNeeded ) {
|
||||
_sendWakeupMsg ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ca_client_context :: _sendWakeupMsg ()
|
||||
{
|
||||
// send short udp message to wake up a file descriptor manager
|
||||
// when a message arrives
|
||||
osiSockAddr tmpAddr;
|
||||
tmpAddr.ia.sin_family = AF_INET;
|
||||
tmpAddr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
|
||||
tmpAddr.ia.sin_port = htons ( this->localPort );
|
||||
char buf = 0;
|
||||
sendto ( this->sock, & buf, sizeof ( buf ),
|
||||
0, & tmpAddr.sa, sizeof ( tmpAddr.sa ) );
|
||||
}
|
||||
|
||||
void ca_client_context::callbackProcessingCompleteNotify ()
|
||||
{
|
||||
// if preemptive callback is enabled then this is a noop
|
||||
if ( this->pCallbackGuard.get() ) {
|
||||
bool signalNeeded = false;
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( this->callbackThreadsPending <= 1 ) {
|
||||
if ( this->callbackThreadsPending == 1 ) {
|
||||
this->callbackThreadsPending = 0;
|
||||
signalNeeded = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->callbackThreadsPending--;
|
||||
}
|
||||
}
|
||||
if ( signalNeeded ) {
|
||||
this->callbackThreadActivityComplete.signal ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cacChannel & ca_client_context::createChannel (
|
||||
epicsGuard < epicsMutex > & guard, const char * pChannelName,
|
||||
cacChannelNotify & chan, cacChannel::priLev pri )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->pServiceContext->createChannel (
|
||||
guard, pChannelName, chan, pri );
|
||||
}
|
||||
|
||||
void ca_client_context::flush ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
this->pServiceContext->flush ( guard );
|
||||
}
|
||||
|
||||
unsigned ca_client_context::circuitCount () const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
return this->pServiceContext->circuitCount ( guard );
|
||||
}
|
||||
|
||||
unsigned ca_client_context::beaconAnomaliesSinceProgramStart () const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
return this->pServiceContext->beaconAnomaliesSinceProgramStart ( guard );
|
||||
}
|
||||
|
||||
void ca_client_context::installCASG (
|
||||
epicsGuard < epicsMutex > & guard, CASG & sg )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->sgTable.idAssignAdd ( sg );
|
||||
}
|
||||
|
||||
void ca_client_context::uninstallCASG (
|
||||
epicsGuard < epicsMutex > & guard, CASG & sg )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->sgTable.remove ( sg );
|
||||
}
|
||||
|
||||
CASG * ca_client_context::lookupCASG (
|
||||
epicsGuard < epicsMutex > & guard, unsigned idIn )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
CASG * psg = this->sgTable.lookup ( idIn );
|
||||
if ( psg ) {
|
||||
if ( ! psg->verify ( guard ) ) {
|
||||
psg = 0;
|
||||
}
|
||||
}
|
||||
return psg;
|
||||
}
|
||||
|
||||
void ca_client_context::selfTest () const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
this->sgTable.verify ();
|
||||
this->pServiceContext->selfTest ( guard );
|
||||
}
|
||||
|
||||
epicsMutex & ca_client_context::mutexRef () const
|
||||
{
|
||||
return this->mutex;
|
||||
}
|
||||
|
||||
cacContext & ca_client_context::createNetworkContext (
|
||||
epicsMutex & mutexIn, epicsMutex & cbMutexIn )
|
||||
{
|
||||
return * new cac ( mutexIn, cbMutexIn, *this );
|
||||
}
|
||||
|
||||
void ca_client_context::installDefaultService ( cacService & service )
|
||||
{
|
||||
epicsThreadOnce ( & cacOnce, cacOnceFunc, 0 );
|
||||
|
||||
epicsGuard < epicsMutex > guard ( *ca_client_context::pDefaultServiceInstallMutex );
|
||||
if ( ca_client_context::pDefaultService ) {
|
||||
throw std::logic_error
|
||||
( "CA in-memory service already installed and can't be replaced");
|
||||
}
|
||||
ca_client_context::pDefaultService = & service;
|
||||
}
|
||||
|
||||
void epicsShareAPI caInstallDefaultService ( cacService & service )
|
||||
{
|
||||
ca_client_context::installDefaultService ( service );
|
||||
}
|
||||
|
||||
epicsShareFunc int epicsShareAPI ca_clear_subscription ( evid pMon )
|
||||
{
|
||||
oldChannelNotify & chan = pMon->channel ();
|
||||
ca_client_context & cac = chan.getClientCtx ();
|
||||
// !!!! the order in which we take the mutex here prevents deadlocks
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
try {
|
||||
// if this stalls out on a live circuit then an exception
|
||||
// can be forthcoming which we must ignore as the clear
|
||||
// request must always be successful
|
||||
chan.eliminateExcessiveSendBacklog ( guard );
|
||||
}
|
||||
catch ( cacChannel::notConnected & ) {
|
||||
// intentionally ignored
|
||||
}
|
||||
}
|
||||
if ( cac.pCallbackGuard.get() &&
|
||||
cac.createdByThread == epicsThreadGetIdSelf () ) {
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
pMon->cancel ( *cac.pCallbackGuard.get(), guard );
|
||||
}
|
||||
else {
|
||||
//
|
||||
// we will definately stall out here if all of the
|
||||
// following are true
|
||||
//
|
||||
// o user creates non-preemtive mode client library context
|
||||
// o user doesnt periodically call a ca function
|
||||
// o user calls this function from an auxiillary thread
|
||||
//
|
||||
CallbackGuard cbGuard ( cac.cbMutex );
|
||||
epicsGuard < epicsMutex > guard ( cac.mutex );
|
||||
pMon->cancel ( cbGuard, guard );
|
||||
}
|
||||
return ECA_NORMAL;
|
||||
}
|
||||
|
||||
void ca_client_context :: eliminateExcessiveSendBacklog (
|
||||
epicsGuard < epicsMutex > & guard, cacChannel & chan )
|
||||
{
|
||||
if ( chan.requestMessageBytesPending ( guard ) >
|
||||
ca_client_context :: flushBlockThreshold ) {
|
||||
if ( this->pCallbackGuard.get() &&
|
||||
this->createdByThread == epicsThreadGetIdSelf () ) {
|
||||
// we need to be very careful about lock hierarchy
|
||||
// inversion in this situation
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > cbunguard (
|
||||
* this->pCallbackGuard.get() );
|
||||
{
|
||||
epicsGuard < epicsMutex > nestedGuard ( this->mutex );
|
||||
chan.flush ( nestedGuard );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
chan.flush ( guard );
|
||||
}
|
||||
}
|
||||
}
|
||||
1336
src/client/cac.cpp
Normal file
1336
src/client/cac.cpp
Normal file
File diff suppressed because it is too large
Load Diff
435
src/client/cac.h
Normal file
435
src/client/cac.h
Normal file
@@ -0,0 +1,435 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef cach
|
||||
#define cach
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define cach_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "compilerDependencies.h"
|
||||
#include "ipAddrToAsciiAsynchronous.h"
|
||||
#include "msgForMultiplyDefinedPV.h"
|
||||
#include "epicsTimer.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "freeList.h"
|
||||
#include "localHostName.h"
|
||||
|
||||
#ifdef cach_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
#include "nciu.h"
|
||||
#include "comBuf.h"
|
||||
#include "bhe.h"
|
||||
#include "cacIO.h"
|
||||
#include "netIO.h"
|
||||
#include "localHostName.h"
|
||||
#include "virtualCircuit.h"
|
||||
|
||||
class netWriteNotifyIO;
|
||||
class netReadNotifyIO;
|
||||
class netSubscription;
|
||||
class tcpiiu;
|
||||
|
||||
// used to control access to cac's recycle routines which
|
||||
// should only be indirectly invoked by CAC when its lock
|
||||
// is applied
|
||||
class cacRecycle {
|
||||
public:
|
||||
virtual void recycleReadNotifyIO (
|
||||
epicsGuard < epicsMutex > &, netReadNotifyIO &io ) = 0;
|
||||
virtual void recycleWriteNotifyIO (
|
||||
epicsGuard < epicsMutex > &, netWriteNotifyIO &io ) = 0;
|
||||
virtual void recycleSubscription (
|
||||
epicsGuard < epicsMutex > &, netSubscription &io ) = 0;
|
||||
protected:
|
||||
virtual ~cacRecycle() {}
|
||||
};
|
||||
|
||||
struct CASG;
|
||||
class inetAddrID;
|
||||
class caServerID;
|
||||
struct caHdrLargeArray;
|
||||
|
||||
class cacComBufMemoryManager : public comBufMemoryManager
|
||||
{
|
||||
public:
|
||||
cacComBufMemoryManager () {}
|
||||
void * allocate ( size_t );
|
||||
void release ( void * );
|
||||
private:
|
||||
tsFreeList < comBuf, 0x20 > freeList;
|
||||
cacComBufMemoryManager ( const cacComBufMemoryManager & );
|
||||
cacComBufMemoryManager & operator = ( const cacComBufMemoryManager & );
|
||||
};
|
||||
|
||||
class notifyGuard {
|
||||
public:
|
||||
notifyGuard ( cacContextNotify & );
|
||||
~notifyGuard ();
|
||||
private:
|
||||
cacContextNotify & notify;
|
||||
notifyGuard ( const notifyGuard & );
|
||||
notifyGuard & operator = ( const notifyGuard & );
|
||||
};
|
||||
|
||||
class callbackManager : public notifyGuard {
|
||||
public:
|
||||
callbackManager (
|
||||
cacContextNotify &,
|
||||
epicsMutex & callbackControl );
|
||||
epicsGuard < epicsMutex > cbGuard;
|
||||
};
|
||||
|
||||
class cac :
|
||||
public cacContext,
|
||||
private cacRecycle,
|
||||
private callbackForMultiplyDefinedPV
|
||||
{
|
||||
public:
|
||||
cac (
|
||||
epicsMutex & mutualExclusion,
|
||||
epicsMutex & callbackControl,
|
||||
cacContextNotify & );
|
||||
virtual ~cac ();
|
||||
|
||||
// beacon management
|
||||
void beaconNotify ( const inetAddrID & addr, const epicsTime & currentTime,
|
||||
ca_uint32_t beaconNumber, unsigned protocolRevision );
|
||||
unsigned beaconAnomaliesSinceProgramStart (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
|
||||
// IO management
|
||||
void flush ( epicsGuard < epicsMutex > & guard );
|
||||
bool executeResponse ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, caHdrLargeArray &, char *pMsgBody );
|
||||
|
||||
// channel routines
|
||||
void transferChanToVirtCircuit (
|
||||
unsigned cid, unsigned sid,
|
||||
ca_uint16_t typeCode, arrayElementCount count,
|
||||
unsigned minorVersionNumber, const osiSockAddr &,
|
||||
const epicsTime & currentTime );
|
||||
cacChannel & createChannel (
|
||||
epicsGuard < epicsMutex > & guard, const char * pChannelName,
|
||||
cacChannelNotify &, cacChannel::priLev );
|
||||
void destroyChannel (
|
||||
epicsGuard < epicsMutex > &, nciu & );
|
||||
void initiateConnect (
|
||||
epicsGuard < epicsMutex > &, nciu &, netiiu * & );
|
||||
nciu * lookupChannel (
|
||||
epicsGuard < epicsMutex > &, const cacChannel::ioid & );
|
||||
|
||||
// IO requests
|
||||
netWriteNotifyIO & writeNotifyRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
||||
unsigned type, arrayElementCount nElem, const void * pValue,
|
||||
cacWriteNotify & );
|
||||
netReadNotifyIO & readNotifyRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
||||
unsigned type, arrayElementCount nElem,
|
||||
cacReadNotify & );
|
||||
netSubscription & subscriptionRequest (
|
||||
epicsGuard < epicsMutex > &, nciu &, privateInterfaceForIO &,
|
||||
unsigned type, arrayElementCount nElem, unsigned mask,
|
||||
cacStateNotify &, bool channelIsInstalled );
|
||||
bool destroyIO (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const cacChannel::ioid & idIn,
|
||||
nciu & chan );
|
||||
void disconnectAllIO (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
nciu &, tsDLList < baseNMIU > & ioList );
|
||||
|
||||
void ioShow (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid &id, unsigned level ) const;
|
||||
|
||||
// exception generation
|
||||
void exception (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo );
|
||||
|
||||
// search destination management
|
||||
void registerSearchDest (
|
||||
epicsGuard < epicsMutex > &, SearchDest & req );
|
||||
bool findOrCreateVirtCircuit (
|
||||
epicsGuard < epicsMutex > &, const osiSockAddr &,
|
||||
unsigned, tcpiiu *&, unsigned, SearchDestTCP * pSearchDest = NULL );
|
||||
|
||||
// diagnostics
|
||||
unsigned circuitCount ( epicsGuard < epicsMutex > & ) const;
|
||||
void show ( epicsGuard < epicsMutex > &, unsigned level ) const;
|
||||
int printFormated (
|
||||
epicsGuard < epicsMutex > & callbackControl,
|
||||
const char *pformat, ... ) const;
|
||||
int varArgsPrintFormated (
|
||||
epicsGuard < epicsMutex > & callbackControl,
|
||||
const char *pformat, va_list args ) const;
|
||||
double connectionTimeout ( epicsGuard < epicsMutex > & );
|
||||
|
||||
unsigned maxContiguousFrames ( epicsGuard < epicsMutex > & ) const;
|
||||
|
||||
// misc
|
||||
const char * userNamePointer () const;
|
||||
unsigned getInitializingThreadsPriority () const;
|
||||
epicsMutex & mutexRef ();
|
||||
void attachToClientCtx ();
|
||||
void selfTest (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
double beaconPeriod (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const nciu & chan ) const;
|
||||
static unsigned lowestPriorityLevelAbove ( unsigned priority );
|
||||
static unsigned highestPriorityLevelBelow ( unsigned priority );
|
||||
void destroyIIU ( tcpiiu & iiu );
|
||||
|
||||
const char * pLocalHostName ();
|
||||
|
||||
private:
|
||||
epicsSingleton < localHostName > :: reference _refLocalHostName;
|
||||
chronIntIdResTable < nciu > chanTable;
|
||||
//
|
||||
// !!!! There is at this point no good reason
|
||||
// !!!! to maintain one IO table for all types of
|
||||
// !!!! IO. It would probably be better to maintain
|
||||
// !!!! an independent table for each IO type. The
|
||||
// !!!! new adaptive sized hash table will not
|
||||
// !!!! waste memory. Making this change will
|
||||
// !!!! avoid virtual function overhead when
|
||||
// !!!! accessing the different types of IO. This
|
||||
// !!!! approach would also probably be safer in
|
||||
// !!!! terms of detecting damaged protocol.
|
||||
//
|
||||
chronIntIdResTable < baseNMIU > ioTable;
|
||||
resTable < bhe, inetAddrID > beaconTable;
|
||||
resTable < tcpiiu, caServerID > serverTable;
|
||||
tsDLList < tcpiiu > circuitList;
|
||||
tsDLList < SearchDest > searchDestList;
|
||||
tsDLList < msgForMultiplyDefinedPV > msgMultiPVList;
|
||||
tsFreeList
|
||||
< class tcpiiu, 32, epicsMutexNOOP >
|
||||
freeListVirtualCircuit;
|
||||
tsFreeList
|
||||
< class netReadNotifyIO, 1024, epicsMutexNOOP >
|
||||
freeListReadNotifyIO;
|
||||
tsFreeList
|
||||
< class netWriteNotifyIO, 1024, epicsMutexNOOP >
|
||||
freeListWriteNotifyIO;
|
||||
tsFreeList
|
||||
< class netSubscription, 1024, epicsMutexNOOP >
|
||||
freeListSubscription;
|
||||
tsFreeList
|
||||
< class nciu, 1024, epicsMutexNOOP >
|
||||
channelFreeList;
|
||||
tsFreeList
|
||||
< class msgForMultiplyDefinedPV, 16 >
|
||||
mdpvFreeList;
|
||||
cacComBufMemoryManager comBufMemMgr;
|
||||
bheFreeStore bheFreeList;
|
||||
epicsTime programBeginTime;
|
||||
double connTMO;
|
||||
// **** lock hierarchy ****
|
||||
// 1) callback lock must always be acquired before
|
||||
// the primary mutex if both locks are needed
|
||||
epicsMutex & mutex;
|
||||
epicsMutex & cbMutex;
|
||||
epicsEvent iiuUninstall;
|
||||
ipAddrToAsciiEngine & ipToAEngine;
|
||||
epicsTimerQueueActive & timerQueue;
|
||||
char * pUserName;
|
||||
class udpiiu * pudpiiu;
|
||||
void * tcpSmallRecvBufFreeList;
|
||||
void * tcpLargeRecvBufFreeList;
|
||||
cacContextNotify & notify;
|
||||
epicsThreadId initializingThreadsId;
|
||||
unsigned initializingThreadsPriority;
|
||||
unsigned maxRecvBytesTCP;
|
||||
unsigned maxContigFrames;
|
||||
unsigned beaconAnomalyCount;
|
||||
unsigned short _serverPort;
|
||||
unsigned iiuExistenceCount;
|
||||
bool cacShutdownInProgress;
|
||||
|
||||
void recycleReadNotifyIO (
|
||||
epicsGuard < epicsMutex > &, netReadNotifyIO &io );
|
||||
void recycleWriteNotifyIO (
|
||||
epicsGuard < epicsMutex > &, netWriteNotifyIO &io );
|
||||
void recycleSubscription (
|
||||
epicsGuard < epicsMutex > &, netSubscription &io );
|
||||
|
||||
void disconnectChannel (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan );
|
||||
|
||||
void ioExceptionNotify ( unsigned id, int status,
|
||||
const char * pContext, unsigned type, arrayElementCount count );
|
||||
void ioExceptionNotifyAndUninstall ( unsigned id, int status,
|
||||
const char * pContext, unsigned type, arrayElementCount count );
|
||||
|
||||
void pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv,
|
||||
const char * pChannelName, const char * pAcc, const char * pRej );
|
||||
|
||||
// recv protocol stubs
|
||||
bool versionAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool echoRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool writeNotifyRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool searchRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool readNotifyRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool eventRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool readRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool clearChannelRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool exceptionRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool accessRightsRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool createChannelRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool verifyAndDisconnectChan ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
bool badTCPRespAction ( callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
|
||||
typedef bool ( cac::*pProtoStubTCP ) (
|
||||
callbackManager &, tcpiiu &,
|
||||
const epicsTime & currentTime, const caHdrLargeArray &, void *pMsgBdy );
|
||||
static const pProtoStubTCP tcpJumpTableCAC [];
|
||||
|
||||
bool defaultExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool eventAddExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool readExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool writeExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool clearChanExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool readNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
bool writeNotifyExcep ( callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
typedef bool ( cac::*pExcepProtoStubTCP ) (
|
||||
callbackManager &, tcpiiu &iiu, const caHdrLargeArray &hdr,
|
||||
const char *pCtx, unsigned status );
|
||||
static const pExcepProtoStubTCP tcpExcepJumpTableCAC [];
|
||||
|
||||
cac ( const cac & );
|
||||
cac & operator = ( const cac & );
|
||||
|
||||
friend class tcpiiu;
|
||||
};
|
||||
|
||||
inline const char * cac::userNamePointer () const
|
||||
{
|
||||
return this->pUserName;
|
||||
}
|
||||
|
||||
inline unsigned cac::getInitializingThreadsPriority () const
|
||||
{
|
||||
return this->initializingThreadsPriority;
|
||||
}
|
||||
|
||||
inline epicsMutex & cac::mutexRef ()
|
||||
{
|
||||
return this->mutex;
|
||||
}
|
||||
|
||||
inline int cac :: varArgsPrintFormated (
|
||||
epicsGuard < epicsMutex > & callbackControl,
|
||||
const char *pformat, va_list args ) const
|
||||
{
|
||||
callbackControl.assertIdenticalMutex ( this->cbMutex );
|
||||
return this->notify.varArgsPrintFormated ( pformat, args );
|
||||
}
|
||||
|
||||
inline void cac::attachToClientCtx ()
|
||||
{
|
||||
this->notify.attachToClientCtx ();
|
||||
}
|
||||
|
||||
inline unsigned cac::beaconAnomaliesSinceProgramStart (
|
||||
epicsGuard < epicsMutex > & guard ) const
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->beaconAnomalyCount;
|
||||
}
|
||||
|
||||
inline notifyGuard::notifyGuard ( cacContextNotify & notifyIn ) :
|
||||
notify ( notifyIn )
|
||||
{
|
||||
this->notify.callbackProcessingInitiateNotify ();
|
||||
}
|
||||
|
||||
inline notifyGuard::~notifyGuard ()
|
||||
{
|
||||
this->notify.callbackProcessingCompleteNotify ();
|
||||
}
|
||||
|
||||
inline callbackManager::callbackManager (
|
||||
cacContextNotify & notify, epicsMutex & callbackControl ) :
|
||||
notifyGuard ( notify ), cbGuard ( callbackControl )
|
||||
{
|
||||
}
|
||||
|
||||
inline nciu * cac::lookupChannel (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
const cacChannel::ioid & idIn )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->chanTable.lookup ( idIn );
|
||||
}
|
||||
|
||||
inline const char * cac :: pLocalHostName ()
|
||||
{
|
||||
return _refLocalHostName->pointer ();
|
||||
}
|
||||
|
||||
inline unsigned cac ::
|
||||
maxContiguousFrames ( epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return maxContigFrames;
|
||||
}
|
||||
|
||||
inline double cac ::
|
||||
connectionTimeout ( epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
return this->connTMO;
|
||||
}
|
||||
|
||||
#endif // ifdef cach
|
||||
145
src/client/cacChannel.cpp
Normal file
145
src/client/cacChannel.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
#include <float.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "localHostName.h"
|
||||
#include "cacIO.h"
|
||||
|
||||
class CACChannelPrivate {
|
||||
public:
|
||||
CACChannelPrivate ();
|
||||
unsigned getHostName ( char * pBuf, unsigned bufLength );
|
||||
const char * pHostName ();
|
||||
private:
|
||||
epicsSingleton < localHostName > :: reference
|
||||
_refLocalHostName;
|
||||
};
|
||||
|
||||
static epicsThreadOnceId cacChannelIdOnce = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
const cacChannel::priLev cacChannel::priorityMax = 99u;
|
||||
const cacChannel::priLev cacChannel::priorityMin = 0u;
|
||||
const cacChannel::priLev cacChannel::priorityDefault = priorityMin;
|
||||
const cacChannel::priLev cacChannel::priorityLinksDB = priorityMax;
|
||||
const cacChannel::priLev cacChannel::priorityArchive = ( priorityMax - priorityMin ) / 2;
|
||||
const cacChannel::priLev cacChannel::priorityOPI = priorityMin;
|
||||
|
||||
cacChannel::~cacChannel ()
|
||||
{
|
||||
}
|
||||
|
||||
caAccessRights cacChannel::accessRights (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
static caAccessRights ar ( true, true );
|
||||
return ar;
|
||||
}
|
||||
|
||||
unsigned cacChannel::searchAttempts (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
double cacChannel::beaconPeriod (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return - DBL_MAX;
|
||||
}
|
||||
|
||||
double cacChannel::receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return - DBL_MAX;
|
||||
}
|
||||
|
||||
bool cacChannel::ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cacChannel::connected (
|
||||
epicsGuard < epicsMutex > & ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CACChannelPrivate ::
|
||||
CACChannelPrivate() :
|
||||
_refLocalHostName ( localHostNameCache.getReference () )
|
||||
{
|
||||
}
|
||||
|
||||
inline unsigned CACChannelPrivate ::
|
||||
getHostName ( char * pBuf, unsigned bufLength )
|
||||
{
|
||||
return _refLocalHostName->getName ( pBuf, bufLength );
|
||||
}
|
||||
|
||||
inline const char * CACChannelPrivate ::
|
||||
pHostName ()
|
||||
{
|
||||
return _refLocalHostName->pointer ();
|
||||
}
|
||||
|
||||
static CACChannelPrivate * pCACChannelPrivate = 0;
|
||||
|
||||
// runs once only for each process
|
||||
extern "C" void cacChannelSetup ( void * )
|
||||
{
|
||||
pCACChannelPrivate = new CACChannelPrivate ();
|
||||
}
|
||||
|
||||
// the default is to assume that it is a locally hosted channel
|
||||
unsigned cacChannel::getHostName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLength ) const throw ()
|
||||
{
|
||||
if ( bufLength ) {
|
||||
epicsThreadOnce ( & cacChannelIdOnce, cacChannelSetup, 0);
|
||||
return pCACChannelPrivate->getHostName ( pBuf, bufLength );
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
|
||||
// the default is to assume that it is a locally hosted channel
|
||||
const char * cacChannel::pHostName (
|
||||
epicsGuard < epicsMutex > & ) const throw ()
|
||||
{
|
||||
epicsThreadOnce ( & cacChannelIdOnce, cacChannelSetup, 0);
|
||||
return pCACChannelPrivate->pHostName ();
|
||||
}
|
||||
|
||||
cacContext::~cacContext () {}
|
||||
|
||||
cacService::~cacService () {}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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
392
src/client/cacIO.h
Normal file
@@ -0,0 +1,392 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef cacIOh
|
||||
#define cacIOh
|
||||
|
||||
//
|
||||
// Open Issues
|
||||
// -----------
|
||||
//
|
||||
// 1) A status code from the old client side interface is passed
|
||||
// to the exception notify callback. Should we just pass a string?
|
||||
// If so, then how do they detect the type of error and recover.
|
||||
// Perhaps we should call a different vf for each type of exception.
|
||||
//
|
||||
// 2) Some exception types are present here but there is no common
|
||||
// exception base class in use.
|
||||
//
|
||||
// 3) Should I be passing the channel reference in cacChannelNotify?
|
||||
//
|
||||
// 4) Should the code for caAccessRights not be inline so that this
|
||||
// interface is version independent.
|
||||
//
|
||||
//
|
||||
|
||||
#include <new>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define cacIOh_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsGuard.h"
|
||||
#include "epicsThread.h"
|
||||
|
||||
#ifdef cacIOh_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
|
||||
class cacChannel;
|
||||
|
||||
typedef unsigned long arrayElementCount;
|
||||
|
||||
// 1) this should not be passing caerr.h status to the exception callback
|
||||
// 2) needless-to-say the data should be passed here using the new data access API
|
||||
class epicsShareClass cacWriteNotify {
|
||||
public:
|
||||
virtual ~cacWriteNotify () = 0;
|
||||
virtual void completion ( epicsGuard < epicsMutex > & ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &,
|
||||
int status, const char * pContext,
|
||||
unsigned type, arrayElementCount count ) = 0;
|
||||
};
|
||||
|
||||
// 1) this should not be passing caerr.h status to the exception callback
|
||||
// 2) needless-to-say the data should be passed here using the new data access API
|
||||
class epicsShareClass cacReadNotify {
|
||||
public:
|
||||
virtual ~cacReadNotify () = 0;
|
||||
virtual void completion (
|
||||
epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, const void * pData ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, int status,
|
||||
const char * pContext, unsigned type,
|
||||
arrayElementCount count ) = 0;
|
||||
};
|
||||
|
||||
// 1) this should not be passing caerr.h status to the exception callback
|
||||
// 2) needless-to-say the data should be passed here using the new data access API
|
||||
class epicsShareClass cacStateNotify {
|
||||
public:
|
||||
virtual ~cacStateNotify () = 0;
|
||||
virtual void current (
|
||||
epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, const void * pData ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, int status,
|
||||
const char *pContext, unsigned type,
|
||||
arrayElementCount count ) = 0;
|
||||
};
|
||||
|
||||
class caAccessRights {
|
||||
public:
|
||||
caAccessRights (
|
||||
bool readPermit = false,
|
||||
bool writePermit = false,
|
||||
bool operatorConfirmationRequest = false);
|
||||
void setReadPermit ();
|
||||
void setWritePermit ();
|
||||
void setOperatorConfirmationRequest ();
|
||||
void clrReadPermit ();
|
||||
void clrWritePermit ();
|
||||
void clrOperatorConfirmationRequest ();
|
||||
bool readPermit () const;
|
||||
bool writePermit () const;
|
||||
bool operatorConfirmationRequest () const;
|
||||
private:
|
||||
bool f_readPermit:1;
|
||||
bool f_writePermit:1;
|
||||
bool f_operatorConfirmationRequest:1;
|
||||
};
|
||||
|
||||
class epicsShareClass cacChannelNotify {
|
||||
public:
|
||||
virtual ~cacChannelNotify () = 0;
|
||||
virtual void connectNotify ( epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual void disconnectNotify ( epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual void serviceShutdownNotify (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
virtual void accessRightsNotify (
|
||||
epicsGuard < epicsMutex > &, const caAccessRights & ) = 0;
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, int status, const char *pContext ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void readException (
|
||||
epicsGuard < epicsMutex > &, int status, const char *pContext,
|
||||
unsigned type, arrayElementCount count, void *pValue ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void writeException (
|
||||
epicsGuard < epicsMutex > &, int status, const char * pContext,
|
||||
unsigned type, arrayElementCount count ) = 0;
|
||||
};
|
||||
|
||||
class CallbackGuard :
|
||||
public epicsGuard < epicsMutex > {
|
||||
public:
|
||||
CallbackGuard ( epicsMutex & mutex ) :
|
||||
epicsGuard < epicsMutex > ( mutex ) {}
|
||||
private:
|
||||
CallbackGuard ( const CallbackGuard & );
|
||||
CallbackGuard & operator = ( const CallbackGuard & );
|
||||
};
|
||||
|
||||
//
|
||||
// Notes
|
||||
// 1) This interface assumes that when a channel is deleted then all
|
||||
// attached IO is deleted. This is left over from the old interface,
|
||||
// but perhaps is a bad practice that should be eliminated? If so,
|
||||
// then the IO should not store or use a pointer to the channel.
|
||||
//
|
||||
class epicsShareClass cacChannel {
|
||||
public:
|
||||
typedef unsigned priLev;
|
||||
static const priLev priorityMax;
|
||||
static const priLev priorityMin;
|
||||
static const priLev priorityDefault;
|
||||
static const priLev priorityLinksDB;
|
||||
static const priLev priorityArchive;
|
||||
static const priLev priorityOPI;
|
||||
|
||||
typedef unsigned ioid;
|
||||
enum ioStatus { iosSynch, iosAsynch };
|
||||
|
||||
cacChannel ( cacChannelNotify & );
|
||||
virtual void destroy (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
cacChannelNotify & notify () const; // required ?????
|
||||
virtual unsigned getName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLen ) const throw () = 0;
|
||||
// !! deprecated, avoid use !!
|
||||
virtual const char * pName (
|
||||
epicsGuard < epicsMutex > & guard ) const throw () = 0;
|
||||
virtual void show (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned level ) const = 0;
|
||||
virtual void initiateConnect (
|
||||
epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual unsigned requestMessageBytesPending (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
virtual void flush (
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard ) = 0;
|
||||
virtual ioStatus read (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
cacReadNotify &, ioid * = 0 ) = 0;
|
||||
virtual void write (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void *pValue ) = 0;
|
||||
virtual ioStatus write (
|
||||
epicsGuard < epicsMutex > &,
|
||||
unsigned type, arrayElementCount count,
|
||||
const void *pValue, cacWriteNotify &, ioid * = 0 ) = 0;
|
||||
virtual void subscribe (
|
||||
epicsGuard < epicsMutex > &, unsigned type,
|
||||
arrayElementCount count, unsigned mask, cacStateNotify &,
|
||||
ioid * = 0 ) = 0;
|
||||
// The primary mutex must be released when calling the user's
|
||||
// callback, and therefore a finite interval exists when we are
|
||||
// moving forward with the intent to call the users callback
|
||||
// but the users IO could be deleted during this interval.
|
||||
// To prevent the user's callback from being called after
|
||||
// destroying his IO we must past a guard for the callback
|
||||
// mutex here.
|
||||
virtual void ioCancel (
|
||||
CallbackGuard & callbackGuard,
|
||||
epicsGuard < epicsMutex > & mutualExclusionGuard,
|
||||
const ioid & ) = 0;
|
||||
virtual void ioShow (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const ioid &, unsigned level ) const = 0;
|
||||
virtual short nativeType (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual arrayElementCount nativeElementCount (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual caAccessRights accessRights (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
virtual unsigned searchAttempts (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
virtual double beaconPeriod (
|
||||
epicsGuard < epicsMutex > & ) const; // negative DBL_MAX if UKN
|
||||
virtual double receiveWatchdogDelay (
|
||||
epicsGuard < epicsMutex > & ) const; // negative DBL_MAX if UKN
|
||||
virtual bool ca_v42_ok (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
virtual bool connected (
|
||||
epicsGuard < epicsMutex > & ) const;
|
||||
virtual unsigned getHostName (
|
||||
epicsGuard < epicsMutex > &,
|
||||
char * pBuf, unsigned bufLength ) const throw ();
|
||||
// !! deprecated, avoid use !!
|
||||
virtual const char * pHostName (
|
||||
epicsGuard < epicsMutex > & guard ) const throw ();
|
||||
|
||||
// exceptions
|
||||
class badString {};
|
||||
class badType {};
|
||||
class badPriority {};
|
||||
class outOfBounds {};
|
||||
class badEventSelection {};
|
||||
class noWriteAccess {};
|
||||
class noReadAccess {};
|
||||
class notConnected {};
|
||||
class unsupportedByService {};
|
||||
class msgBodyCacheTooSmall {}; // hopefully this one goes away in the future
|
||||
class requestTimedOut {};
|
||||
|
||||
protected:
|
||||
virtual ~cacChannel () = 0;
|
||||
|
||||
private:
|
||||
cacChannelNotify & callback;
|
||||
cacChannel ( const cacChannel & );
|
||||
cacChannel & operator = ( const cacChannel & );
|
||||
};
|
||||
|
||||
class epicsShareClass cacContext {
|
||||
public:
|
||||
virtual ~cacContext ();
|
||||
virtual cacChannel & createChannel (
|
||||
epicsGuard < epicsMutex > &,
|
||||
const char * pChannelName, cacChannelNotify &,
|
||||
cacChannel::priLev = cacChannel::priorityDefault ) = 0;
|
||||
virtual void flush (
|
||||
epicsGuard < epicsMutex > & ) = 0;
|
||||
virtual unsigned circuitCount (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual void selfTest (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual unsigned beaconAnomaliesSinceProgramStart (
|
||||
epicsGuard < epicsMutex > & ) const = 0;
|
||||
virtual void show (
|
||||
epicsGuard < epicsMutex > &, unsigned level ) const = 0;
|
||||
};
|
||||
|
||||
class epicsShareClass cacContextNotify {
|
||||
public:
|
||||
virtual ~cacContextNotify () = 0;
|
||||
virtual cacContext & createNetworkContext (
|
||||
epicsMutex & mutualExclusion, epicsMutex & callbackControl ) = 0;
|
||||
// we should probably have a different vf for each type of exception ????
|
||||
virtual void exception (
|
||||
epicsGuard < epicsMutex > &, int status, const char * pContext,
|
||||
const char * pFileName, unsigned lineNo ) = 0;
|
||||
// perhaps this should be phased out in deference to the exception mechanism
|
||||
virtual int varArgsPrintFormated ( const char * pformat, va_list args ) const = 0;
|
||||
// backwards compatibility (from here down)
|
||||
virtual void attachToClientCtx () = 0;
|
||||
virtual void callbackProcessingInitiateNotify () = 0;
|
||||
virtual void callbackProcessingCompleteNotify () = 0;
|
||||
};
|
||||
|
||||
// **** Lock Hierarchy ****
|
||||
// callbackControl must be taken before mutualExclusion if both are held at
|
||||
// the same time
|
||||
class epicsShareClass cacService {
|
||||
public:
|
||||
virtual ~cacService () = 0;
|
||||
virtual cacContext & contextCreate (
|
||||
epicsMutex & mutualExclusion,
|
||||
epicsMutex & callbackControl,
|
||||
cacContextNotify & ) = 0;
|
||||
};
|
||||
|
||||
epicsShareFunc void epicsShareAPI caInstallDefaultService ( cacService & service );
|
||||
|
||||
epicsShareExtern epicsThreadPrivateId caClientCallbackThreadId;
|
||||
|
||||
inline cacChannel::cacChannel ( cacChannelNotify & notify ) :
|
||||
callback ( notify )
|
||||
{
|
||||
}
|
||||
|
||||
inline cacChannelNotify & cacChannel::notify () const
|
||||
{
|
||||
return this->callback;
|
||||
}
|
||||
|
||||
inline caAccessRights::caAccessRights (
|
||||
bool readPermit, bool writePermit, bool operatorConfirmationRequest) :
|
||||
f_readPermit ( readPermit ), f_writePermit ( writePermit ),
|
||||
f_operatorConfirmationRequest ( operatorConfirmationRequest ) {}
|
||||
|
||||
inline void caAccessRights::setReadPermit ()
|
||||
{
|
||||
this->f_readPermit = true;
|
||||
}
|
||||
|
||||
inline void caAccessRights::setWritePermit ()
|
||||
{
|
||||
this->f_writePermit = true;
|
||||
}
|
||||
|
||||
inline void caAccessRights::setOperatorConfirmationRequest ()
|
||||
{
|
||||
this->f_operatorConfirmationRequest = true;
|
||||
}
|
||||
|
||||
inline void caAccessRights::clrReadPermit ()
|
||||
{
|
||||
this->f_readPermit = false;
|
||||
}
|
||||
|
||||
inline void caAccessRights::clrWritePermit ()
|
||||
{
|
||||
this->f_writePermit = false;
|
||||
}
|
||||
|
||||
inline void caAccessRights::clrOperatorConfirmationRequest ()
|
||||
{
|
||||
this->f_operatorConfirmationRequest = false;
|
||||
}
|
||||
|
||||
inline bool caAccessRights::readPermit () const
|
||||
{
|
||||
return this->f_readPermit;
|
||||
}
|
||||
|
||||
inline bool caAccessRights::writePermit () const
|
||||
{
|
||||
return this->f_writePermit;
|
||||
}
|
||||
|
||||
inline bool caAccessRights::operatorConfirmationRequest () const
|
||||
{
|
||||
return this->f_operatorConfirmationRequest;
|
||||
}
|
||||
|
||||
#endif // ifndef cacIOh
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
904
src/client/cadef.h
Normal file
@@ -0,0 +1,904 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INCLcadefh
|
||||
#define INCLcadefh
|
||||
|
||||
/*
|
||||
* done in two ifdef steps so that we will remain compatible with
|
||||
* traditional C
|
||||
*/
|
||||
#ifndef CA_DONT_INCLUDE_STDARGH
|
||||
# include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define INCLcadefh_accessh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsThread.h"
|
||||
|
||||
#ifdef INCLcadefh_accessh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "caerr.h"
|
||||
#include "db_access.h"
|
||||
#include "caeventmask.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct oldChannelNotify *chid;
|
||||
typedef chid chanId; /* for when the structures field name is "chid" */
|
||||
typedef long chtype;
|
||||
typedef struct oldSubscription *evid;
|
||||
typedef double ca_real;
|
||||
|
||||
/* arguments passed to user connection handlers */
|
||||
struct connection_handler_args {
|
||||
chanId chid; /* channel id */
|
||||
long op; /* one of CA_OP_CONN_UP or CA_OP_CONN_DOWN */
|
||||
};
|
||||
|
||||
typedef void caCh (struct connection_handler_args args);
|
||||
|
||||
typedef struct ca_access_rights {
|
||||
unsigned read_access:1;
|
||||
unsigned write_access:1;
|
||||
} caar;
|
||||
|
||||
/* arguments passed to user access rights handlers */
|
||||
struct access_rights_handler_args {
|
||||
chanId chid; /* channel id */
|
||||
caar ar; /* new access rights state */
|
||||
};
|
||||
|
||||
typedef void caArh (struct access_rights_handler_args args);
|
||||
|
||||
/* The conversion routine to call for each type */
|
||||
#define VALID_TYPE(TYPE) (((unsigned short)TYPE)<=LAST_BUFFER_TYPE)
|
||||
|
||||
/*
|
||||
* Arguments passed to event handlers and get/put call back handlers.
|
||||
*
|
||||
* The status field below is the CA ECA_XXX status of the requested
|
||||
* operation which is saved from when the operation was attempted in the
|
||||
* server and copied back to the clients call back routine.
|
||||
* If the status is not ECA_NORMAL then the dbr pointer will be NULL
|
||||
* and the requested operation can not be assumed to be successful.
|
||||
*/
|
||||
typedef struct event_handler_args {
|
||||
void *usr; /* user argument supplied with request */
|
||||
chanId chid; /* channel id */
|
||||
long type; /* the type of the item returned */
|
||||
long count; /* the element count of the item returned */
|
||||
const void *dbr; /* a pointer to the item returned */
|
||||
int status; /* ECA_XXX status of the requested op from the server */
|
||||
} evargs;
|
||||
typedef void caEventCallBackFunc (struct event_handler_args);
|
||||
|
||||
epicsShareFunc void epicsShareAPI ca_test_event
|
||||
(
|
||||
struct event_handler_args
|
||||
);
|
||||
|
||||
/* arguments passed to user exception handlers */
|
||||
struct exception_handler_args {
|
||||
void *usr; /* user argument supplied when installed */
|
||||
chanId chid; /* channel id (may be nill) */
|
||||
long type; /* type requested */
|
||||
long count; /* count requested */
|
||||
void *addr; /* user's address to write results of CA_OP_GET */
|
||||
long stat; /* channel access ECA_XXXX status code */
|
||||
long op; /* CA_OP_GET, CA_OP_PUT, ..., CA_OP_OTHER */
|
||||
const char *ctx; /* a character string containing context info */
|
||||
const char *pFile; /* source file name (may be NULL) */
|
||||
unsigned lineNo; /* source file line number (may be zero) */
|
||||
};
|
||||
|
||||
typedef unsigned CA_SYNC_GID;
|
||||
|
||||
/*
|
||||
* External OP codes for CA operations
|
||||
*/
|
||||
#define CA_OP_GET 0
|
||||
#define CA_OP_PUT 1
|
||||
#define CA_OP_CREATE_CHANNEL 2
|
||||
#define CA_OP_ADD_EVENT 3
|
||||
#define CA_OP_CLEAR_EVENT 4
|
||||
#define CA_OP_OTHER 5
|
||||
|
||||
/*
|
||||
* used with connection_handler_args
|
||||
*/
|
||||
#define CA_OP_CONN_UP 6
|
||||
#define CA_OP_CONN_DOWN 7
|
||||
|
||||
/* depricated */
|
||||
#define CA_OP_SEARCH 2
|
||||
|
||||
/*
|
||||
* provides efficient test and display of channel access errors
|
||||
*/
|
||||
#define SEVCHK(CA_ERROR_CODE, MESSAGE_STRING) \
|
||||
{ \
|
||||
int ca_unique_status_name = (CA_ERROR_CODE); \
|
||||
if(!(ca_unique_status_name & CA_M_SUCCESS)) \
|
||||
ca_signal_with_file_and_lineno( \
|
||||
ca_unique_status_name, \
|
||||
(MESSAGE_STRING), \
|
||||
__FILE__, \
|
||||
__LINE__); \
|
||||
}
|
||||
|
||||
|
||||
#define TYPENOTCONN (-1) /* the channel's native type when disconnected */
|
||||
epicsShareFunc short epicsShareAPI ca_field_type (chid chan);
|
||||
epicsShareFunc unsigned long epicsShareAPI ca_element_count (chid chan);
|
||||
epicsShareFunc const char * epicsShareAPI ca_name (chid chan);
|
||||
epicsShareFunc void epicsShareAPI ca_set_puser (chid chan, void *puser);
|
||||
epicsShareFunc void * epicsShareAPI ca_puser (chid chan);
|
||||
epicsShareFunc unsigned epicsShareAPI ca_read_access (chid chan);
|
||||
epicsShareFunc unsigned epicsShareAPI ca_write_access (chid chan);
|
||||
|
||||
/*
|
||||
* cs_ - `channel state'
|
||||
*
|
||||
* cs_never_conn valid chid, IOC not found
|
||||
* cs_prev_conn valid chid, IOC was found, but unavailable
|
||||
* cs_conn valid chid, IOC was found, still available
|
||||
* cs_closed channel deleted by user
|
||||
*/
|
||||
enum channel_state {cs_never_conn, cs_prev_conn, cs_conn, cs_closed};
|
||||
epicsShareFunc enum channel_state epicsShareAPI ca_state (chid chan);
|
||||
|
||||
/************************************************************************/
|
||||
/* Perform Library Initialization */
|
||||
/* */
|
||||
/* Must be called once before calling any of the other routines */
|
||||
/************************************************************************/
|
||||
epicsShareFunc int epicsShareAPI ca_task_initialize (void);
|
||||
enum ca_preemptive_callback_select
|
||||
{ ca_disable_preemptive_callback, ca_enable_preemptive_callback };
|
||||
epicsShareFunc int epicsShareAPI
|
||||
ca_context_create (enum ca_preemptive_callback_select select);
|
||||
epicsShareFunc void epicsShareAPI ca_detach_context ();
|
||||
|
||||
/************************************************************************/
|
||||
/* Remove CA facility from your task */
|
||||
/* */
|
||||
/* Normally called automatically at task exit */
|
||||
/************************************************************************/
|
||||
epicsShareFunc int epicsShareAPI ca_task_exit (void);
|
||||
epicsShareFunc void epicsShareAPI ca_context_destroy (void);
|
||||
|
||||
typedef unsigned capri;
|
||||
#define CA_PRIORITY_MAX 99
|
||||
#define CA_PRIORITY_MIN 0
|
||||
#define CA_PRIORITY_DEFAULT CA_PRIORITY_MIN
|
||||
|
||||
#define CA_PRIORITY_DB_LINKS 80
|
||||
#define CA_PRIORITY_ARCHIVE 20
|
||||
#define CA_PRIORITY_OPI 0
|
||||
|
||||
/*
|
||||
* ca_create_channel ()
|
||||
*
|
||||
* pChanName R channel name string
|
||||
* pConnStateCallback R address of connection state change
|
||||
* callback function
|
||||
* pUserPrivate R placed in the channel's user private field
|
||||
* o can be fetched later by ca_puser(CHID)
|
||||
* o passed as void * arg to *pConnectCallback above
|
||||
* priority R priority level in the server 0 - 100
|
||||
* pChanID RW channel id written here
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_create_channel
|
||||
(
|
||||
const char *pChanName,
|
||||
caCh *pConnStateCallback,
|
||||
void *pUserPrivate,
|
||||
capri priority,
|
||||
chid *pChanID
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_change_connection_event()
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pfunc R address of connection call-back function
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_change_connection_event
|
||||
(
|
||||
chid chan,
|
||||
caCh * pfunc
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_replace_access_rights_event ()
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pfunc R address of access rights call-back function
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_replace_access_rights_event (
|
||||
chid chan,
|
||||
caArh *pfunc
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_add_exception_event ()
|
||||
*
|
||||
* replace the default exception handler
|
||||
*
|
||||
* pfunc R address of exception call-back function
|
||||
* pArg R copy of this pointer passed to exception
|
||||
* call-back function
|
||||
*/
|
||||
typedef void caExceptionHandler (struct exception_handler_args);
|
||||
epicsShareFunc int epicsShareAPI ca_add_exception_event
|
||||
(
|
||||
caExceptionHandler *pfunc,
|
||||
void *pArg
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_clear_channel()
|
||||
* - deallocate resources reserved for a channel
|
||||
*
|
||||
* chanId R channel ID
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_clear_channel
|
||||
(
|
||||
chid chanId
|
||||
);
|
||||
|
||||
/************************************************************************/
|
||||
/* Write a value to a channel */
|
||||
/************************************************************************/
|
||||
/*
|
||||
* ca_bput()
|
||||
*
|
||||
* WARNING: this copies the new value from a string (dbr_string_t)
|
||||
* (and not as an integer)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value string copied from this location
|
||||
*/
|
||||
#define ca_bput(chan, pValue) \
|
||||
ca_array_put(DBR_STRING, 1u, chan, (const dbr_string_t *) (pValue))
|
||||
|
||||
/*
|
||||
* ca_rput()
|
||||
*
|
||||
* WARNING: this copies the new value from a dbr_float_t
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
*/
|
||||
#define ca_rput(chan,pValue) \
|
||||
ca_array_put(DBR_FLOAT, 1u, chan, (const dbr_float_t *) pValue)
|
||||
|
||||
/*
|
||||
* ca_put()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
*/
|
||||
#define ca_put(type, chan, pValue) ca_array_put (type, 1u, chan, pValue)
|
||||
|
||||
/*
|
||||
* ca_array_put()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_array_put
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
const void * pValue
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_array_put_callback()
|
||||
*
|
||||
* This routine functions identically to the original ca put request
|
||||
* with the addition of a callback to the user supplied function
|
||||
* after recod processing completes in the IOC. The arguments
|
||||
* to the user supplied callback function are declared in
|
||||
* the structure event_handler_args and include the pointer
|
||||
* sized user argument supplied when ca_array_put_callback() is called.
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_array_put_callback
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
const void * pValue,
|
||||
caEventCallBackFunc * pFunc,
|
||||
void * pArg
|
||||
);
|
||||
|
||||
#define ca_put_callback(type, chan, pValue, pFunc, pArg) \
|
||||
ca_array_put_callback(type, 1u, chan, pValue, pFunc, pArg)
|
||||
|
||||
/************************************************************************/
|
||||
/* Read a value from a channel */
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* ca_bget()
|
||||
*
|
||||
* WARNING: this copies the new value into a string (dbr_string_t)
|
||||
* (and not into an integer)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
#define ca_bget(chan, pValue) \
|
||||
ca_array_get(DBR_STRING, 1u, chan, (dbr_string_t *)(pValue))
|
||||
|
||||
/*
|
||||
* ca_rget()
|
||||
*
|
||||
* WARNING: this copies the new value into a 32 bit float (dbr_float_t)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
#define ca_rget(chan, pValue) \
|
||||
ca_array_get(DBR_FLOAT, 1u, chan, (dbr_float_t *)(pValue))
|
||||
|
||||
/*
|
||||
* ca_rget()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
#define ca_get(type, chan, pValue) ca_array_get(type, 1u, chan, pValue)
|
||||
|
||||
/*
|
||||
* ca_array_get()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_array_get
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
void * pValue
|
||||
);
|
||||
|
||||
/************************************************************************/
|
||||
/* Read a value from a channel and run a callback when the value */
|
||||
/* returns */
|
||||
/* */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
/*
|
||||
* ca_bget_callback()
|
||||
*
|
||||
* WARNING: this returns the new value as a string (dbr_string_t)
|
||||
* (and not as an integer)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
#define ca_bget_callback(chan, pFunc, pArg)\
|
||||
ca_array_get_callback (DBR_STRING, 1u, chan, pFunc, pArg)
|
||||
|
||||
/*
|
||||
* ca_rget_callback()
|
||||
*
|
||||
* WARNING: this returns the new value as a float (dbr_float_t)
|
||||
*
|
||||
* chan R channel identifier
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
#define ca_rget_callback(chan, pFunc, pArg)\
|
||||
ca_array_get_callback (DBR_FLOAT, 1u, chan, pFunc, pArg)
|
||||
|
||||
/*
|
||||
* ca_get_callback()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* chan R channel identifier
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
#define ca_get_callback(type, chan, pFunc, pArg)\
|
||||
ca_array_get_callback (type, 1u, chan, pFunc, pArg)
|
||||
|
||||
/*
|
||||
* ca_array_get_callback()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_array_get_callback
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
caEventCallBackFunc * pFunc,
|
||||
void * pArg
|
||||
);
|
||||
|
||||
/************************************************************************/
|
||||
/* Specify a function to be executed whenever significant changes */
|
||||
/* occur to a channel. */
|
||||
/* NOTES: */
|
||||
/* 1) Evid may be omited by passing a NULL pointer */
|
||||
/* */
|
||||
/* 2) An array count of zero specifies the native db count */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* ca_create_subscription ()
|
||||
*
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* mask R event mask - one of {DBE_VALUE, DBE_ALARM, DBE_LOG}
|
||||
* pFunc R pointer to call-back function
|
||||
* pArg R copy of this pointer passed to pFunc
|
||||
* pEventID W event id written at specified address
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_create_subscription
|
||||
(
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chanId,
|
||||
long mask,
|
||||
caEventCallBackFunc * pFunc,
|
||||
void * pArg,
|
||||
evid * pEventID
|
||||
);
|
||||
|
||||
/************************************************************************/
|
||||
/* Remove a function from a list of those specified to run */
|
||||
/* whenever significant changes occur to a channel */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
/*
|
||||
* ca_clear_subscription()
|
||||
*
|
||||
* eventID R event id
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_clear_subscription
|
||||
(
|
||||
evid eventID
|
||||
);
|
||||
|
||||
epicsShareFunc chid epicsShareAPI ca_evid_to_chid ( evid id );
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/* Requested data is not necessarily stable prior to */
|
||||
/* return from called subroutine. Call ca_pend_io() */
|
||||
/* to guarantee that requested data is stable. Call the routine */
|
||||
/* ca_flush_io() to force all outstanding requests to be */
|
||||
/* sent out over the network. Significant increases in */
|
||||
/* performance have been measured when batching several remote */
|
||||
/* requests together into one message. Additional */
|
||||
/* improvements can be obtained by performing local processing */
|
||||
/* in parallel with outstanding remote processing. */
|
||||
/* */
|
||||
/* FLOW OF TYPICAL APPLICATION */
|
||||
/* */
|
||||
/* search() ! Obtain Channel ids */
|
||||
/* . ! " */
|
||||
/* . ! " */
|
||||
/* pend_io ! wait for channels to connect */
|
||||
/* */
|
||||
/* get() ! several requests for remote info */
|
||||
/* get() ! " */
|
||||
/* add_event() ! " */
|
||||
/* get() ! " */
|
||||
/* . */
|
||||
/* . */
|
||||
/* . */
|
||||
/* flush_io() ! send get requests */
|
||||
/* ! optional parallel processing */
|
||||
/* . ! " */
|
||||
/* . ! " */
|
||||
/* pend_io() ! wait for replies from get requests */
|
||||
/* . ! access to requested data */
|
||||
/* . ! " */
|
||||
/* pend_event() ! wait for requested events */
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
/************************************************************************/
|
||||
/* These routines wait for channel subscription events and call the */
|
||||
/* functions specified with add_event when events occur. If the */
|
||||
/* timeout is specified as 0 an infinite timeout is assumed. */
|
||||
/* ca_flush_io() is called by this routine. If ca_pend_io () */
|
||||
/* is called when no IO is outstanding then it will return immediately */
|
||||
/* without processing. */
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* ca_pend_event()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_pend_event (ca_real timeOut);
|
||||
#define ca_poll() ca_pend_event(1e-12)
|
||||
|
||||
/*
|
||||
* ca_pend_io()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds but return early
|
||||
* if all get requests (or search requests with null
|
||||
* connection handler pointer have completed)
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_pend_io (ca_real timeOut);
|
||||
|
||||
/* calls ca_pend_io() if early is true otherwise ca_pend_event() is called */
|
||||
epicsShareFunc int epicsShareAPI ca_pend (ca_real timeout, int early);
|
||||
|
||||
/*
|
||||
* ca_test_io()
|
||||
*
|
||||
* returns TRUE when get requests (or search requests with null
|
||||
* connection handler pointer) are outstanding
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_test_io (void);
|
||||
|
||||
/************************************************************************/
|
||||
/* Send out all outstanding messages in the send queue */
|
||||
/************************************************************************/
|
||||
/*
|
||||
* ca_flush_io()
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_flush_io (void);
|
||||
|
||||
|
||||
/*
|
||||
* ca_signal()
|
||||
*
|
||||
* errorCode R status returned from channel access function
|
||||
* pCtxStr R context string included with error print out
|
||||
*/
|
||||
epicsShareFunc void epicsShareAPI ca_signal
|
||||
(
|
||||
long errorCode,
|
||||
const char *pCtxStr
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_signal_with_file_and_lineno()
|
||||
* errorCode R status returned from channel access function
|
||||
* pCtxStr R context string included with error print out
|
||||
* pFileStr R file name string included with error print out
|
||||
* lineNo R line number included with error print out
|
||||
*
|
||||
*/
|
||||
epicsShareFunc void epicsShareAPI ca_signal_with_file_and_lineno
|
||||
(
|
||||
long errorCode,
|
||||
const char *pCtxStr,
|
||||
const char *pFileStr,
|
||||
int lineNo
|
||||
);
|
||||
|
||||
/*
|
||||
* ca_signal_formated()
|
||||
* errorCode R status returned from channel access function
|
||||
* pFileStr R file name string included with error print out
|
||||
* lineNo R line number included with error print out
|
||||
* pFormat R printf dtyle format string (and optional arguments)
|
||||
*
|
||||
*/
|
||||
epicsShareFunc void epicsShareAPI ca_signal_formated (long ca_status, const char *pfilenm,
|
||||
int lineno, const char *pFormat, ...);
|
||||
|
||||
/*
|
||||
* ca_host_name_function()
|
||||
*
|
||||
* channel R channel identifier
|
||||
*
|
||||
* !!!! this function is _not_ thread safe !!!!
|
||||
*/
|
||||
epicsShareFunc const char * epicsShareAPI ca_host_name (chid channel);
|
||||
/* thread safe version */
|
||||
epicsShareFunc unsigned epicsShareAPI ca_get_host_name ( chid pChan,
|
||||
char *pBuf, unsigned bufLength );
|
||||
|
||||
/*
|
||||
* CA_ADD_FD_REGISTRATION
|
||||
*
|
||||
* call their function with their argument whenever
|
||||
* a new fd is added or removed
|
||||
* (for use with a manager of the select system call under UNIX)
|
||||
*
|
||||
* if (opened) then fd was created
|
||||
* if (!opened) then fd was deleted
|
||||
*
|
||||
*/
|
||||
typedef void CAFDHANDLER (void *parg, int fd, int opened);
|
||||
|
||||
/*
|
||||
* ca_add_fd_registration()
|
||||
*
|
||||
* pHandler R pointer to function which is to be called
|
||||
* when an fd is created or deleted
|
||||
* pArg R argument passed to above function
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_add_fd_registration
|
||||
(
|
||||
CAFDHANDLER *pHandler,
|
||||
void *pArg
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
* CA synch groups
|
||||
*
|
||||
* This facility will allow the programmer to create
|
||||
* any number of synchronization groups. The programmer might then
|
||||
* interleave IO requests within any of the groups. Once The
|
||||
* IO operations are initiated then the programmer is free to
|
||||
* block for IO completion within any one of the groups as needed.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ca_sg_create()
|
||||
*
|
||||
* create a sync group
|
||||
*
|
||||
* pgid W pointer to sync group id that will be written
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_create (CA_SYNC_GID * pgid);
|
||||
|
||||
/*
|
||||
* ca_sg_delete()
|
||||
*
|
||||
* delete a sync group
|
||||
*
|
||||
* gid R sync group id
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_delete (const CA_SYNC_GID gid);
|
||||
|
||||
/*
|
||||
* ca_sg_block()
|
||||
*
|
||||
* block for IO performed within a sync group to complete
|
||||
*
|
||||
* gid R sync group id
|
||||
* timeout R wait for this duration prior to timing out
|
||||
* and returning ECA_TIMEOUT
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_block (const CA_SYNC_GID gid, ca_real timeout);
|
||||
|
||||
/*
|
||||
* ca_sg_test()
|
||||
*
|
||||
* test for sync group IO operations in progress
|
||||
*
|
||||
* gid R sync group id
|
||||
*
|
||||
* returns one of ECA_BADSYNCGRP, ECA_IOINPROGRESS, ECA_IODONE
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_test (const CA_SYNC_GID gid);
|
||||
|
||||
/*
|
||||
* ca_sg_reset
|
||||
*
|
||||
* gid R sync group id
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_reset(const CA_SYNC_GID gid);
|
||||
|
||||
/*
|
||||
* ca_sg_array_get()
|
||||
*
|
||||
* initiate a get within a sync group
|
||||
* (essentially a ca_array_get() with a sync group specified)
|
||||
*
|
||||
* gid R sync group id
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue W channel value copied to this location
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_array_get
|
||||
(
|
||||
const CA_SYNC_GID gid,
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chan,
|
||||
void *pValue
|
||||
);
|
||||
|
||||
#define ca_sg_get(gid, type, chan, pValue) \
|
||||
ca_sg_array_get (gid, type, 1u, chan, pValue)
|
||||
|
||||
/*
|
||||
* ca_sg_array_put()
|
||||
*
|
||||
* initiate a put within a sync group
|
||||
* (essentially a ca_array_put() with a sync group specified)
|
||||
*
|
||||
* gid R sync group id
|
||||
* type R data type from db_access.h
|
||||
* count R array element count
|
||||
* chan R channel identifier
|
||||
* pValue R new channel value copied from this location
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_array_put
|
||||
(
|
||||
const CA_SYNC_GID gid,
|
||||
chtype type,
|
||||
unsigned long count,
|
||||
chid chan,
|
||||
const void *pValue
|
||||
);
|
||||
|
||||
#define ca_sg_put(gid, type, chan, pValue) \
|
||||
ca_sg_array_put (gid, type, 1u, chan, pValue)
|
||||
|
||||
/*
|
||||
* ca_sg_stat()
|
||||
*
|
||||
* print status of a sync group
|
||||
*
|
||||
* gid R sync group id
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_sg_stat (CA_SYNC_GID gid);
|
||||
|
||||
epicsShareFunc void epicsShareAPI ca_dump_dbr (chtype type, unsigned count, const void * pbuffer);
|
||||
|
||||
|
||||
/*
|
||||
* ca_v42_ok()
|
||||
*
|
||||
* Put call back is available if the CA server is on version is 4.2
|
||||
* or higher.
|
||||
*
|
||||
* chan R channel identifier
|
||||
*
|
||||
* (returns true or false)
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_v42_ok (chid chan);
|
||||
|
||||
/*
|
||||
* ca_version()
|
||||
*
|
||||
* returns the CA version string
|
||||
*/
|
||||
epicsShareFunc const char * epicsShareAPI ca_version (void);
|
||||
|
||||
/*
|
||||
* ca_replace_printf_handler ()
|
||||
*
|
||||
* for apps that want to change where ca formatted
|
||||
* text output goes
|
||||
*
|
||||
* use two ifdef's for trad C compatibility
|
||||
*
|
||||
* ca_printf_func R pointer to new function called when
|
||||
* CA prints an error message
|
||||
*/
|
||||
#ifndef CA_DONT_INCLUDE_STDARGH
|
||||
typedef int caPrintfFunc (const char *pformat, va_list args);
|
||||
epicsShareFunc int epicsShareAPI ca_replace_printf_handler (
|
||||
caPrintfFunc *ca_printf_func
|
||||
);
|
||||
#endif /*CA_DONT_INCLUDE_STDARGH*/
|
||||
|
||||
/*
|
||||
* (for testing purposes only)
|
||||
*/
|
||||
epicsShareFunc unsigned epicsShareAPI ca_get_ioc_connection_count (void);
|
||||
epicsShareFunc int epicsShareAPI ca_preemtive_callback_is_enabled (void);
|
||||
epicsShareFunc void epicsShareAPI ca_self_test (void);
|
||||
epicsShareFunc unsigned epicsShareAPI ca_beacon_anomaly_count (void);
|
||||
epicsShareFunc unsigned epicsShareAPI ca_search_attempts (chid chan);
|
||||
epicsShareFunc double epicsShareAPI ca_beacon_period (chid chan);
|
||||
epicsShareFunc double epicsShareAPI ca_receive_watchdog_delay (chid chan);
|
||||
|
||||
/*
|
||||
* used when an auxillary thread needs to join a CA client context started
|
||||
* by another thread
|
||||
*/
|
||||
epicsShareFunc struct ca_client_context * epicsShareAPI ca_current_context ();
|
||||
epicsShareFunc int epicsShareAPI ca_attach_context ( struct ca_client_context * context );
|
||||
|
||||
|
||||
epicsShareFunc int epicsShareAPI ca_client_status ( unsigned level );
|
||||
epicsShareFunc int epicsShareAPI ca_context_status ( struct ca_client_context *, unsigned level );
|
||||
|
||||
/*
|
||||
* deprecated
|
||||
*/
|
||||
#define ca_build_channel(NAME,XXXXX,CHIDPTR,YYYYY)\
|
||||
ca_build_and_connect(NAME, XXXXX, 1, CHIDPTR, YYYYY, 0, 0)
|
||||
#define ca_array_build(NAME,XXXXX, ZZZZZZ, CHIDPTR,YYYYY)\
|
||||
ca_build_and_connect(NAME, XXXXX, ZZZZZZ, CHIDPTR, YYYYY, 0, 0)
|
||||
epicsShareFunc int epicsShareAPI ca_build_and_connect
|
||||
( const char *pChanName, chtype, unsigned long,
|
||||
chid * pChanID, void *, caCh * pFunc, void * pArg );
|
||||
#define ca_search(pChanName, pChanID)\
|
||||
ca_search_and_connect (pChanName, pChanID, 0, 0)
|
||||
epicsShareFunc int epicsShareAPI ca_search_and_connect
|
||||
( const char * pChanName, chid * pChanID,
|
||||
caCh *pFunc, void * pArg );
|
||||
epicsShareFunc int epicsShareAPI ca_channel_status (epicsThreadId tid);
|
||||
epicsShareFunc int epicsShareAPI ca_clear_event ( evid eventID );
|
||||
#define ca_add_event(type,chan,pFunc,pArg,pEventID)\
|
||||
ca_add_array_event(type,1u,chan,pFunc,pArg,0.0,0.0,0.0,pEventID)
|
||||
#define ca_add_delta_event(TYPE,CHID,ENTRY,ARG,DELTA,EVID)\
|
||||
ca_add_array_event(TYPE,1,CHID,ENTRY,ARG,DELTA,DELTA,0.0,EVID)
|
||||
#define ca_add_general_event(TYPE,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)\
|
||||
ca_add_array_event(TYPE,1,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)
|
||||
#define ca_add_array_event(TYPE,COUNT,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)\
|
||||
ca_add_masked_array_event(TYPE,COUNT,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID, DBE_VALUE | DBE_ALARM)
|
||||
epicsShareFunc int epicsShareAPI ca_add_masked_array_event
|
||||
( chtype type, unsigned long count, chid chanId, caEventCallBackFunc * pFunc,
|
||||
void * pArg, ca_real p_delta, ca_real n_delta, ca_real timeout,
|
||||
evid * pEventID, long mask );
|
||||
|
||||
/*
|
||||
* defunct
|
||||
*/
|
||||
epicsShareFunc int epicsShareAPI ca_modify_user_name ( const char *pUserName );
|
||||
epicsShareFunc int epicsShareAPI ca_modify_host_name ( const char *pHostName );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* no additions below this endif
|
||||
*/
|
||||
#endif /* ifndef INCLcadefh */
|
||||
|
||||
160
src/client/caerr.h
Normal file
160
src/client/caerr.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeffrey O. Hill
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLcaerrh
|
||||
#define INCLcaerrh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define INCLcaerrh_accessh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
# include "epicsTypes.h"
|
||||
|
||||
#ifdef INCLcaerrh_accessh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
/* CA Status Code Definitions */
|
||||
|
||||
#define CA_K_INFO 3 /* successful */
|
||||
#define CA_K_ERROR 2 /* failed- continue */
|
||||
#define CA_K_SUCCESS 1 /* successful */
|
||||
#define CA_K_WARNING 0 /* unsuccessful */
|
||||
#define CA_K_SEVERE 4 /* failed- quit */
|
||||
#define CA_K_FATAL CA_K_ERROR | CA_K_SEVERE
|
||||
|
||||
#define CA_M_MSG_NO 0x0000FFF8
|
||||
#define CA_M_SEVERITY 0x00000007
|
||||
#define CA_M_LEVEL 0x00000003
|
||||
#define CA_M_SUCCESS 0x00000001
|
||||
#define CA_M_ERROR 0x00000002
|
||||
#define CA_M_SEVERE 0x00000004
|
||||
|
||||
#define CA_S_MSG_NO 0x0D
|
||||
#define CA_S_SEVERITY 0x03
|
||||
|
||||
#define CA_V_MSG_NO 0x03
|
||||
#define CA_V_SEVERITY 0x00
|
||||
#define CA_V_SUCCESS 0x00
|
||||
|
||||
/* Define MACROS to extract/insert individual fields from a status value */
|
||||
|
||||
#define CA_EXTRACT_MSG_NO(code)\
|
||||
( ( (code) & CA_M_MSG_NO ) >> CA_V_MSG_NO )
|
||||
#define CA_EXTRACT_SEVERITY(code)\
|
||||
( ( (code) & CA_M_SEVERITY ) >> CA_V_SEVERITY )
|
||||
#define CA_EXTRACT_SUCCESS(code)\
|
||||
( ( (code) & CA_M_SUCCESS ) >> CA_V_SUCCESS )
|
||||
|
||||
#define CA_INSERT_MSG_NO(code)\
|
||||
( ((code)<< CA_V_MSG_NO) & CA_M_MSG_NO )
|
||||
#define CA_INSERT_SEVERITY(code)\
|
||||
( ((code)<< CA_V_SEVERITY)& CA_M_SEVERITY )
|
||||
#define CA_INSERT_SUCCESS(code)\
|
||||
( ((code)<< CA_V_SUCCESS) & CA_M_SUCCESS )
|
||||
|
||||
#define DEFMSG(SEVERITY,NUMBER)\
|
||||
(CA_INSERT_MSG_NO(NUMBER) | CA_INSERT_SEVERITY(SEVERITY))
|
||||
|
||||
/*
|
||||
* In the lines below "defunct" indicates that current release
|
||||
* servers and client library will not return this error code, but
|
||||
* servers on earlier releases that communicate with current clients
|
||||
* might still generate exceptions with these error constants
|
||||
*/
|
||||
#define ECA_NORMAL DEFMSG(CA_K_SUCCESS, 0) /* success */
|
||||
#define ECA_MAXIOC DEFMSG(CA_K_ERROR, 1) /* defunct */
|
||||
#define ECA_UKNHOST DEFMSG(CA_K_ERROR, 2) /* defunct */
|
||||
#define ECA_UKNSERV DEFMSG(CA_K_ERROR, 3) /* defunct */
|
||||
#define ECA_SOCK DEFMSG(CA_K_ERROR, 4) /* defunct */
|
||||
#define ECA_CONN DEFMSG(CA_K_WARNING, 5) /* defunct */
|
||||
#define ECA_ALLOCMEM DEFMSG(CA_K_WARNING, 6)
|
||||
#define ECA_UKNCHAN DEFMSG(CA_K_WARNING, 7) /* defunct */
|
||||
#define ECA_UKNFIELD DEFMSG(CA_K_WARNING, 8) /* defunct */
|
||||
#define ECA_TOLARGE DEFMSG(CA_K_WARNING, 9)
|
||||
#define ECA_TIMEOUT DEFMSG(CA_K_WARNING, 10)
|
||||
#define ECA_NOSUPPORT DEFMSG(CA_K_WARNING, 11) /* defunct */
|
||||
#define ECA_STRTOBIG DEFMSG(CA_K_WARNING, 12) /* defunct */
|
||||
#define ECA_DISCONNCHID DEFMSG(CA_K_ERROR, 13) /* defunct */
|
||||
#define ECA_BADTYPE DEFMSG(CA_K_ERROR, 14)
|
||||
#define ECA_CHIDNOTFND DEFMSG(CA_K_INFO, 15) /* defunct */
|
||||
#define ECA_CHIDRETRY DEFMSG(CA_K_INFO, 16) /* defunct */
|
||||
#define ECA_INTERNAL DEFMSG(CA_K_FATAL, 17)
|
||||
#define ECA_DBLCLFAIL DEFMSG(CA_K_WARNING, 18) /* defunct */
|
||||
#define ECA_GETFAIL DEFMSG(CA_K_WARNING, 19)
|
||||
#define ECA_PUTFAIL DEFMSG(CA_K_WARNING, 20)
|
||||
#define ECA_ADDFAIL DEFMSG(CA_K_WARNING, 21) /* defunct */
|
||||
#define ECA_BADCOUNT DEFMSG(CA_K_WARNING, 22)
|
||||
#define ECA_BADSTR DEFMSG(CA_K_ERROR, 23)
|
||||
#define ECA_DISCONN DEFMSG(CA_K_WARNING, 24)
|
||||
#define ECA_DBLCHNL DEFMSG(CA_K_WARNING, 25)
|
||||
#define ECA_EVDISALLOW DEFMSG(CA_K_ERROR, 26)
|
||||
#define ECA_BUILDGET DEFMSG(CA_K_WARNING, 27) /* defunct */
|
||||
#define ECA_NEEDSFP DEFMSG(CA_K_WARNING, 28) /* defunct */
|
||||
#define ECA_OVEVFAIL DEFMSG(CA_K_WARNING, 29) /* defunct */
|
||||
#define ECA_BADMONID DEFMSG(CA_K_ERROR, 30)
|
||||
#define ECA_NEWADDR DEFMSG(CA_K_WARNING, 31) /* defunct */
|
||||
#define ECA_NEWCONN DEFMSG(CA_K_INFO, 32) /* defunct */
|
||||
#define ECA_NOCACTX DEFMSG(CA_K_WARNING, 33) /* defunct */
|
||||
#define ECA_DEFUNCT DEFMSG(CA_K_FATAL, 34) /* defunct */
|
||||
#define ECA_EMPTYSTR DEFMSG(CA_K_WARNING, 35) /* defunct */
|
||||
#define ECA_NOREPEATER DEFMSG(CA_K_WARNING, 36) /* defunct */
|
||||
#define ECA_NOCHANMSG DEFMSG(CA_K_WARNING, 37) /* defunct */
|
||||
#define ECA_DLCKREST DEFMSG(CA_K_WARNING, 38) /* defunct */
|
||||
#define ECA_SERVBEHIND DEFMSG(CA_K_WARNING, 39) /* defunct */
|
||||
#define ECA_NOCAST DEFMSG(CA_K_WARNING, 40) /* defunct */
|
||||
#define ECA_BADMASK DEFMSG(CA_K_ERROR, 41)
|
||||
#define ECA_IODONE DEFMSG(CA_K_INFO, 42)
|
||||
#define ECA_IOINPROGRESS DEFMSG(CA_K_INFO, 43)
|
||||
#define ECA_BADSYNCGRP DEFMSG(CA_K_ERROR, 44)
|
||||
#define ECA_PUTCBINPROG DEFMSG(CA_K_ERROR, 45)
|
||||
#define ECA_NORDACCESS DEFMSG(CA_K_WARNING, 46)
|
||||
#define ECA_NOWTACCESS DEFMSG(CA_K_WARNING, 47)
|
||||
#define ECA_ANACHRONISM DEFMSG(CA_K_ERROR, 48)
|
||||
#define ECA_NOSEARCHADDR DEFMSG(CA_K_WARNING, 49)
|
||||
#define ECA_NOCONVERT DEFMSG(CA_K_WARNING, 50)
|
||||
#define ECA_BADCHID DEFMSG(CA_K_ERROR, 51)
|
||||
#define ECA_BADFUNCPTR DEFMSG(CA_K_ERROR, 52)
|
||||
#define ECA_ISATTACHED DEFMSG(CA_K_WARNING, 53)
|
||||
#define ECA_UNAVAILINSERV DEFMSG(CA_K_WARNING, 54)
|
||||
#define ECA_CHANDESTROY DEFMSG(CA_K_WARNING, 55)
|
||||
#define ECA_BADPRIORITY DEFMSG(CA_K_ERROR, 56)
|
||||
#define ECA_NOTTHREADED DEFMSG(CA_K_ERROR, 57)
|
||||
#define ECA_16KARRAYCLIENT DEFMSG(CA_K_WARNING, 58)
|
||||
#define ECA_CONNSEQTMO DEFMSG(CA_K_WARNING, 59)
|
||||
#define ECA_UNRESPTMO DEFMSG(CA_K_WARNING, 60)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
epicsShareFunc const char * epicsShareAPI ca_message(long ca_status);
|
||||
|
||||
epicsShareExtern const char * ca_message_text [];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
44
src/client/caeventmask.h
Normal file
44
src/client/caeventmask.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef INCLcaeventmaskh
|
||||
#define INCLcaeventmaskh
|
||||
|
||||
/*
|
||||
event selections
|
||||
(If any more than 8 of these are needed then update the
|
||||
select field in the event_block struct in db_event.c from
|
||||
unsigned char to unsigned short)
|
||||
|
||||
|
||||
DBE_VALUE
|
||||
Trigger an event when a significant change in the channel's value
|
||||
occurs. Relies on the monitor deadband field under DCT.
|
||||
|
||||
DBE_ARCHIVE (DBE_LOG)
|
||||
Trigger an event when an archive significant change in the channel's
|
||||
value occurs. Relies on the archiver monitor deadband field under DCT.
|
||||
|
||||
DBE_ALARM
|
||||
Trigger an event when the alarm state changes
|
||||
|
||||
DBE_PROPERTY
|
||||
Trigger an event when a property change (control limit, graphical
|
||||
limit, status string, enum string ...) occurs.
|
||||
|
||||
*/
|
||||
|
||||
#define DBE_VALUE (1<<0)
|
||||
#define DBE_ARCHIVE (1<<1)
|
||||
#define DBE_LOG DBE_ARCHIVE
|
||||
#define DBE_ALARM (1<<2)
|
||||
#define DBE_PROPERTY (1<<3)
|
||||
|
||||
#endif
|
||||
306
src/client/casw.cpp
Normal file
306
src/client/casw.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "envDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "osiWireFormat.h"
|
||||
|
||||
#include "bhe.h"
|
||||
#include "udpiiu.h"
|
||||
#include "inetAddrID.h"
|
||||
|
||||
// using a wrapper class around the free list avoids
|
||||
// Tornado 2.0.1 GNU compiler bugs
|
||||
class bheFreeStoreMgr : public bheMemoryManager {
|
||||
public:
|
||||
bheFreeStoreMgr () {}
|
||||
void * allocate ( size_t );
|
||||
void release ( void * );
|
||||
private:
|
||||
tsFreeList < class bhe, 0x100 > freeList;
|
||||
bheFreeStoreMgr ( const bheFreeStoreMgr & );
|
||||
bheFreeStoreMgr & operator = ( const bheFreeStoreMgr & );
|
||||
};
|
||||
|
||||
void * bheFreeStoreMgr::allocate ( size_t size )
|
||||
{
|
||||
return freeList.allocate ( size );
|
||||
}
|
||||
|
||||
void bheFreeStoreMgr::release ( void * pCadaver )
|
||||
{
|
||||
freeList.release ( pCadaver );
|
||||
}
|
||||
|
||||
int main ( int argc, char ** argv )
|
||||
{
|
||||
epicsMutex mutex;
|
||||
epicsGuard < epicsMutex > guard ( mutex );
|
||||
bheFreeStoreMgr bheFreeList;
|
||||
epicsTime programBeginTime = epicsTime::getCurrent ();
|
||||
bool validCommandLine = false;
|
||||
unsigned interest = 0u;
|
||||
SOCKET sock;
|
||||
osiSockAddr addr;
|
||||
osiSocklen_t addrSize;
|
||||
char buf [0x4000];
|
||||
const char *pCurBuf;
|
||||
const caHdr *pCurMsg;
|
||||
ca_uint16_t serverPort;
|
||||
ca_uint16_t repeaterPort;
|
||||
int status;
|
||||
|
||||
if ( argc == 1 ) {
|
||||
validCommandLine = true;
|
||||
}
|
||||
else if ( argc == 2 ) {
|
||||
status = sscanf ( argv[1], " -i%u ", & interest );
|
||||
if ( status == 1 ) {
|
||||
validCommandLine = true;
|
||||
}
|
||||
}
|
||||
else if ( argc == 3 ) {
|
||||
if ( strcmp ( argv[1], "-i" ) == 0 ) {
|
||||
status = sscanf ( argv[2], " %u ", & interest );
|
||||
if ( status == 1 ) {
|
||||
validCommandLine = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! validCommandLine ) {
|
||||
printf ( "usage: casw <-i interestLevel>\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
serverPort =
|
||||
envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT,
|
||||
static_cast <unsigned short> (CA_SERVER_PORT) );
|
||||
|
||||
repeaterPort =
|
||||
envGetInetPortConfigParam ( &EPICS_CA_REPEATER_PORT,
|
||||
static_cast <unsigned short> (CA_REPEATER_PORT) );
|
||||
|
||||
caStartRepeaterIfNotInstalled ( repeaterPort );
|
||||
|
||||
sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
||||
if ( sock == INVALID_SOCKET ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("casw: unable to create datagram socket because = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset ( (char *) &addr, 0 , sizeof (addr) );
|
||||
addr.ia.sin_family = AF_INET;
|
||||
addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
|
||||
addr.ia.sin_port = htons ( 0 ); // any port
|
||||
status = bind ( sock, &addr.sa, sizeof (addr) );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ( "casw: unable to bind to an unconstrained address because = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
osiSockIoctl_t yes = true;
|
||||
status = socket_ioctl ( sock, FIONBIO, &yes );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ( "casw: unable to set socket to nonblocking state because \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned attemptNumber = 0u;
|
||||
while ( true ) {
|
||||
caRepeaterRegistrationMessage ( sock, repeaterPort, attemptNumber );
|
||||
epicsThreadSleep ( 0.1 );
|
||||
addrSize = ( osiSocklen_t ) sizeof ( addr );
|
||||
status = recvfrom ( sock, buf, sizeof ( buf ), 0,
|
||||
&addr.sa, &addrSize );
|
||||
if ( status >= static_cast <int> ( sizeof ( *pCurMsg ) ) ) {
|
||||
pCurMsg = reinterpret_cast < caHdr * > ( buf );
|
||||
epicsUInt16 cmmd = AlignedWireRef < const epicsUInt16 > ( pCurMsg->m_cmmd );
|
||||
if ( cmmd == REPEATER_CONFIRM ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
attemptNumber++;
|
||||
if ( attemptNumber > 100 ) {
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ( "casw: unable to register with the CA repeater\n" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
osiSockIoctl_t no = false;
|
||||
status = socket_ioctl ( sock, FIONBIO, &no );
|
||||
if ( status < 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ( "casw: unable to set socket to blocking state because \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
resTable < bhe, inetAddrID > beaconTable;
|
||||
while ( true ) {
|
||||
|
||||
addrSize = ( osiSocklen_t ) sizeof ( addr );
|
||||
status = recvfrom ( sock, buf, sizeof ( buf ), 0,
|
||||
&addr.sa, &addrSize );
|
||||
if ( status <= 0 ) {
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
epicsSocketDestroy ( sock );
|
||||
errlogPrintf ("casw: error from recv was = \"%s\"\n",
|
||||
sockErrBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( addr.sa.sa_family != AF_INET ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned byteCount = static_cast <unsigned> ( status );
|
||||
pCurMsg = reinterpret_cast < const caHdr * > ( ( pCurBuf = buf ) );
|
||||
while ( byteCount ) {
|
||||
AlignedWireRef < const epicsUInt16 > pstSize ( pCurMsg->m_postsize );
|
||||
size_t msgSize = pstSize + sizeof ( *pCurMsg ) ;
|
||||
if ( msgSize > byteCount ) {
|
||||
errlogPrintf ( "CASW: udp input protocol violation\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
epicsUInt16 cmmd = AlignedWireRef < const epicsUInt16 > ( pCurMsg->m_cmmd );
|
||||
if ( cmmd == CA_PROTO_RSRV_IS_UP ) {
|
||||
bool anomaly = false;
|
||||
epicsTime previousTime;
|
||||
struct sockaddr_in ina;
|
||||
|
||||
/*
|
||||
* this allows a fan-out server to potentially
|
||||
* insert the true address of the CA server
|
||||
*
|
||||
* old servers:
|
||||
* 1) set this field to one of the ip addresses of the host _or_
|
||||
* 2) set this field to INADDR_ANY
|
||||
* new servers:
|
||||
* always set this field to INADDR_ANY
|
||||
*
|
||||
* clients always assume that if this
|
||||
* field is set to something that isnt INADDR_ANY
|
||||
* then it is the overriding IP address of the server.
|
||||
*/
|
||||
ina.sin_family = AF_INET;
|
||||
ina.sin_addr.s_addr = pCurMsg->m_available;
|
||||
|
||||
if ( pCurMsg->m_count != 0 ) {
|
||||
ina.sin_port = pCurMsg->m_count;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* old servers dont supply this and the
|
||||
* default port must be assumed
|
||||
*/
|
||||
ina.sin_port = htons ( serverPort );
|
||||
}
|
||||
|
||||
ca_uint32_t beaconNumber = ntohl ( pCurMsg->m_cid );
|
||||
unsigned protocolRevision = ntohs ( pCurMsg->m_dataType );
|
||||
|
||||
epicsTime currentTime = epicsTime::getCurrent();
|
||||
|
||||
/*
|
||||
* look for it in the hash table
|
||||
*/
|
||||
bhe *pBHE = beaconTable.lookup ( ina );
|
||||
if ( pBHE ) {
|
||||
previousTime = pBHE->updateTime ( guard );
|
||||
anomaly = pBHE->updatePeriod (
|
||||
guard, programBeginTime,
|
||||
currentTime, beaconNumber, protocolRevision );
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* This is the first beacon seen from this server.
|
||||
* Wait until 2nd beacon is seen before deciding
|
||||
* if it is a new server (or just the first
|
||||
* time that we have seen a server's beacon
|
||||
* shortly after the program started up)
|
||||
*/
|
||||
pBHE = new ( bheFreeList )
|
||||
bhe ( mutex, currentTime, beaconNumber, ina );
|
||||
if ( pBHE ) {
|
||||
if ( beaconTable.add ( *pBHE ) < 0 ) {
|
||||
pBHE->~bhe ();
|
||||
bheFreeList.release ( pBHE );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( anomaly || interest > 1 ) {
|
||||
char date[64];
|
||||
currentTime.strftime ( date, sizeof ( date ),
|
||||
"%Y-%m-%d %H:%M:%S.%09f");
|
||||
char host[64];
|
||||
ipAddrToA ( &ina, host, sizeof ( host ) );
|
||||
const char * pPrefix = "";
|
||||
if ( interest > 1 ) {
|
||||
if ( anomaly ) {
|
||||
pPrefix = "* ";
|
||||
}
|
||||
else {
|
||||
pPrefix = " ";
|
||||
}
|
||||
}
|
||||
printf ( "%s%-40s %s\n",
|
||||
pPrefix, host, date );
|
||||
if ( anomaly && interest > 0 ) {
|
||||
printf ( "\testimate=%f current=%f\n",
|
||||
pBHE->period ( guard ),
|
||||
currentTime - previousTime );
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
pCurBuf += msgSize;
|
||||
pCurMsg = reinterpret_cast < const caHdr * > ( pCurBuf );
|
||||
byteCount -= msgSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
685
src/client/catime.c
Normal file
685
src/client/catime.c
Normal file
@@ -0,0 +1,685 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
* CA performance test
|
||||
*
|
||||
* History
|
||||
* joh 09-12-89 Initial release
|
||||
* joh 12-20-94 portability
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsTime.h"
|
||||
#include "cadef.h"
|
||||
#include "caProto.h"
|
||||
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#define WAIT_FOR_ACK
|
||||
|
||||
typedef struct testItem {
|
||||
chid chix;
|
||||
char name[128];
|
||||
int type;
|
||||
int count;
|
||||
void * pValue;
|
||||
} ti;
|
||||
|
||||
typedef void tf ( ti *pItems, unsigned iterations, unsigned *pInlineIter );
|
||||
|
||||
/*
|
||||
* test_pend()
|
||||
*/
|
||||
static void test_pend(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
unsigned i;
|
||||
int status;
|
||||
|
||||
for (i=0; i<iterations; i++) {
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
status = ca_pend_event(1e-9);
|
||||
if (status != ECA_TIMEOUT && status != ECA_NORMAL) {
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
}
|
||||
*pInlineIter = 5;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_search ()
|
||||
*/
|
||||
static void test_search (
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
unsigned i;
|
||||
int status;
|
||||
|
||||
for ( i = 0u; i < iterations; i++ ) {
|
||||
status = ca_search ( pItems[i].name, &pItems[i].chix );
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
status = ca_pend_io ( 0.0 );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
*pInlineIter = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_sync_search()
|
||||
*/
|
||||
#if 0
|
||||
static void test_sync_search(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
unsigned i;
|
||||
int status;
|
||||
|
||||
for (i=0u; i<iterations; i++) {
|
||||
status = ca_search (pItems[i].name, &pItems[i].chix);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_pend_io(0.0);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
|
||||
*pInlineIter = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* test_free ()
|
||||
*/
|
||||
static void test_free(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
int status;
|
||||
unsigned i;
|
||||
|
||||
for (i=0u; i<iterations; i++) {
|
||||
status = ca_clear_channel (pItems[i].chix);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
status = ca_flush_io();
|
||||
SEVCHK (status, NULL);
|
||||
*pInlineIter = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_put ()
|
||||
*/
|
||||
static void test_put(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
ti *pi;
|
||||
int status;
|
||||
dbr_int_t val;
|
||||
|
||||
for (pi=pItems; pi < &pItems[iterations]; pi++) {
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_put(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
#ifdef WAIT_FOR_ACK
|
||||
status = ca_array_get (DBR_INT, 1, pItems[0].chix, &val);
|
||||
SEVCHK (status, NULL);
|
||||
ca_pend_io(100.0);
|
||||
#endif
|
||||
status = ca_array_put(
|
||||
pItems[0].type,
|
||||
pItems[0].count,
|
||||
pItems[0].chix,
|
||||
pItems[0].pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_flush_io();
|
||||
SEVCHK (status, NULL);
|
||||
|
||||
*pInlineIter = 10;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_get ()
|
||||
*/
|
||||
static void test_get(
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
ti *pi;
|
||||
int status;
|
||||
|
||||
for (pi=pItems; pi<&pItems[iterations]; pi++) {
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
status = ca_pend_io(1e20);
|
||||
SEVCHK (status, NULL);
|
||||
|
||||
*pInlineIter = 10;
|
||||
}
|
||||
|
||||
/*
|
||||
* test_wait ()
|
||||
*/
|
||||
static void test_wait (
|
||||
ti *pItems,
|
||||
unsigned iterations,
|
||||
unsigned *pInlineIter
|
||||
)
|
||||
{
|
||||
ti *pi;
|
||||
int status;
|
||||
|
||||
for (pi=pItems; pi<&pItems[iterations]; pi++) {
|
||||
status = ca_array_get(
|
||||
pi->type,
|
||||
pi->count,
|
||||
pi->chix,
|
||||
pi->pValue);
|
||||
SEVCHK (status, NULL);
|
||||
status = ca_pend_io(100.0);
|
||||
SEVCHK (status, NULL);
|
||||
}
|
||||
|
||||
*pInlineIter = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* measure_get_latency
|
||||
*/
|
||||
static void measure_get_latency (ti *pItems, unsigned iterations)
|
||||
{
|
||||
epicsTimeStamp end_time;
|
||||
epicsTimeStamp start_time;
|
||||
double delay;
|
||||
double X = 0u;
|
||||
double XX = 0u;
|
||||
double max = DBL_MIN;
|
||||
double min = DBL_MAX;
|
||||
double mean;
|
||||
double stdDev;
|
||||
ti *pi;
|
||||
int status;
|
||||
|
||||
for ( pi = pItems; pi < &pItems[iterations]; pi++ ) {
|
||||
epicsTimeGetCurrent ( &start_time );
|
||||
status = ca_array_get ( pi->type, pi->count,
|
||||
pi->chix, pi->pValue );
|
||||
SEVCHK ( status, NULL );
|
||||
status = ca_pend_io ( 100.0 );
|
||||
SEVCHK ( status, NULL );
|
||||
|
||||
epicsTimeGetCurrent ( &end_time );
|
||||
|
||||
delay = epicsTimeDiffInSeconds ( &end_time,&start_time );
|
||||
|
||||
X += delay;
|
||||
XX += delay*delay;
|
||||
|
||||
if ( delay > max ) {
|
||||
max = delay;
|
||||
}
|
||||
|
||||
if ( delay < min ) {
|
||||
min = delay;
|
||||
}
|
||||
}
|
||||
|
||||
mean = X/iterations;
|
||||
stdDev = sqrt ( XX/iterations - mean*mean );
|
||||
printf (
|
||||
"Get Latency - "
|
||||
"mean = %3.1f uS, "
|
||||
"std dev = %3.1f uS, "
|
||||
"min = %3.1f uS "
|
||||
"max = %3.1f uS\n",
|
||||
mean * 1e6, stdDev * 1e6,
|
||||
min * 1e6, max * 1e6 );
|
||||
}
|
||||
|
||||
/*
|
||||
* printSearchStat()
|
||||
*/
|
||||
static void printSearchStat ( const ti * pi, unsigned iterations )
|
||||
{
|
||||
unsigned i;
|
||||
double X = 0u;
|
||||
double XX = 0u;
|
||||
double max = DBL_MIN;
|
||||
double min = DBL_MAX;
|
||||
double mean;
|
||||
double stdDev;
|
||||
|
||||
for ( i = 0; i < iterations; i++ ) {
|
||||
double retry = ca_search_attempts ( pi[i].chix );
|
||||
X += retry;
|
||||
XX += retry * retry;
|
||||
if ( retry > max ) {
|
||||
max = retry;
|
||||
}
|
||||
if ( retry < min ) {
|
||||
min = retry;
|
||||
}
|
||||
}
|
||||
|
||||
mean = X / iterations;
|
||||
stdDev = sqrt( XX / iterations - mean * mean );
|
||||
printf (
|
||||
"Search tries per chan - "
|
||||
"mean = %3.1f "
|
||||
"std dev = %3.1f "
|
||||
"min = %3.1f "
|
||||
"max = %3.1f\n",
|
||||
mean, stdDev, min, max);
|
||||
}
|
||||
|
||||
/*
|
||||
* timeIt ()
|
||||
*/
|
||||
void timeIt ( tf *pfunc, ti *pItems, unsigned iterations,
|
||||
unsigned nBytesSent, unsigned nBytesRecv )
|
||||
{
|
||||
epicsTimeStamp end_time;
|
||||
epicsTimeStamp start_time;
|
||||
double delay;
|
||||
unsigned inlineIter;
|
||||
|
||||
epicsTimeGetCurrent ( &start_time );
|
||||
(*pfunc) ( pItems, iterations, &inlineIter );
|
||||
epicsTimeGetCurrent ( &end_time );
|
||||
delay = epicsTimeDiffInSeconds ( &end_time, &start_time );
|
||||
if ( delay > 0.0 ) {
|
||||
double freq = ( iterations * inlineIter ) / delay;
|
||||
printf ( "Per Op, %8.4f uS ( %8.4f MHz )",
|
||||
1e6 / freq, freq / 1e6 );
|
||||
if ( pItems != NULL ) {
|
||||
printf(", %8.4f snd Mbps, %8.4f rcv Mbps\n",
|
||||
(inlineIter*nBytesSent*CHAR_BIT)/(delay*1e6),
|
||||
(inlineIter*nBytesRecv*CHAR_BIT)/(delay*1e6) );
|
||||
}
|
||||
else {
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* test ()
|
||||
*/
|
||||
static void test ( ti *pItems, unsigned iterations )
|
||||
{
|
||||
unsigned payloadSize, dblPayloadSize;
|
||||
unsigned nBytesSent, nBytesRecv;
|
||||
|
||||
payloadSize =
|
||||
dbr_size_n ( pItems[0].type, pItems[0].count );
|
||||
payloadSize = CA_MESSAGE_ALIGN ( payloadSize );
|
||||
|
||||
dblPayloadSize = dbr_size [ DBR_DOUBLE ];
|
||||
dblPayloadSize = CA_MESSAGE_ALIGN ( dblPayloadSize );
|
||||
|
||||
if ( payloadSize > dblPayloadSize ) {
|
||||
unsigned factor = payloadSize / dblPayloadSize;
|
||||
while ( factor ) {
|
||||
if ( iterations > 10 * factor ) {
|
||||
iterations /= factor;
|
||||
break;
|
||||
}
|
||||
factor /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
printf ( "\t### async put test ###\n");
|
||||
nBytesSent = sizeof ( caHdr ) + CA_MESSAGE_ALIGN( payloadSize );
|
||||
nBytesRecv = 0u;
|
||||
timeIt ( test_put, pItems, iterations,
|
||||
nBytesSent * iterations,
|
||||
nBytesRecv * iterations );
|
||||
|
||||
printf ( "\t### async get test ###\n");
|
||||
nBytesSent = sizeof ( caHdr );
|
||||
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
|
||||
timeIt ( test_get, pItems, iterations,
|
||||
nBytesSent * ( iterations ),
|
||||
nBytesRecv * ( iterations ) );
|
||||
|
||||
printf ("\t### synch get test ###\n");
|
||||
nBytesSent = sizeof ( caHdr );
|
||||
nBytesRecv = sizeof ( caHdr ) + CA_MESSAGE_ALIGN ( payloadSize );
|
||||
if ( iterations > 100 ) {
|
||||
iterations /= 100;
|
||||
}
|
||||
else if ( iterations > 10 ) {
|
||||
iterations /= 10;
|
||||
}
|
||||
timeIt ( test_wait, pItems, iterations,
|
||||
nBytesSent * iterations,
|
||||
nBytesRecv * iterations );
|
||||
}
|
||||
|
||||
/*
|
||||
* catime ()
|
||||
*/
|
||||
int catime ( const char * channelName,
|
||||
unsigned channelCount, enum appendNumberFlag appNF )
|
||||
{
|
||||
unsigned i;
|
||||
int j;
|
||||
unsigned strsize;
|
||||
unsigned nBytesSent, nBytesRecv;
|
||||
ti *pItemList;
|
||||
|
||||
if ( channelCount == 0 ) {
|
||||
printf ( "channel count was zero\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
pItemList = calloc ( channelCount, sizeof (ti) );
|
||||
if ( ! pItemList ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SEVCHK ( ca_context_create ( ca_disable_preemptive_callback ),
|
||||
"Unable to initialize" );
|
||||
|
||||
if ( appNF == appendNumber ) {
|
||||
printf ( "Testing with %u channels named %snnn\n",
|
||||
channelCount, channelName );
|
||||
}
|
||||
else {
|
||||
printf ( "Testing with %u channels named %s\n",
|
||||
channelCount, channelName );
|
||||
}
|
||||
|
||||
strsize = sizeof ( pItemList[0].name ) - 1;
|
||||
nBytesSent = 0;
|
||||
nBytesRecv = 0;
|
||||
for ( i=0; i < channelCount; i++ ) {
|
||||
if ( appNF == appendNumber ) {
|
||||
sprintf ( pItemList[i].name,"%.*s%.6u",
|
||||
(int) (strsize - 15u), channelName, i );
|
||||
}
|
||||
else {
|
||||
strncpy ( pItemList[i].name, channelName, strsize);
|
||||
}
|
||||
pItemList[i].name[strsize]= '\0';
|
||||
pItemList[i].count = 0;
|
||||
pItemList[i].pValue = 0;
|
||||
nBytesSent += 2 * ( CA_MESSAGE_ALIGN ( strlen ( pItemList[i].name ) )
|
||||
+ sizeof (caHdr) );
|
||||
nBytesRecv += 2 * sizeof (caHdr);
|
||||
}
|
||||
|
||||
printf ( "Channel Connect Test\n" );
|
||||
printf ( "--------------------\n" );
|
||||
timeIt ( test_search, pItemList, channelCount, nBytesSent, nBytesRecv );
|
||||
printSearchStat ( pItemList, channelCount );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
size_t count = ca_element_count ( pItemList[i].chix );
|
||||
size_t size = sizeof ( dbr_string_t ) * count;
|
||||
pItemList[i].count = count;
|
||||
pItemList[i].pValue = malloc ( size );
|
||||
assert ( pItemList[i].pValue );
|
||||
}
|
||||
|
||||
printf (
|
||||
"channel name=%s, native type=%d, native count=%u\n",
|
||||
ca_name (pItemList[0].chix),
|
||||
ca_field_type (pItemList[0].chix),
|
||||
pItemList[0].count );
|
||||
|
||||
printf ("Pend Event Test\n");
|
||||
printf ( "----------------\n" );
|
||||
timeIt ( test_pend, NULL, 100, 0, 0 );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_float_t * pFltVal = ( dbr_float_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pFltVal[j] = (dbr_float_t) val;
|
||||
}
|
||||
pItemList[i].type = DBR_FLOAT;
|
||||
}
|
||||
printf ( "DBR_FLOAT Test\n" );
|
||||
printf ( "--------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pDblVal[j] = (dbr_double_t) val;
|
||||
}
|
||||
pItemList[i].type = DBR_DOUBLE;
|
||||
}
|
||||
printf ( "DBR_DOUBLE Test\n" );
|
||||
printf ( "---------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_string_t * pStrVal = ( dbr_string_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
sprintf ( pStrVal[j], "%f", val );
|
||||
}
|
||||
pItemList[i].type = DBR_STRING;
|
||||
}
|
||||
printf ( "DBR_STRING Test\n" );
|
||||
printf ( "---------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_int_t * pIntVal = ( dbr_int_t * ) pItemList[i].pValue;
|
||||
double val = i;
|
||||
val /= channelCount;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pIntVal[j] = (dbr_int_t) val;
|
||||
}
|
||||
pItemList[i].type = DBR_INT;
|
||||
}
|
||||
printf ( "DBR_INT Test\n" );
|
||||
printf ( "------------\n" );
|
||||
test ( pItemList, channelCount );
|
||||
|
||||
printf ( "Get Latency Test\n" );
|
||||
printf ( "----------------\n" );
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
dbr_double_t * pDblVal = ( dbr_double_t * ) pItemList[i].pValue;
|
||||
for ( j = 0; j < pItemList[i].count; j++ ) {
|
||||
pDblVal[j] = 0;
|
||||
}
|
||||
pItemList[i].type = DBR_DOUBLE;
|
||||
}
|
||||
measure_get_latency ( pItemList, channelCount );
|
||||
|
||||
printf ( "Free Channel Test\n" );
|
||||
printf ( "-----------------\n" );
|
||||
timeIt ( test_free, pItemList, channelCount, 0, 0 );
|
||||
|
||||
SEVCHK ( ca_task_exit (), "Unable to free resources at exit" );
|
||||
|
||||
for ( i = 0; i < channelCount; i++ ) {
|
||||
free ( pItemList[i].pValue );
|
||||
}
|
||||
|
||||
free ( pItemList );
|
||||
|
||||
return CATIME_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
53
src/client/catimeMain.c
Normal file
53
src/client/catimeMain.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "caDiagnostics.h"
|
||||
|
||||
static const unsigned defaultIterations = 10000u;
|
||||
|
||||
int main ( int argc, char **argv )
|
||||
{
|
||||
const char *pUsage = "<PV name> [<channel count> [<append number to pv name if true>]]";
|
||||
|
||||
if ( argc > 1 ) {
|
||||
char *pname = argv[1];
|
||||
if ( argc > 2 ) {
|
||||
int iterations = atoi (argv[2]);
|
||||
if ( iterations > 0) {
|
||||
if ( argc > 3 ) {
|
||||
if ( argc == 4 ) {
|
||||
int status;
|
||||
unsigned appendNumberBool;
|
||||
status = sscanf ( argv[3], " %u ", &appendNumberBool );
|
||||
if ( status == 1 ) {
|
||||
if ( appendNumberBool ) {
|
||||
return catime ( pname, (unsigned) iterations, appendNumber );
|
||||
}
|
||||
else {
|
||||
return catime ( pname, (unsigned) iterations, dontAppendNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return catime ( pname, (unsigned) iterations, dontAppendNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return catime ( pname, defaultIterations, dontAppendNumber );
|
||||
}
|
||||
}
|
||||
printf ( "usage: %s %s\n", argv[0], pUsage);
|
||||
return -1;
|
||||
}
|
||||
66
src/client/comBuf.cpp
Normal file
66
src/client/comBuf.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "comBuf.h"
|
||||
#include "errlog.h"
|
||||
|
||||
bool comBuf::flushToWire ( wireSendAdapter & wire, const epicsTime & currentTime )
|
||||
{
|
||||
unsigned index = this->nextReadIndex;
|
||||
unsigned finalIndex = this->commitIndex;
|
||||
while ( index < finalIndex ) {
|
||||
unsigned nBytes = wire.sendBytes (
|
||||
&this->buf[index], finalIndex - index, currentTime );
|
||||
if ( nBytes == 0u ) {
|
||||
this->nextReadIndex = index;
|
||||
return false;
|
||||
}
|
||||
index += nBytes;
|
||||
}
|
||||
this->nextReadIndex = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
// throwing the exception from a function that isnt inline
|
||||
// shrinks the GNU compiled object code
|
||||
void comBuf::throwInsufficentBytesException ()
|
||||
{
|
||||
throw comBuf::insufficentBytesAvailable ();
|
||||
}
|
||||
|
||||
void comBuf::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
comBufMemoryManager::~comBufMemoryManager () {}
|
||||
335
src/client/comBuf.h
Normal file
335
src/client/comBuf.h
Normal file
@@ -0,0 +1,335 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
#ifndef comBufh
|
||||
#define comBufh
|
||||
|
||||
#include <new>
|
||||
#include <cstring>
|
||||
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsTypes.h"
|
||||
#include "tsFreeList.h"
|
||||
#include "tsDLList.h"
|
||||
#include "osiWireFormat.h"
|
||||
#include "compilerDependencies.h"
|
||||
|
||||
static const unsigned comBufSize = 0x4000;
|
||||
|
||||
// this wrapper avoids Tornado 2.0.1 compiler bugs
|
||||
class comBufMemoryManager {
|
||||
public:
|
||||
virtual ~comBufMemoryManager ();
|
||||
virtual void * allocate ( size_t ) = 0;
|
||||
virtual void release ( void * ) = 0;
|
||||
};
|
||||
|
||||
class wireSendAdapter {
|
||||
public:
|
||||
virtual unsigned sendBytes ( const void * pBuf,
|
||||
unsigned nBytesInBuf,
|
||||
const class epicsTime & currentTime ) = 0;
|
||||
protected:
|
||||
virtual ~wireSendAdapter() {}
|
||||
};
|
||||
|
||||
enum swioCircuitState {
|
||||
swioConnected,
|
||||
swioPeerHangup,
|
||||
swioPeerAbort,
|
||||
swioLinkFailure,
|
||||
swioLocalAbort
|
||||
};
|
||||
struct statusWireIO {
|
||||
unsigned bytesCopied;
|
||||
swioCircuitState circuitState;
|
||||
};
|
||||
|
||||
class wireRecvAdapter {
|
||||
public:
|
||||
virtual void recvBytes ( void * pBuf,
|
||||
unsigned nBytesInBuf, statusWireIO & ) = 0;
|
||||
protected:
|
||||
virtual ~wireRecvAdapter() {}
|
||||
};
|
||||
|
||||
class comBuf : public tsDLNode < comBuf > {
|
||||
public:
|
||||
class insufficentBytesAvailable {};
|
||||
comBuf ();
|
||||
unsigned unoccupiedBytes () const;
|
||||
unsigned occupiedBytes () const;
|
||||
unsigned uncommittedBytes () const;
|
||||
static unsigned capacityBytes ();
|
||||
void clear ();
|
||||
unsigned copyInBytes ( const void *pBuf, unsigned nBytes );
|
||||
unsigned push ( comBuf & );
|
||||
template < class T >
|
||||
bool push ( const T & value );
|
||||
template < class T >
|
||||
unsigned push ( const T * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsInt8 * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsUInt8 * pValue, unsigned nElem );
|
||||
unsigned push ( const epicsOldString * pValue, unsigned nElem );
|
||||
void commitIncomming ();
|
||||
void clearUncommittedIncomming ();
|
||||
bool copyInAllBytes ( const void *pBuf, unsigned nBytes );
|
||||
unsigned copyOutBytes ( void *pBuf, unsigned nBytes );
|
||||
bool copyOutAllBytes ( void *pBuf, unsigned nBytes );
|
||||
unsigned removeBytes ( unsigned nBytes );
|
||||
bool flushToWire ( wireSendAdapter &, const epicsTime & currentTime );
|
||||
void fillFromWire ( wireRecvAdapter &, statusWireIO & );
|
||||
struct popStatus {
|
||||
bool success;
|
||||
bool nowEmpty;
|
||||
};
|
||||
template < class T >
|
||||
popStatus pop ( T & );
|
||||
static void throwInsufficentBytesException ();
|
||||
void * operator new ( size_t size,
|
||||
comBufMemoryManager & );
|
||||
epicsPlacementDeleteOperator (( void *, comBufMemoryManager & ))
|
||||
private:
|
||||
unsigned commitIndex;
|
||||
unsigned nextWriteIndex;
|
||||
unsigned nextReadIndex;
|
||||
epicsUInt8 buf [ comBufSize ];
|
||||
void operator delete ( void * );
|
||||
template < class T >
|
||||
bool push ( const T * ); // disabled
|
||||
};
|
||||
|
||||
inline void * comBuf::operator new ( size_t size,
|
||||
comBufMemoryManager & mgr )
|
||||
{
|
||||
return mgr.allocate ( size );
|
||||
}
|
||||
|
||||
#ifdef CXX_PLACEMENT_DELETE
|
||||
inline void comBuf::operator delete ( void * pCadaver,
|
||||
comBufMemoryManager & mgr )
|
||||
{
|
||||
mgr.release ( pCadaver );
|
||||
}
|
||||
#endif
|
||||
|
||||
inline comBuf::comBuf () : commitIndex ( 0u ),
|
||||
nextWriteIndex ( 0u ), nextReadIndex ( 0u )
|
||||
{
|
||||
}
|
||||
|
||||
inline void comBuf :: clear ()
|
||||
{
|
||||
this->commitIndex = 0u;
|
||||
this->nextWriteIndex = 0u;
|
||||
this->nextReadIndex = 0u;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: unoccupiedBytes () const
|
||||
{
|
||||
return sizeof ( this->buf ) - this->nextWriteIndex;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: occupiedBytes () const
|
||||
{
|
||||
return this->commitIndex - this->nextReadIndex;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: uncommittedBytes () const
|
||||
{
|
||||
return this->nextWriteIndex - this->commitIndex;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( comBuf & bufIn )
|
||||
{
|
||||
unsigned nBytes = this->copyInBytes (
|
||||
& bufIn.buf[ bufIn.nextReadIndex ],
|
||||
bufIn.commitIndex - bufIn.nextReadIndex );
|
||||
bufIn.nextReadIndex += nBytes;
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: capacityBytes ()
|
||||
{
|
||||
return comBufSize;
|
||||
}
|
||||
|
||||
inline void comBuf :: fillFromWire (
|
||||
wireRecvAdapter & wire, statusWireIO & stat )
|
||||
{
|
||||
wire.recvBytes (
|
||||
& this->buf[this->nextWriteIndex],
|
||||
sizeof ( this->buf ) - this->nextWriteIndex, stat );
|
||||
if ( stat.circuitState == swioConnected ) {
|
||||
this->nextWriteIndex += stat.bytesCopied;
|
||||
}
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline bool comBuf :: push ( const T & value )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
if ( sizeof ( value ) > available ) {
|
||||
return false;
|
||||
}
|
||||
WireSet ( value, & this->buf[index] );
|
||||
this->nextWriteIndex = index + sizeof ( value );
|
||||
return true;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const epicsInt8 *pValue, unsigned nElem )
|
||||
{
|
||||
return copyInBytes ( pValue, nElem );
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const epicsUInt8 *pValue, unsigned nElem )
|
||||
{
|
||||
return copyInBytes ( pValue, nElem );
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: push ( const epicsOldString * pValue, unsigned nElem )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
unsigned nBytes = sizeof ( *pValue ) * nElem;
|
||||
if ( nBytes > available ) {
|
||||
nElem = available / sizeof ( *pValue );
|
||||
nBytes = nElem * sizeof ( *pValue );
|
||||
}
|
||||
memcpy ( &this->buf[ index ], pValue, nBytes );
|
||||
this->nextWriteIndex = index + nBytes;
|
||||
return nElem;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
unsigned comBuf :: push ( const T * pValue, unsigned nElem )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
unsigned nBytes = sizeof ( *pValue ) * nElem;
|
||||
if ( nBytes > available ) {
|
||||
nElem = available / sizeof ( *pValue );
|
||||
}
|
||||
for ( unsigned i = 0u; i < nElem; i++ ) {
|
||||
// allow native floating point formats to be converted to IEEE
|
||||
WireSet( pValue[i], &this->buf[index] );
|
||||
index += sizeof ( *pValue );
|
||||
}
|
||||
this->nextWriteIndex = index;
|
||||
return nElem;
|
||||
}
|
||||
|
||||
inline void comBuf :: commitIncomming ()
|
||||
{
|
||||
this->commitIndex = this->nextWriteIndex;
|
||||
}
|
||||
|
||||
inline void comBuf :: clearUncommittedIncomming ()
|
||||
{
|
||||
this->nextWriteIndex = this->commitIndex;
|
||||
}
|
||||
|
||||
inline bool comBuf :: copyInAllBytes ( const void *pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
if ( nBytes <= available ) {
|
||||
memcpy ( & this->buf[index], pBuf, nBytes );
|
||||
this->nextWriteIndex = index + nBytes;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: copyInBytes ( const void * pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextWriteIndex;
|
||||
unsigned available = sizeof ( this->buf ) - index;
|
||||
if ( nBytes > available ) {
|
||||
nBytes = available;
|
||||
}
|
||||
memcpy ( & this->buf[index], pBuf, nBytes );
|
||||
this->nextWriteIndex = index + nBytes;
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
inline bool comBuf :: copyOutAllBytes ( void * pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextReadIndex;
|
||||
unsigned occupied = this->commitIndex - index;
|
||||
if ( nBytes <= occupied ) {
|
||||
memcpy ( pBuf, &this->buf[index], nBytes);
|
||||
this->nextReadIndex = index + nBytes;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: copyOutBytes ( void *pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextReadIndex;
|
||||
unsigned occupied = this->commitIndex - index;
|
||||
if ( nBytes > occupied ) {
|
||||
nBytes = occupied;
|
||||
}
|
||||
memcpy ( pBuf, &this->buf[index], nBytes);
|
||||
this->nextReadIndex = index + nBytes;
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
inline unsigned comBuf :: removeBytes ( unsigned nBytes )
|
||||
{
|
||||
unsigned index = this->nextReadIndex;
|
||||
unsigned occupied = this->commitIndex - index;
|
||||
if ( nBytes > occupied ) {
|
||||
nBytes = occupied;
|
||||
}
|
||||
this->nextReadIndex = index + nBytes;
|
||||
return nBytes;
|
||||
}
|
||||
|
||||
template < class T >
|
||||
comBuf :: popStatus comBuf :: pop ( T & returnVal )
|
||||
{
|
||||
unsigned nrIndex = this->nextReadIndex;
|
||||
unsigned popIndex = nrIndex + sizeof ( returnVal );
|
||||
unsigned cIndex = this->commitIndex;
|
||||
popStatus status;
|
||||
status.success = true;
|
||||
status.nowEmpty = false;
|
||||
if ( popIndex >= cIndex ) {
|
||||
if ( popIndex == cIndex ) {
|
||||
status.nowEmpty = true;
|
||||
}
|
||||
else {
|
||||
status.success = false;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
WireGet ( & this->buf[ nrIndex ], returnVal );
|
||||
this->nextReadIndex = popIndex;
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif // ifndef comBufh
|
||||
269
src/client/comQueRecv.cpp
Normal file
269
src/client/comQueRecv.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include "iocinf.h"
|
||||
#include "virtualCircuit.h"
|
||||
|
||||
comQueRecv::comQueRecv ( comBufMemoryManager & comBufMemoryManagerIn ):
|
||||
comBufMemMgr ( comBufMemoryManagerIn ), nBytesPending ( 0u )
|
||||
{
|
||||
}
|
||||
|
||||
comQueRecv::~comQueRecv ()
|
||||
{
|
||||
this->clear ();
|
||||
}
|
||||
|
||||
void comQueRecv::clear ()
|
||||
{
|
||||
comBuf *pBuf;
|
||||
while ( ( pBuf = this->bufs.get () ) ) {
|
||||
pBuf->~comBuf ();
|
||||
this->comBufMemMgr.release ( pBuf );
|
||||
}
|
||||
this->nBytesPending = 0u;
|
||||
}
|
||||
|
||||
unsigned comQueRecv::copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes )
|
||||
{
|
||||
unsigned totalBytes = 0u;
|
||||
do {
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
this->nBytesPending -= totalBytes;
|
||||
return totalBytes;
|
||||
}
|
||||
totalBytes += pComBuf->copyOutBytes ( &pBuf[totalBytes], nBytes - totalBytes );
|
||||
if ( pComBuf->occupiedBytes () == 0u ) {
|
||||
this->bufs.remove ( *pComBuf );
|
||||
pComBuf->~comBuf ();
|
||||
this->comBufMemMgr.release ( pComBuf );
|
||||
}
|
||||
}
|
||||
while ( totalBytes < nBytes );
|
||||
this->nBytesPending -= totalBytes;
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
unsigned comQueRecv::removeBytes ( unsigned nBytes )
|
||||
{
|
||||
unsigned totalBytes = 0u;
|
||||
unsigned bytesLeft = nBytes;
|
||||
while ( bytesLeft ) {
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
this->nBytesPending -= totalBytes;
|
||||
return totalBytes;
|
||||
}
|
||||
unsigned nBytesThisTime = pComBuf->removeBytes ( bytesLeft );
|
||||
if ( pComBuf->occupiedBytes () == 0u ) {
|
||||
this->bufs.remove ( *pComBuf );
|
||||
pComBuf->~comBuf ();
|
||||
this->comBufMemMgr.release ( pComBuf );
|
||||
}
|
||||
if ( nBytesThisTime == 0u) {
|
||||
break;
|
||||
}
|
||||
totalBytes += nBytesThisTime;
|
||||
bytesLeft = nBytes - totalBytes;
|
||||
}
|
||||
this->nBytesPending -= totalBytes;
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
void comQueRecv::popString ( epicsOldString *pStr )
|
||||
{
|
||||
for ( unsigned i = 0u; i < sizeof ( *pStr ); i++ ) {
|
||||
pStr[0][i] = this->popInt8 ();
|
||||
}
|
||||
}
|
||||
|
||||
void comQueRecv::pushLastComBufReceived ( comBuf & bufIn )
|
||||
|
||||
{
|
||||
bufIn.commitIncomming ();
|
||||
comBuf * pComBuf = this->bufs.last ();
|
||||
if ( pComBuf ) {
|
||||
if ( pComBuf->unoccupiedBytes() ) {
|
||||
this->nBytesPending += pComBuf->push ( bufIn );
|
||||
pComBuf->commitIncomming ();
|
||||
}
|
||||
}
|
||||
unsigned bufBytes = bufIn.occupiedBytes();
|
||||
if ( bufBytes ) {
|
||||
this->nBytesPending += bufBytes;
|
||||
this->bufs.add ( bufIn );
|
||||
}
|
||||
else {
|
||||
bufIn.~comBuf ();
|
||||
this->comBufMemMgr.release ( & bufIn );
|
||||
}
|
||||
}
|
||||
|
||||
// 1) split between buffers expected to run slower
|
||||
// 2) using canonical unsigned tmp avoids ANSI C conversions to int
|
||||
// 3) cast required because sizeof(unsigned) >= sizeof(epicsUInt32)
|
||||
epicsUInt16 comQueRecv::multiBufferPopUInt16 ()
|
||||
{
|
||||
epicsUInt16 tmp;
|
||||
if ( this->occupiedBytes() >= sizeof (tmp) ) {
|
||||
unsigned byte1 = this->popUInt8 ();
|
||||
unsigned byte2 = this->popUInt8 ();
|
||||
tmp = static_cast <epicsUInt16> ( ( byte1 << 8u ) | byte2 );
|
||||
}
|
||||
else {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
tmp = 0u;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// 1) split between buffers expected to run slower
|
||||
// 2) using canonical unsigned temporary avoids ANSI C conversions to int
|
||||
// 3) cast required because sizeof(unsigned) >= sizeof(epicsUInt32)
|
||||
epicsUInt32 comQueRecv::multiBufferPopUInt32 ()
|
||||
{
|
||||
epicsUInt32 tmp;
|
||||
if ( this->occupiedBytes() >= sizeof (tmp) ) {
|
||||
// 1) split between buffers expected to run slower
|
||||
// 2) using canonical unsigned temporary avoids ANSI C conversions to int
|
||||
// 3) cast required because sizeof(unsigned) >= sizeof(epicsUInt32)
|
||||
unsigned byte1 = this->popUInt8();
|
||||
unsigned byte2 = this->popUInt8();
|
||||
unsigned byte3 = this->popUInt8();
|
||||
unsigned byte4 = this->popUInt8();
|
||||
tmp = static_cast <epicsUInt32>
|
||||
( ( byte1 << 24u ) | ( byte2 << 16u ) |
|
||||
( byte3 << 8u ) | byte4 );
|
||||
}
|
||||
else {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
tmp = 0u; // avoid compiler warnings
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void comQueRecv::removeAndDestroyBuf ( comBuf & buf )
|
||||
{
|
||||
this->bufs.remove ( buf );
|
||||
buf.~comBuf ();
|
||||
this->comBufMemMgr.release ( & buf );
|
||||
}
|
||||
|
||||
epicsUInt8 comQueRecv::popUInt8 ()
|
||||
{
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
epicsUInt8 tmp = '\0';
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( ! status.success ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
if ( status.nowEmpty ) {
|
||||
this->removeAndDestroyBuf ( *pComBuf );
|
||||
}
|
||||
this->nBytesPending--;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
epicsUInt16 comQueRecv::popUInt16 ()
|
||||
{
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
// try first for all in one buffer efficent version
|
||||
epicsUInt16 tmp = 0;
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( status.success ) {
|
||||
this->nBytesPending -= sizeof ( epicsUInt16 );
|
||||
if ( status.nowEmpty ) {
|
||||
this->removeAndDestroyBuf ( *pComBuf );
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
return this->multiBufferPopUInt16 ();
|
||||
}
|
||||
|
||||
epicsUInt32 comQueRecv::popUInt32 ()
|
||||
{
|
||||
comBuf *pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
comBuf::throwInsufficentBytesException ();
|
||||
}
|
||||
// try first for all in one buffer efficent version
|
||||
epicsUInt32 tmp = 0;
|
||||
comBuf::popStatus status = pComBuf->pop ( tmp );
|
||||
if ( status.success ) {
|
||||
this->nBytesPending -= sizeof ( epicsUInt32 );
|
||||
if ( status.nowEmpty ) {
|
||||
this->removeAndDestroyBuf ( *pComBuf );
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
return this->multiBufferPopUInt32 ();
|
||||
}
|
||||
|
||||
bool comQueRecv::popOldMsgHeader ( caHdrLargeArray & msg )
|
||||
{
|
||||
// try first for all in one buffer efficent version
|
||||
comBuf * pComBuf = this->bufs.first ();
|
||||
if ( ! pComBuf ) {
|
||||
return false;
|
||||
}
|
||||
unsigned avail = pComBuf->occupiedBytes ();
|
||||
if ( avail >= sizeof ( caHdr ) ) {
|
||||
pComBuf->pop ( msg.m_cmmd );
|
||||
ca_uint16_t smallPostsize = 0;
|
||||
pComBuf->pop ( smallPostsize );
|
||||
msg.m_postsize = smallPostsize;
|
||||
pComBuf->pop ( msg.m_dataType );
|
||||
ca_uint16_t smallCount = 0;
|
||||
pComBuf->pop ( smallCount );
|
||||
msg.m_count = smallCount;
|
||||
pComBuf->pop ( msg.m_cid );
|
||||
pComBuf->pop ( msg.m_available );
|
||||
this->nBytesPending -= sizeof ( caHdr );
|
||||
if ( avail == sizeof ( caHdr ) ) {
|
||||
this->removeAndDestroyBuf ( *pComBuf );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if ( this->occupiedBytes () >= sizeof ( caHdr ) ) {
|
||||
msg.m_cmmd = this->popUInt16 ();
|
||||
msg.m_postsize = this->popUInt16 ();
|
||||
msg.m_dataType = this->popUInt16 ();
|
||||
msg.m_count = this->popUInt16 ();
|
||||
msg.m_cid = this->popUInt32 ();
|
||||
msg.m_available = this->popUInt32 ();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
111
src/client/comQueRecv.h
Normal file
111
src/client/comQueRecv.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef comQueRecvh
|
||||
#define comQueRecvh
|
||||
|
||||
#include "comBuf.h"
|
||||
|
||||
class comQueRecv {
|
||||
public:
|
||||
comQueRecv ( comBufMemoryManager & );
|
||||
~comQueRecv ();
|
||||
unsigned occupiedBytes () const;
|
||||
unsigned copyOutBytes ( epicsInt8 *pBuf, unsigned nBytes );
|
||||
unsigned removeBytes ( unsigned nBytes );
|
||||
void pushLastComBufReceived ( comBuf & );
|
||||
void clear ();
|
||||
bool popOldMsgHeader ( struct caHdrLargeArray & );
|
||||
epicsInt8 popInt8 ();
|
||||
epicsUInt8 popUInt8 ();
|
||||
epicsInt16 popInt16 ();
|
||||
epicsUInt16 popUInt16 ();
|
||||
epicsInt32 popInt32 ();
|
||||
epicsUInt32 popUInt32 ();
|
||||
epicsFloat32 popFloat32 ();
|
||||
epicsFloat64 popFloat64 ();
|
||||
void popString ( epicsOldString * );
|
||||
private:
|
||||
tsDLList < comBuf > bufs;
|
||||
comBufMemoryManager & comBufMemMgr;
|
||||
unsigned nBytesPending;
|
||||
epicsUInt16 multiBufferPopUInt16 ();
|
||||
epicsUInt32 multiBufferPopUInt32 ();
|
||||
void removeAndDestroyBuf ( comBuf & );
|
||||
comQueRecv ( const comQueRecv & );
|
||||
comQueRecv & operator = ( const comQueRecv & );
|
||||
};
|
||||
|
||||
inline unsigned comQueRecv::occupiedBytes () const
|
||||
{
|
||||
return this->nBytesPending;
|
||||
}
|
||||
|
||||
inline epicsInt8 comQueRecv::popInt8 ()
|
||||
{
|
||||
return static_cast < epicsInt8 > ( this->popUInt8() );
|
||||
}
|
||||
|
||||
inline epicsInt16 comQueRecv::popInt16 ()
|
||||
{
|
||||
return static_cast < epicsInt16 > ( this->popUInt16() );
|
||||
}
|
||||
|
||||
inline epicsInt32 comQueRecv::popInt32 ()
|
||||
{
|
||||
return static_cast < epicsInt32 > ( this->popUInt32() );
|
||||
}
|
||||
|
||||
// this has been optimized to aligned convert, maybe more could be done,
|
||||
// but since it is currently not used ...
|
||||
inline epicsFloat32 comQueRecv::popFloat32 ()
|
||||
{
|
||||
union {
|
||||
epicsUInt8 _wire[ sizeof ( epicsFloat32 ) ];
|
||||
epicsFloat32 _fp;
|
||||
} tmp;
|
||||
// optimizer will unroll this loop
|
||||
for ( unsigned i = 0u; i < sizeof ( tmp._wire ); i++ ) {
|
||||
tmp._wire[i] = this->popUInt8 ();
|
||||
}
|
||||
return AlignedWireRef < epicsFloat32 > ( tmp._fp );
|
||||
}
|
||||
|
||||
// this has been optimized to aligned convert, maybe more could be done,
|
||||
// but since it is currently not used ...
|
||||
inline epicsFloat64 comQueRecv::popFloat64 ()
|
||||
{
|
||||
union {
|
||||
epicsUInt8 _wire[ sizeof ( epicsFloat64 ) ];
|
||||
epicsFloat64 _fp;
|
||||
} tmp;
|
||||
// optimizer will unroll this loop
|
||||
for ( unsigned i = 0u; i < sizeof ( tmp._wire ); i++ ) {
|
||||
tmp._wire[i] = this->popUInt8 ();
|
||||
}
|
||||
return AlignedWireRef < epicsFloat64 > ( tmp._fp );
|
||||
}
|
||||
|
||||
#endif // ifndef comQueRecvh
|
||||
411
src/client/comQueSend.cpp
Normal file
411
src/client/comQueSend.cpp
Normal file
@@ -0,0 +1,411 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
//
|
||||
// Requirements:
|
||||
// 1) Allow sufficent headroom so that users will be able to perform
|
||||
// a reasonable amount of IO within CA callbacks without experiencing
|
||||
// a push/pull deadlock. If a potential push/pull deadlock situation
|
||||
// occurs then detect and avoid it and provide diagnotic to the user
|
||||
// via special status.
|
||||
// 2) Return status to the user when there is insufficent memory to
|
||||
// queue a complete message.
|
||||
// 3) return status to the user when a message cant be flushed because
|
||||
// a connection dropped.
|
||||
// 4) Do not allocate too much memory in exception situatons (such as
|
||||
// after a circuit disconnect).
|
||||
// 5) Avoid allocating more memory than is absolutely necessary to meet
|
||||
// the above requirements.
|
||||
// 6) Message fragments must never be sent to the IOC when there isnt
|
||||
// enough memory to queue part of a message (we also must not force
|
||||
// a disconnect because the client is starved for memory).
|
||||
// 7) avoid the need to check status for each byte pushed into the
|
||||
// protocol stream.
|
||||
//
|
||||
// Implementation:
|
||||
// 1) When queuing a complete message, first test to see if a flush is
|
||||
// required. If it is a receive thread scheduals the flush with the
|
||||
// send thread, and otherwise directly execute the system call. The
|
||||
// send thread must run at a higher priority than the receive thread
|
||||
// if we are to minimize memory consumption.
|
||||
// 2) Preallocate space for the entire message prior to copying in the
|
||||
// message so that message fragments are not flushed out just prior
|
||||
// to detecting that memory is unavailable.
|
||||
// 3) Return a special error constant when the following situations
|
||||
// are detected when the user is attempting to queue a request
|
||||
// from within a user callback executed by a receive thread:
|
||||
// a) A user is queuing more requests that demand a response from a
|
||||
// callback than are removed by the response that initiated the
|
||||
// callback, and this situation persists for many callbacks until
|
||||
// all buffering in the system is exausted.
|
||||
// b) A user is queuing many requests that demand a response from one
|
||||
// callback until all buffering in the system is exausted.
|
||||
// c) Some combination of both (a) nad (b).
|
||||
//
|
||||
//
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "virtualCircuit.h"
|
||||
#include "db_access.h" // for dbr_short_t etc
|
||||
|
||||
// nill message alignment pad bytes
|
||||
const char cacNillBytes [] =
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
comQueSend::comQueSend ( wireSendAdapter & wireIn,
|
||||
comBufMemoryManager & comBufMemMgrIn ):
|
||||
comBufMemMgr ( comBufMemMgrIn ), wire ( wireIn ),
|
||||
nBytesPending ( 0u )
|
||||
{
|
||||
}
|
||||
|
||||
comQueSend::~comQueSend ()
|
||||
{
|
||||
this->clear ();
|
||||
}
|
||||
|
||||
void comQueSend::clear ()
|
||||
{
|
||||
comBuf *pBuf;
|
||||
|
||||
while ( ( pBuf = this->bufs.get () ) ) {
|
||||
this->nBytesPending -= pBuf->occupiedBytes ();
|
||||
pBuf->~comBuf ();
|
||||
this->comBufMemMgr.release ( pBuf );
|
||||
}
|
||||
this->pFirstUncommited = tsDLIter < comBuf > ();
|
||||
assert ( this->nBytesPending == 0 );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_string ( const void * pValue )
|
||||
{
|
||||
this->push ( static_cast < const char * > ( pValue ), MAX_STRING_SIZE );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_short ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_short_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_float ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_float_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_char ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_char_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_long ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_long_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_double ( const void * pValue )
|
||||
{
|
||||
this->push ( * static_cast <const dbr_double_t *> ( pValue ) );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_invalid ( const void * )
|
||||
{
|
||||
throw cacChannel::badType ();
|
||||
}
|
||||
|
||||
const comQueSend::copyScalarFunc_t comQueSend::dbrCopyScalar [39] = {
|
||||
&comQueSend::copy_dbr_string,
|
||||
&comQueSend::copy_dbr_short,
|
||||
&comQueSend::copy_dbr_float,
|
||||
&comQueSend::copy_dbr_short, // DBR_ENUM
|
||||
&comQueSend::copy_dbr_char,
|
||||
&comQueSend::copy_dbr_long,
|
||||
&comQueSend::copy_dbr_double,
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_INT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_DOUBLE
|
||||
&comQueSend::copy_dbr_short, // DBR_PUT_ACKT
|
||||
&comQueSend::copy_dbr_short, // DBR_PUT_ACKS
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STSACK_STRING
|
||||
&comQueSend::copy_dbr_invalid // DBR_CLASS_NAME
|
||||
};
|
||||
|
||||
void comQueSend::copy_dbr_string ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast < const char * > ( pValue ), nElem * MAX_STRING_SIZE );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_short ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_short_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_float ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_float_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_char ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_char_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_long ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_long_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_double ( const void *pValue, unsigned nElem )
|
||||
{
|
||||
this->push ( static_cast <const dbr_double_t *> ( pValue ), nElem );
|
||||
}
|
||||
|
||||
void comQueSend::copy_dbr_invalid ( const void *, unsigned )
|
||||
{
|
||||
throw cacChannel::badType ();
|
||||
}
|
||||
|
||||
const comQueSend::copyVectorFunc_t comQueSend::dbrCopyVector [39] = {
|
||||
&comQueSend::copy_dbr_string,
|
||||
&comQueSend::copy_dbr_short,
|
||||
&comQueSend::copy_dbr_float,
|
||||
&comQueSend::copy_dbr_short, // DBR_ENUM
|
||||
&comQueSend::copy_dbr_char,
|
||||
&comQueSend::copy_dbr_long,
|
||||
&comQueSend::copy_dbr_double,
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STS_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_INT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_TIME_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_GR_DOUBLE
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_STRING
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_SHORT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_FLOAT
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_ENUM
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_CHAR
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_LONG
|
||||
&comQueSend::copy_dbr_invalid, // DBR_CTRL_DOUBLE
|
||||
&comQueSend::copy_dbr_short, // DBR_PUT_ACKT
|
||||
&comQueSend::copy_dbr_short, // DBR_PUT_ACKS
|
||||
&comQueSend::copy_dbr_invalid, // DBR_STSACK_STRING
|
||||
&comQueSend::copy_dbr_invalid // DBR_CLASS_NAME
|
||||
};
|
||||
|
||||
comBuf * comQueSend::popNextComBufToSend ()
|
||||
{
|
||||
comBuf *pBuf = this->bufs.get ();
|
||||
if ( pBuf ) {
|
||||
unsigned nBytesThisBuf = pBuf->occupiedBytes ();
|
||||
if ( nBytesThisBuf ) {
|
||||
assert ( this->nBytesPending >= nBytesThisBuf );
|
||||
this->nBytesPending -= nBytesThisBuf;
|
||||
}
|
||||
else {
|
||||
this->bufs.push ( *pBuf );
|
||||
pBuf = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert ( this->nBytesPending == 0u );
|
||||
}
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
void comQueSend::insertRequestHeader (
|
||||
ca_uint16_t request, ca_uint32_t payloadSize,
|
||||
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
|
||||
ca_uint32_t requestDependent, bool v49Ok )
|
||||
{
|
||||
if ( payloadSize < 0xffff && nElem < 0xffff ) {
|
||||
comBuf * pComBuf = this->bufs.last ();
|
||||
if ( ! pComBuf || pComBuf->unoccupiedBytes() < 16u ) {
|
||||
pComBuf = newComBuf ();
|
||||
this->pushComBuf ( *pComBuf );
|
||||
}
|
||||
pComBuf->push ( request );
|
||||
pComBuf->push ( static_cast < ca_uint16_t > ( payloadSize ) );
|
||||
pComBuf->push ( dataType );
|
||||
pComBuf->push ( static_cast < ca_uint16_t > ( nElem ) );
|
||||
pComBuf->push ( cid );
|
||||
pComBuf->push ( requestDependent );
|
||||
}
|
||||
else if ( v49Ok ) {
|
||||
comBuf * pComBuf = this->bufs.last ();
|
||||
if ( ! pComBuf || pComBuf->unoccupiedBytes() < 24u ) {
|
||||
pComBuf = newComBuf ();
|
||||
this->pushComBuf ( *pComBuf );
|
||||
}
|
||||
pComBuf->push ( request );
|
||||
pComBuf->push ( static_cast < ca_uint16_t > ( 0xffff ) );
|
||||
pComBuf->push ( dataType );
|
||||
pComBuf->push ( static_cast < ca_uint16_t > ( 0u ) );
|
||||
pComBuf->push ( cid );
|
||||
pComBuf->push ( requestDependent );
|
||||
pComBuf->push ( payloadSize );
|
||||
pComBuf->push ( nElem );
|
||||
}
|
||||
else {
|
||||
throw cacChannel::outOfBounds ();
|
||||
}
|
||||
}
|
||||
|
||||
void comQueSend::insertRequestWithPayLoad (
|
||||
ca_uint16_t request, unsigned dataType, arrayElementCount nElem,
|
||||
ca_uint32_t cid, ca_uint32_t requestDependent,
|
||||
const void * pPayload, bool v49Ok )
|
||||
{
|
||||
if ( INVALID_DB_REQ ( dataType ) ) {
|
||||
throw cacChannel::badType ();
|
||||
}
|
||||
if ( dataType >= comQueSendCopyDispatchSize ) {
|
||||
throw cacChannel::badType();
|
||||
}
|
||||
ca_uint32_t size = 0u;
|
||||
ca_uint32_t payloadSize = 0u;
|
||||
if ( nElem == 1 ) {
|
||||
if ( dataType == DBR_STRING ) {
|
||||
const char * pStr = static_cast < const char * > ( pPayload );
|
||||
size = strlen ( pStr ) + 1u;
|
||||
if ( size > MAX_STRING_SIZE ) {
|
||||
throw cacChannel::outOfBounds();
|
||||
}
|
||||
payloadSize = CA_MESSAGE_ALIGN ( size );
|
||||
this->insertRequestHeader ( request, payloadSize,
|
||||
static_cast <ca_uint16_t> ( dataType ),
|
||||
nElem, cid, requestDependent, v49Ok );
|
||||
this->pushString ( pStr, size );
|
||||
}
|
||||
else {
|
||||
size = dbr_size[dataType];
|
||||
payloadSize = CA_MESSAGE_ALIGN ( size );
|
||||
this->insertRequestHeader ( request, payloadSize,
|
||||
static_cast <ca_uint16_t> ( dataType ),
|
||||
nElem, cid, requestDependent, v49Ok );
|
||||
( this->*dbrCopyScalar [dataType] ) ( pPayload );
|
||||
}
|
||||
}
|
||||
else {
|
||||
arrayElementCount maxBytes;
|
||||
if ( v49Ok ) {
|
||||
maxBytes = 0xffffffff;
|
||||
}
|
||||
else {
|
||||
maxBytes = MAX_TCP - sizeof ( caHdr );
|
||||
}
|
||||
arrayElementCount maxElem =
|
||||
( maxBytes - sizeof (dbr_double_t) - dbr_size[dataType] ) /
|
||||
dbr_value_size[dataType];
|
||||
if ( nElem >= maxElem ) {
|
||||
throw cacChannel::outOfBounds();
|
||||
}
|
||||
// the above checks verify that the total size
|
||||
// is lest that 0xffffffff
|
||||
size = static_cast < ca_uint32_t >
|
||||
( dbr_size_n ( dataType, nElem ) );
|
||||
payloadSize = CA_MESSAGE_ALIGN ( size );
|
||||
this->insertRequestHeader ( request, payloadSize,
|
||||
static_cast <ca_uint16_t> ( dataType ),
|
||||
static_cast < ca_uint32_t > ( nElem ),
|
||||
cid, requestDependent, v49Ok );
|
||||
( this->*dbrCopyVector [dataType] ) ( pPayload, nElem );
|
||||
}
|
||||
// set pad bytes to nill
|
||||
unsigned padSize = payloadSize - size;
|
||||
if ( padSize ) {
|
||||
this->pushString ( cacNillBytes, payloadSize - size );
|
||||
}
|
||||
}
|
||||
|
||||
void comQueSend::commitMsg ()
|
||||
{
|
||||
while ( this->pFirstUncommited.valid() ) {
|
||||
this->nBytesPending += this->pFirstUncommited->uncommittedBytes ();
|
||||
this->pFirstUncommited->commitIncomming ();
|
||||
this->pFirstUncommited++;
|
||||
}
|
||||
// printf ( "NBP: %u\n", this->nBytesPending );
|
||||
}
|
||||
|
||||
|
||||
void comQueSend::clearUncommitedMsg ()
|
||||
{
|
||||
while ( this->pFirstUncommited.valid() ) {
|
||||
tsDLIter < comBuf > next = this->pFirstUncommited;
|
||||
next++;
|
||||
this->pFirstUncommited->clearUncommittedIncomming ();
|
||||
if ( this->pFirstUncommited->occupiedBytes() == 0u ) {
|
||||
this->bufs.remove ( *this->pFirstUncommited );
|
||||
this->pFirstUncommited->~comBuf ();
|
||||
this->comBufMemMgr.release ( this->pFirstUncommited.pointer() );
|
||||
}
|
||||
this->pFirstUncommited = next;
|
||||
}
|
||||
}
|
||||
|
||||
238
src/client/comQueSend.h
Normal file
238
src/client/comQueSend.h
Normal file
@@ -0,0 +1,238 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef comQueSendh
|
||||
#define comQueSendh
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "tsDLList.h"
|
||||
#include "comBuf.h"
|
||||
|
||||
#define comQueSendCopyDispatchSize 39
|
||||
|
||||
class epicsMutex;
|
||||
template < class T > class epicsGuard;
|
||||
|
||||
class comQueSendMsgMinder {
|
||||
public:
|
||||
comQueSendMsgMinder (
|
||||
class comQueSend &, epicsGuard < epicsMutex > & );
|
||||
~comQueSendMsgMinder ();
|
||||
void commit ();
|
||||
private:
|
||||
class comQueSend * pSendQue;
|
||||
};
|
||||
|
||||
//
|
||||
// Notes.
|
||||
// o calling popNextComBufToSend() will clear any uncommitted bytes
|
||||
//
|
||||
class comQueSend {
|
||||
public:
|
||||
comQueSend ( wireSendAdapter &, comBufMemoryManager & );
|
||||
~comQueSend ();
|
||||
void clear ();
|
||||
unsigned occupiedBytes () const;
|
||||
bool flushEarlyThreshold ( unsigned nBytesThisMsg ) const;
|
||||
bool flushBlockThreshold () const;
|
||||
void pushUInt16 ( const ca_uint16_t value );
|
||||
void pushUInt32 ( const ca_uint32_t value );
|
||||
void pushFloat32 ( const ca_float32_t value );
|
||||
void pushString ( const char *pVal, unsigned nChar );
|
||||
void insertRequestHeader (
|
||||
ca_uint16_t request, ca_uint32_t payloadSize,
|
||||
ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid,
|
||||
ca_uint32_t requestDependent, bool v49Ok );
|
||||
void insertRequestWithPayLoad (
|
||||
ca_uint16_t request, unsigned dataType, arrayElementCount nElem,
|
||||
ca_uint32_t cid, ca_uint32_t requestDependent,
|
||||
const void * pPayload, bool v49Ok );
|
||||
comBuf * popNextComBufToSend ();
|
||||
private:
|
||||
comBufMemoryManager & comBufMemMgr;
|
||||
tsDLList < comBuf > bufs;
|
||||
tsDLIter < comBuf > pFirstUncommited;
|
||||
wireSendAdapter & wire;
|
||||
unsigned nBytesPending;
|
||||
|
||||
typedef void ( comQueSend::*copyScalarFunc_t ) (
|
||||
const void * pValue );
|
||||
static const copyScalarFunc_t dbrCopyScalar [comQueSendCopyDispatchSize];
|
||||
void copy_dbr_string ( const void * pValue );
|
||||
void copy_dbr_short ( const void * pValue );
|
||||
void copy_dbr_float ( const void * pValue );
|
||||
void copy_dbr_char ( const void * pValue );
|
||||
void copy_dbr_long ( const void * pValue );
|
||||
void copy_dbr_double ( const void * pValue );
|
||||
void copy_dbr_invalid ( const void * pValue );
|
||||
|
||||
typedef void ( comQueSend::*copyVectorFunc_t ) (
|
||||
const void * pValue, unsigned nElem );
|
||||
static const copyVectorFunc_t dbrCopyVector [comQueSendCopyDispatchSize];
|
||||
void copy_dbr_string ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_short ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_float ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_char ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_long ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_double ( const void *pValue, unsigned nElem );
|
||||
void copy_dbr_invalid ( const void * pValue, unsigned nElem );
|
||||
|
||||
void pushComBuf ( comBuf & );
|
||||
comBuf * newComBuf ();
|
||||
|
||||
void beginMsg ();
|
||||
void commitMsg ();
|
||||
void clearUncommitedMsg ();
|
||||
|
||||
friend class comQueSendMsgMinder;
|
||||
|
||||
//
|
||||
// visual C++ versions 6 & 7 do not allow out of
|
||||
// class member template function definition
|
||||
//
|
||||
template < class T >
|
||||
inline void push ( const T *pVal, const unsigned nElem )
|
||||
{
|
||||
comBuf * pLastBuf = this->bufs.last ();
|
||||
unsigned nCopied;
|
||||
if ( pLastBuf ) {
|
||||
nCopied = pLastBuf->push ( pVal, nElem );
|
||||
}
|
||||
else {
|
||||
nCopied = 0u;
|
||||
}
|
||||
while ( nElem > nCopied ) {
|
||||
comBuf * pComBuf = newComBuf ();
|
||||
nCopied += pComBuf->push
|
||||
( &pVal[nCopied], nElem - nCopied );
|
||||
this->pushComBuf ( *pComBuf );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// visual C++ versions 6 and 7 do not allow out of
|
||||
// class member template function definition
|
||||
//
|
||||
template < class T >
|
||||
inline void push ( const T & val )
|
||||
{
|
||||
comBuf * pComBuf = this->bufs.last ();
|
||||
if ( pComBuf && pComBuf->push ( val ) ) {
|
||||
return;
|
||||
}
|
||||
pComBuf = newComBuf ();
|
||||
bool success = pComBuf->push ( val );
|
||||
assert ( success );
|
||||
this->pushComBuf ( *pComBuf );
|
||||
}
|
||||
|
||||
template < class T >
|
||||
inline void push ( const T * ); // disabled
|
||||
|
||||
comQueSend ( const comQueSend & );
|
||||
comQueSend & operator = ( const comQueSend & );
|
||||
};
|
||||
|
||||
extern const char cacNillBytes[];
|
||||
|
||||
inline comQueSendMsgMinder::comQueSendMsgMinder (
|
||||
class comQueSend & sendQueIn, epicsGuard < epicsMutex > & ) :
|
||||
pSendQue ( & sendQueIn )
|
||||
{
|
||||
sendQueIn.beginMsg ();
|
||||
}
|
||||
|
||||
inline comQueSendMsgMinder::~comQueSendMsgMinder ()
|
||||
{
|
||||
if ( this->pSendQue ) {
|
||||
this->pSendQue->clearUncommitedMsg ();
|
||||
}
|
||||
}
|
||||
|
||||
inline void comQueSendMsgMinder::commit ()
|
||||
{
|
||||
if ( this->pSendQue ) {
|
||||
this->pSendQue->commitMsg ();
|
||||
this->pSendQue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void comQueSend::beginMsg ()
|
||||
{
|
||||
this->pFirstUncommited = this->bufs.lastIter ();
|
||||
}
|
||||
|
||||
inline void comQueSend::pushUInt16 ( const ca_uint16_t value )
|
||||
{
|
||||
this->push ( value );
|
||||
}
|
||||
|
||||
inline void comQueSend::pushUInt32 ( const ca_uint32_t value )
|
||||
{
|
||||
this->push ( value );
|
||||
}
|
||||
|
||||
inline void comQueSend::pushFloat32 ( const ca_float32_t value )
|
||||
{
|
||||
this->push ( value );
|
||||
}
|
||||
|
||||
inline void comQueSend::pushString ( const char *pVal, unsigned nChar )
|
||||
{
|
||||
this->push ( pVal, nChar );
|
||||
}
|
||||
|
||||
inline void comQueSend::pushComBuf ( comBuf & cb )
|
||||
{
|
||||
this->bufs.add ( cb );
|
||||
if ( ! this->pFirstUncommited.valid() ) {
|
||||
this->pFirstUncommited = this->bufs.lastIter ();
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned comQueSend::occupiedBytes () const
|
||||
{
|
||||
return this->nBytesPending;
|
||||
}
|
||||
|
||||
inline bool comQueSend::flushBlockThreshold () const
|
||||
{
|
||||
return ( this->nBytesPending > 16 * comBuf::capacityBytes () );
|
||||
}
|
||||
|
||||
inline bool comQueSend::flushEarlyThreshold ( unsigned nBytesThisMsg ) const
|
||||
{
|
||||
return ( this->nBytesPending + nBytesThisMsg > 4 * comBuf::capacityBytes () );
|
||||
}
|
||||
|
||||
// wrapping this with a function avoids WRS T2.2 Cygnus GNU compiler bugs
|
||||
inline comBuf * comQueSend::newComBuf ()
|
||||
{
|
||||
return new ( this->comBufMemMgr ) comBuf;
|
||||
}
|
||||
|
||||
#endif // ifndef comQueSendh
|
||||
1440
src/client/convert.cpp
Normal file
1440
src/client/convert.cpp
Normal file
File diff suppressed because it is too large
Load Diff
740
src/client/db_access.h
Normal file
740
src/client/db_access.h
Normal file
@@ -0,0 +1,740 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* base/include/db_access.h */
|
||||
/* Author: Bob Dalesio
|
||||
* Date: 4-4-88
|
||||
*/
|
||||
|
||||
#ifndef INCLdb_accessh
|
||||
#define INCLdb_accessh
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define INCLdb_accessh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsTypes.h"
|
||||
#include "epicsTime.h"
|
||||
|
||||
#ifdef INCLdb_accessh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_UNITS_SIZE 8
|
||||
#define MAX_ENUM_STRING_SIZE 26
|
||||
#define MAX_ENUM_STATES 16
|
||||
|
||||
/*
|
||||
* architecture independent types
|
||||
*
|
||||
* (so far this is sufficient for all archs we have ported to)
|
||||
*/
|
||||
typedef epicsOldString dbr_string_t;
|
||||
typedef epicsUInt8 dbr_char_t;
|
||||
typedef epicsInt16 dbr_short_t;
|
||||
typedef epicsUInt16 dbr_ushort_t;
|
||||
typedef epicsInt16 dbr_int_t;
|
||||
typedef epicsUInt16 dbr_enum_t;
|
||||
typedef epicsInt32 dbr_long_t;
|
||||
typedef epicsUInt32 dbr_ulong_t;
|
||||
typedef epicsFloat32 dbr_float_t;
|
||||
typedef epicsFloat64 dbr_double_t;
|
||||
typedef epicsUInt16 dbr_put_ackt_t;
|
||||
typedef epicsUInt16 dbr_put_acks_t;
|
||||
typedef epicsOldString dbr_stsack_string_t;
|
||||
typedef epicsOldString dbr_class_name_t;
|
||||
|
||||
#ifndef db_accessHFORdb_accessC
|
||||
/* database field types */
|
||||
#define DBF_STRING 0
|
||||
#define DBF_INT 1
|
||||
#define DBF_SHORT 1
|
||||
#define DBF_FLOAT 2
|
||||
#define DBF_ENUM 3
|
||||
#define DBF_CHAR 4
|
||||
#define DBF_LONG 5
|
||||
#define DBF_DOUBLE 6
|
||||
#define DBF_NO_ACCESS 7
|
||||
#define LAST_TYPE DBF_DOUBLE
|
||||
#define VALID_DB_FIELD(x) ((x >= 0) && (x <= LAST_TYPE))
|
||||
#define INVALID_DB_FIELD(x) ((x < 0) || (x > LAST_TYPE))
|
||||
|
||||
/* data request buffer types */
|
||||
#define DBR_STRING DBF_STRING
|
||||
#define DBR_INT DBF_INT
|
||||
#define DBR_SHORT DBF_INT
|
||||
#define DBR_FLOAT DBF_FLOAT
|
||||
#define DBR_ENUM DBF_ENUM
|
||||
#define DBR_CHAR DBF_CHAR
|
||||
#define DBR_LONG DBF_LONG
|
||||
#define DBR_DOUBLE DBF_DOUBLE
|
||||
#define DBR_STS_STRING 7
|
||||
#define DBR_STS_SHORT 8
|
||||
#define DBR_STS_INT DBR_STS_SHORT
|
||||
#define DBR_STS_FLOAT 9
|
||||
#define DBR_STS_ENUM 10
|
||||
#define DBR_STS_CHAR 11
|
||||
#define DBR_STS_LONG 12
|
||||
#define DBR_STS_DOUBLE 13
|
||||
#define DBR_TIME_STRING 14
|
||||
#define DBR_TIME_INT 15
|
||||
#define DBR_TIME_SHORT 15
|
||||
#define DBR_TIME_FLOAT 16
|
||||
#define DBR_TIME_ENUM 17
|
||||
#define DBR_TIME_CHAR 18
|
||||
#define DBR_TIME_LONG 19
|
||||
#define DBR_TIME_DOUBLE 20
|
||||
#define DBR_GR_STRING 21
|
||||
#define DBR_GR_SHORT 22
|
||||
#define DBR_GR_INT DBR_GR_SHORT
|
||||
#define DBR_GR_FLOAT 23
|
||||
#define DBR_GR_ENUM 24
|
||||
#define DBR_GR_CHAR 25
|
||||
#define DBR_GR_LONG 26
|
||||
#define DBR_GR_DOUBLE 27
|
||||
#define DBR_CTRL_STRING 28
|
||||
#define DBR_CTRL_SHORT 29
|
||||
#define DBR_CTRL_INT DBR_CTRL_SHORT
|
||||
#define DBR_CTRL_FLOAT 30
|
||||
#define DBR_CTRL_ENUM 31
|
||||
#define DBR_CTRL_CHAR 32
|
||||
#define DBR_CTRL_LONG 33
|
||||
#define DBR_CTRL_DOUBLE 34
|
||||
#define DBR_PUT_ACKT DBR_CTRL_DOUBLE + 1
|
||||
#define DBR_PUT_ACKS DBR_PUT_ACKT + 1
|
||||
#define DBR_STSACK_STRING DBR_PUT_ACKS + 1
|
||||
#define DBR_CLASS_NAME DBR_STSACK_STRING + 1
|
||||
#define LAST_BUFFER_TYPE DBR_CLASS_NAME
|
||||
#define VALID_DB_REQ(x) ((x >= 0) && (x <= LAST_BUFFER_TYPE))
|
||||
#define INVALID_DB_REQ(x) ((x < 0) || (x > LAST_BUFFER_TYPE))
|
||||
|
||||
/*
|
||||
* The enumeration "epicsType" is an index to this array
|
||||
* of type DBR types. In some cases we select the a
|
||||
* larger type to avoid loss of information
|
||||
*/
|
||||
epicsShareExtern const int epicsTypeToDBR_XXXX [lastEpicsType+1];
|
||||
|
||||
/*
|
||||
* The DBR_XXXX types are indicies into this array
|
||||
*/
|
||||
epicsShareExtern const epicsType DBR_XXXXToEpicsType [LAST_BUFFER_TYPE+1];
|
||||
|
||||
/* values returned for each field type
|
||||
* DBR_STRING returns a NULL terminated string
|
||||
* DBR_SHORT returns an unsigned short
|
||||
* DBR_INT returns an unsigned short
|
||||
* DBR_FLOAT returns an IEEE floating point value
|
||||
* DBR_ENUM returns an unsigned short which is the enum item
|
||||
* DBR_CHAR returns an unsigned char
|
||||
* DBR_LONG returns an unsigned long
|
||||
* DBR_DOUBLE returns a double precision floating point number
|
||||
* DBR_STS_STRING returns a string status structure (dbr_sts_string)
|
||||
* DBR_STS_SHORT returns a short status structure (dbr_sts_short)
|
||||
* DBR_STS_INT returns a short status structure (dbr_sts_int)
|
||||
* DBR_STS_FLOAT returns a float status structure (dbr_sts_float)
|
||||
* DBR_STS_ENUM returns an enum status structure (dbr_sts_enum)
|
||||
* DBR_STS_CHAR returns a char status structure (dbr_sts_char)
|
||||
* DBR_STS_LONG returns a long status structure (dbr_sts_long)
|
||||
* DBR_STS_DOUBLE returns a double status structure (dbr_sts_double)
|
||||
* DBR_TIME_STRING returns a string time structure (dbr_time_string)
|
||||
* DBR_TIME_SHORT returns a short time structure (dbr_time_short)
|
||||
* DBR_TIME_INT returns a short time structure (dbr_time_short)
|
||||
* DBR_TIME_FLOAT returns a float time structure (dbr_time_float)
|
||||
* DBR_TIME_ENUM returns an enum time structure (dbr_time_enum)
|
||||
* DBR_TIME_CHAR returns a char time structure (dbr_time_char)
|
||||
* DBR_TIME_LONG returns a long time structure (dbr_time_long)
|
||||
* DBR_TIME_DOUBLE returns a double time structure (dbr_time_double)
|
||||
* DBR_GR_STRING returns a graphic string structure (dbr_gr_string)
|
||||
* DBR_GR_SHORT returns a graphic short structure (dbr_gr_short)
|
||||
* DBR_GR_INT returns a graphic short structure (dbr_gr_int)
|
||||
* DBR_GR_FLOAT returns a graphic float structure (dbr_gr_float)
|
||||
* DBR_GR_ENUM returns a graphic enum structure (dbr_gr_enum)
|
||||
* DBR_GR_CHAR returns a graphic char structure (dbr_gr_char)
|
||||
* DBR_GR_LONG returns a graphic long structure (dbr_gr_long)
|
||||
* DBR_GR_DOUBLE returns a graphic double structure (dbr_gr_double)
|
||||
* DBR_CTRL_STRING returns a control string structure (dbr_ctrl_int)
|
||||
* DBR_CTRL_SHORT returns a control short structure (dbr_ctrl_short)
|
||||
* DBR_CTRL_INT returns a control short structure (dbr_ctrl_int)
|
||||
* DBR_CTRL_FLOAT returns a control float structure (dbr_ctrl_float)
|
||||
* DBR_CTRL_ENUM returns a control enum structure (dbr_ctrl_enum)
|
||||
* DBR_CTRL_CHAR returns a control char structure (dbr_ctrl_char)
|
||||
* DBR_CTRL_LONG returns a control long structure (dbr_ctrl_long)
|
||||
* DBR_CTRL_DOUBLE returns a control double structure (dbr_ctrl_double)
|
||||
*/
|
||||
#endif /*db_accessHFORdb_accessC*/
|
||||
|
||||
/* VALUES WITH STATUS STRUCTURES */
|
||||
|
||||
/* structure for a string status field */
|
||||
struct dbr_sts_string {
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_string_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a string status and ack field */
|
||||
struct dbr_stsack_string{
|
||||
dbr_ushort_t status; /* status of value */
|
||||
dbr_ushort_t severity; /* severity of alarm */
|
||||
dbr_ushort_t ackt; /* ack transient? */
|
||||
dbr_ushort_t acks; /* ack severity */
|
||||
dbr_string_t value; /* current value */
|
||||
};
|
||||
/* structure for an short status field */
|
||||
struct dbr_sts_int{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
struct dbr_sts_short{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a float status field */
|
||||
struct dbr_sts_float{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_float_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a enum status field */
|
||||
struct dbr_sts_enum{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_enum_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a char status field */
|
||||
struct dbr_sts_char{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_char_t RISC_pad; /* RISC alignment */
|
||||
dbr_char_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a long status field */
|
||||
struct dbr_sts_long{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_long_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a double status field */
|
||||
struct dbr_sts_double{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_long_t RISC_pad; /* RISC alignment */
|
||||
dbr_double_t value; /* current value */
|
||||
};
|
||||
|
||||
/* VALUES WITH STATUS AND TIME STRUCTURES */
|
||||
|
||||
/* structure for a string time field */
|
||||
struct dbr_time_string{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_string_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for an short time field */
|
||||
struct dbr_time_short{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_short_t RISC_pad; /* RISC alignment */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a float time field */
|
||||
struct dbr_time_float{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_float_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a enum time field */
|
||||
struct dbr_time_enum{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_short_t RISC_pad; /* RISC alignment */
|
||||
dbr_enum_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a char time field */
|
||||
struct dbr_time_char{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_short_t RISC_pad0; /* RISC alignment */
|
||||
dbr_char_t RISC_pad1; /* RISC alignment */
|
||||
dbr_char_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a long time field */
|
||||
struct dbr_time_long{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_long_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a double time field */
|
||||
struct dbr_time_double{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
epicsTimeStamp stamp; /* time stamp */
|
||||
dbr_long_t RISC_pad; /* RISC alignment */
|
||||
dbr_double_t value; /* current value */
|
||||
};
|
||||
|
||||
/* VALUES WITH STATUS AND GRAPHIC STRUCTURES */
|
||||
|
||||
/* structure for a graphic string */
|
||||
/* not implemented; use struct_dbr_sts_string */
|
||||
|
||||
/* structure for a graphic short field */
|
||||
struct dbr_gr_int{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_short_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_short_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_short_t upper_alarm_limit;
|
||||
dbr_short_t upper_warning_limit;
|
||||
dbr_short_t lower_warning_limit;
|
||||
dbr_short_t lower_alarm_limit;
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
struct dbr_gr_short{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_short_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_short_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_short_t upper_alarm_limit;
|
||||
dbr_short_t upper_warning_limit;
|
||||
dbr_short_t lower_warning_limit;
|
||||
dbr_short_t lower_alarm_limit;
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic floating point field */
|
||||
struct dbr_gr_float{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t precision; /* number of decimal places */
|
||||
dbr_short_t RISC_pad0; /* RISC alignment */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_float_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_float_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_float_t upper_alarm_limit;
|
||||
dbr_float_t upper_warning_limit;
|
||||
dbr_float_t lower_warning_limit;
|
||||
dbr_float_t lower_alarm_limit;
|
||||
dbr_float_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic enumeration field */
|
||||
struct dbr_gr_enum{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t no_str; /* number of strings */
|
||||
char strs[MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];
|
||||
/* state strings */
|
||||
dbr_enum_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic char field */
|
||||
struct dbr_gr_char{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_char_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_char_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_char_t upper_alarm_limit;
|
||||
dbr_char_t upper_warning_limit;
|
||||
dbr_char_t lower_warning_limit;
|
||||
dbr_char_t lower_alarm_limit;
|
||||
dbr_char_t RISC_pad; /* RISC alignment */
|
||||
dbr_char_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic long field */
|
||||
struct dbr_gr_long{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_long_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_long_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_long_t upper_alarm_limit;
|
||||
dbr_long_t upper_warning_limit;
|
||||
dbr_long_t lower_warning_limit;
|
||||
dbr_long_t lower_alarm_limit;
|
||||
dbr_long_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a graphic double field */
|
||||
struct dbr_gr_double{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t precision; /* number of decimal places */
|
||||
dbr_short_t RISC_pad0; /* RISC alignment */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_double_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_double_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_double_t upper_alarm_limit;
|
||||
dbr_double_t upper_warning_limit;
|
||||
dbr_double_t lower_warning_limit;
|
||||
dbr_double_t lower_alarm_limit;
|
||||
dbr_double_t value; /* current value */
|
||||
};
|
||||
|
||||
/* VALUES WITH STATUS, GRAPHIC and CONTROL STRUCTURES */
|
||||
|
||||
/* structure for a control string */
|
||||
/* not implemented; use struct_dbr_sts_string */
|
||||
|
||||
/* structure for a control integer */
|
||||
struct dbr_ctrl_int{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_short_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_short_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_short_t upper_alarm_limit;
|
||||
dbr_short_t upper_warning_limit;
|
||||
dbr_short_t lower_warning_limit;
|
||||
dbr_short_t lower_alarm_limit;
|
||||
dbr_short_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_short_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
struct dbr_ctrl_short{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_short_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_short_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_short_t upper_alarm_limit;
|
||||
dbr_short_t upper_warning_limit;
|
||||
dbr_short_t lower_warning_limit;
|
||||
dbr_short_t lower_alarm_limit;
|
||||
dbr_short_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_short_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_short_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control floating point field */
|
||||
struct dbr_ctrl_float{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t precision; /* number of decimal places */
|
||||
dbr_short_t RISC_pad; /* RISC alignment */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_float_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_float_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_float_t upper_alarm_limit;
|
||||
dbr_float_t upper_warning_limit;
|
||||
dbr_float_t lower_warning_limit;
|
||||
dbr_float_t lower_alarm_limit;
|
||||
dbr_float_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_float_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_float_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control enumeration field */
|
||||
struct dbr_ctrl_enum{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t no_str; /* number of strings */
|
||||
char strs[MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];
|
||||
/* state strings */
|
||||
dbr_enum_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control char field */
|
||||
struct dbr_ctrl_char{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_char_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_char_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_char_t upper_alarm_limit;
|
||||
dbr_char_t upper_warning_limit;
|
||||
dbr_char_t lower_warning_limit;
|
||||
dbr_char_t lower_alarm_limit;
|
||||
dbr_char_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_char_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_char_t RISC_pad; /* RISC alignment */
|
||||
dbr_char_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control long field */
|
||||
struct dbr_ctrl_long{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_long_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_long_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_long_t upper_alarm_limit;
|
||||
dbr_long_t upper_warning_limit;
|
||||
dbr_long_t lower_warning_limit;
|
||||
dbr_long_t lower_alarm_limit;
|
||||
dbr_long_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_long_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_long_t value; /* current value */
|
||||
};
|
||||
|
||||
/* structure for a control double field */
|
||||
struct dbr_ctrl_double{
|
||||
dbr_short_t status; /* status of value */
|
||||
dbr_short_t severity; /* severity of alarm */
|
||||
dbr_short_t precision; /* number of decimal places */
|
||||
dbr_short_t RISC_pad0; /* RISC alignment */
|
||||
char units[MAX_UNITS_SIZE]; /* units of value */
|
||||
dbr_double_t upper_disp_limit; /* upper limit of graph */
|
||||
dbr_double_t lower_disp_limit; /* lower limit of graph */
|
||||
dbr_double_t upper_alarm_limit;
|
||||
dbr_double_t upper_warning_limit;
|
||||
dbr_double_t lower_warning_limit;
|
||||
dbr_double_t lower_alarm_limit;
|
||||
dbr_double_t upper_ctrl_limit; /* upper control limit */
|
||||
dbr_double_t lower_ctrl_limit; /* lower control limit */
|
||||
dbr_double_t value; /* current value */
|
||||
};
|
||||
|
||||
#define dbr_size_n(TYPE,COUNT)\
|
||||
((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
|
||||
|
||||
/* size for each type - array indexed by the DBR_ type code */
|
||||
epicsShareExtern const unsigned short dbr_size[];
|
||||
|
||||
/* size for each type's value - array indexed by the DBR_ type code */
|
||||
epicsShareExtern const unsigned short dbr_value_size[];
|
||||
|
||||
#ifndef db_accessHFORdb_accessC
|
||||
/* class for each type's value */
|
||||
enum dbr_value_class {
|
||||
dbr_class_int,
|
||||
dbr_class_float,
|
||||
dbr_class_string,
|
||||
dbr_class_max};
|
||||
|
||||
epicsShareExtern const enum dbr_value_class dbr_value_class[LAST_BUFFER_TYPE+1];
|
||||
|
||||
/*
|
||||
* ptr to value given a pointer to the structure and the DBR type
|
||||
*/
|
||||
#define dbr_value_ptr(PDBR, DBR_TYPE) \
|
||||
((void *)(((char *)PDBR)+dbr_value_offset[DBR_TYPE]))
|
||||
|
||||
/*
|
||||
* ptr to value given a pointer to the structure and the structure declaration
|
||||
*/
|
||||
#define dbr_value_ptr_from_structure(PDBR, STRUCTURE)\
|
||||
((void *)(((char *)PDBR)+BYTE_OS(STRUCTURE, value)))
|
||||
|
||||
epicsShareExtern const unsigned short dbr_value_offset[LAST_BUFFER_TYPE+1];
|
||||
|
||||
|
||||
/* union for each fetch buffers */
|
||||
union db_access_val{
|
||||
dbr_string_t strval; /* string max size */
|
||||
dbr_short_t shrtval; /* short */
|
||||
dbr_short_t intval; /* short */
|
||||
dbr_float_t fltval; /* IEEE Float */
|
||||
dbr_enum_t enmval; /* item number */
|
||||
dbr_char_t charval; /* character */
|
||||
dbr_long_t longval; /* long */
|
||||
dbr_double_t doubleval; /* double */
|
||||
struct dbr_sts_string sstrval; /* string field with status */
|
||||
struct dbr_sts_short sshrtval; /* short field with status */
|
||||
struct dbr_sts_float sfltval; /* float field with status */
|
||||
struct dbr_sts_enum senmval; /* item number with status */
|
||||
struct dbr_sts_char schrval; /* char field with status */
|
||||
struct dbr_sts_long slngval; /* long field with status */
|
||||
struct dbr_sts_double sdblval; /* double field with time */
|
||||
struct dbr_time_string tstrval; /* string field with time */
|
||||
struct dbr_time_short tshrtval; /* short field with time */
|
||||
struct dbr_time_float tfltval; /* float field with time */
|
||||
struct dbr_time_enum tenmval; /* item number with time */
|
||||
struct dbr_time_char tchrval; /* char field with time */
|
||||
struct dbr_time_long tlngval; /* long field with time */
|
||||
struct dbr_time_double tdblval; /* double field with time */
|
||||
struct dbr_sts_string gstrval; /* graphic string info */
|
||||
struct dbr_gr_short gshrtval; /* graphic short info */
|
||||
struct dbr_gr_float gfltval; /* graphic float info */
|
||||
struct dbr_gr_enum genmval; /* graphic item info */
|
||||
struct dbr_gr_char gchrval; /* graphic char info */
|
||||
struct dbr_gr_long glngval; /* graphic long info */
|
||||
struct dbr_gr_double gdblval; /* graphic double info */
|
||||
struct dbr_sts_string cstrval; /* control string info */
|
||||
struct dbr_ctrl_short cshrtval; /* control short info */
|
||||
struct dbr_ctrl_float cfltval; /* control float info */
|
||||
struct dbr_ctrl_enum cenmval; /* control item info */
|
||||
struct dbr_ctrl_char cchrval; /* control char info */
|
||||
struct dbr_ctrl_long clngval; /* control long info */
|
||||
struct dbr_ctrl_double cdblval; /* control double info */
|
||||
dbr_put_ackt_t putackt; /* item number */
|
||||
dbr_put_acks_t putacks; /* item number */
|
||||
struct dbr_sts_string sastrval; /* string field with status */
|
||||
dbr_string_t classname; /* string max size */
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* repository for some useful PV database constants and utilities
|
||||
*
|
||||
* item dimensions
|
||||
* db_strval_dim dimension for string values
|
||||
* db_units_dim dimension for record units text
|
||||
* db_desc_dim dimension for record description text
|
||||
* db_name_dim dimension for channel names (record.field\0)
|
||||
* db_state_dim number of states possible in a state table
|
||||
* db_state_text_dim dimension for a state text string
|
||||
* usage: char state_table[db_state_dim][db_state_text_dim]
|
||||
*
|
||||
* type checking macros -- return non-zero if condition is true, zero otherwise
|
||||
*
|
||||
* int dbf_type_is_valid(type) type is a valid DBF_xxx
|
||||
* int dbr_type_is_valid(type) type is a valid DBR_xxx
|
||||
* int dbr_type_is_plain(type) type is a valid plain DBR_xxx
|
||||
* int dbr_type_is_STS(type) type is a valid DBR_STS_xxx
|
||||
* int dbr_type_is_TIME(type) type is a valid DBR_TIME_xxx
|
||||
* int dbr_type_is_GR(type) type is a valid DBR_GR_xxx
|
||||
* int dbr_type_is_CTRL(type) type is a valid DBR_CTRL_xxx
|
||||
* int dbr_type_is_STRING(type) type is a valid DBR_STRING_xxx
|
||||
* int dbr_type_is_SHORT(type) type is a valid DBR_SHORT_xxx
|
||||
* int dbr_type_is_FLOAT(type) type is a valid DBR_FLOAT_xxx
|
||||
* int dbr_type_is_ENUM(type) type is a valid DBR_ENUM_xxx
|
||||
* int dbr_type_is_CHAR(type) type is a valid DBR_CHAR_xxx
|
||||
* int dbr_type_is_LONG(type) type is a valid DBR_LONG_xxx
|
||||
* int dbr_type_is_DOUBLE(type) type is a valid DBR_DOUBLE_xxx
|
||||
*
|
||||
* type conversion macros
|
||||
*
|
||||
* char *dbf_type_to_text(type) returns text matching DBF_xxx
|
||||
* void dbf_text_to_type(text, type) finds DBF_xxx matching text
|
||||
* int dbf_type_to_DBR(type) returns DBR_xxx matching DBF_xxx
|
||||
* int dbf_type_to_DBR_TIME(type) returns DBR_TIME_xxx matching DBF_xxx
|
||||
* int dbf_type_to_DBR_GR(type) returns DBR_GR_xxx matching DBF_xxx
|
||||
* int dbf_type_to_DBR_CTRL(type) returns DBR_CTRL_xxx matching DBF_xxx
|
||||
* char *dbr_type_to_text(type) returns text matching DBR_xxx
|
||||
* void dbr_text_to_type(text, type) finds DBR_xxx matching text
|
||||
*---------------------------------------------------------------------------*/
|
||||
#define db_strval_dim MAX_STRING_SIZE
|
||||
#define db_units_dim MAX_UNITS_SIZE
|
||||
#define db_desc_dim 24
|
||||
#define db_name_dim 36
|
||||
#define db_state_dim MAX_ENUM_STATES
|
||||
#define db_state_text_dim MAX_ENUM_STRING_SIZE
|
||||
|
||||
#define dbf_type_is_valid(type) ((type) >= 0 && (type) <= LAST_TYPE)
|
||||
#define dbr_type_is_valid(type) ((type) >= 0 && (type) <= LAST_BUFFER_TYPE)
|
||||
#define dbr_type_is_plain(type) \
|
||||
((type) >= DBR_STRING && (type) <= DBR_DOUBLE)
|
||||
#define dbr_type_is_STS(type) \
|
||||
((type) >= DBR_STS_STRING && (type) <= DBR_STS_DOUBLE)
|
||||
#define dbr_type_is_TIME(type) \
|
||||
((type) >= DBR_TIME_STRING && (type) <= DBR_TIME_DOUBLE)
|
||||
#define dbr_type_is_GR(type) \
|
||||
((type) >= DBR_GR_STRING && (type) <= DBR_GR_DOUBLE)
|
||||
#define dbr_type_is_CTRL(type) \
|
||||
((type) >= DBR_CTRL_STRING && (type) <= DBR_CTRL_DOUBLE)
|
||||
#define dbr_type_is_STRING(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_STRING)
|
||||
#define dbr_type_is_SHORT(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_SHORT)
|
||||
#define dbr_type_is_FLOAT(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_FLOAT)
|
||||
#define dbr_type_is_ENUM(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_ENUM)
|
||||
#define dbr_type_is_CHAR(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_CHAR)
|
||||
#define dbr_type_is_LONG(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_LONG)
|
||||
#define dbr_type_is_DOUBLE(type) \
|
||||
((type) >= 0 && (type) <= LAST_BUFFER_TYPE && \
|
||||
(type)%(LAST_TYPE+1) == DBR_DOUBLE)
|
||||
|
||||
#define dbf_type_to_text(type) \
|
||||
( ((type) >= -1 && (type) < dbf_text_dim-2) ? \
|
||||
dbf_text[type+1] : dbf_text_invalid )
|
||||
|
||||
#define dbf_text_to_type(text, type) \
|
||||
for (type=dbf_text_dim-3; type>=0; type--) { \
|
||||
if (strcmp(text, dbf_text[type+1]) == 0) \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define dbr_type_to_text(type) \
|
||||
( ((type) >= 0 && (type) < dbr_text_dim) ? \
|
||||
dbr_text[(type)] : dbr_text_invalid )
|
||||
|
||||
#define dbr_text_to_type(text, type) \
|
||||
for (type=dbr_text_dim-2; type>=0; type--) { \
|
||||
if (strcmp(text, dbr_text[type]) == 0) \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define dbf_type_to_DBR(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) : -1 )
|
||||
|
||||
#define dbf_type_to_DBR_STS(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) + (dbf_text_dim-2) : -1 )
|
||||
|
||||
#define dbf_type_to_DBR_TIME(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) + 2*(dbf_text_dim-2) : -1 )
|
||||
|
||||
#define dbf_type_to_DBR_GR(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) + 3*(dbf_text_dim-2) : -1 )
|
||||
|
||||
#define dbf_type_to_DBR_CTRL(type) \
|
||||
(((type) >= 0 && (type) <= dbf_text_dim-3) ? \
|
||||
(type) + 4*(dbf_text_dim-2) : -1 )
|
||||
|
||||
|
||||
epicsShareExtern const char *dbf_text[LAST_TYPE+3];
|
||||
epicsShareExtern const short dbf_text_dim;
|
||||
epicsShareExtern const char *dbf_text_invalid;
|
||||
|
||||
epicsShareExtern const char *dbr_text[LAST_BUFFER_TYPE+1];
|
||||
epicsShareExtern const short dbr_text_dim;
|
||||
epicsShareExtern const char *dbr_text_invalid;
|
||||
#endif /*db_accessHFORdb_accessC*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INCLdb_accessh */
|
||||
110
src/client/disconnectGovernorTimer.cpp
Normal file
110
src/client/disconnectGovernorTimer.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
//
|
||||
//
|
||||
// L O S A L A M O S
|
||||
// Los Alamos National Laboratory
|
||||
// Los Alamos, New Mexico 87545
|
||||
//
|
||||
// Copyright, 1986, The Regents of the University of California.
|
||||
//
|
||||
// Author: Jeff Hill
|
||||
//
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "disconnectGovernorTimer.h"
|
||||
#include "udpiiu.h"
|
||||
#include "nciu.h"
|
||||
|
||||
static const double disconnectGovernorPeriod = 10.0; // sec
|
||||
|
||||
disconnectGovernorTimer::disconnectGovernorTimer (
|
||||
disconnectGovernorNotify & iiuIn,
|
||||
epicsTimerQueue & queueIn,
|
||||
epicsMutex & mutexIn ) :
|
||||
mutex ( mutexIn ), timer ( queueIn.createTimer () ),
|
||||
iiu ( iiuIn )
|
||||
{
|
||||
}
|
||||
|
||||
disconnectGovernorTimer::~disconnectGovernorTimer ()
|
||||
{
|
||||
this->timer.destroy ();
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer:: start ()
|
||||
{
|
||||
this->timer.start ( *this, disconnectGovernorPeriod );
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer::shutdown (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard )
|
||||
{
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > cbUnguard ( cbGuard );
|
||||
this->timer.cancel ();
|
||||
}
|
||||
}
|
||||
while ( nciu * pChan = this->chanList.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
pChan->serviceShutdownNotify ( cbGuard, guard );
|
||||
}
|
||||
}
|
||||
|
||||
epicsTimerNotify::expireStatus disconnectGovernorTimer::expire (
|
||||
const epicsTime & /* currentTime */ )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
while ( nciu * pChan = chanList.get () ) {
|
||||
pChan->channelNode::listMember =
|
||||
channelNode::cs_none;
|
||||
this->iiu.govExpireNotify ( guard, *pChan );
|
||||
}
|
||||
return expireStatus ( restart, disconnectGovernorPeriod );
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer::show ( unsigned level ) const
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
::printf ( "disconnect governor timer: with %u channels pending\n",
|
||||
this->chanList.count () );
|
||||
if ( level > 0u ) {
|
||||
tsDLIterConst < nciu > pChan = this->chanList.firstIter ();
|
||||
while ( pChan.valid () ) {
|
||||
pChan->show ( level - 1u );
|
||||
pChan++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer::installChan (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->chanList.add ( chan );
|
||||
chan.channelNode::listMember = channelNode::cs_disconnGov;
|
||||
}
|
||||
|
||||
void disconnectGovernorTimer::uninstallChan (
|
||||
epicsGuard < epicsMutex > & guard, nciu & chan )
|
||||
{
|
||||
guard.assertIdenticalMutex ( this->mutex );
|
||||
this->chanList.remove ( chan );
|
||||
chan.channelNode::listMember = channelNode::cs_none;
|
||||
}
|
||||
|
||||
disconnectGovernorNotify::~disconnectGovernorNotify () {}
|
||||
|
||||
77
src/client/disconnectGovernorTimer.h
Normal file
77
src/client/disconnectGovernorTimer.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// L O S A L A M O S
|
||||
// Los Alamos National Laboratory
|
||||
// Los Alamos, New Mexico 87545
|
||||
//
|
||||
// Copyright, 1986, The Regents of the University of California.
|
||||
//
|
||||
//
|
||||
// Author Jeffrey O. Hill
|
||||
// johill@lanl.gov
|
||||
// 505 665 1831
|
||||
//
|
||||
|
||||
#ifndef disconnectGovernorTimerh
|
||||
#define disconnectGovernorTimerh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define searchTimerh_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsGuard.h"
|
||||
#include "epicsTimer.h"
|
||||
|
||||
#ifdef searchTimerh_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# include "shareLib.h"
|
||||
#endif
|
||||
|
||||
#include "caProto.h"
|
||||
#include "netiiu.h"
|
||||
|
||||
class disconnectGovernorNotify {
|
||||
public:
|
||||
virtual ~disconnectGovernorNotify () = 0;
|
||||
virtual void govExpireNotify (
|
||||
epicsGuard < epicsMutex > &, nciu & ) = 0;
|
||||
};
|
||||
|
||||
class disconnectGovernorTimer : private epicsTimerNotify {
|
||||
public:
|
||||
disconnectGovernorTimer (
|
||||
class disconnectGovernorNotify &, epicsTimerQueue &, epicsMutex & );
|
||||
virtual ~disconnectGovernorTimer ();
|
||||
void start ();
|
||||
void shutdown (
|
||||
epicsGuard < epicsMutex > & cbGuard,
|
||||
epicsGuard < epicsMutex > & guard );
|
||||
void installChan (
|
||||
epicsGuard < epicsMutex > &, nciu & );
|
||||
void uninstallChan (
|
||||
epicsGuard < epicsMutex > &, nciu & );
|
||||
void show ( unsigned level ) const;
|
||||
private:
|
||||
tsDLList < nciu > chanList;
|
||||
epicsMutex & mutex;
|
||||
epicsTimer & timer;
|
||||
class disconnectGovernorNotify & iiu;
|
||||
epicsTimerNotify::expireStatus expire ( const epicsTime & currentTime );
|
||||
disconnectGovernorTimer ( const disconnectGovernorTimer & );
|
||||
disconnectGovernorTimer & operator = ( const disconnectGovernorTimer & );
|
||||
};
|
||||
|
||||
#endif // ifdef disconnectGovernorTimerh
|
||||
95
src/client/evtime.c
Normal file
95
src/client/evtime.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dbDefs.h"
|
||||
#include "epicsTime.h"
|
||||
#include "cadef.h"
|
||||
|
||||
void event_handler (struct event_handler_args args);
|
||||
int evtime (char *pname);
|
||||
|
||||
static unsigned iteration_count;
|
||||
static epicsUInt32 last_time;
|
||||
|
||||
#ifndef iocCore
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *pname;
|
||||
|
||||
if(argc == 2){
|
||||
pname = argv[1];
|
||||
evtime(pname);
|
||||
}
|
||||
else{
|
||||
printf("usage: %s <channel name>", argv[0]);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* evtime()
|
||||
*/
|
||||
int evtime(char *pname)
|
||||
{
|
||||
chid chan;
|
||||
int status;
|
||||
|
||||
status = ca_search(pname, &chan);
|
||||
SEVCHK(status, NULL);
|
||||
|
||||
status = ca_pend_io(10.0);
|
||||
if(status != ECA_NORMAL){
|
||||
printf("%s not found\n", pname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = ca_add_event(
|
||||
DBR_FLOAT,
|
||||
chan,
|
||||
event_handler,
|
||||
NULL,
|
||||
NULL);
|
||||
SEVCHK(status, __FILE__);
|
||||
|
||||
status = ca_pend_event(0.0);
|
||||
SEVCHK(status, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* event_handler()
|
||||
*
|
||||
*/
|
||||
void event_handler(struct event_handler_args args)
|
||||
{
|
||||
epicsUInt32 current_time;
|
||||
# define COUNT 0x8000
|
||||
double interval;
|
||||
double delay;
|
||||
epicsTimeStamp ts;
|
||||
|
||||
if(iteration_count%COUNT == 0){
|
||||
epicsTimeGetCurrent(&ts);
|
||||
current_time = ts.secPastEpoch;
|
||||
if(last_time != 0){
|
||||
interval = current_time - last_time;
|
||||
delay = interval/COUNT;
|
||||
printf("Delay = %f sec per event\n",
|
||||
delay);
|
||||
}
|
||||
last_time = current_time;
|
||||
}
|
||||
|
||||
iteration_count++;
|
||||
}
|
||||
|
||||
38
src/client/future_work.txt
Normal file
38
src/client/future_work.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
Potential upgrades to Channel Access
|
||||
|
||||
o generalized access to abstract data
|
||||
o use multicast for broadcasting and ax the repeater
|
||||
o improve client API
|
||||
o improve security
|
||||
o name service (wildcard queries)
|
||||
o PV name prefix (for all PVs)
|
||||
o client access to process passive and for maximize severity
|
||||
o detect name conflicts at boot time
|
||||
o multi priority connections (quality of service)
|
||||
o reduce protocol overhead
|
||||
o compressed protocol
|
||||
|
||||
|
||||
o If there is a beacon anomaly then this indicates that
|
||||
the server is _not_ available. Perhaps we should only
|
||||
reset the search timer interval when we see a beacon
|
||||
anomaly transition into a sure steady beacon.
|
||||
|
||||
o make certain that a monitor callback canceling itself
|
||||
does not deadlock.
|
||||
|
||||
o the free list library does not now cause exceptions to
|
||||
occur (it uses new ( nothrow )), and therefore we should
|
||||
change the new handlers to be nothrow also if this is
|
||||
the design goal.
|
||||
|
||||
o test the library when an IOC is running low on memory.
|
||||
|
||||
o The new CA interface should be multi-threaded by default.
|
||||
We should continue to support a single-threaded interface,
|
||||
but this would should be restricted so that it always
|
||||
runs with preemptive callback disable and no threads
|
||||
may join in. Alternatively, the new CA interface could
|
||||
be 100% preemptive multi-threaded and the old interface
|
||||
could be layered on this.
|
||||
104
src/client/getCallback.cpp
Normal file
104
src/client/getCallback.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "oldAccess.h"
|
||||
|
||||
getCallback::getCallback ( oldChannelNotify & chanIn,
|
||||
caEventCallBackFunc *pFuncIn, void *pPrivateIn ) :
|
||||
chan ( chanIn ), pFunc ( pFuncIn ), pPrivate ( pPrivateIn )
|
||||
{
|
||||
}
|
||||
|
||||
getCallback::~getCallback ()
|
||||
{
|
||||
}
|
||||
|
||||
void getCallback::completion (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
unsigned type, arrayElementCount count, const void *pData )
|
||||
{
|
||||
struct event_handler_args args;
|
||||
args.usr = this->pPrivate;
|
||||
args.chid = & this->chan;
|
||||
args.type = type;
|
||||
args.count = count;
|
||||
args.status = ECA_NORMAL;
|
||||
args.dbr = pData;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
|
||||
if ( pFuncTmp ) {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
pFuncTmp ( args );
|
||||
}
|
||||
}
|
||||
|
||||
void getCallback::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char * /* pContext */,
|
||||
unsigned type, arrayElementCount count )
|
||||
{
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
struct event_handler_args args;
|
||||
args.usr = this->pPrivate;
|
||||
args.chid = & this->chan;
|
||||
args.type = type;
|
||||
args.count = count;
|
||||
args.status = status;
|
||||
args.dbr = 0;
|
||||
caEventCallBackFunc * pFuncTmp = this->pFunc;
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
( *pFuncTmp ) ( args );
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->chan.getClientCtx().destroyGetCallback ( guard, *this );
|
||||
}
|
||||
}
|
||||
|
||||
void getCallback::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
118
src/client/getCopy.cpp
Normal file
118
src/client/getCopy.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "errlog.h"
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "iocinf.h"
|
||||
#include "oldAccess.h"
|
||||
#include "cac.h"
|
||||
|
||||
getCopy::getCopy (
|
||||
epicsGuard < epicsMutex > & guard, ca_client_context & cacCtxIn,
|
||||
oldChannelNotify & chanIn, unsigned typeIn,
|
||||
arrayElementCount countIn, void * pValueIn ) :
|
||||
count ( countIn ), cacCtx ( cacCtxIn ), chan ( chanIn ), pValue ( pValueIn ),
|
||||
ioSeqNo ( 0 ), type ( typeIn )
|
||||
{
|
||||
this->ioSeqNo = cacCtxIn.sequenceNumberOfOutstandingIO ( guard );
|
||||
cacCtxIn.incrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
}
|
||||
|
||||
getCopy::~getCopy ()
|
||||
{
|
||||
}
|
||||
|
||||
void getCopy::cancel ()
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->cacCtx.mutexRef () );
|
||||
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
}
|
||||
|
||||
void getCopy::completion (
|
||||
epicsGuard < epicsMutex > & guard, unsigned typeIn,
|
||||
arrayElementCount countIn, const void *pDataIn )
|
||||
{
|
||||
if ( this->type == typeIn ) {
|
||||
unsigned size = dbr_size_n ( typeIn, countIn );
|
||||
memcpy ( this->pValue, pDataIn, size );
|
||||
this->cacCtx.decrementOutstandingIO ( guard, this->ioSeqNo );
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
// this object destroyed by preceding function call
|
||||
}
|
||||
else {
|
||||
this->exception ( guard, ECA_INTERNAL,
|
||||
"bad data type match in get copy back response",
|
||||
typeIn, countIn);
|
||||
// this object destroyed by preceding function call
|
||||
}
|
||||
}
|
||||
|
||||
void getCopy::exception (
|
||||
epicsGuard < epicsMutex > & guard,
|
||||
int status, const char *pContext,
|
||||
unsigned /* typeIn */, arrayElementCount /* countIn */ )
|
||||
{
|
||||
oldChannelNotify & chanTmp ( this->chan );
|
||||
unsigned typeTmp ( this->type );
|
||||
arrayElementCount countTmp ( this->count );
|
||||
ca_client_context & caClientCtx ( this->cacCtx );
|
||||
// fetch client context and destroy prior to releasing
|
||||
// the lock and calling cb in case they destroy channel there
|
||||
this->cacCtx.destroyGetCopy ( guard, *this );
|
||||
if ( status != ECA_CHANDESTROY ) {
|
||||
caClientCtx.exception ( guard, status, pContext,
|
||||
__FILE__, __LINE__, chanTmp, typeTmp,
|
||||
countTmp, CA_OP_GET );
|
||||
}
|
||||
}
|
||||
|
||||
void getCopy::show ( unsigned level ) const
|
||||
{
|
||||
int tmpType = static_cast <int> ( this->type );
|
||||
::printf ( "read copy IO at %p, type %s, element count %lu\n",
|
||||
static_cast <const void *> ( this ), dbf_type_to_text ( tmpType ), this->count );
|
||||
if ( level > 0u ) {
|
||||
::printf ( "\tIO sequence number %u, user's storage %p\n",
|
||||
this->ioSeqNo, static_cast <const void *> ( this->pValue ) );
|
||||
}
|
||||
}
|
||||
|
||||
void getCopy::operator delete ( void * )
|
||||
{
|
||||
// Visual C++ .net appears to require operator delete if
|
||||
// placement operator delete is defined? I smell a ms rat
|
||||
// because if I declare placement new and delete, but
|
||||
// comment out the placement delete definition there are
|
||||
// no undefined symbols.
|
||||
errlogPrintf ( "%s:%d this compiler is confused about placement delete - memory was probably leaked",
|
||||
__FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
92
src/client/hostNameCache.cpp
Normal file
92
src/client/hostNameCache.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
#include "hostNameCache.h"
|
||||
#include "epicsGuard.h"
|
||||
|
||||
hostNameCache::hostNameCache (
|
||||
const osiSockAddr & addr, ipAddrToAsciiEngine & engine ) :
|
||||
dnsTransaction ( engine.createTransaction() ), nameLength ( 0 )
|
||||
{
|
||||
sockAddrToDottedIP ( &addr.sa, hostNameBuf, sizeof ( hostNameBuf ) );
|
||||
hostNameBuf[ sizeof ( hostNameBuf ) - 1 ] = '\0';
|
||||
nameLength = strlen ( hostNameBuf );
|
||||
this->dnsTransaction.ipAddrToAscii ( addr, *this );
|
||||
}
|
||||
|
||||
void hostNameCache::destroy ()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
hostNameCache::~hostNameCache ()
|
||||
{
|
||||
this->dnsTransaction.release ();
|
||||
}
|
||||
|
||||
void hostNameCache::transactionComplete ( const char * pHostNameIn )
|
||||
{
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
// a few legacy clients have a direct pointer to this buffer so we
|
||||
// set the entrire string to nill terminators before we start copying
|
||||
// in the name (this reduces the chance that another thread will see
|
||||
// garbage characters).
|
||||
size_t newNameLen = strlen ( pHostNameIn );
|
||||
if ( newNameLen > sizeof ( this->hostNameBuf ) - 1u ) {
|
||||
newNameLen = sizeof ( this->hostNameBuf ) - 1u;
|
||||
}
|
||||
strncpy ( this->hostNameBuf, "", sizeof ( this->hostNameBuf ) );
|
||||
strncpy ( this->hostNameBuf, pHostNameIn, sizeof ( this->hostNameBuf ) - 1 );
|
||||
this->nameLength = newNameLen;
|
||||
}
|
||||
|
||||
unsigned hostNameCache::getName (
|
||||
char * pBuf, unsigned bufSize ) const
|
||||
{
|
||||
if ( bufSize == 0u ) {
|
||||
return 0u;
|
||||
}
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
if ( this->nameLength > 0u ) {
|
||||
if ( this->nameLength < bufSize ) {
|
||||
strcpy ( pBuf, this->hostNameBuf );
|
||||
return this->nameLength;
|
||||
}
|
||||
else {
|
||||
unsigned reducedSize = bufSize - 1u;
|
||||
strncpy ( pBuf, this->hostNameBuf, reducedSize );
|
||||
pBuf [ reducedSize ] = '\0';
|
||||
return reducedSize;
|
||||
}
|
||||
}
|
||||
else {
|
||||
osiSockAddr tmpAddr = this->dnsTransaction.address ();
|
||||
return sockAddrToDottedIP ( &tmpAddr.sa, pBuf, bufSize );
|
||||
}
|
||||
}
|
||||
|
||||
61
src/client/hostNameCache.h
Normal file
61
src/client/hostNameCache.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef hostNameCacheh
|
||||
#define hostNameCacheh
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define hostNameCache_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "ipAddrToAsciiAsynchronous.h"
|
||||
#include "epicsMutex.h"
|
||||
|
||||
#ifdef hostNameCache_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
class hostNameCache : public ipAddrToAsciiCallBack {
|
||||
public:
|
||||
hostNameCache ( const osiSockAddr & addr, ipAddrToAsciiEngine & engine );
|
||||
~hostNameCache ();
|
||||
void destroy ();
|
||||
void transactionComplete ( const char * pHostName );
|
||||
unsigned getName ( char *pBuf, unsigned bufLength ) const;
|
||||
const char * pointer () const;
|
||||
private:
|
||||
char hostNameBuf [128];
|
||||
mutable epicsMutex mutex;
|
||||
ipAddrToAsciiTransaction & dnsTransaction;
|
||||
unsigned nameLength;
|
||||
};
|
||||
|
||||
inline const char * hostNameCache::pointer () const
|
||||
{
|
||||
return this->hostNameBuf;
|
||||
}
|
||||
|
||||
#endif // #ifndef hostNameCacheh
|
||||
72
src/client/inetAddrID.h
Normal file
72
src/client/inetAddrID.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#ifndef inetAddrIDh
|
||||
#define inetAddrIDh
|
||||
|
||||
#include "osiSock.h"
|
||||
#include "resourceLib.h"
|
||||
|
||||
class inetAddrID {
|
||||
public:
|
||||
inetAddrID ( const struct sockaddr_in & addrIn );
|
||||
bool operator == ( const inetAddrID & ) const;
|
||||
resTableIndex hash () const;
|
||||
void name ( char *pBuf, unsigned bufSize ) const;
|
||||
private:
|
||||
struct sockaddr_in addr;
|
||||
};
|
||||
|
||||
inline inetAddrID::inetAddrID ( const struct sockaddr_in & addrIn ) :
|
||||
addr ( addrIn )
|
||||
{
|
||||
}
|
||||
|
||||
inline bool inetAddrID::operator == ( const inetAddrID &rhs ) const
|
||||
{
|
||||
if ( this->addr.sin_addr.s_addr == rhs.addr.sin_addr.s_addr ) {
|
||||
if ( this->addr.sin_port == rhs.addr.sin_port ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline resTableIndex inetAddrID::hash () const
|
||||
{
|
||||
const unsigned inetAddrMinIndexBitWidth = 8u;
|
||||
const unsigned inetAddrMaxIndexBitWidth = 32u;
|
||||
unsigned index;
|
||||
index = this->addr.sin_addr.s_addr;
|
||||
index ^= this->addr.sin_port;
|
||||
index ^= this->addr.sin_port >> 8u;
|
||||
return integerHash ( inetAddrMinIndexBitWidth,
|
||||
inetAddrMaxIndexBitWidth, index );
|
||||
}
|
||||
|
||||
inline void inetAddrID::name ( char *pBuf, unsigned bufSize ) const
|
||||
{
|
||||
ipAddrToDottedIP ( &this->addr, pBuf, bufSize );
|
||||
}
|
||||
|
||||
#endif // ifdef inetAddrID
|
||||
|
||||
|
||||
265
src/client/iocinf.cpp
Normal file
265
src/client/iocinf.cpp
Normal file
@@ -0,0 +1,265 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "envDefs.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsStdioRedirect.h"
|
||||
#include "errlog.h"
|
||||
#include "osiWireFormat.h"
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "addrList.h"
|
||||
#undef epicsExportSharedSymbols
|
||||
|
||||
#include "iocinf.h"
|
||||
|
||||
/*
|
||||
* getToken()
|
||||
*/
|
||||
static char *getToken ( const char **ppString, char *pBuf, unsigned bufSIze )
|
||||
{
|
||||
bool tokenFound = false;
|
||||
const char *pToken;
|
||||
unsigned i;
|
||||
|
||||
pToken = *ppString;
|
||||
while ( isspace (*pToken) && *pToken ){
|
||||
pToken++;
|
||||
}
|
||||
|
||||
for ( i=0u; i<bufSIze; i++ ) {
|
||||
if ( isspace (pToken[i]) || pToken[i]=='\0' ) {
|
||||
pBuf[i] = '\0';
|
||||
*ppString = &pToken[i];
|
||||
if ( i != 0 ) {
|
||||
tokenFound = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pBuf[i] = pToken[i];
|
||||
}
|
||||
|
||||
if ( tokenFound ) {
|
||||
pBuf[bufSIze-1] = '\0';
|
||||
return pBuf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* addAddrToChannelAccessAddressList ()
|
||||
*/
|
||||
extern "C" int epicsShareAPI addAddrToChannelAccessAddressList
|
||||
( ELLLIST *pList, const ENV_PARAM *pEnv,
|
||||
unsigned short port, int ignoreNonDefaultPort )
|
||||
{
|
||||
osiSockAddrNode *pNewNode;
|
||||
const char *pStr;
|
||||
const char *pToken;
|
||||
struct sockaddr_in addr;
|
||||
char buf[32u]; /* large enough to hold an IP address */
|
||||
int status, ret = -1;
|
||||
|
||||
pStr = envGetConfigParamPtr (pEnv);
|
||||
if (!pStr) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ( ( pToken = getToken (&pStr, buf, sizeof (buf) ) ) ) {
|
||||
status = aToIPAddr ( pToken, port, &addr );
|
||||
if (status<0) {
|
||||
fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name);
|
||||
fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
|
||||
if (pNewNode==NULL) {
|
||||
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
|
||||
break;
|
||||
}
|
||||
|
||||
pNewNode->addr.ia = addr;
|
||||
|
||||
/*
|
||||
* LOCK applied externally
|
||||
*/
|
||||
ellAdd (pList, &pNewNode->node);
|
||||
ret = 0; /* success if anything is added to the list */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* removeDuplicateAddresses ()
|
||||
*/
|
||||
extern "C" void epicsShareAPI removeDuplicateAddresses
|
||||
( ELLLIST *pDestList, ELLLIST *pSrcList, int silent )
|
||||
{
|
||||
ELLNODE *pRawNode;
|
||||
|
||||
while ( (pRawNode = ellGet ( pSrcList ) ) ) {
|
||||
STATIC_ASSERT ( offsetof (osiSockAddrNode, node) == 0 );
|
||||
osiSockAddrNode *pNode = reinterpret_cast <osiSockAddrNode *> ( pRawNode );
|
||||
osiSockAddrNode *pTmpNode;
|
||||
|
||||
if ( pNode->addr.sa.sa_family == AF_INET ) {
|
||||
|
||||
pTmpNode = (osiSockAddrNode *) ellFirst (pDestList);
|
||||
while ( pTmpNode ) {
|
||||
if (pTmpNode->addr.sa.sa_family == AF_INET) {
|
||||
if ( pNode->addr.ia.sin_addr.s_addr == pTmpNode->addr.ia.sin_addr.s_addr &&
|
||||
pNode->addr.ia.sin_port == pTmpNode->addr.ia.sin_port ) {
|
||||
if ( ! silent ) {
|
||||
char buf[64];
|
||||
ipAddrToDottedIP ( &pNode->addr.ia, buf, sizeof (buf) );
|
||||
fprintf ( stderr,
|
||||
"Warning: Duplicate EPICS CA Address list entry \"%s\" discarded\n", buf );
|
||||
}
|
||||
free (pNode);
|
||||
pNode = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pTmpNode = (osiSockAddrNode *) ellNext (&pTmpNode->node);
|
||||
}
|
||||
if (pNode) {
|
||||
ellAdd (pDestList, &pNode->node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ellAdd (pDestList, &pNode->node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* forcePort ()
|
||||
*/
|
||||
static void forcePort ( ELLLIST *pList, unsigned short port )
|
||||
{
|
||||
osiSockAddrNode *pNode;
|
||||
|
||||
pNode = ( osiSockAddrNode * ) ellFirst ( pList );
|
||||
while ( pNode ) {
|
||||
if ( pNode->addr.sa.sa_family == AF_INET ) {
|
||||
pNode->addr.ia.sin_port = htons ( port );
|
||||
}
|
||||
pNode = ( osiSockAddrNode * ) ellNext ( &pNode->node );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* configureChannelAccessAddressList ()
|
||||
*/
|
||||
extern "C" void epicsShareAPI configureChannelAccessAddressList
|
||||
( ELLLIST *pList, SOCKET sock, unsigned short port )
|
||||
{
|
||||
ELLLIST tmpList;
|
||||
char *pstr;
|
||||
char yesno[32u];
|
||||
int yes;
|
||||
|
||||
/*
|
||||
* dont load the list twice
|
||||
*/
|
||||
assert ( ellCount (pList) == 0 );
|
||||
|
||||
ellInit ( &tmpList );
|
||||
|
||||
/*
|
||||
* Check to see if the user has disabled
|
||||
* initializing the search b-cast list
|
||||
* from the interfaces found.
|
||||
*/
|
||||
yes = true;
|
||||
pstr = envGetConfigParam ( &EPICS_CA_AUTO_ADDR_LIST,
|
||||
sizeof (yesno), yesno );
|
||||
if ( pstr ) {
|
||||
if ( strstr ( pstr, "no" ) || strstr ( pstr, "NO" ) ) {
|
||||
yes = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* LOCK is for piiu->destAddr list
|
||||
* (lock outside because this is used by the server also)
|
||||
*/
|
||||
if (yes) {
|
||||
ELLLIST bcastList;
|
||||
osiSockAddr addr;
|
||||
ellInit ( &bcastList );
|
||||
addr.ia.sin_family = AF_UNSPEC;
|
||||
osiSockDiscoverBroadcastAddresses ( &bcastList, sock, &addr );
|
||||
forcePort ( &bcastList, port );
|
||||
removeDuplicateAddresses ( &tmpList, &bcastList, 1 );
|
||||
if ( ellCount ( &tmpList ) == 0 ) {
|
||||
osiSockAddrNode *pNewNode;
|
||||
pNewNode = (osiSockAddrNode *) calloc ( 1, sizeof (*pNewNode) );
|
||||
if ( pNewNode ) {
|
||||
/*
|
||||
* if no interfaces found then look for local channels
|
||||
* with the loop back interface
|
||||
*/
|
||||
pNewNode->addr.ia.sin_family = AF_INET;
|
||||
pNewNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
|
||||
pNewNode->addr.ia.sin_port = htons ( port );
|
||||
ellAdd ( &tmpList, &pNewNode->node );
|
||||
}
|
||||
else {
|
||||
errlogPrintf ( "configureChannelAccessAddressList(): no memory available for configuration\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
addAddrToChannelAccessAddressList ( &tmpList, &EPICS_CA_ADDR_LIST, port, false );
|
||||
|
||||
removeDuplicateAddresses ( pList, &tmpList, 0 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* printChannelAccessAddressList ()
|
||||
*/
|
||||
extern "C" void epicsShareAPI printChannelAccessAddressList ( const ELLLIST *pList )
|
||||
{
|
||||
osiSockAddrNode *pNode;
|
||||
|
||||
::printf ( "Channel Access Address List\n" );
|
||||
pNode = (osiSockAddrNode *) ellFirst ( pList );
|
||||
while (pNode) {
|
||||
char buf[64];
|
||||
ipAddrToA ( &pNode->addr.ia, buf, sizeof ( buf ) );
|
||||
::printf ( "%s\n", buf );
|
||||
pNode = (osiSockAddrNode *) ellNext ( &pNode->node );
|
||||
}
|
||||
}
|
||||
70
src/client/iocinf.h
Normal file
70
src/client/iocinf.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
*
|
||||
* Author Jeffrey O. Hill
|
||||
* johill@lanl.gov
|
||||
* 505 665 1831
|
||||
*/
|
||||
|
||||
#ifndef INCiocinfh
|
||||
#define INCiocinfh
|
||||
|
||||
#ifdef DEBUG
|
||||
# define debugPrintf(argsInParen) ::printf argsInParen
|
||||
#else
|
||||
# define debugPrintf(argsInParen)
|
||||
#endif
|
||||
|
||||
#if defined ( CLOCKS_PER_SEC )
|
||||
# define CAC_SIGNIFICANT_DELAY ( 1.0 / CLOCKS_PER_SEC )
|
||||
#else
|
||||
# define CAC_SIGNIFICANT_DELAY (1.0 / 1000000u)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* these two control the period of connection verifies
|
||||
* (echo requests) - CA_CONN_VERIFY_PERIOD - and how
|
||||
* long we will wait for an echo reply before we
|
||||
* give up and flag the connection for disconnect
|
||||
* - CA_ECHO_TIMEOUT.
|
||||
*
|
||||
* CA_CONN_VERIFY_PERIOD is normally obtained from an
|
||||
* EPICS environment variable.
|
||||
*/
|
||||
static const double CA_ECHO_TIMEOUT = 5.0; /* (sec) disconn no echo reply tmo */
|
||||
static const double CA_CONN_VERIFY_PERIOD = 30.0; /* (sec) how often to request echo */
|
||||
|
||||
/*
|
||||
* this determines the number of messages received
|
||||
* without a delay in between before we go into
|
||||
* monitor flow control
|
||||
*
|
||||
* turning this down effects maximum throughput
|
||||
* because we dont get an optimal number of bytes
|
||||
* per network frame
|
||||
*/
|
||||
static const unsigned contiguousMsgCountWhichTriggersFlowControl = 10u;
|
||||
|
||||
/*
|
||||
* CA internal functions
|
||||
*/
|
||||
#define genLocalExcep( CBGUARD, GUARD, CAC, STAT, PCTX ) \
|
||||
(CAC).exception ( CBGUARD, GUARD, STAT, PCTX, __FILE__, __LINE__ )
|
||||
|
||||
#endif // ifdef INCiocinfh
|
||||
66
src/client/localHostName.cpp
Normal file
66
src/client/localHostName.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#include "osiSock.h"
|
||||
|
||||
#include "localHostName.h"
|
||||
|
||||
epicsSingleton < localHostName > localHostNameCache;
|
||||
|
||||
localHostName::localHostName () :
|
||||
attachedToSockLib ( osiSockAttach () != 0 ), length ( 0u )
|
||||
{
|
||||
const char * pErrStr = "<unknown host>";
|
||||
int status = -1;
|
||||
if ( this->attachedToSockLib ) {
|
||||
status = gethostname (
|
||||
this->cache, sizeof ( this->cache ) );
|
||||
}
|
||||
if ( status ) {
|
||||
strncpy ( this->cache, pErrStr, sizeof ( this->cache ) );
|
||||
}
|
||||
this->cache [ sizeof ( this->cache ) - 1u ] = '\0';
|
||||
this->length = strlen ( this->cache );
|
||||
}
|
||||
|
||||
localHostName::~localHostName ()
|
||||
{
|
||||
if ( this->attachedToSockLib ) {
|
||||
osiSockRelease ();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned localHostName::getName (
|
||||
char * pBuf, unsigned bufLength ) const
|
||||
{
|
||||
if ( bufLength ) {
|
||||
strncpy ( pBuf, this->cache, bufLength );
|
||||
if ( this->length < bufLength ) {
|
||||
return this->length;
|
||||
}
|
||||
else {
|
||||
unsigned reducedSize = bufLength - 1;
|
||||
pBuf [ reducedSize ] = '\0';
|
||||
return reducedSize;
|
||||
}
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
65
src/client/localHostName.h
Normal file
65
src/client/localHostName.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
*
|
||||
* L O S A L A M O S
|
||||
* Los Alamos National Laboratory
|
||||
* Los Alamos, New Mexico 87545
|
||||
*
|
||||
* Copyright, 1986, The Regents of the University of California.
|
||||
*
|
||||
* Author: Jeff Hill
|
||||
*/
|
||||
|
||||
#ifndef localHostNameh
|
||||
#define localHostNameh
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define localHostNameh_restore_epicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include "epicsSingleton.h"
|
||||
|
||||
#ifdef localHostNameh_restore_epicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
class localHostName {
|
||||
public:
|
||||
localHostName ();
|
||||
~localHostName ();
|
||||
const char * pointer () const;
|
||||
unsigned getName ( char * pBuf, unsigned bufLength ) const;
|
||||
unsigned nameLength () const;
|
||||
private:
|
||||
bool attachedToSockLib;
|
||||
unsigned length;
|
||||
char cache [128];
|
||||
};
|
||||
|
||||
extern epicsSingleton < localHostName > localHostNameCache;
|
||||
|
||||
inline unsigned localHostName::nameLength () const
|
||||
{
|
||||
return this->length;
|
||||
}
|
||||
|
||||
inline const char * localHostName::pointer () const
|
||||
{
|
||||
return this->cache;
|
||||
}
|
||||
|
||||
#endif // ifndef localHostNameh
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user