From e9e576f4bb66b1e57ec0327789e5650187fb3005 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 Nov 2021 10:25:50 -0700 Subject: [PATCH] add testdbCaWaitForUpdateCount() and fix dbCaSync() Add testdbCaWaitForUpdateCount() to wait for CA link data event counter. dbCaSync() actually wait for work queue to be empty --- modules/database/src/ioc/db/dbCa.c | 70 ++++++++++++++++++++++++++++-- modules/database/src/ioc/db/dbCa.h | 4 ++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/modules/database/src/ioc/db/dbCa.c b/modules/database/src/ioc/db/dbCa.c index 56d700396..e9d0f53e3 100644 --- a/modules/database/src/ioc/db/dbCa.c +++ b/modules/database/src/ioc/db/dbCa.c @@ -196,6 +196,53 @@ static void caLinkDec(caLink *pca) if (callback) callback(userPvt); } +struct waitPvt { + caLink *pca; + epicsEventId evt; +}; + +static +void testdbCaWaitForUpdateCountCB(void *raw) +{ + struct waitPvt *pvt = raw; + + epicsMutexMustLock(pvt->pca->lock); + epicsEventMustTrigger(pvt->evt); + epicsMutexUnlock(pvt->pca->lock); +} + +void testdbCaWaitForUpdateCount(DBLINK *plink, unsigned long cnt) +{ + + caLink *pca; + epicsEventId evt = epicsEventMustCreate(epicsEventEmpty); + + dbScanLock(plink->precord); + + pca = (caLink *)plink->value.pv_link.pvt; + + assert(plink->type==CA_LINK); + epicsMutexMustLock(pca->lock); + assert(!pca->monitor && !pca->userPvt); + + while(pca->nUpdate < cnt) { + struct waitPvt pvt = {pca, evt}; + pca->monitor = &testdbCaWaitForUpdateCountCB; + pca->userPvt = &pvt; + epicsMutexUnlock(pca->lock); + dbScanUnlock(plink->precord); + epicsEventMustWait(evt); + dbScanLock(plink->precord); + epicsMutexMustLock(pca->lock); + pca->monitor = NULL; + pca->userPvt = NULL; + } + + epicsEventDestroy(evt); + epicsMutexUnlock(pca->lock); + dbScanUnlock(plink->precord); +} + /* Block until worker thread has processed all previously queued actions. * Does not prevent additional actions from being queued. */ @@ -234,16 +281,23 @@ void dbCaSync(void) DBCORE_API unsigned long dbCaGetUpdateCount(struct link *plink) { - caLink *pca = (caLink *)plink->value.pv_link.pvt; + caLink *pca; unsigned long ret; - if (!pca) return (unsigned long)-1; + dbScanLock(plink->precord); + pca= (caLink *)plink->value.pv_link.pvt; + + if (!pca) { + dbScanUnlock(plink->precord); + return (unsigned long)-1; + } epicsMutexMustLock(pca->lock); ret = pca->nUpdate; epicsMutexUnlock(pca->lock); + dbScanUnlock(plink->precord); return ret; } @@ -1058,6 +1112,7 @@ static void getAttribEventCallback(struct event_handler_args arg) static void dbCaTask(void *arg) { + epicsEventId requestSync = NULL; taskwdInsert(0, NULL, NULL); SEVCHK(ca_context_create(ca_enable_preemptive_callback), "dbCaTask calling ca_context_create"); @@ -1078,13 +1133,20 @@ static void dbCaTask(void *arg) epicsMutexMustLock(workListLock); if (!(pca = (caLink *)ellGet(&workList))){ /* Take off list head */ + if(requestSync) { + /* dbCaSync() requires workListLock to be held here */ + epicsEventMustTrigger(requestSync); + requestSync = NULL; + } epicsMutexUnlock(workListLock); if (dbCaCtl == ctlExit) goto shutdown; break; /* workList is empty */ } link_action = pca->link_action; - if (link_action&CA_SYNC) - epicsEventMustTrigger((epicsEventId)pca->userPvt); /* dbCaSync() requires workListLock to be held here */ + if (link_action&CA_SYNC) { + assert(!requestSync); + requestSync = pca->userPvt; + } pca->link_action = 0; if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding; epicsMutexUnlock(workListLock); /* Give back immediately */ diff --git a/modules/database/src/ioc/db/dbCa.h b/modules/database/src/ioc/db/dbCa.h index 42ce1b338..88bfadf25 100644 --- a/modules/database/src/ioc/db/dbCa.h +++ b/modules/database/src/ioc/db/dbCa.h @@ -48,8 +48,12 @@ DBCORE_API long dbCaPutLink(struct link *plink,short dbrType, extern struct ca_client_context * dbCaClientContext; #ifdef EPICS_DBCA_PRIVATE_API +/* Wait CA link work queue to become empty. eg. after from dbPut() to OUT */ DBCORE_API void dbCaSync(void); +/* Get current number of data updates received. */ DBCORE_API unsigned long dbCaGetUpdateCount(struct link *plink); +/* Wait for the data update counter to reach the specified value. */ +DBCORE_API void testdbCaWaitForUpdateCount(DBLINK *plink, unsigned long cnt); #endif /* These macros are for backwards compatibility */