diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index f427dcce9..38479d81c 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -13,6 +13,21 @@
An Extended Device Support mechanism has been introduced which is +designed as a safe way to widen the API between iocCore and the device +support software it interfaces with. An extended device support can +now be notified of changes to a record's hardware address, and is +given the chance to approve or reject that change.
+ +As a result of introducing this notification mechanism, any device +support that was capable of handling runtime address changes in prior +versions of Base will have to be updated to provide the new interface, +since the absence of extended device support is now taken to mean that +runtime address changes are not understood by the device support. +This requirement is not expected to affect many EPICS sites.
+POSIX thread priority scheduling is now supported. There is a new user option USE_POSIX_THREAD_PRIORITY_SCHEDULING in the CONFIG_SITE @@ -32,6 +47,7 @@ should contain location definitions for EPICS modules only.
configure/RELEASE and moved to configure/os/CONFIG_SITE.Common.RTEMS. The configure/RELEASE* files should contain location definitions for EPICS modules only. +dbLockGetLockId incorrectly always returned 0. dbBkpt (database breakpoint facility) is the only code that needed this. This caused unknown errors @@ -63,7 +78,6 @@ if the dbBkpt facility is used.
Add additional cast to prevent 'strict aliaising' warnings.
-I/O redirection from vxWorks startup scripts now works.
@@ -83,7 +97,6 @@ server required.Set IOC_NAME and IOC_STARTUP_SCRIPT environment variables from bootstrap parameters.
-Builds on Tiger.
Readline now used by default.
diff --git a/src/db/dbAccess.c b/src/db/dbAccess.c index 71dddda90..0d39cc47a 100644 --- a/src/db/dbAccess.c +++ b/src/db/dbAccess.c @@ -35,6 +35,7 @@ #include "link.h" #include "dbFldTypes.h" #include "recSup.h" +#include "devSup.h" #include "caeventmask.h" #include "db_field_log.h" #include "dbCommon.h" @@ -1029,6 +1030,188 @@ long epicsShareAPI dbGet(DBADDR *paddr,short dbrType, return(status); } +devSup* epicsShareAPI dbDTYPtoDevSup(dbRecordType *pdbRecordType, int dtyp) { + return (devSup *)ellNth(&pdbRecordType->devList, dtyp+1); +} + +devSup* epicsShareAPI dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset) { + devSup *pdevSup = (devSup *)ellFirst(&prdes->devList); + while (pdevSup) { + if (pdset == pdevSup->pdset) return pdevSup; + pdevSup = (devSup *)ellNext(&pdevSup->node); + } + return NULL; +} + +static long dbPutFieldLink( + DBADDR *paddr,short dbrType,const void *pbuffer,long nRequest) +{ + long status = 0; + long special=paddr->special; + dbCommon *precord = (dbCommon *)(paddr->precord); + DBLINK *plink = (DBLINK *)paddr->pfield; + const char *pstring = (const char *)pbuffer; + DBENTRY dbEntry; + dbFldDes *pfldDes = (dbFldDes *)paddr->pfldDes; + DBADDR dbaddr; + devSup *pdevSup = NULL; + struct dset *new_dset = NULL; + struct dsxt *new_dsxt = NULL; + int inpOut; + short scan; + + if ((dbrType!=DBR_STRING) && (dbrType!=DBR_CHAR) && (dbrType!=DBR_UCHAR)) + return S_db_badDbrtype; + + if (((dbrType==DBR_CHAR) || (dbrType==DBR_UCHAR)) && + (pstring[nRequest] != '\0')) + return S_db_badField; + + dbInitEntry(pdbbase,&dbEntry); + status=dbFindRecord(&dbEntry,precord->name); + if (!status) status=dbFindField(&dbEntry,pfldDes->name); + if (status) return status; + + inpOut = !(strcmp(pfldDes->name,"INP") && strcmp(pfldDes->name,"OUT")); + + dbLockSetGblLock(); + dbLockSetRecordLock(precord); + + if (inpOut) { + pdevSup = dbDTYPtoDevSup(precord->rdes, precord->dtyp); + if (pdevSup == NULL || + (new_dset = pdevSup->pdset) == NULL || + (new_dsxt = pdevSup->pdsxt) == NULL || + new_dsxt->add_record == NULL || + (precord->dset && + ((pdevSup = dbDSETtoDevSup(precord->rdes, precord->dset)) == NULL || + pdevSup->pdsxt == NULL || + pdevSup->pdsxt->del_record == NULL))) { + status = S_db_noSupport; + goto unlock; + } + } + + scan = precord->scan; + if (inpOut && (scan==SCAN_IO_EVENT)) { + scanDelete(precord); + precord->scan = SCAN_PASSIVE; + } + + switch (plink->type) { /* Old link type */ + case DB_LINK: + free(plink->value.pv_link.pvt); + plink->value.pv_link.pvt = 0; + plink->type = PV_LINK; + plink->value.pv_link.getCvt = 0; + plink->value.pv_link.pvlMask = 0; + plink->value.pv_link.lastGetdbrType = 0; + dbLockSetSplit(precord); + break; + + case CA_LINK: + dbCaRemoveLink(plink); + plink->type = PV_LINK; + plink->value.pv_link.getCvt = 0; + plink->value.pv_link.pvlMask = 0; + plink->value.pv_link.lastGetdbrType = 0; + break; + + case CONSTANT: + break; /* do nothing */ + + case PV_LINK: + case MACRO_LINK: + break; /* should never get here */ + + default: /* Hardware address */ + if (!inpOut) + status = S_db_badHWaddr; + else + status = pdevSup->pdsxt->del_record(precord); + if (status) goto restoreScan; + break; + } + + if (special) status = putSpecial(paddr,0); + if (!status) status=dbPutString(&dbEntry,pstring); + + if (inpOut) { + precord->dset = new_dset; + precord->dpvt = NULL; + precord->pact = FALSE; + } + + if (!status && special) status = putSpecial(paddr,1); + if (status) goto restoreScan; + + switch (plink->type) { /* New link type */ + case PV_LINK: + if (plink==&precord->tsel) recGblTSELwasModified(plink); + if (!(plink->value.pv_link.pvlMask & (pvlOptCA|pvlOptCP|pvlOptCPP)) && + (dbNameToAddr(plink->value.pv_link.pvname,&dbaddr)==0)) { + /* It's a DB link */ + DBADDR *pdbAddr; + + plink->type = DB_LINK; + pdbAddr = dbCalloc(1,sizeof(struct dbAddr)); + *pdbAddr = dbaddr; /* NB: structure copy */; + plink->value.pv_link.precord = precord; + plink->value.pv_link.pvt = pdbAddr; + dbLockSetRecordLock(pdbAddr->precord); + dbLockSetMerge(precord,pdbAddr->precord); + } else { /* Make it a CA link */ + char *pperiod; + + plink->type = CA_LINK; + plink->value.pv_link.precord = precord; + if (pfldDes->field_type==DBF_INLINK) { + plink->value.pv_link.pvlMask |= pvlOptInpNative; + } + dbCaAddLink(plink); + if (pfldDes->field_type==DBF_FWDLINK) { + pperiod = strrchr(plink->value.pv_link.pvname,'.'); + if (pperiod && strstr(pperiod,"PROC")) + plink->value.pv_link.pvlMask |= pvlOptFWD; + } + } + break; + + case CONSTANT: + break; + + case DB_LINK: + case CA_LINK: + case MACRO_LINK: + break; /* should never get here */ + + default: /* Hardware address */ + if (!inpOut) + status = S_db_badHWaddr; + else + status = new_dsxt->add_record(precord); + if (status) { + precord->dset = 0; + precord->pact = TRUE; + goto restoreScan; + } + break; + } + db_post_events(precord,plink,DBE_VALUE|DBE_LOG); + +restoreScan: + if (inpOut && (scan==SCAN_IO_EVENT)) { /* undo scanDelete() */ + precord->scan = scan; + scanAdd(precord); + } + if (scan != precord->scan) + db_post_events(precord, &precord->scan, DBE_VALUE|DBE_LOG); +unlock: + dbLockSetGblUnlock(); + dbFinishEntry(&dbEntry); + return status; +} + long epicsShareAPI dbPutField( DBADDR *paddr,short dbrType,const void *pbuffer,long nRequest) { @@ -1038,107 +1221,17 @@ long epicsShareAPI dbPutField( dbCommon *precord = (dbCommon *)(paddr->precord); short dbfType = paddr->field_type; - if(special==SPC_ATTRIBUTE) return(S_db_noMod); + if(special==SPC_ATTRIBUTE) + return S_db_noMod; + /*check for putField disabled*/ - if(precord->disp) { - if((void *)(&precord->disp) != paddr->pfield) return(S_db_putDisabled); - } - if(dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK) { - DBLINK *plink = (DBLINK *)paddr->pfield; - DBENTRY dbEntry; - dbFldDes *pfldDes = (dbFldDes *)paddr->pfldDes; - char buffer[MAX_STRING_SIZE+2]; - int len,j; - char *lastblank; + if (precord->disp && + (void *)(&precord->disp) != paddr->pfield) + return(S_db_putDisabled); - if(dbrType!=DBR_STRING) return(S_db_badDbrtype); - /*begin kludge for old db_access MAX_STRING_SIZE*/ - /*Allow M for MS and (N or NM) for NMS */ - if(strlen((char *)pbuffer)>=MAX_STRING_SIZE) { - errlogPrintf("dbPutField input string length >= MAX_STRING_SIZE"); - return(S_db_badField); - } - strncpy(buffer,(char *)pbuffer,MAX_STRING_SIZE); - buffer[MAX_STRING_SIZE] = 0; - /*Strip trailing blanks*/ - len = strlen(buffer); - for(j=len-1; j>0; j--) { - if(buffer[j]==' ') - buffer[j] = 0; - else - break; - } - lastblank = strrchr(buffer,' '); - if(lastblank) { - if(strcmp(lastblank,"M")==0) { - strcpy(lastblank,"MS"); - } else { - if((strcmp(lastblank,"N")==0) || (strcmp(lastblank,"NM")==0)) { - strcpy(lastblank,"NMS"); - } - } - } - /*End kludge for old db_access MAX_STRING_SIZE*/ - dbLockSetGblLock(); - dbLockSetRecordLock(precord); - if((plink->type == DB_LINK)||(plink->type == CA_LINK)) { - if(plink->type == DB_LINK) { - free(plink->value.pv_link.pvt); - plink->value.pv_link.pvt = 0; - plink->type = PV_LINK; - dbLockSetSplit(precord); - } else if(plink->type == CA_LINK) { - dbCaRemoveLink(plink); - } - plink->value.pv_link.getCvt = 0; - plink->value.pv_link.pvlMask = 0; - plink->value.pv_link.lastGetdbrType = 0; - plink->type = PV_LINK; - } - dbInitEntry(pdbbase,&dbEntry); - status=dbFindRecord(&dbEntry,precord->name); - if(!status) status=dbFindField(&dbEntry,pfldDes->name); - if(!status && special) status = putSpecial(paddr,0); - if(!status) status=dbPutString(&dbEntry,buffer); - dbFinishEntry(&dbEntry); - if(!status && special) status = putSpecial(paddr,1); - if(status) goto done; - if(plink->type == PV_LINK) { - DBADDR dbaddr; + if(dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK) + return dbPutFieldLink(paddr,dbrType,pbuffer,nRequest); - if(plink==&precord->tsel) recGblTSELwasModified(plink); - if(!(plink->value.pv_link.pvlMask &(pvlOptCA|pvlOptCP|pvlOptCPP)) - &&(dbNameToAddr(plink->value.pv_link.pvname,&dbaddr)==0)){ - DBADDR *pdbAddr; - - plink->type = DB_LINK; - pdbAddr = dbCalloc(1,sizeof(struct dbAddr)); - *pdbAddr = dbaddr; /*structure copy*/; - plink->value.pv_link.precord = precord; - plink->value.pv_link.pvt = pdbAddr; - dbLockSetRecordLock(pdbAddr->precord); - dbLockSetMerge(precord,pdbAddr->precord); - } else {/*It is a CA link*/ - char *pperiod; - - plink->type = CA_LINK; - plink->value.pv_link.precord = precord; - if(pfldDes->field_type==DBF_INLINK) { - plink->value.pv_link.pvlMask |= pvlOptInpNative; - } - dbCaAddLink(plink); - if(pfldDes->field_type==DBF_FWDLINK) { - pperiod = strrchr(plink->value.pv_link.pvname,'.'); - if(pperiod && strstr(pperiod,"PROC")) - plink->value.pv_link.pvlMask |= pvlOptFWD; - } - } - } - db_post_events(precord,plink,DBE_VALUE|DBE_LOG); -done: - dbLockSetGblUnlock(); - return(status); - } dbScanLock(precord); status=dbPut(paddr,dbrType,pbuffer,nRequest); if(status==0){ diff --git a/src/db/dbAccessDefs.h b/src/db/dbAccessDefs.h index 33abea68f..6e4a2f2d6 100644 --- a/src/db/dbAccessDefs.h +++ b/src/db/dbAccessDefs.h @@ -184,6 +184,7 @@ struct dbr_alDouble {DBRalDouble}; #define S_db_Blocked (M_dbAccess|39) /*Request is Blocked*/ #define S_db_putDisabled (M_dbAccess|41) /*putFields are disabled*/ +#define S_db_badHWaddr (M_dbAccess|43) /*Hardware link type not on INP/OUT*/ #define S_db_bkptSet (M_dbAccess|53) /*Breakpoint already set*/ #define S_db_bkptNotSet (M_dbAccess|55) /*No breakpoint set in record*/ #define S_db_notStopped (M_dbAccess|57) /*Record not stopped*/ @@ -227,6 +228,8 @@ epicsShareFunc void epicsShareAPI dbScanFwdLink(struct link *plink); epicsShareFunc long epicsShareAPI dbProcess(struct dbCommon *precord); epicsShareFunc long epicsShareAPI dbNameToAddr( const char *pname,struct dbAddr *); +epicsShareFunc devSup* epicsShareAPI dbDTYPtoDevSup(dbRecordType *prdes, int dtyp); +epicsShareFunc devSup* epicsShareAPI dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset); epicsShareFunc long epicsShareAPI dbGetLinkValue( struct link *,short dbrType,void *pbuffer,long *options,long *nRequest); epicsShareFunc long epicsShareAPI dbGetField( diff --git a/src/dbStatic/dbBase.h b/src/dbStatic/dbBase.h index b63239632..38ba2d8c7 100644 --- a/src/dbStatic/dbBase.h +++ b/src/dbStatic/dbBase.h @@ -41,6 +41,7 @@ typedef struct devSup { int link_type; /*Following only available on run time system*/ struct dset *pdset; + struct dsxt *pdsxt; /* Extended device support */ }devSup; typedef struct dbDeviceMenu { diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index 97d9a30f0..94fb62d8e 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -3798,6 +3798,7 @@ void epicsShareAPI dbDumpDevice(DBBASE *pdbbase,const char *recordTypeName) printf("\t choice: %s\n",pdevSup->choice); printf("\tlink_type: %d\n",pdevSup->link_type); printf("\t pdset: %p\n",(void *)pdevSup->pdset); + printf("\t pdsxt: %p\n",(void *)pdevSup->pdsxt); } if(recordTypeName) break; } diff --git a/src/dbStatic/devSup.h b/src/dbStatic/devSup.h index 621892527..508b0a224 100644 --- a/src/dbStatic/devSup.h +++ b/src/dbStatic/devSup.h @@ -27,12 +27,19 @@ typedef long (*DEVSUPFUN)(); /* ptr to device support function*/ typedef struct dset { /* device support entry table */ long number; /*number of support routines*/ DEVSUPFUN report; /*print report*/ - DEVSUPFUN init; /*init support*/ - DEVSUPFUN init_record; /*init support for particular record*/ + DEVSUPFUN init; /*init support layer*/ + DEVSUPFUN init_record; /*init device for particular record*/ DEVSUPFUN get_ioint_info; /* get io interrupt information*/ /*other functions are record dependent*/ }dset; +struct dbCommon; +typedef struct dsxt { /* device support extension table */ + long (*add_record)(struct dbCommon *precord); + long (*del_record)(struct dbCommon *precord); + /* Recordtypes are *not* allowed to extend this table */ +} dsxt; + #define S_dev_noDevSup (M_devSup| 1) /*SDR_DEVSUP: Device support missing*/ #define S_dev_noDSET (M_devSup| 3) /*Missing device support entry table*/ #define S_dev_missingSup (M_devSup| 5) /*Missing device support routine*/ @@ -46,6 +53,12 @@ typedef struct dset { /* device support entry table */ #define S_dev_Conflict (M_devSup|21) /*Multiple records accessing same signal*/ #define S_dev_noDeviceFound (M_devSup|23) /*No device found at specified address*/ + +/* This routine is defined in src/misc/iocInit.c */ + +extern void devExtend(dsxt *pdsxt); + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/misc/iocInit.c b/src/misc/iocInit.c index 9b79f419c..93b4ab813 100644 --- a/src/misc/iocInit.c +++ b/src/misc/iocInit.c @@ -178,42 +178,62 @@ LOCAL void initRecSup(void) return; } +static long do_nothing(struct dbCommon *precord) { return 0; } + +/* Dummy DSXT used for soft device supports */ +struct dsxt devSoft_DSXT = { + do_nothing, + do_nothing +}; + +LOCAL devSup *pthisDevSup = NULL; + LOCAL void initDevSup(void) { dbRecordType *pdbRecordType; - devSup *pdevSup; struct dset *pdset; - for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); - pdbRecordType; - pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) { - for(pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup; - pdevSup = (devSup *)ellNext(&pdevSup->node)) { - pdset = registryDeviceSupportFind(pdevSup->name); + for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); + pdbRecordType; + pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) { + for (pthisDevSup = (devSup *)ellFirst(&pdbRecordType->devList); + pthisDevSup; + pthisDevSup = (devSup *)ellNext(&pthisDevSup->node)) { + pdset = registryDeviceSupportFind(pthisDevSup->name); if (pdset==0) { - errlogPrintf("device support %s not found\n",pdevSup->name); + errlogPrintf("device support %s not found\n",pthisDevSup->name); continue; } - pdevSup->pdset = pdset; - if(pdset->init) (*pdset->init)(0); + if (pthisDevSup->link_type == CONSTANT) + pthisDevSup->pdsxt = &devSoft_DSXT; + pthisDevSup->pdset = pdset; + if (pdset->init) (*pdset->init)(0); } } return; } +void devExtend(dsxt *pdsxt) +{ + if (!pthisDevSup) + errlogPrintf("devExtend() called outside of initDevSup()\n"); + else + pthisDevSup->pdsxt = pdsxt; +} + LOCAL void finishDevSup(void) { dbRecordType *pdbRecordType; - devSup *pdevSup; struct dset *pdset; - for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); - pdbRecordType; - pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) { - for(pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup; - pdevSup = (devSup *)ellNext(&pdevSup->node)) { - if(!(pdset = pdevSup->pdset)) continue; - if(pdset->init) (*pdset->init)(1); + for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); + pdbRecordType; + pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) { + for (pthisDevSup = (devSup *)ellFirst(&pdbRecordType->devList); + pthisDevSup; + pthisDevSup = (devSup *)ellNext(&pthisDevSup->node)) { + pdset = pthisDevSup->pdset; + if (pdset && pdset->init) (*pdset->init)(1); } } @@ -253,7 +273,7 @@ LOCAL void initDatabase(void) precord->pact=FALSE; /* Init DSET NOTE that result may be NULL */ - pdevSup = (devSup *)ellNth(&pdbRecordType->devList,precord->dtyp+1); + pdevSup = dbDTYPtoDevSup(pdbRecordType,precord->dtyp); pdset = (pdevSup ? pdevSup->pdset : 0); precord->dset = pdset; if(prset->init_record) (*prset->init_record)(precord,0); @@ -306,6 +326,12 @@ LOCAL void initDatabase(void) } } } + pdevSup = dbDTYPtoDevSup(pdbRecordType,precord->dtyp); + if (pdevSup) { + struct dsxt *pdsxt = pdevSup->pdsxt; + if (pdsxt && pdsxt->add_record) + (*pdsxt->add_record)(precord); + } } }