dbCa: iocInit wait for all conditions

After connectCallback, need to wait for up to three
concurrent actions.  Native and string subscriptions,
as well as GET of metadata.

Complicated because event_handler_args does not identify
the evid.

see 717d69e1fc
This commit is contained in:
Michael Davidsaver authored and Andrew Johnson committed 2026-04-15 10:05:07 -05:00
1 parent b761beaf0c
commit ef48298294
3 files changed
+54 -18

No files matched your search

+42 -16
View File
@@ -65,7 +65,7 @@ extern int dbServiceIsolate;
static ELLLIST workList = ELLLIST_INIT; /* Work list for dbCaTask */
static epicsMutexId workListLock; /*Mutual exclusions semaphores for workList*/
static epicsEventId workListEvent; /*wakeup event for dbCaTask*/
static size_t initOutstanding; // one count for every link with DBCA_CALLBACK_INIT_WAIT
static size_t initOutstanding; // one count for every link with a DBCA_CALLBACK_INIT_WAIT bit
static int removesOutstanding = 0;
#define removesOutstandingWarning 10000
@@ -405,7 +405,7 @@ void dbCaAddLinkCallbackOpt(struct dbLocker *locker, struct link *plink,
pca->userPvt = userPvt;
pca->flags = flags;
if(flags & DBCA_CALLBACK_INIT_WAIT)
if(flags & DBCA_CALLBACK_INIT_WAITING)
epicsAtomicIncrSizeT(&initOutstanding);
epicsMutexMustLock(pca->lock);
@@ -830,6 +830,21 @@ static lset dbCa_lset = {
scanForward, doLocked
};
// caller must hold caLink::lock
static
short testInitReady(caLink *pca, unsigned clear)
{
if(pca->flags & DBCA_CALLBACK_INIT_WAIT_MASK) {
pca->flags &= ~clear;
assert(pca->flags & DBCA_CALLBACK_INIT_WAITING); // only cleared by dbCa worker
if(!(pca->flags & DBCA_CALLBACK_INIT_WAIT_MASK)) {
// all complete
return CA_INIT_READY;
}
}
return 0;
}
static void connectionCallback(struct connection_handler_args arg)
{
caLink *pca;
@@ -859,8 +874,6 @@ static void connectionCallback(struct connection_handler_args arg)
}
pca->hasReadAccess = ca_read_access(arg.chid);
pca->hasWriteAccess = ca_write_access(arg.chid);
if (pca->flags & DBCA_CALLBACK_INIT_WAIT)
link_action |= CA_INIT_READY; // declare initialized, unless cleared below
if (pca->gotFirstConnection) {
if (pca->nelements != ca_element_count(arg.chid) ||
@@ -895,11 +908,13 @@ static void connectionCallback(struct connection_handler_args arg)
pca->dbrType = ca_field_type(arg.chid);
if ((plink->value.pv_link.pvlMask & pvlOptInpNative) && !pca->pgetNative) {
link_action |= CA_MONITOR_NATIVE;
link_action &= ~CA_INIT_READY; // defer to eventCallback()
} else {
link_action |= testInitReady(pca, DBCA_CALLBACK_INIT_WAIT_NATIVE);
}
if ((plink->value.pv_link.pvlMask & pvlOptInpString) && !pca->pgetString) {
link_action |= CA_MONITOR_STRING;
link_action &= ~CA_INIT_READY; // defer to eventCallback()
} else {
link_action |= testInitReady(pca, DBCA_CALLBACK_INIT_WAIT_STRING);
}
if ((plink->value.pv_link.pvlMask & pvlOptOutNative) && pca->gotOutNative) {
link_action |= CA_WRITE_NATIVE;
@@ -911,8 +926,8 @@ static void connectionCallback(struct connection_handler_args arg)
if (pca->dbrType != DBR_STRING) {
/* will run connect() callback later */
link_action |= CA_GET_ATTRIBUTES;
link_action &= ~CA_INIT_READY; // defer to getAttribEventCallback()
} else {
link_action |= testInitReady(pca, DBCA_CALLBACK_INIT_WAIT_ATTRIB);
connect = pca->connect;
userPvt = pca->userPvt;
}
@@ -922,7 +937,7 @@ done:
if (connect) connect(userPvt);
}
static void eventCallback(struct event_handler_args arg)
static void eventCallbackComm(struct event_handler_args arg, unsigned initmask)
{
caLink *pca = (caLink *)arg.usr;
struct link *plink;
@@ -996,13 +1011,22 @@ static void eventCallback(struct event_handler_args arg)
link_action |= CA_DBPROCESS;
}
}
if (pca->flags & DBCA_CALLBACK_INIT_WAIT)
link_action |= CA_INIT_READY;
link_action |= testInitReady(pca, initmask);
done:
if (link_action) addAction(pca, link_action);
epicsMutexUnlock(pca->lock);
if (monitor) monitor(userPvt);
}
static void eventCallbackNative(struct event_handler_args arg)
{
eventCallbackComm(arg, DBCA_CALLBACK_INIT_WAIT_NATIVE);
}
static void eventCallbackString(struct event_handler_args arg)
{
eventCallbackComm(arg, DBCA_CALLBACK_INIT_WAIT_STRING);
}
static void exceptionCallback(struct exception_handler_args args)
{
@@ -1123,8 +1147,9 @@ static void getAttribEventCallback(struct event_handler_args arg)
pca->alarmLimits[3] = pdbr->upper_alarm_limit;
pca->precision = pdbr->precision;
memcpy(pca->units, pdbr->units, MAX_UNITS_SIZE);
if (pca->flags & DBCA_CALLBACK_INIT_WAIT)
addAction(pca, CA_INIT_READY);
short link_action = testInitReady(pca, DBCA_CALLBACK_INIT_WAIT_ATTRIB);
if (link_action)
addAction(pca, link_action);
epicsMutexUnlock(pca->lock);
if (getAttributes) getAttributes(getAttributesPvt);
if (connect) connect(userPvt);
@@ -1265,7 +1290,7 @@ static void dbCaTask(void *arg)
status = ca_add_array_event(
dbf_type_to_DBR_TIME(ca_field_type(pca->chid)),
0, /* dynamic size */
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0,
pca->chid, eventCallbackNative, pca, 0.0, 0.0, 0.0,
&pca->evidNative);
if (status != ECA_NORMAL) {
errlogPrintf("dbCaTask ca_add_array_event %s\n",
@@ -1278,7 +1303,7 @@ static void dbCaTask(void *arg)
pca->pgetString = dbCalloc(1, MAX_STRING_SIZE);
epicsMutexUnlock(pca->lock);
status = ca_add_array_event(DBR_TIME_STRING, 1,
pca->chid, eventCallback, pca, 0.0, 0.0, 0.0,
pca->chid, eventCallbackString, pca, 0.0, 0.0, 0.0,
&pca->evidString);
if (status != ECA_NORMAL) {
errlogPrintf("dbCaTask ca_add_array_event %s\n",
@@ -1295,8 +1320,9 @@ static void dbCaTask(void *arg)
db_process(prec);
dbScanUnlock(prec);
}
if ((link_action & CA_INIT_READY) && (pca->flags & DBCA_CALLBACK_INIT_WAIT)) {
pca->flags &= ~DBCA_CALLBACK_INIT_WAIT;
if ((link_action & CA_INIT_READY) && (pca->flags & DBCA_CALLBACK_INIT_WAITING)) {
assert(!(pca->flags & DBCA_CALLBACK_INIT_WAIT_MASK));
pca->flags &= ~DBCA_CALLBACK_INIT_WAITING;
if (epicsAtomicDecrSizeT(&initOutstanding)==0)
{
epicsEventSignal(startStopEvent); /* unblock dbCaRun() */
+11 -1
View File
@@ -112,7 +112,17 @@ typedef struct caLink
unsigned long nUpdate;
}caLink;
#define DBCA_CALLBACK_INIT_WAIT (1)
/* Local link initial connection waiting
*/
// starting condition
#define DBCA_CALLBACK_INIT_START (0xf)
// set while initOutstanding incremented
#define DBCA_CALLBACK_INIT_WAITING (0x1)
// set for each condition necessary prior to completion (decrement initOutstanding)
#define DBCA_CALLBACK_INIT_WAIT_NATIVE (0x2)
#define DBCA_CALLBACK_INIT_WAIT_STRING (0x4)
#define DBCA_CALLBACK_INIT_WAIT_ATTRIB (0x8)
#define DBCA_CALLBACK_INIT_WAIT_MASK (0xe)
void dbCaAddLinkCallbackOpt(struct dbLocker *locker, struct link *plink,
dbCaCallback connect, dbCaCallback monitor,
+1 -1
View File
@@ -127,7 +127,7 @@ void dbInitLink(struct link *plink, short dbfType)
int isLocal = dbChannelTest(plink->value.pv_link.pvname)==0;
dbCaAddLinkCallbackOpt(NULL, plink, NULL, NULL, NULL, isLocal ? DBCA_CALLBACK_INIT_WAIT : 0);
dbCaAddLinkCallbackOpt(NULL, plink, NULL, NULL, NULL, isLocal ? DBCA_CALLBACK_INIT_START : 0);
if (dbfType == DBF_FWDLINK) {
char *pperiod = strrchr(plink->value.pv_link.pvname, '.');