Merge branch '7.0' into PSI-7.0

This commit is contained in:
2025-03-21 13:57:06 +01:00
31 changed files with 486 additions and 281 deletions
+18 -38
View File
@@ -115,10 +115,9 @@ static int dbca_chan_count;
* During link modification or IOC shutdown the pca->plink pointer (guarded by caLink.lock)
* is used as a flag to indicate that a link is no longer active.
*
* References to the struct caLink are owned by the dbCaTask, and any scanOnceCallback()
* which is in progress.
* References to the struct caLink are owned by the dbCaTask.
*
* The libca and scanOnceCallback callbacks take no action if pca->plink==NULL.
* The libca callbacks take no action if pca->plink==NULL.
*
* dbCaPutLinkCallback causes an additional complication because
* when dbCaRemoveLink is called the callback may not have occured.
@@ -788,38 +787,6 @@ static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
return status;
}
static void scanComplete(void *raw, dbCommon *prec)
{
caLink *pca = raw;
epicsMutexMustLock(pca->lock);
if(!pca->plink) {
/* IOC shutdown or link re-targeted. Do nothing. */
} else if(pca->scanningOnce==0) {
errlogPrintf("dbCa.c complete callback w/ scanningOnce==0\n");
} else if(--pca->scanningOnce){
/* another scan is queued */
if(scanOnceCallback(prec, scanComplete, raw)) {
errlogPrintf("dbCa.c failed to re-queue scanOnce\n");
} else
caLinkInc(pca);
}
epicsMutexUnlock(pca->lock);
caLinkDec(pca);
}
/* must be called with pca->lock held */
static void scanLinkOnce(dbCommon *prec, caLink *pca) {
if(pca->scanningOnce==0) {
if(scanOnceCallback(prec, scanComplete, pca)) {
errlogPrintf("dbCa.c failed to queue scanOnce\n");
} else
caLinkInc(pca);
}
if(pca->scanningOnce<5)
pca->scanningOnce++;
/* else too many scans queued */
}
static lset dbCa_lset = {
0, 1, /* not Constant, Volatile */
NULL, dbCaRemoveLink,
@@ -856,7 +823,9 @@ static void connectionCallback(struct connection_handler_args arg)
if (precord &&
((ppv_link->pvlMask & pvlOptCP) ||
((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0)))
scanLinkOnce(precord, pca);
{
link_action |= CA_DBPROCESS;
}
goto done;
}
pca->hasReadAccess = ca_read_access(arg.chid);
@@ -988,7 +957,9 @@ static void eventCallback(struct event_handler_args arg)
if ((ppv_link->pvlMask & pvlOptCP) ||
((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0))
scanLinkOnce(precord, pca);
{
addAction(pca, CA_DBPROCESS);
}
}
done:
epicsMutexUnlock(pca->lock);
@@ -1061,7 +1032,9 @@ static void accessRightsCallback(struct access_rights_handler_args arg)
if (precord &&
((ppv_link->pvlMask & pvlOptCP) ||
((ppv_link->pvlMask & pvlOptCPP) && precord->scan == 0)))
scanLinkOnce(precord, pca);
{
addAction(pca, CA_DBPROCESS);
}
done:
epicsMutexUnlock(pca->lock);
}
@@ -1273,6 +1246,13 @@ static void dbCaTask(void *arg)
printLinks(pca);
}
}
if (link_action & CA_DBPROCESS) {
dbCommon *prec;
epicsMutexMustLock(pca->lock);
prec = pca->plink->precord;
epicsMutexUnlock(pca->lock);
db_process(prec);
}
}
SEVCHK(ca_flush_io(), "dbCaTask");
}
+1
View File
@@ -31,6 +31,7 @@
#define CA_MONITOR_STRING 0x20
#define CA_GET_ATTRIBUTES 0x40
#define CA_SYNC 0x1000
#define CA_DBPROCESS 0x2000
/* write type */
#define CA_PUT 0x1
#define CA_PUT_CALLBACK 0x2
+12
View File
@@ -635,9 +635,21 @@ long dbChannelGetField(dbChannel *chan, short dbrType, void *pbuffer,
{
dbCommon *precord = chan->addr.precord;
long status = 0;
unsigned char local_fl = 0;
dbScanLock(precord);
if (!pfl && (ellCount(&chan->pre_chain) || ellCount(&chan->post_chain))) {
pfl = db_create_read_log(chan);
if (pfl) {
local_fl = 1;
pfl = dbChannelRunPreChain(chan, pfl);
pfl = dbChannelRunPostChain(chan, pfl);
}
}
status = dbChannelGet(chan, dbrType, pbuffer, options, nRequest, pfl);
if (local_fl) {
db_delete_field_log(pfl);
}
dbScanUnlock(precord);
return status;
}
+4
View File
@@ -511,6 +511,10 @@ DBCORE_API long dbChannelGet(dbChannel *chan, short type,
* \param[in,out] nRequest Pointer to the element count.
* \param[in] pfl Pointer to a db_field_log or NULL.
* \returns 0, or an error status value.
*
* \since UNRELEASED If pfl is NULL and chan has filters, db_create_read_log() will be called
* internally to create a temporary db_field_log which is passed to dbChannelGet()
* then deallocated.
*/
DBCORE_API long dbChannelGetField(dbChannel *chan, short type,
void *pbuffer, long *options, long *nRequest, void *pfl);
+25
View File
@@ -127,6 +127,31 @@ int dbServerClient(char *pBuf, size_t bufSize)
return -1;
}
int dbServerStats(const char *name, unsigned *channels, unsigned *clients)
{
dbServer *psrv = (dbServer *)ellFirst(&serverList);
if (state != running || !psrv)
return -1;
unsigned tch = 0, tcl = 0, nmatch = 0;
for (; psrv; psrv = (dbServer *)ellNext(&psrv->node)) {
if (psrv->stats &&
(!name || strcmp(name, psrv->name) == 0)) {
unsigned lch = 0, lcl = 0;
psrv->stats(&lch, &lcl);
tch += lch;
tcl += lcl;
nmatch++;
if (name)
break; /* No duplicate names in serverList */
}
}
if (channels) *channels = tch;
if (clients) *clients = tcl;
return nmatch;
}
#define STARTSTOP(routine, method, newState) \
void routine(void) \
{ \
+26 -5
View File
@@ -17,9 +17,6 @@
* the dbServer interface provides allow the IOC to start, pause and stop
* the servers together, and to provide status and debugging information
* to the IOC user/developer through a common set of commands.
*
* @todo No API is provided yet for calling stats() methods.
* Nothing in the IOC calls dbStopServers(), not sure where it should go.
*/
#ifndef INC_dbServer_H
@@ -59,8 +56,8 @@ typedef struct dbServer {
/** @brief Get number of channels and clients currently connected.
*
* @param channels NULL or pointer for returning channel count.
* @param clients NULL or pointer for returning client count.
* @param channels @c NULL or pointer for returning channel count.
* @param clients @c NULL or pointer for returning client count.
*/
void (* stats) (unsigned *channels, unsigned *clients);
@@ -145,6 +142,30 @@ DBCORE_API void dbsr(unsigned level);
*/
DBCORE_API int dbServerClient(char *pBuf, size_t bufSize);
/** @brief CPP Macro indicating the dbServerStats() routine exists.
* @since UNRELEASED
*/
#define HAS_DBSERVER_STATS
/** @brief Fetch statistics from server layers.
*
* This is an API for iocStats and similar to fetch the number of channels
* and clients connected to the registered server layers.
* If the name given is NULL the statistics returned are the totals from
* all registered server layers, otherwise just from the named server.
* @param name Server name
* @param channels NULL, or where to return the channel count
* @param clients NULL or where to return the client count
* @returns -1 if the IOC isn't running or no servers are registered, without
* writing to the statistics variables. Otherwise it writes to the statistics
* variables and returns the number of dbServer::stats() methods called,
* 0 if a named server wasn't found or doesn't have a stats() method.
*
* @since UNRELEASED
*/
DBCORE_API int dbServerStats(const char *name, unsigned *channels,
unsigned *clients);
/** @brief Initialize all registered servers.
*
* Calls all dbServer::init() methods.
+2 -27
View File
@@ -202,7 +202,6 @@ void testdbGetFieldEqual(const char* pv, int dbrType, ...)
void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
{
dbChannel *chan = dbChannelCreate(pv);
db_field_log *pfl = NULL;
long nReq = 1;
union anybuf pod;
long status = S_dbLib_recNotFound;
@@ -212,18 +211,7 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
goto done;
}
if(ellCount(&chan->filters)) {
pfl = db_create_read_log(chan);
if (!pfl) {
testFail("can't db_create_read_log w/ %s", pv);
goto done;
}
pfl = dbChannelRunPreChain(chan, pfl);
pfl = dbChannelRunPostChain(chan, pfl);
}
status = dbChannelGetField(chan, dbrType, pod.bytes, NULL, &nReq, pfl);
status = dbChannelGetField(chan, dbrType, pod.bytes, NULL, &nReq, NULL);
if (status) {
testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status));
goto done;
@@ -261,7 +249,6 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
}
done:
db_delete_field_log(pfl);
if(chan)
dbChannelDelete(chan);
}
@@ -288,7 +275,6 @@ done:
void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsigned long cnt, const void *pbufraw)
{
dbChannel *chan = dbChannelCreate(pv);
db_field_log *pfl = NULL;
const long vSize = dbValueSize(dbfType);
const long nStore = vSize * nRequest;
long status = S_dbLib_recNotFound;
@@ -300,24 +286,13 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
goto done;
}
if(ellCount(&chan->filters)) {
pfl = db_create_read_log(chan);
if (!pfl) {
testFail("can't db_create_read_log w/ %s", pv);
goto done;
}
pfl = dbChannelRunPreChain(chan, pfl);
pfl = dbChannelRunPostChain(chan, pfl);
}
gbuf = gstore = malloc(nStore);
if(!gbuf && nStore!=0) { /* note that malloc(0) is allowed to return NULL on success */
testFail("Allocation failed esize=%ld total=%ld", vSize, nStore);
return;
}
status = dbChannelGetField(chan, dbfType, gbuf, NULL, &nRequest, pfl);
status = dbChannelGetField(chan, dbfType, gbuf, NULL, &nRequest, NULL);
if (status) {
testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status);
+27
View File
@@ -148,6 +148,7 @@ int dbChannel_get_count(
long options;
long i;
long zero = 0;
unsigned char local_fl = 0;
/* The order of the DBR* elements in the "newSt" structures below is
* very important and must correspond to the order of processing
@@ -156,6 +157,16 @@ int dbChannel_get_count(
dbScanLock(dbChannelRecord(chan));
/* If filters are involved in a read, create field log and run filters */
if (!pfl && (ellCount(&chan->pre_chain) || ellCount(&chan->post_chain))) {
pfl = db_create_read_log(chan);
if (pfl) {
local_fl = 1;
pfl = dbChannelRunPreChain(chan, pfl);
pfl = dbChannelRunPostChain(chan, pfl);
}
}
switch(buffer_type) {
case(oldDBR_STRING):
status = dbChannelGet(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl);
@@ -800,6 +811,8 @@ int dbChannel_get_count(
dbScanUnlock(dbChannelRecord(chan));
if (local_fl) db_delete_field_log(pfl);
if (status) return -1;
return 0;
}
@@ -1029,3 +1042,17 @@ int db_put_process(processNotify *ppn, notifyPutType type,
ppn->status = notifyError;
return 1;
}
void db_process(struct dbCommon *prec)
{
if (prec->pact) {
if (dbAccessDebugPUTF && prec->tpro)
printf("%s: dbPutField to Active '%s', setting RPRO=1\n",
epicsThreadGetNameSelf(), prec->name);
prec->rpro = TRUE;
} else {
/* indicate that dbPutField called dbProcess */
prec->putf = TRUE;
(void)dbProcess(prec);
}
}
@@ -22,6 +22,8 @@ extern "C" {
#include "dbCoreAPI.h"
struct dbCommon;
DBCORE_API extern struct dbBase *pdbbase;
DBCORE_API extern volatile int interruptAccept;
@@ -36,7 +38,9 @@ DBCORE_API int dbChannel_put(struct dbChannel *chan, int src_type,
const void *psrc, long no_elements);
DBCORE_API int dbChannel_get_count(struct dbChannel *chan,
int buffer_type, void *pbuffer, long *nRequest, void *pfl);
#ifdef EPICS_DBCA_PRIVATE_API
DBCORE_API void db_process(struct dbCommon *prec);
#endif
#ifdef __cplusplus
}
-26
View File
@@ -540,7 +540,6 @@ static void read_reply ( void *pArg, struct dbChannel *dbch,
const int readAccess = asCheckGet ( pciu->asClientPVT );
int status;
int autosize;
int local_fl = 0;
long item_count;
ca_uint32_t payload_size;
dbAddr *paddr=&dbch->addr;
@@ -582,21 +581,9 @@ static void read_reply ( void *pArg, struct dbChannel *dbch,
return;
}
/* If filters are involved in a read, create field log and run filters */
if (!pfl && (ellCount(&dbch->pre_chain) || ellCount(&dbch->post_chain))) {
pfl = db_create_read_log(dbch);
if (pfl) {
local_fl = 1;
pfl = dbChannelRunPreChain(dbch, pfl);
pfl = dbChannelRunPostChain(dbch, pfl);
}
}
status = dbChannel_get_count ( dbch, pevext->msg.m_dataType,
pPayload, &item_count, pfl);
if (local_fl) db_delete_field_log(pfl);
if ( status < 0 ) {
/* Clients recv the status of the operation directly to the
* event/put/get callback. (from CA_V41())
@@ -663,7 +650,6 @@ static int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *p
ca_uint32_t payloadSize;
void *pPayload;
int status;
int local_fl = 0;
db_field_log *pfl = NULL;
if ( ! pciu ) {
@@ -702,21 +688,9 @@ static int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *p
return RSRV_OK;
}
/* If filters are involved in a read, create field log and run filters */
if (ellCount(&pciu->dbch->pre_chain) || ellCount(&pciu->dbch->post_chain)) {
pfl = db_create_read_log(pciu->dbch);
if (pfl) {
local_fl = 1;
pfl = dbChannelRunPreChain(pciu->dbch, pfl);
pfl = dbChannelRunPostChain(pciu->dbch, pfl);
}
}
status = dbChannel_get ( pciu->dbch, mp->m_dataType,
pPayload, mp->m_count, pfl );
if (local_fl) db_delete_field_log(pfl);
if ( status < 0 ) {
send_err ( mp, ECA_GETFAIL, pClient, RECORD_NAME ( pciu->dbch ) );
SEND_UNLOCK ( pClient );