add dbCaPutLinkCallback

This commit is contained in:
Marty Kraimer
2003-11-06 16:39:05 +00:00
parent eab7314e36
commit 46a8fac619
4 changed files with 248 additions and 140 deletions
+234 -137
View File
@@ -61,6 +61,10 @@ struct ca_client_context * dbCaClientContext;
void dbCaTask(void); /*The Channel Access Task*/
extern void dbServiceIOInit();
#define printLinks(pcaLink) \
errlogPrintf("%s has DB CA link to %s\n",\
((dbCommon*)((pcaLink)->plink->value.pv_link.precord))->name,(pcaLink->pvname))
/* caLink locking
*
@@ -108,6 +112,15 @@ extern void dbServiceIOInit();
* it finds pca->plink=0 and does nothing. Once ca_clear_channel
* is called no other callback for this caLink will be called.
*
* dbCaPutLinkCallback causes an additional complication because
* because when dbCaRemoveLink is called The callback may not have occured.
* What is done is the following:
* If callback has not occured dbCaRemoveLink sets plinkPutCallback=plink
* If putCallback is called before dbCaTask calls ca_clear_channel
* It does NOT call the users callback.
* dbCaTask calls the users callback passing plinkPutCallback AFTER
* it has called ca_clear_channel
* Thus the users callback will get called exactly once
*/
STATIC void addAction(caLink *pca, short link_action)
@@ -119,12 +132,14 @@ STATIC void addAction(caLink *pca, short link_action)
if((pca->link_action&CA_CLEAR_CHANNEL)!=0) {
errlogPrintf("dbCa:addAction %d but CA_CLEAR_CHANNEL already requested\n",
link_action);
printLinks(pca);
callAdd = FALSE;
link_action=0;
}
if(link_action&CA_CLEAR_CHANNEL) {
if(++removesOutstanding>=removesOutstandingWarning) {
errlogPrintf("dbCa: Warning removesOutstanding %d\n",removesOutstanding);
printLinks(pca);
}
while(removesOutstanding>=removesOutstandingWarning) {
epicsMutexUnlock(workListLock);
@@ -148,7 +163,7 @@ void epicsShareAPI dbCaLinkInit(void)
epicsThreadGetStackSize(epicsThreadStackBig),
(EPICSTHREADFUNC) dbCaTask,0);
}
void epicsShareAPI dbCaAddLink( struct link *plink)
{
caLink *pca;
@@ -177,6 +192,7 @@ void epicsShareAPI dbCaRemoveLink( struct link *plink)
epicsMutexMustLock(pca->lock);
pca->plink = 0;
plink->value.pv_link.pvt = 0;
if(pca->putCallback) pca->plinkPutCallback = plink;
/*Must unlock before addAction. Otherwise dbCaTask might free first*/
epicsMutexUnlock(pca->lock);
addAction(pca,CA_CLEAR_CHANNEL);
@@ -246,8 +262,8 @@ done:
return(status);
}
long epicsShareAPI dbCaPutLink(struct link *plink,short dbrType,
const void *psource,long nelements)
long putLinkPvt(struct link *plink,short dbrType,
const void *psource,long nelements,dbCaPutCallback callback)
{
caLink *pca = (caLink *)plink->value.pv_link.pvt;
long (*pconvert)();
@@ -299,10 +315,24 @@ long epicsShareAPI dbCaPutLink(struct link *plink,short dbrType,
if(pca->newOutNative) pca->nNoWrite++;
pca->newOutNative = TRUE;
}
if(callback) {
pca->putType = CA_PUT_CALLBACK;
pca->putCallback = callback;
} else {
pca->putType = CA_PUT;
pca->putCallback = 0;
}
addAction(pca,link_action);
epicsMutexUnlock(pca->lock);
return(status);
}
long epicsShareAPI dbCaPutLink(struct link *plink,short dbrType,
const void *pbuffer,long nRequest)
{return(putLinkPvt(plink,dbrType,pbuffer,nRequest,0));}
long epicsShareAPI dbCaPutLinkCallback( struct link *plink,short dbrType,
const void *pbuffer,long nRequest,dbCaPutCallback callback)
{return(putLinkPvt(plink,dbrType,pbuffer,nRequest,callback));}
#define pcaGetCheck \
assert(plink); \
@@ -474,29 +504,72 @@ long epicsShareAPI dbCaGetUnits(
return(gotAttributes ? 0 : -1);
}
STATIC void exceptionCallback(struct exception_handler_args args)
STATIC void connectionCallback(struct connection_handler_args arg)
{
const char *context = (args.ctx ? args.ctx : "unknown");
caLink *pca;
short link_action = 0;
struct link *plink;
errlogPrintf("DB CA Link Exception: \"%s\", context \"%s\"\n",
ca_message(args.stat), context);
if (args.chid) {
errlogPrintf(
"DB CA Link Exception: channel \"%s\"\n",
ca_name(args.chid));
if (ca_state(args.chid)==cs_conn) {
errlogPrintf(
"DB CA Link Exception: native T=%s, request T=%s,"
" native N=%ld, request N=%ld, "
" access rights {%s%s}\n",
dbr_type_to_text(ca_field_type(args.chid)),
dbr_type_to_text(args.type),
ca_element_count(args.chid),
args.count,
ca_read_access(args.chid) ? "R" : "",
ca_write_access(args.chid) ? "W" : "");
pca = ca_puser(arg.chid);
assert(pca);
epicsMutexMustLock(pca->lock);
plink = pca->plink;
if(!plink) goto done;
pca->isConnected = (ca_state(arg.chid)==cs_conn) ? TRUE : FALSE ;
if(!pca->isConnected) {
struct pv_link *ppv_link = &(plink->value.pv_link);
dbCommon *precord = ppv_link->precord;
pca->nDisconnect++;
if(precord) {
if((ppv_link->pvlMask&pvlOptCP)
|| ((ppv_link->pvlMask&pvlOptCPP)&&(precord->scan==0)))
scanOnce(precord);
}
goto done;
}
pca->hasReadAccess = ca_read_access(arg.chid);
pca->hasWriteAccess = ca_write_access(arg.chid);
if(pca->gotFirstConnection) {
if((pca->nelements != ca_element_count(arg.chid))
|| (pca->dbrType != ca_field_type(arg.chid))){
/* field type or nelements changed */
/* Let next dbCaGetLink and/or dbCaPutLink determine options*/
plink->value.pv_link.pvlMask &=
~(pvlOptInpNative|pvlOptInpString|pvlOptOutNative|pvlOptOutString);
pca->gotInNative = 0;
pca->gotOutNative=0;
pca->gotInString=0;
pca->gotOutString=0;
free(pca->pgetNative); pca->pgetNative = 0;
free(pca->pgetString); pca->pgetString = 0;
free(pca->pputNative); pca->pputNative = 0;
free(pca->pputString); pca->pputString = 0;
}
}
pca->gotFirstConnection = TRUE;
pca->nelements = ca_element_count(arg.chid);
pca->dbrType = ca_field_type(arg.chid);
if((plink->value.pv_link.pvlMask & pvlOptInpNative) && (!pca->pgetNative)){
link_action |= CA_MONITOR_NATIVE;
}
if((plink->value.pv_link.pvlMask & pvlOptInpString) && (!pca->pgetString)){
link_action |= CA_MONITOR_STRING;
}
if((plink->value.pv_link.pvlMask & pvlOptOutNative) && (pca->gotOutNative)){
link_action |= CA_WRITE_NATIVE;
}
if((plink->value.pv_link.pvlMask & pvlOptOutString) && (pca->gotOutString)){
link_action |= CA_WRITE_STRING;
}
pca->gotAttributes = 0;
if(pca->dbrType!=DBR_STRING) {
link_action |= CA_GET_ATTRIBUTES;
}
done:
if(link_action) addAction(pca,link_action);
epicsMutexUnlock(pca->lock);
}
STATIC void eventCallback(struct event_handler_args arg)
@@ -559,6 +632,74 @@ done:
epicsMutexUnlock(pca->lock);
}
STATIC void exceptionCallback(struct exception_handler_args args)
{
const char *context = (args.ctx ? args.ctx : "unknown");
errlogPrintf("DB CA Link Exception: \"%s\", context \"%s\"\n",
ca_message(args.stat), context);
if (args.chid) {
errlogPrintf(
"DB CA Link Exception: channel \"%s\"\n",
ca_name(args.chid));
if (ca_state(args.chid)==cs_conn) {
errlogPrintf(
"DB CA Link Exception: native T=%s, request T=%s,"
" native N=%ld, request N=%ld, "
" access rights {%s%s}\n",
dbr_type_to_text(ca_field_type(args.chid)),
dbr_type_to_text(args.type),
ca_element_count(args.chid),
args.count,
ca_read_access(args.chid) ? "R" : "",
ca_write_access(args.chid) ? "W" : "");
}
}
}
STATIC void putCallback(struct event_handler_args arg)
{
caLink *pca = (caLink *)arg.usr;
struct link *plink;
dbCaPutCallback callback = 0;
epicsMutexMustLock(pca->lock);
plink = pca->plink;
if(!plink) goto done;
callback = pca->putCallback;
pca->putCallback = 0;
pca->putType = 0;
done:
epicsMutexUnlock(pca->lock);
if(callback) callback(plink);
}
STATIC void accessRightsCallback(struct access_rights_handler_args arg)
{
caLink *pca = (caLink *)ca_puser(arg.chid);
struct link *plink;
struct pv_link *ppv_link;
dbCommon *precord;
assert(pca);
if(ca_state(pca->chid) != cs_conn) return;/*connectionCallback will handle*/
epicsMutexMustLock(pca->lock);
plink = pca->plink;
if(!plink) goto done;
pca->hasReadAccess = ca_read_access(arg.chid);
pca->hasWriteAccess = ca_write_access(arg.chid);
if(pca->hasReadAccess && pca->hasWriteAccess) goto done;
ppv_link = &(plink->value.pv_link);
precord = ppv_link->precord;
if(precord) {
if((ppv_link->pvlMask&pvlOptCP)
|| ((ppv_link->pvlMask&pvlOptCPP)&&(precord->scan==0)))
scanOnce(precord);
}
done:
epicsMutexUnlock(pca->lock);
}
STATIC void getAttribEventCallback(struct event_handler_args arg)
{
caLink *pca = (caLink *)arg.usr;
@@ -600,106 +741,9 @@ STATIC void getAttribEventCallback(struct event_handler_args arg)
epicsMutexUnlock(pca->lock);
if(pca->callback) (*pca->callback)(pca->userPvt);
}
STATIC void accessRightsCallback(struct access_rights_handler_args arg)
{
caLink *pca = (caLink *)ca_puser(arg.chid);
struct link *plink;
struct pv_link *ppv_link;
dbCommon *precord;
assert(pca);
if(ca_state(pca->chid) != cs_conn) return;/*connectionCallback will handle*/
epicsMutexMustLock(pca->lock);
plink = pca->plink;
if(!plink) goto done;
pca->hasReadAccess = ca_read_access(arg.chid);
pca->hasWriteAccess = ca_write_access(arg.chid);
if(pca->hasReadAccess && pca->hasWriteAccess) goto done;
ppv_link = &(plink->value.pv_link);
precord = ppv_link->precord;
if(precord) {
if((ppv_link->pvlMask&pvlOptCP)
|| ((ppv_link->pvlMask&pvlOptCPP)&&(precord->scan==0)))
scanOnce(precord);
}
done:
epicsMutexUnlock(pca->lock);
}
STATIC void connectionCallback(struct connection_handler_args arg)
{
caLink *pca;
short link_action = 0;
struct link *plink;
pca = ca_puser(arg.chid);
assert(pca);
epicsMutexMustLock(pca->lock);
plink = pca->plink;
if(!plink) goto done;
pca->isConnected = (ca_state(arg.chid)==cs_conn) ? TRUE : FALSE ;
if(!pca->isConnected) {
struct pv_link *ppv_link = &(plink->value.pv_link);
dbCommon *precord = ppv_link->precord;
pca->nDisconnect++;
if(precord) {
if((ppv_link->pvlMask&pvlOptCP)
|| ((ppv_link->pvlMask&pvlOptCPP)&&(precord->scan==0)))
scanOnce(precord);
}
goto done;
}
pca->hasReadAccess = ca_read_access(arg.chid);
pca->hasWriteAccess = ca_write_access(arg.chid);
if(pca->gotFirstConnection) {
if((pca->nelements != ca_element_count(arg.chid))
|| (pca->dbrType != ca_field_type(arg.chid))){
/* field type or nelements changed */
/* Let next dbCaGetLink and/or dbCaPutLink determine options*/
plink->value.pv_link.pvlMask &=
~(pvlOptInpNative|pvlOptInpString|pvlOptOutNative|pvlOptOutString);
pca->gotInNative = 0;
pca->gotOutNative=0;
pca->gotInString=0;
pca->gotOutString=0;
free(pca->pgetNative); pca->pgetNative = 0;
free(pca->pgetString); pca->pgetString = 0;
free(pca->pputNative); pca->pputNative = 0;
free(pca->pputString); pca->pputString = 0;
}
}
pca->gotFirstConnection = TRUE;
pca->nelements = ca_element_count(arg.chid);
pca->dbrType = ca_field_type(arg.chid);
if((plink->value.pv_link.pvlMask & pvlOptInpNative) && (!pca->pgetNative)){
link_action |= CA_MONITOR_NATIVE;
}
if((plink->value.pv_link.pvlMask & pvlOptInpString) && (!pca->pgetString)){
link_action |= CA_MONITOR_STRING;
}
if((plink->value.pv_link.pvlMask & pvlOptOutNative) && (pca->gotOutNative)){
link_action |= CA_WRITE_NATIVE;
}
if((plink->value.pv_link.pvlMask & pvlOptOutString) && (pca->gotOutString)){
link_action |= CA_WRITE_STRING;
}
pca->gotAttributes = 0;
link_action |= CA_GET_ATTRIBUTES;
done:
if(link_action) addAction(pca,link_action);
epicsMutexUnlock(pca->lock);
}
void dbCaTask()
{
caLink *pca;
short link_action;
int status;
taskwdInsert(epicsThreadGetIdSelf(),NULL,NULL);
SEVCHK(ca_context_create(ca_enable_preemptive_callback),
"dbCaTask calling ca_context_create");
@@ -712,6 +756,10 @@ void dbCaTask()
while (TRUE){
epicsEventMustWait(workListEvent);
while(TRUE) { /* process all requests in workList*/
caLink *pca;
short link_action;
int status;
epicsMutexMustLock(workListLock);
if(!(pca = (caLink *)ellFirst(&workList))){/*Take off list head*/
epicsMutexUnlock(workListLock);
@@ -723,7 +771,17 @@ void dbCaTask()
if(link_action&CA_CLEAR_CHANNEL) --removesOutstanding;
epicsMutexUnlock(workListLock); /*Give it back immediately*/
if(link_action&CA_CLEAR_CHANNEL) {/*This must be first*/
dbCaPutCallback callback;
struct link *plinkPutCallback = 0;
if(pca->chid) ca_clear_channel(pca->chid);
callback = pca->putCallback;
if(callback) {
plinkPutCallback = pca->plinkPutCallback;
pca->plinkPutCallback = 0;
pca->putCallback = 0;
pca->putType = 0;
}
free(pca->pgetNative);
free(pca->pputNative);
free(pca->pgetString);
@@ -731,6 +789,8 @@ void dbCaTask()
free(pca->pvname);
epicsMutexDestroy(pca->lock);
free(pca);
/*No alarm is raised. Since link is changing so what.*/
if(callback) callback(plinkPutCallback);
continue; /*No other link_action makes sense*/
}
if(link_action&CA_CONNECT) {
@@ -738,32 +798,63 @@ void dbCaTask()
pca->pvname,connectionCallback,(void *)pca,
CA_PRIORITY_DB_LINKS, &(pca->chid));
if(status!=ECA_NORMAL) {
errlogPrintf("dbCaTask ca_create_channel %s\n",
ca_message(status));
errlogPrintf("dbCaTask ca_create_channel %s\n",
ca_message(status));
printLinks(pca);
continue;
}
status = ca_replace_access_rights_event(pca->chid,
accessRightsCallback);
if(status!=ECA_NORMAL)
errlogPrintf("dbCaTask replace_access_rights_event %s\n",
ca_message(status));
if(status!=ECA_NORMAL) {
errlogPrintf("dbCaTask replace_access_rights_event %s\n",
ca_message(status));
printLinks(pca);
}
continue; /*Other options must wait until connect*/
}
if(ca_state(pca->chid) != cs_conn) continue;
if(link_action&CA_WRITE_NATIVE) {
assert(pca->pputNative);
status = ca_array_put(
pca->dbrType,pca->nelements,
pca->chid,pca->pputNative);
if(pca->putType==CA_PUT) {
status = ca_array_put(
pca->dbrType,pca->nelements,
pca->chid,pca->pputNative);
} else if(pca->putType==CA_PUT_CALLBACK) {
status = ca_array_put_callback(
pca->dbrType,pca->nelements,
pca->chid,pca->pputNative,
putCallback,pca);
} else {
status = ECA_PUTFAIL;
}
if(status!=ECA_NORMAL) {
errlogPrintf("dbCaTask ca_array_put %s\n",
ca_message(status));
printLinks(pca);
}
epicsMutexMustLock(pca->lock);
if(status==ECA_NORMAL) pca->newOutNative = FALSE;
epicsMutexUnlock(pca->lock);
}
if(link_action&CA_WRITE_STRING) {
assert(pca->pputString);
status = ca_array_put(
DBR_STRING,1,
pca->chid,pca->pputString);
if(pca->putType==CA_PUT) {
status = ca_array_put(
DBR_STRING,1,
pca->chid,pca->pputString);
} else if(pca->putType==CA_PUT_CALLBACK) {
status = ca_array_put_callback(
DBR_STRING,1,
pca->chid,pca->pputString,
putCallback,pca);
} else {
status = ECA_PUTFAIL;
}
if(status!=ECA_NORMAL) {
errlogPrintf("dbCaTask ca_array_put %s\n",
ca_message(status));
printLinks(pca);
}
epicsMutexMustLock(pca->lock);
if(status==ECA_NORMAL) pca->newOutString = FALSE;
epicsMutexUnlock(pca->lock);
@@ -773,9 +864,11 @@ void dbCaTask()
if(link_action&CA_GET_ATTRIBUTES) {
status = ca_get_callback(DBR_CTRL_DOUBLE,
pca->chid,getAttribEventCallback,pca);
if(status!=ECA_NORMAL)
errlogPrintf("dbCaTask ca_add_array_event %s\n",
ca_message(status));
if(status!=ECA_NORMAL) {
errlogPrintf("dbCaTask ca_get_callback %s\n",
ca_message(status));
printLinks(pca);
}
}
if(link_action&CA_MONITOR_NATIVE) {
short element_size;
@@ -788,9 +881,11 @@ void dbCaTask()
ca_field_type(pca->chid)+DBR_TIME_STRING,
ca_element_count(pca->chid),
pca->chid, eventCallback,pca,0.0,0.0,0.0,0);
if(status!=ECA_NORMAL)
if(status!=ECA_NORMAL) {
errlogPrintf("dbCaTask ca_add_array_event %s\n",
ca_message(status));
ca_message(status));
printLinks(pca);
}
}
if(link_action&CA_MONITOR_STRING) {
epicsMutexMustLock(pca->lock);
@@ -799,9 +894,11 @@ void dbCaTask()
status = ca_add_array_event(DBR_TIME_STRING,1,
pca->chid, eventCallback,pca,0.0,0.0,0.0,
0);
if(status!=ECA_NORMAL)
if(status!=ECA_NORMAL) {
errlogPrintf("dbCaTask ca_add_array_event %s\n",
ca_message(status));
ca_message(status));
printLinks(pca);
}
}
}
SEVCHK(ca_flush_io(),"dbCaTask");
+5 -1
View File
@@ -18,6 +18,8 @@
extern "C" {
#endif
typedef void (*dbCaPutCallback)(struct link *plink);
epicsShareFunc void epicsShareAPI dbCaLinkInit(void);
epicsShareFunc void epicsShareAPI dbCaAddLink(struct link *plink);
epicsShareFunc void epicsShareAPI dbCaRemoveLink(struct link *plink);
@@ -26,7 +28,9 @@ epicsShareFunc long epicsShareAPI dbCaGetLink(
unsigned short *psevr,long *nRequest);
epicsShareFunc long epicsShareAPI dbCaPutLink(
struct link *plink,short dbrType,const void *pbuffer,long nRequest);
epicsShareFunc long epicsShareAPI dbCaPutLinkCallback(
struct link *plink,short dbrType,const void *pbuffer,long nRequest,
dbCaPutCallback callback);
epicsShareFunc int epicsShareAPI dbCaIsLinkConnected(const struct link *plink);
/* The following are available after the link is connected*/
epicsShareFunc long epicsShareAPI dbCaGetNelements(
+8 -1
View File
@@ -27,7 +27,10 @@
#define CA_MONITOR_NATIVE 0x10
#define CA_MONITOR_STRING 0x20
#define CA_GET_ATTRIBUTES 0x40
/* write type */
#define CA_PUT 0x1
#define CA_PUT_CALLBACK 0x2
typedef struct caLink
{
ELLNODE node;
@@ -46,6 +49,10 @@ typedef struct caLink
char hasWriteAccess;
char isConnected;
char gotFirstConnection;
/* The following are for write request */
short putType;
dbCaPutCallback putCallback;
struct link *plinkPutCallback;
/* The following are for access to additional attributes*/
char gotAttributes;
void (*callback)(void *usrPvt);
+1 -1
View File
@@ -44,8 +44,8 @@
#include "dbLock.h"
#include "db_access_routines.h"
#include "db_convert.h"
#include "dbCaPvt.h"
#include "dbCa.h"
#include "dbCaPvt.h"
#include "dbCaTest.h"