diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index d34f07ae6..96f10ecfc 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -14,6 +14,14 @@
If EPICS Base is built with readline support, any IOC that calls epicsExit() +from a thread other than the main thread is likely to leave the user's terminal +in a weird state, requiring the user to run something like 'stty sane' to clean +it up. This release patches the readline support code to clean up automatically +by registering an epicsAtExit() routine.
+The IOC has not called the get_value() routine in the RSET for a very long diff --git a/src/ca/client/CAref.html b/src/ca/client/CAref.html index ce1b71054..f7210477e 100644 --- a/src/ca/client/CAref.html +++ b/src/ca/client/CAref.html @@ -209,6 +209,7 @@ $Date$
dbr_size[]dbr_size[]#include <db_access.h> extern unsigned dbr_size[/* TYPE */];@@ -3953,11 +3954,12 @@ int ca_sg_create ( CA_SYNC_GID *PGID );
A synchronous group can be used to guarantee that a set of channel access
requests have completed. Once a synchronous group has been created then channel
-access get and put requests may be issued within it using ca_sg_get() and
-ca_sg_put() respectively. The routines ca_sg_block() and ca_sg_test() can be
+access get and put requests may be issued within it using
+ca_sg_array_get() and ca_sg_array_put() respectively.
+The routines ca_sg_block() and ca_sg_test() can be
used to block for and test for completion respectively. The routine
-ca_sg_reset() is used to discard knowledge of old requests which have timed out
-and in all likelihood will never be satisfied.
ca_sg_reset() is used to discard knowledge of old requests which
+have timed out and in all likelihood will never be satisfied.
Any number of asynchronous groups can have application requested operations outstanding within them at any given time.
@@ -4131,16 +4133,20 @@ status = ca_sg_reset(gid);ca_sg_array_put()#include <cadef.h>
+int ca_sg_put ( CA_SYNC_GID GID, chtype TYPE,
+ chid CHID, void *PVALUE );
int ca_sg_array_put ( CA_SYNC_GID GID, chtype TYPE,
unsigned long COUNT, chid CHID, void *PVALUE );
-Write a value, or array of values, to a channel and increment the
-outstanding request count of a synchronous group. The ca_sg_array_put()
-functionality is implemented using ca_array_put_callback().
Write a value, or array of values, to a channel and increment the outstanding
+request count of a synchronous group. The ca_sg_put() and
+ca_sg_array_put() functionality is implemented using
+ca_array_put_callback().
All remote operation requests such as the above are accumulated (buffered)
-and not forwarded to the server until one of ca_flush_io(), ca_pend_io(),
-ca_pend_event(), or ca_sg_block() are called. This allows several requests to be
+and not forwarded to the server until one of ca_flush_io(),
+ca_pend_io(), ca_pend_event(), or
+ca_sg_block() are called. This allows several requests to be
efficiently sent in one message.
If a connection is lost and then resumed outstanding puts are not @@ -4193,6 +4199,8 @@ reissued.
ca_sg_array_get()#include <cadef.h>
+int ca_sg_get ( CA_SYNC_GID GID, chtype TYPE,
+ chid CHID, void *PVALUE );
int ca_sg_array_get ( CA_SYNC_GID GID,
chtype TYPE, unsigned long COUNT,
chid CHID, void *PVALUE );
@@ -4200,16 +4208,19 @@ int ca_sg_array_get ( CA_SYNC_GID GID,
Read a value from a channel and increment the outstanding request count of a
-synchronous group. The ca_sg_array_get() functionality is implemented using
+synchronous group. The ca_sg_get() and
+ca_sg_array_get() functionality is implemented using
ca_array_get_callback().
The values written into your program's variables by ca_sg_get() should not be
-referenced by your program until ECA_NORMAL has been received from ca_sg_block(),
-or until ca_sg_test() returns ECA_IODONE.
The values written into your program's variables by ca_sg_get()
+or ca_sg_array_get() should not be referenced by your program until
+ECA_NORMAL has been received from ca_sg_block(), or until
+ca_sg_test() returns ECA_IODONE.
All remote operation requests such as the above are accumulated (buffered)
-and not forwarded to the server until one of ca_flush_io(), ca_pend_io(),
-ca_pend_event(), or ca_sg_block() are called. This allows several requests to be
+and not forwarded to the server until one of ca_flush_io(),
+ca_pend_io(), ca_pend_event(), or
+ca_sg_block() are called. This allows several requests to be
efficiently sent in one message.
If a connection is lost and then resumed outstanding gets are not diff --git a/src/ioc/db/dbIocRegister.c b/src/ioc/db/dbIocRegister.c index 9edec59dc..1a1aafb9a 100644 --- a/src/ioc/db/dbIocRegister.c +++ b/src/ioc/db/dbIocRegister.c @@ -233,6 +233,17 @@ static void dbtpnCallFunc(const iocshArgBuf *args) static const iocshFuncDef dbNotifyDumpFuncDef = {"dbNotifyDump",0,0}; static void dbNotifyDumpCallFunc(const iocshArgBuf *args) { dbNotifyDump();} +/* dbPutAttribute */ +static const iocshArg dbPutAttrArg0 = { "record type",iocshArgString}; +static const iocshArg dbPutAttrArg1 = { "attribute name",iocshArgString}; +static const iocshArg dbPutAttrArg2 = { "value",iocshArgString}; +static const iocshArg * const dbPutAttrArgs[] = + {&dbPutAttrArg0, &dbPutAttrArg1, &dbPutAttrArg2}; +static const iocshFuncDef dbPutAttrFuncDef = + {"dbPutAttribute",3,dbPutAttrArgs}; +static void dbPutAttrCallFunc(const iocshArgBuf *args) +{ dbPutAttribute(args[0].sval,args[1].sval,args[2].sval);} + /* tpn */ static const iocshArg tpnArg0 = { "record name",iocshArgString}; static const iocshArg tpnArg1 = { "value",iocshArgString}; @@ -405,6 +416,7 @@ void dbIocRegister(void) iocshRegister(&pftFuncDef,pftCallFunc); iocshRegister(&dbtpnFuncDef,dbtpnCallFunc); iocshRegister(&dbNotifyDumpFuncDef,dbNotifyDumpCallFunc); + iocshRegister(&dbPutAttrFuncDef,dbPutAttrCallFunc); iocshRegister(&tpnFuncDef,tpnCallFunc); iocshRegister(&dblsrFuncDef,dblsrCallFunc); iocshRegister(&dbLockShowLockedFuncDef,dbLockShowLockedCallFunc); diff --git a/src/ioc/db/initHooks.c b/src/ioc/db/initHooks.c index cfd3a4ccf..8590480ae 100644 --- a/src/ioc/db/initHooks.c +++ b/src/ioc/db/initHooks.c @@ -132,7 +132,7 @@ const char *initHookName(int state) "initHookAfterInterruptAccept", "initHookAtEnd" }; - if (state < 0 || state > NELEMENTS(stateName)) { + if (state < 0 || state >= NELEMENTS(stateName)) { return "Not an initHookState"; } return stateName[state]; diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c index 0a8615506..b30cb5f79 100644 --- a/src/ioc/db/recGbl.c +++ b/src/ioc/db/recGbl.c @@ -309,11 +309,11 @@ static void getMaxRangeValues(short field_type, double *pupper_limit, { switch(field_type){ case DBF_CHAR: - *pupper_limit = -128.0; - *plower_limit = 127.0; + *pupper_limit = (double) CHAR_MAX; + *plower_limit = (double) CHAR_MIN; break; case DBF_UCHAR: - *pupper_limit = 255.0; + *pupper_limit = (double) UCHAR_MAX; *plower_limit = 0.0; break; case DBF_SHORT: diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index c0751ecbb..703624950 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -1198,7 +1198,7 @@ long dbPutRecordAttribute( pnew = dbCalloc(1,sizeof(dbRecordAttribute)); if(pattribute) { - ellInsert(&precordType->attributeList,&pattribute->node, + ellInsert(&precordType->attributeList,pattribute->node.previous, &pnew->node); } else { ellAdd(&precordType->attributeList,&pnew->node); @@ -1232,11 +1232,16 @@ long dbGetAttributePart(DBENTRY *pdbentry, const char **ppname) size_t nameLen = strlen(pattribute->name); int compare = strncmp(pattribute->name, pname, nameLen); int ch = pname[nameLen]; - if (compare == 0 && !(ch == '_' || isalnum(ch))) { - pdbentry->pflddes = pattribute->pdbFldDes; - pdbentry->pfield = pattribute->value; - *ppname = &pname[nameLen]; - return 0; + if (compare == 0) { + if (!(ch == '_' || isalnum(ch))) { + pdbentry->pflddes = pattribute->pdbFldDes; + pdbentry->pfield = pattribute->value; + *ppname = &pname[nameLen]; + return 0; + } + if (strlen(pname) > nameLen) { + compare = -1; + } } if (compare >= 0) break; pattribute = (dbRecordAttribute *)ellNext(&pattribute->node); diff --git a/src/libCom/osi/os/default/epicsReadline.c b/src/libCom/osi/os/default/epicsReadline.c index 6c442e376..1d7d9c1d5 100644 --- a/src/libCom/osi/os/default/epicsReadline.c +++ b/src/libCom/osi/os/default/epicsReadline.c @@ -14,6 +14,7 @@ #define epicsExportSharedSymbols #include "envDefs.h" +#include "epicsExit.h" #include "epicsReadline.h" #define EPICS_COMMANDLINE_LIBRARY_EPICS 0 @@ -84,6 +85,14 @@ struct readlineContext { char *line; }; +static enum {rlNone, rlIdle, rlBusy} rlState = rlNone; + +static void rlExit(void *dummy) { + if (rlState == rlBusy) + rl_cleanup_after_signal(); +} + + /* * Create a command-line context */ @@ -92,6 +101,11 @@ epicsReadlineBegin(FILE *in) { struct readlineContext *readlineContext; + if (rlState == rlNone) { + epicsAtExit(rlExit, NULL); + rlState = rlIdle; + } + readlineContext = malloc(sizeof *readlineContext); if (readlineContext != NULL) { readlineContext->in = in; @@ -124,7 +138,9 @@ epicsReadline (const char *prompt, void *context) free (readlineContext->line); readlineContext->line = NULL; if (readlineContext->in == NULL) { + rlState = rlBusy; line = readline (prompt); + rlState = rlIdle; } else { line = (char *)malloc (linesize * sizeof *line);