diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index a24ac1d25..d8ea79fe1 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -109,6 +109,20 @@ dbQuietMacroWarnings=1 VxWorks

Changes pulled from the 3.14 branch since 3.15.3

+

Making IOC ca_get operations atomic

+ +

When a CA client gets data from an IOC record using a compound data type such +as DBR_TIME_DOUBLE the value field is fetched from the database in a +separate call than the other metadata, without keeping the record locked. This +allows some other thread such as a periodic scan thread a chance to interrupt +the get operation and process the record in between. CA monitors have always +been atomic as long as the value data isn't a string or an array, but this race +condition in the CA get path has now been fixed so the record will stay locked +between the two fetch operations.

+ +

This fixes +Launchpad bug #1581212, thanks to Till Strauman and Dehong Zhang.

+

New CONFIG_SITE variable for running self-tests

The 'make runtests' and 'make tapfiles' build targets normally only run the diff --git a/src/ioc/db/db_access.c b/src/ioc/db/db_access.c index 3e957b4ed..35712ddd6 100644 --- a/src/ioc/db/db_access.c +++ b/src/ioc/db/db_access.c @@ -39,6 +39,7 @@ #include "dbChannel.h" #include "dbCommon.h" #include "dbEvent.h" +#include "dbLock.h" #include "dbNotify.h" #include "dbStaticLib.h" #include "recSup.h" @@ -153,28 +154,30 @@ int dbChannel_get_count( * in the dbAccess.c dbGet() and getOptions() routines. */ + dbScanLock(dbChannelRecord(chan)); + switch(buffer_type) { case(oldDBR_STRING): - status = dbChannelGetField(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl); + status = dbChannelGet(chan, DBR_STRING, pbuffer, &zero, nRequest, pfl); break; /* case(oldDBR_INT): */ case(oldDBR_SHORT): - status = dbChannelGetField(chan, DBR_SHORT, pbuffer, &zero, nRequest, pfl); + status = dbChannelGet(chan, DBR_SHORT, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_FLOAT): - status = dbChannelGetField(chan, DBR_FLOAT, pbuffer, &zero, nRequest, pfl); + status = dbChannelGet(chan, DBR_FLOAT, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_ENUM): - status = dbChannelGetField(chan, DBR_ENUM, pbuffer, &zero, nRequest, pfl); + status = dbChannelGet(chan, DBR_ENUM, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_CHAR): - status = dbChannelGetField(chan, DBR_CHAR, pbuffer, &zero, nRequest, pfl); + status = dbChannelGet(chan, DBR_CHAR, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_LONG): - status = dbChannelGetField(chan, DBR_LONG, pbuffer, &zero, nRequest, pfl); + status = dbChannelGet(chan, DBR_LONG, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_DOUBLE): - status = dbChannelGetField(chan, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl); + status = dbChannelGet(chan, DBR_DOUBLE, pbuffer, &zero, nRequest, pfl); break; case(oldDBR_STS_STRING): @@ -187,10 +190,10 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS; - status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - status = dbChannelGetField(chan, DBR_STRING, pold->value, &zero, + status = dbChannelGet(chan, DBR_STRING, pold->value, &zero, nRequest, pfl); } break; @@ -203,10 +206,10 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS; - status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &zero, + status = dbChannelGet(chan, DBR_SHORT, &pold->value, &zero, nRequest, pfl); } break; @@ -218,10 +221,10 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS; - status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &zero, + status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &zero, nRequest, pfl); } break; @@ -233,10 +236,10 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS; - status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &zero, + status = dbChannelGet(chan, DBR_ENUM, &pold->value, &zero, nRequest, pfl); } break; @@ -248,10 +251,10 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS; - status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &zero, + status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &zero, nRequest, pfl); } break; @@ -263,10 +266,10 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS; - status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; - status = dbChannelGetField(chan, DBR_LONG, &pold->value, &zero, + status = dbChannelGet(chan, DBR_LONG, &pold->value, &zero, nRequest, pfl); } break; @@ -278,11 +281,11 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS; - status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; options = 0; - status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options, + status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options, nRequest, pfl); } break; @@ -296,12 +299,12 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_TIME; - status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - status = dbChannelGetField(chan, DBR_STRING, pold->value, &options, + status = dbChannelGet(chan, DBR_STRING, pold->value, &options, nRequest, pfl); } break; @@ -315,12 +318,12 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_TIME; - status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options, + status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options, nRequest, pfl); } break; @@ -333,12 +336,12 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_TIME; - status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options, + status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options, nRequest, pfl); } break; @@ -351,12 +354,12 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_TIME; - status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options, + status = dbChannelGet(chan, DBR_ENUM, &pold->value, &options, nRequest, pfl); } break; @@ -369,12 +372,12 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_TIME; - status = dbChannelGetField(chan, DBR_CHAR, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_CHAR, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - status = dbChannelGetField(chan, DBR_CHAR, &pold->value, &options, + status = dbChannelGet(chan, DBR_CHAR, &pold->value, &options, nRequest, pfl); } break; @@ -387,12 +390,12 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_TIME; - status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options, + status = dbChannelGet(chan, DBR_LONG, &pold->value, &options, nRequest, pfl); } break; @@ -405,12 +408,12 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_TIME; - status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->stamp = newSt.time; /* structure copy */ options = 0; - status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options, + status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options, nRequest, pfl); } break; @@ -428,7 +431,7 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG; - status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -440,7 +443,7 @@ int dbChannel_get_count( pold->lower_warning_limit = newSt.lower_warning_limit; pold->lower_alarm_limit = newSt.lower_alarm_limit; options = 0; - status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options, + status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options, nRequest, pfl); } break; @@ -457,7 +460,7 @@ int dbChannel_get_count( options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE | DBR_AL_DOUBLE; - status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->precision = (dbr_short_t) newSt.precision.dp; @@ -470,7 +473,7 @@ int dbChannel_get_count( pold->upper_warning_limit = epicsConvertDoubleToFloat(newSt.upper_warning_limit); pold->lower_warning_limit = epicsConvertDoubleToFloat(newSt.lower_warning_limit); options = 0; - status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options, + status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options, nRequest, pfl); } break; @@ -486,7 +489,7 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG; - status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -498,7 +501,7 @@ int dbChannel_get_count( pold->lower_warning_limit = newSt.lower_warning_limit; pold->lower_alarm_limit = newSt.lower_alarm_limit; options = 0; - status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options, + status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &options, nRequest, pfl); } break; @@ -513,7 +516,7 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_AL_LONG; - status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -525,7 +528,7 @@ int dbChannel_get_count( pold->lower_warning_limit = newSt.lower_warning_limit; pold->lower_alarm_limit = newSt.lower_alarm_limit; options = 0; - status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options, + status = dbChannelGet(chan, DBR_LONG, &pold->value, &options, nRequest, pfl); } break; @@ -542,7 +545,7 @@ int dbChannel_get_count( options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE | DBR_AL_DOUBLE; - status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->precision = (dbr_short_t) newSt.precision.dp; @@ -555,7 +558,7 @@ int dbChannel_get_count( pold->lower_warning_limit = newSt.lower_warning_limit; pold->lower_alarm_limit = newSt.lower_alarm_limit; options = 0; - status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options, + status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options, nRequest, pfl); } break; @@ -574,7 +577,7 @@ int dbChannel_get_count( options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG | DBR_AL_LONG; - status = dbChannelGetField(chan, DBR_SHORT, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_SHORT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -588,7 +591,7 @@ int dbChannel_get_count( pold->upper_ctrl_limit = newSt.upper_ctrl_limit; pold->lower_ctrl_limit = newSt.lower_ctrl_limit; options = 0; - status = dbChannelGetField(chan, DBR_SHORT, &pold->value, &options, + status = dbChannelGet(chan, DBR_SHORT, &pold->value, &options, nRequest, pfl); } break; @@ -606,7 +609,7 @@ int dbChannel_get_count( options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE | DBR_CTRL_DOUBLE | DBR_AL_DOUBLE; - status = dbChannelGetField(chan, DBR_FLOAT, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_FLOAT, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->precision = (dbr_short_t) newSt.precision.dp; @@ -621,7 +624,7 @@ int dbChannel_get_count( pold->upper_ctrl_limit = epicsConvertDoubleToFloat(newSt.upper_ctrl_limit); pold->lower_ctrl_limit = epicsConvertDoubleToFloat(newSt.lower_ctrl_limit); options = 0; - status = dbChannelGetField(chan, DBR_FLOAT, &pold->value, &options, + status = dbChannelGet(chan, DBR_FLOAT, &pold->value, &options, nRequest, pfl); } break; @@ -638,7 +641,7 @@ int dbChannel_get_count( memset(pold, '\0', sizeof(struct dbr_ctrl_enum)); /* first get status and severity */ options = DBR_STATUS | DBR_ENUM_STRS; - status = dbChannelGetField(chan, DBR_ENUM, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_ENUM, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; no_str = newSt.no_str; @@ -648,7 +651,7 @@ int dbChannel_get_count( strncpy(pold->strs[i], newSt.strs[i], sizeof(pold->strs[i])); /*now get values*/ options = 0; - status = dbChannelGetField(chan, DBR_ENUM, &pold->value, &options, + status = dbChannelGet(chan, DBR_ENUM, &pold->value, &options, nRequest, pfl); } break; @@ -665,7 +668,7 @@ int dbChannel_get_count( options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG | DBR_AL_LONG; - status = dbChannelGetField(chan, DBR_UCHAR, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_UCHAR, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -679,7 +682,7 @@ int dbChannel_get_count( pold->upper_ctrl_limit = newSt.upper_ctrl_limit; pold->lower_ctrl_limit = newSt.lower_ctrl_limit; options = 0; - status = dbChannelGetField(chan, DBR_UCHAR, &pold->value, &options, + status = dbChannelGet(chan, DBR_UCHAR, &pold->value, &options, nRequest, pfl); } break; @@ -696,7 +699,7 @@ int dbChannel_get_count( options = DBR_STATUS | DBR_UNITS | DBR_GR_LONG | DBR_CTRL_LONG | DBR_AL_LONG; - status = dbChannelGetField(chan, DBR_LONG, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_LONG, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; strncpy(pold->units, newSt.units, MAX_UNITS_SIZE); @@ -710,7 +713,7 @@ int dbChannel_get_count( pold->upper_ctrl_limit = newSt.upper_ctrl_limit; pold->lower_ctrl_limit = newSt.lower_ctrl_limit; options = 0; - status = dbChannelGetField(chan, DBR_LONG, &pold->value, &options, + status = dbChannelGet(chan, DBR_LONG, &pold->value, &options, nRequest, pfl); } break; @@ -728,7 +731,7 @@ int dbChannel_get_count( options = DBR_STATUS | DBR_UNITS | DBR_PRECISION | DBR_GR_DOUBLE | DBR_CTRL_DOUBLE | DBR_AL_DOUBLE; - status = dbChannelGetField(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_DOUBLE, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->precision = (dbr_short_t) newSt.precision.dp; @@ -743,7 +746,7 @@ int dbChannel_get_count( pold->upper_ctrl_limit = newSt.upper_ctrl_limit; pold->lower_ctrl_limit = newSt.lower_ctrl_limit; options = 0; - status = dbChannelGetField(chan, DBR_DOUBLE, &pold->value, &options, + status = dbChannelGet(chan, DBR_DOUBLE, &pold->value, &options, nRequest, pfl); } break; @@ -756,13 +759,13 @@ int dbChannel_get_count( } newSt; options = DBR_STATUS; - status = dbChannelGetField(chan, DBR_STRING, &newSt, &options, &zero, pfl); + status = dbChannelGet(chan, DBR_STRING, &newSt, &options, &zero, pfl); pold->status = newSt.status; pold->severity = newSt.severity; pold->ackt = newSt.ackt; pold->acks = newSt.acks; options = 0; - status = dbChannelGetField(chan, DBR_STRING, pold->value, + status = dbChannelGet(chan, DBR_STRING, pold->value, &options, nRequest, pfl); } break; @@ -791,8 +794,12 @@ int dbChannel_get_count( } break; default: - return -1; + status = -1; + break; } + + dbScanUnlock(dbChannelRecord(chan)); + if (status) return -1; return 0; }