From 8857d0bb4e467cb6ef34cd6cfc12eb5fec2f02f0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 29 May 2014 17:09:08 -0500 Subject: [PATCH 1/6] Add dbServer files. --- src/ioc/db/Makefile | 2 ++ src/ioc/db/dbServer.c | 58 +++++++++++++++++++++++++++++++++++++++++++ src/ioc/db/dbServer.h | 58 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 src/ioc/db/dbServer.c create mode 100644 src/ioc/db/dbServer.h diff --git a/src/ioc/db/Makefile b/src/ioc/db/Makefile index c957842cb..5d58542fe 100644 --- a/src/ioc/db/Makefile +++ b/src/ioc/db/Makefile @@ -26,6 +26,7 @@ INC += dbLink.h INC += dbLock.h INC += dbNotify.h INC += dbScan.h +INC += dbServer.h INC += dbTest.h INC += dbCaTest.h INC += db_test.h @@ -86,4 +87,5 @@ dbCore_SRCS += templateInstances.cpp dbCore_SRCS += dbIocRegister.c dbCore_SRCS += chfPlugin.c dbCore_SRCS += dbState.c +dbCore_SRCS += dbServer.c diff --git a/src/ioc/db/dbServer.c b/src/ioc/db/dbServer.c new file mode 100644 index 000000000..bc1094ce7 --- /dev/null +++ b/src/ioc/db/dbServer.c @@ -0,0 +1,58 @@ +/*************************************************************************\ +* Copyright (c) 2014 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. +\*************************************************************************/ + +/* + * Author: Andrew Johnson + */ + +#include + +#include "ellLib.h" +#include "epicsStdio.h" + +#define epicsExportSharedSymbols +#include "dbServer.h" + +static ELLLIST serverList = ELLLIST_INIT; + + +void dbRegisterServer(dbServer *psrv) +{ + if (ellNext(&psrv->node)) { + fprintf(stderr, "dbRegisterServer: '%s' registered twice?\n", + psrv->name); + return; + } + + ellAdd(&serverList, &psrv->node); +} + +void dbsr(unsigned level) +{ + dbServer *psrv = (dbServer *)ellFirst(&serverList); + + while (psrv) { + printf("Server '%s':\n", psrv->name); + if (psrv->report) + psrv->report(level); + psrv = (dbServer *)ellNext(&psrv->node); + } +} + +int dbServerClient(char *pBuf, size_t bufSize) +{ + dbServer *psrv = (dbServer *)ellFirst(&serverList); + + while (psrv) { + if (psrv->client && + psrv->client(pBuf, bufSize) == 0) + return 0; + psrv = (dbServer *)ellNext(&psrv->node); + } + return -1; +} + diff --git a/src/ioc/db/dbServer.h b/src/ioc/db/dbServer.h new file mode 100644 index 000000000..345468676 --- /dev/null +++ b/src/ioc/db/dbServer.h @@ -0,0 +1,58 @@ +/*************************************************************************\ +* Copyright (c) 2014 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. +\*************************************************************************/ + +/* + * Author: Andrew Johnson + */ + +#ifndef INC_dbServer_H +#define INC_dbServer_H + +#include + +#include "ellLib.h" +#include "shareLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Server information structure */ + +typedef struct dbServer { + ELLNODE node; + const char *name; + + /* Print level-dependent status report to stdout */ + void (* report) (unsigned level); + + /* Get number of channels and clients connected */ + void (* stats) (unsigned *channels, unsigned *clients); + + /* Get identity of client initiating the calling thread */ + /* Must return 0 (OK), or -1 (ERROR) from unknown threads */ + int (* client) (char *pBuf, size_t bufSize); +} dbServer; + + +epicsShareFunc void dbRegisterServer(dbServer *psrv); + +/* Extra routines could be added if/when needed: + * + * epicsShareFunc const dbServer* dbFindServer(const char *name); + * epicsShareFunc void dbIterateServers(srvIterFunc func, void *user); + */ + +epicsShareFunc void dbsr(unsigned level); + +epicsShareFunc int dbServerClient(char *pBuf, size_t bufSize); + +#ifdef __cplusplus +} +#endif + +#endif /* INC_dbServer_H */ From fc8ad6b9eccc03416bfcbb9f5122be507ac5ea84 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 29 May 2014 17:10:26 -0500 Subject: [PATCH 2/6] rsrv: Register with dbServer API. --- src/ioc/rsrv/camsgtask.c | 41 +++++++++++-------------------------- src/ioc/rsrv/caservertask.c | 24 ++++++++++++++++------ src/ioc/rsrv/rsrv.h | 19 +++++++++++------ 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/ioc/rsrv/camsgtask.c b/src/ioc/rsrv/camsgtask.c index 8317b60f4..16af5bb0d 100644 --- a/src/ioc/rsrv/camsgtask.c +++ b/src/ioc/rsrv/camsgtask.c @@ -17,13 +17,13 @@ #include #include -#include #include #include #include "dbDefs.h" #include "osiSock.h" #include "epicsTime.h" +#include "epicsStdio.h" #include "errlog.h" #include "taskwd.h" #include "db_access.h" @@ -165,35 +165,18 @@ void camsgtask ( void *pParm ) } -void casHostNameInitiatingCurrentThread ( char * pBuf, unsigned bufSize ) +int casClientInitiatingCurrentThread ( char * pBuf, size_t bufSize ) { - if ( bufSize ) { - const char * pHostName = ""; - { - struct client * pClient = ( struct client * ) - epicsThreadPrivateGet ( rsrvCurrentClient ); - if ( pClient ) { - pHostName = pClient->pHostName; - } - } - strncpy ( pBuf, pHostName, bufSize ); - pBuf [ bufSize - 1u ] = '\0'; - } -} - -void casUserNameInitiatingCurrentThread ( char * pBuf, unsigned bufSize ) -{ - if ( bufSize ) { - const char * pUserName = ""; - { - struct client * pClient = ( struct client * ) - epicsThreadPrivateGet ( rsrvCurrentClient ); - if ( pClient ) { - pUserName = pClient->pUserName; - } - } - strncpy ( pBuf, pUserName, bufSize ); - pBuf [ bufSize - 1u ] = '\0'; + struct client * pClient = ( struct client * ) + epicsThreadPrivateGet ( rsrvCurrentClient ); + + if ( ! pClient ) + return RSRV_ERROR; + + if ( pBuf && bufSize ) { + epicsSnprintf(pBuf, bufSize, "%s@%s", + pClient->pUserName, pClient->pHostName); } + return RSRV_OK; } diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c index e3ab087f1..34226b72f 100644 --- a/src/ioc/rsrv/caservertask.c +++ b/src/ioc/rsrv/caservertask.c @@ -39,12 +39,14 @@ #include "dbEvent.h" #include "dbChannel.h" #include "dbCommon.h" +#include "dbServer.h" #include "rsrv.h" #define GLBLSOURCE #include "server.h" -#define DELETE_TASK(NAME)\ -if(threadNameToId(NAME)!=0)threadDestroy(threadNameToId(NAME)); +#define DELETE_TASK(NAME) \ + if (threadNameToId(NAME)!=0) \ + threadDestroy(threadNameToId(NAME)); epicsThreadPrivateId rsrvCurrentClient; @@ -230,6 +232,14 @@ static void req_server (void *pParm) } } +static dbServer rsrv_server = { + ELLNODE_INIT, + "rsrv", + casr, + casStatsFetch, + casClientInitiatingCurrentThread +}; + /* * rsrv_init () */ @@ -250,6 +260,8 @@ int rsrv_init (void) freeListInitPvt ( &rsrvSmallBufFreeListTCP, MAX_TCP, 16 ); initializePutNotifyFreeList (); + dbRegisterServer(&rsrv_server); + status = envGetLongConfigParam ( &EPICS_CA_MAX_ARRAY_BYTES, &maxBytesAsALong ); if ( status || maxBytesAsALong < 0 ) { errlogPrintf ( "cas: EPICS_CA_MAX_ARRAY_BYTES was not a positive integer\n" ); @@ -948,16 +960,16 @@ struct client *create_tcp_client ( SOCKET sock ) void casStatsFetch ( unsigned *pChanCount, unsigned *pCircuitCount ) { - LOCK_CLIENTQ; + LOCK_CLIENTQ; { int circuitCount = ellCount ( &clientQ ); if ( circuitCount < 0 ) { - *pCircuitCount = 0; + *pCircuitCount = 0; } else { - *pCircuitCount = (unsigned) circuitCount; + *pCircuitCount = (unsigned) circuitCount; } *pChanCount = rsrvChannelCount; } - UNLOCK_CLIENTQ; + UNLOCK_CLIENTQ; } diff --git a/src/ioc/rsrv/rsrv.h b/src/ioc/rsrv/rsrv.h index 4eae9bf5a..84414fc8d 100644 --- a/src/ioc/rsrv/rsrv.h +++ b/src/ioc/rsrv/rsrv.h @@ -19,21 +19,28 @@ #ifndef rsrvh #define rsrvh +#include #include "shareLib.h" +#define RSRV_OK 0 +#define RSRV_ERROR (-1) + +#ifdef __cplusplus +extern "C" { +#endif + epicsShareFunc int rsrv_init(void); epicsShareFunc int rsrv_run(void); epicsShareFunc int rsrv_pause(void); epicsShareFunc void casr (unsigned level); -epicsShareFunc void casHostNameInitiatingCurrentThread ( - char * pBuf, unsigned bufSize ); -epicsShareFunc void casUserNameInitiatingCurrentThread ( - char * pBuf, unsigned bufSize ); +epicsShareFunc int casClientInitiatingCurrentThread ( + char * pBuf, size_t bufSize ); epicsShareFunc void casStatsFetch ( unsigned *pChanCount, unsigned *pConnCount ); -#define RSRV_OK 0 -#define RSRV_ERROR (-1) +#ifdef __cplusplus +} +#endif #endif /*rsrvh */ From dbe2a890ecc092c8d18bf3959957d62717be4516 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 29 May 2014 17:11:31 -0500 Subject: [PATCH 3/6] db: Use dbServer API Setting TPRO now prints user@hostname instead of the thread name when a record is processed as a result of a caput. Also added the dbsr command, which currently just calls casr but will call all registered server report routines (e.g. pvaSrv). --- src/ioc/db/dbAccess.c | 65 ++++++++++++++++++++++++-------------- src/ioc/db/dbIocRegister.c | 8 +++++ 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 904423a71..3856d0edc 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -59,6 +59,7 @@ #include "dbNotify.h" #include "dbAccessDefs.h" #include "recGbl.h" +#include "dbServer.h" epicsShareDef struct dbBase *pdbbase = 0; epicsShareDef volatile int interruptAccept=FALSE; @@ -454,6 +455,7 @@ long dbProcess(dbCommon *precord) struct rset *prset = precord->rset; dbRecordType *pdbRecordType = precord->rdes; unsigned char tpro = precord->tpro; + char context[20] = ""; long status = 0; int *ptrace; int set_trace = FALSE; @@ -484,23 +486,33 @@ long dbProcess(dbCommon *precord) /* check for trace processing*/ if (tpro) { - if(*ptrace==0) { + if (!*ptrace) { *ptrace = 1; set_trace = TRUE; } } + if (*ptrace) { + /* Identify this thread's client from server layer */ + if (dbServerClient(context, sizeof(context))) { + /* No client, use thread name */ + strncpy(context, epicsThreadGetNameSelf(), sizeof(context)); + context[sizeof(context) - 1] = 0; + } + } + /* If already active dont process */ if (precord->pact) { - unsigned short monitor_mask; + unsigned short monitor_mask; if (*ptrace) - printf("%s: Active %s\n", - epicsThreadGetNameSelf(), precord->name); + printf("%s: Active %s\n", context, precord->name); + /* raise scan alarm after MAX_LOCK times */ - if (precord->stat==SCAN_ALARM) goto all_done; - if (precord->lcnt++ !=MAX_LOCK) goto all_done; - if (precord->sevr>=INVALID_ALARM) goto all_done; + if ((precord->stat == SCAN_ALARM) || + (precord->lcnt++ < MAX_LOCK) || + (precord->sevr >= INVALID_ALARM)) goto all_done; + recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM); monitor_mask = recGblResetAlarms(precord); monitor_mask |= DBE_VALUE|DBE_LOG; @@ -510,7 +522,8 @@ long dbProcess(dbCommon *precord) monitor_mask); goto all_done; } - else precord->lcnt = 0; + else + precord->lcnt = 0; /* * Check the record disable link. A record will not be @@ -521,9 +534,8 @@ long dbProcess(dbCommon *precord) /* if disabled check disable alarm severity and return success */ if (precord->disa == precord->disv) { - if(*ptrace) - printf("%s: Disabled %s\n", - epicsThreadGetNameSelf(), precord->name); + if (*ptrace) + printf("%s: Disabled %s\n", context, precord->name); /*take care of caching and notifyCompletion*/ precord->rpro = FALSE; @@ -531,7 +543,9 @@ long dbProcess(dbCommon *precord) callNotifyCompletion = TRUE; /* raise disable alarm */ - if (precord->stat==DISABLE_ALARM) goto all_done; + if (precord->stat == DISABLE_ALARM) + goto all_done; + precord->sevr = precord->diss; precord->stat = DISABLE_ALARM; precord->nsev = 0; @@ -547,29 +561,34 @@ long dbProcess(dbCommon *precord) /* locate record processing routine */ /* FIXME: put this in iocInit() !!! */ - if (!(prset=precord->rset) || !(prset->process)) { + if (!prset || !prset->process) { callNotifyCompletion = TRUE; - precord->pact=1;/*set pact TRUE so error is issued only once*/ + precord->pact = 1;/*set pact so error is issued only once*/ recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess"); status = S_db_noRSET; if (*ptrace) - printf("%s: No RSET for %s\n", - epicsThreadGetNameSelf(), precord->name); + printf("%s: No RSET for %s\n", context, precord->name); goto all_done; } - if(*ptrace) - printf("%s: Process %s\n", - epicsThreadGetNameSelf(), precord->name); + + if (*ptrace) + printf("%s: Process %s\n", context, precord->name); + /* process record */ - status = (*prset->process)(precord); + status = prset->process(precord); + /* Print record's fields if PRINT_MASK set in breakpoint field */ if (lset_stack_count != 0) { dbPrint(precord); } + all_done: - if (set_trace) *ptrace = 0; - if(callNotifyCompletion && precord->ppn) dbNotifyCompletion(precord); - return(status); + if (set_trace) + *ptrace = 0; + if (callNotifyCompletion && precord->ppn) + dbNotifyCompletion(precord); + + return status; } /* diff --git a/src/ioc/db/dbIocRegister.c b/src/ioc/db/dbIocRegister.c index 0de2d7172..c07dcc730 100644 --- a/src/ioc/db/dbIocRegister.c +++ b/src/ioc/db/dbIocRegister.c @@ -18,6 +18,7 @@ #include "db_test.h" #include "dbLock.h" #include "dbScan.h" +#include "dbServer.h" #include "dbNotify.h" #include "callback.h" #include "dbIocRegister.h" @@ -90,6 +91,12 @@ static const iocshArg * const dbapArgs[1] = {&dbapArg0}; static const iocshFuncDef dbapFuncDef = {"dbap",1,dbapArgs}; static void dbapCallFunc(const iocshArgBuf *args) { dbap(args[0].sval);} +/* dbsr */ +static const iocshArg dbsrArg0 = { "interest level",iocshArgInt}; +static const iocshArg * const dbsrArgs[1] = {&dbsrArg0}; +static const iocshFuncDef dbsrFuncDef = {"dbsr",1,dbsrArgs}; +static void dbsrCallFunc(const iocshArgBuf *args) { dbsr(args[0].ival);} + /* dbcar */ static const iocshArg dbcarArg0 = { "record name",iocshArgString}; static const iocshArg dbcarArg1 = { "level",iocshArgInt}; @@ -360,6 +367,7 @@ void dbIocRegister(void) iocshRegister(&dbpFuncDef,dbpCallFunc); iocshRegister(&dbapFuncDef,dbapCallFunc); + iocshRegister(&dbsrFuncDef,dbsrCallFunc); iocshRegister(&dbcarFuncDef,dbcarCallFunc); iocshRegister(&dbelFuncDef,dbelCallFunc); From 511b2e4f5c936a962955bac81635857650865244 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 29 May 2014 17:34:23 -0500 Subject: [PATCH 4/6] Document briefly. --- documentation/RELEASE_NOTES.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index d20d9bc65..25590d490 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -15,6 +15,18 @@ EPICS Base 3.15.0.x releases are not intended for use in production systems.

Changes between 3.15.0.1 and 3.15.0.2

+

Added optional dbServer API to database

+ +

A server layer that sits on top of the IOC database may now register itself +as such by calling dbRegisterServer() and providing optional routines +that other components can use. The initial purpose of this API allows the Trace +Processing implementation in dbProcess() to identify a client that +causes a record to process when TPRO is set.

+ +

To support the client idenfication, the server provides a routine that +returns that identity string when called by one of its own processing +threads.

+

Added echo command to iocsh

The single argument string may contain escaped characters, which will be From 42a3b4fbfd1a7c8b0359da6ce56bceba3849c58e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 29 May 2014 17:36:04 -0500 Subject: [PATCH 5/6] Add a ca: prefix to RSRV's identity string --- src/ioc/rsrv/camsgtask.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ioc/rsrv/camsgtask.c b/src/ioc/rsrv/camsgtask.c index 16af5bb0d..126bafd80 100644 --- a/src/ioc/rsrv/camsgtask.c +++ b/src/ioc/rsrv/camsgtask.c @@ -174,7 +174,7 @@ int casClientInitiatingCurrentThread ( char * pBuf, size_t bufSize ) return RSRV_ERROR; if ( pBuf && bufSize ) { - epicsSnprintf(pBuf, bufSize, "%s@%s", + epicsSnprintf(pBuf, bufSize, "ca:%s@%s", pClient->pUserName, pClient->pHostName); } return RSRV_OK; From 6e3e14448ae3099bcee61bb9c78cc9984f524dce Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 17 Sep 2014 10:12:40 -0500 Subject: [PATCH 6/6] Increase context string to 40 characters. --- src/ioc/db/dbAccess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 3856d0edc..5a4b6b613 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -455,7 +455,7 @@ long dbProcess(dbCommon *precord) struct rset *prset = precord->rset; dbRecordType *pdbRecordType = precord->rdes; unsigned char tpro = precord->tpro; - char context[20] = ""; + char context[40] = ""; long status = 0; int *ptrace; int set_trace = FALSE;