Avoid race in linkRetarget
Add dbCaSync() to avoid a race between a call to dbCaGetField() and the link becoming connected.
This commit is contained in:
+41
-1
@@ -13,7 +13,7 @@
|
||||
* Date: 26MAR96
|
||||
*
|
||||
*/
|
||||
|
||||
#define EPICS_DBCA_PRIVATE_API
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -191,6 +191,42 @@ static void caLinkDec(caLink *pca)
|
||||
if (callback) callback(userPvt);
|
||||
}
|
||||
|
||||
/* Block until worker thread has processed all previously queued actions.
|
||||
* Does not prevent additional actions from being queued.
|
||||
*/
|
||||
void dbCaSync(void)
|
||||
{
|
||||
epicsEventId wake;
|
||||
caLink templink;
|
||||
|
||||
/* we only partially initialize templink.
|
||||
* It has no link field and no subscription
|
||||
* so the worker must handle it early
|
||||
*/
|
||||
memset(&templink, 0, sizeof(templink));
|
||||
templink.refcount = 1;
|
||||
|
||||
wake = epicsEventMustCreate(epicsEventEmpty);
|
||||
templink.lock = epicsMutexMustCreate();
|
||||
|
||||
templink.userPvt = wake;
|
||||
|
||||
addAction(&templink, CA_SYNC);
|
||||
|
||||
epicsEventMustWait(wake);
|
||||
/* Worker holds workListLock when calling epicsEventMustTrigger()
|
||||
* we cycle through workListLock to ensure worker call to
|
||||
* epicsEventMustTrigger() returns before we destroy the event.
|
||||
*/
|
||||
epicsMutexMustLock(workListLock);
|
||||
epicsMutexUnlock(workListLock);
|
||||
|
||||
assert(templink.refcount==1);
|
||||
|
||||
epicsMutexDestroy(templink.lock);
|
||||
epicsEventDestroy(wake);
|
||||
}
|
||||
|
||||
void dbCaCallbackProcess(void *userPvt)
|
||||
{
|
||||
struct link *plink = (struct link *)userPvt;
|
||||
@@ -947,9 +983,13 @@ static void dbCaTask(void *arg)
|
||||
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 */
|
||||
pca->link_action = 0;
|
||||
if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding;
|
||||
epicsMutexUnlock(workListLock); /* Give back immediately */
|
||||
if (link_action&CA_SYNC)
|
||||
continue;
|
||||
if (link_action & CA_CLEAR_CHANNEL) { /* This must be first */
|
||||
caLinkDec(pca);
|
||||
/* No alarm is raised. Since link is changing so what? */
|
||||
|
||||
@@ -71,6 +71,10 @@ epicsShareFunc long dbCaGetUnits(const struct link *plink,
|
||||
|
||||
extern struct ca_client_context * dbCaClientContext;
|
||||
|
||||
#ifdef EPICS_DBCA_PRIVATE_API
|
||||
epicsShareFunc void dbCaSync(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define CA_MONITOR_NATIVE 0x10
|
||||
#define CA_MONITOR_STRING 0x20
|
||||
#define CA_GET_ATTRIBUTES 0x40
|
||||
#define CA_SYNC 0x1000
|
||||
/* write type */
|
||||
#define CA_PUT 0x1
|
||||
#define CA_PUT_CALLBACK 0x2
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*
|
||||
* Test using several stringout records to retarget the link of another record
|
||||
*/
|
||||
#define EPICS_DBCA_PRIVATE_API
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -37,6 +38,13 @@ static void testRetarget(void)
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
/* wait for local CA links to be connected or dbPutField() will fail */
|
||||
/* wait for initial CA_CONNECT actions to be processed.
|
||||
* Assume that local CA links deliver callbacks synchronously
|
||||
* eg. that ca_create_channel() will invoke the connection callback
|
||||
* before returning.
|
||||
*/
|
||||
dbCaSync();
|
||||
|
||||
lnkmon = testMonitorCreate("rec:ai.INP", DBE_VALUE, 0);
|
||||
valmon = testMonitorCreate("rec:ai", DBE_VALUE, 0);
|
||||
|
||||
Reference in New Issue
Block a user