diff --git a/modules/ca/src/client/access.cpp b/modules/ca/src/client/access.cpp index 3fc26ae88..19f62460f 100644 --- a/modules/ca/src/client/access.cpp +++ b/modules/ca/src/client/access.cpp @@ -717,6 +717,18 @@ int epicsStdCall ca_context_status ( ca_client_context * pcac, unsigned level ) return ECA_NORMAL; } +extern "C" +LIBCA_API +void dbCaSyncLocal(void); + +void dbCaSyncLocal(void) +{ + if(struct ca_client_context * ctxt = ca_current_context()) { + // bounce for access to private data member + ctxt->sync(); + } +} + /* * ca_current_context () * diff --git a/modules/ca/src/client/ca_client_context.cpp b/modules/ca/src/client/ca_client_context.cpp index 6a3b3b1b2..6dd15826c 100644 --- a/modules/ca/src/client/ca_client_context.cpp +++ b/modules/ca/src/client/ca_client_context.cpp @@ -728,6 +728,12 @@ epicsMutex & ca_client_context::mutexRef () const return this->mutex; } +void ca_client_context::sync() +{ + // bounce through vtable + this->pServiceContext->sync(); +} + cacContext & ca_client_context::createNetworkContext ( epicsMutex & mutexIn, epicsMutex & cbMutexIn ) { diff --git a/modules/ca/src/client/cac.cpp b/modules/ca/src/client/cac.cpp index fd641ad21..13ef7514c 100644 --- a/modules/ca/src/client/cac.cpp +++ b/modules/ca/src/client/cac.cpp @@ -398,6 +398,8 @@ void cac::flush ( epicsGuard < epicsMutex > & guard ) } } +void cac::sync() {} + unsigned cac::circuitCount ( epicsGuard < epicsMutex > & guard ) const { diff --git a/modules/ca/src/client/cac.h b/modules/ca/src/client/cac.h index 8fcb7c563..725254f78 100644 --- a/modules/ca/src/client/cac.h +++ b/modules/ca/src/client/cac.h @@ -115,6 +115,7 @@ public: // IO management void flush ( epicsGuard < epicsMutex > & guard ); + void sync (); bool executeResponse ( callbackManager &, tcpiiu &, const epicsTime & currentTime, caHdrLargeArray &, char *pMsgBody ); diff --git a/modules/ca/src/client/cacIO.h b/modules/ca/src/client/cacIO.h index 777155047..84938246c 100644 --- a/modules/ca/src/client/cacIO.h +++ b/modules/ca/src/client/cacIO.h @@ -279,6 +279,7 @@ public: cacChannel::priLev = cacChannel::priorityDefault ) = 0; virtual void flush ( epicsGuard < epicsMutex > & ) = 0; + virtual void sync () = 0; virtual unsigned circuitCount ( epicsGuard < epicsMutex > & ) const = 0; virtual void selfTest ( diff --git a/modules/ca/src/client/oldAccess.h b/modules/ca/src/client/oldAccess.h index ec2df38ca..6fbef965c 100644 --- a/modules/ca/src/client/oldAccess.h +++ b/modules/ca/src/client/oldAccess.h @@ -349,6 +349,7 @@ public: void destroyPutCallback ( epicsGuard < epicsMutex > &, putCallback & ); void destroySubscription ( epicsGuard < epicsMutex > &, oldSubscription & ); epicsMutex & mutexRef () const; + void sync(); template < class T > void whenThereIsAnExceptionDestroySyncGroupIO ( epicsGuard < epicsMutex > &, T & ); diff --git a/modules/database/src/ioc/db/dbCAC.h b/modules/database/src/ioc/db/dbCAC.h index 9fbba07cd..dfd7e3311 100644 --- a/modules/database/src/ioc/db/dbCAC.h +++ b/modules/database/src/ioc/db/dbCAC.h @@ -207,6 +207,7 @@ private: cacChannel::priLev ); void flush ( epicsGuard < epicsMutex > & ); + void sync (); unsigned circuitCount ( epicsGuard < epicsMutex > & ) const; void selfTest ( diff --git a/modules/database/src/ioc/db/dbCa.c b/modules/database/src/ioc/db/dbCa.c index 03490e9b7..0a5214895 100644 --- a/modules/database/src/ioc/db/dbCa.c +++ b/modules/database/src/ioc/db/dbCa.c @@ -209,9 +209,9 @@ void testdbCaWaitForEventCB(void *raw) { struct waitPvt *pvt = raw; - epicsMutexMustLock(pvt->pca->lock); + epicsMutexMustLock(workListLock); epicsEventMustTrigger(pvt->evt); - epicsMutexUnlock(pvt->pca->lock); + epicsMutexUnlock(workListLock); } static @@ -239,8 +239,6 @@ void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event dbScanUnlock(plink->precord); epicsEventMustWait(evt); - /* ensure worker has finished executing */ - dbCaSync(); dbScanLock(plink->precord); epicsMutexMustLock(pca->lock); @@ -250,8 +248,15 @@ void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event pca->userPvt = NULL; } - epicsEventDestroy(evt); epicsMutexUnlock(pca->lock); + + /* ensure worker has finished executing */ + dbCaSync(); + + epicsMutexMustLock(workListLock); /* lock to ensure that epicsEventMustTrigger() has returned */ + epicsEventDestroy(evt); + epicsMutexUnlock(workListLock); + caLinkDec(pca); dbScanUnlock(plink->precord); } @@ -266,6 +271,10 @@ void testdbCaWaitForUpdateCount(DBLINK *plink, unsigned long cnt) testdbCaWaitForEvent(plink, cnt, testEventCount); } +// private access to access.cpp +LIBCA_API +void dbCaSyncLocal(void); + /* Block until worker thread has processed all previously queued actions. * Does not prevent additional actions from being queued. */ @@ -274,6 +283,8 @@ void dbCaSync(void) epicsEventId wake; caLink templink; + dbCaSyncLocal(); + /* we only partially initialize templink. * It has no link field and no subscription * so the worker must handle it early diff --git a/modules/database/src/ioc/db/dbContext.cpp b/modules/database/src/ioc/db/dbContext.cpp index c38ca663c..9aca23d1a 100644 --- a/modules/database/src/ioc/db/dbContext.cpp +++ b/modules/database/src/ioc/db/dbContext.cpp @@ -399,6 +399,23 @@ void dbContext::flush ( } } +static +void dbContextDummyExtraLabor(void *) {} + +void dbContext::sync() +{ + // ctx created lazily on first subscription + { + epicsGuard G(mutex); + if(!ctx) + return; + } + // assumes dbContext makes no other use of extra labor + db_add_extra_labor_event(ctx, dbContextDummyExtraLabor, NULL); + db_post_extra_labor(ctx); + db_flush_extra_labor_event(ctx); +} + unsigned dbContext::circuitCount ( epicsGuard < epicsMutex > & guard ) const {