Better protection against bad periodic scan rates
This commit is contained in:
@@ -3,16 +3,28 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||||
<title>EPICS Base R3.14.12.6 Release Notes</title>
|
||||
<title>EPICS Base R3.14.12.7 Release Notes</title>
|
||||
</head>
|
||||
|
||||
<body lang="en">
|
||||
<h1 align="center">EPICS Base Release 3.14.12.6</h1>
|
||||
<h1 align="center">EPICS Base Release 3.14.12.7</h1>
|
||||
|
||||
<h2 align="center">Changes between 3.14.12.5 and 3.14.12.6</h2>
|
||||
<h2 align="center">Changes between 3.14.12.6 and 3.14.12.7</h2>
|
||||
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
<h3>Checking Periodic Scan Rates</h3>
|
||||
|
||||
<p>Code has been added to the IOC startup to better protect it against bad
|
||||
periodic scan rates, including against locales where <q><tt>.</tt></q> is not
|
||||
accepted as a decimal separator character. If the scan period in a menuScan
|
||||
choice string cannot be parsed, the associated periodic scan thread will no
|
||||
longer be started by the IOC and a warning message will be displayed at iocInit
|
||||
time. The <tt>scanppl</tt> command will also flag the faulty menuScan value.</p>
|
||||
|
||||
|
||||
<h2 align="center">Changes between 3.14.12.5 and 3.14.12.6</h2>
|
||||
|
||||
<h3>Launchpad Bug-fixes</h3>
|
||||
|
||||
<p>In addition to the more detailed change descriptions below, the following
|
||||
@@ -277,8 +289,6 @@ it up. This release patches the readline support code to clean up automatically
|
||||
by registering an epicsAtExit() routine.</p>
|
||||
|
||||
|
||||
<h1 align="center">EPICS Base Release 3.14.12.5</h1>
|
||||
|
||||
<h2 align="center">Changes between 3.14.12.4 and 3.14.12.5</h2>
|
||||
|
||||
<h3>aoRecord raw conversion overflows</h3>
|
||||
|
||||
@@ -148,8 +148,11 @@ static void scanShutdown(void *arg)
|
||||
interruptAccept = FALSE;
|
||||
|
||||
for (i = 0; i < nPeriodic; i++) {
|
||||
papPeriodic[i]->scanCtl = ctlExit;
|
||||
epicsEventSignal(papPeriodic[i]->loopEvent);
|
||||
periodic_scan_list *ppsl = papPeriodic[i];
|
||||
|
||||
if (!ppsl) continue;
|
||||
ppsl->scanCtl = ctlExit;
|
||||
epicsEventSignal(ppsl->loopEvent);
|
||||
epicsEventWait(startStopEvent);
|
||||
}
|
||||
|
||||
@@ -182,16 +185,24 @@ void scanRun(void)
|
||||
interruptAccept = TRUE;
|
||||
scanCtl = ctlRun;
|
||||
|
||||
for (i = 0; i < nPeriodic; i++)
|
||||
papPeriodic[i]->scanCtl = ctlRun;
|
||||
for (i = 0; i < nPeriodic; i++) {
|
||||
periodic_scan_list *ppsl = papPeriodic[i];
|
||||
|
||||
if (!ppsl) continue;
|
||||
ppsl->scanCtl = ctlRun;
|
||||
}
|
||||
}
|
||||
|
||||
void scanPause(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = nPeriodic - 1; i >= 0; --i)
|
||||
papPeriodic[i]->scanCtl = ctlPause;
|
||||
for (i = nPeriodic - 1; i >= 0; --i) {
|
||||
periodic_scan_list *ppsl = papPeriodic[i];
|
||||
|
||||
if (!ppsl) continue;
|
||||
ppsl->scanCtl = ctlPause;
|
||||
}
|
||||
|
||||
scanCtl = ctlPause;
|
||||
interruptAccept = FALSE;
|
||||
@@ -275,9 +286,11 @@ void scanAdd(struct dbCommon *precord)
|
||||
piosl += prio; /* get piosl for correct priority*/
|
||||
addToList(precord, &piosl->scan_list);
|
||||
} else if (scan >= SCAN_1ST_PERIODIC) {
|
||||
addToList(precord, &papPeriodic[scan - SCAN_1ST_PERIODIC]->scan_list);
|
||||
periodic_scan_list *ppsl = papPeriodic[scan - SCAN_1ST_PERIODIC];
|
||||
|
||||
if (ppsl)
|
||||
addToList(precord, &ppsl->scan_list);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void scanDelete(struct dbCommon *precord)
|
||||
@@ -348,28 +361,48 @@ void scanDelete(struct dbCommon *precord)
|
||||
piosl += prio; /*get piosl for correct priority*/
|
||||
deleteFromList(precord, &piosl->scan_list);
|
||||
} else if (scan >= SCAN_1ST_PERIODIC) {
|
||||
deleteFromList(precord, &papPeriodic[scan - SCAN_1ST_PERIODIC]->scan_list);
|
||||
periodic_scan_list *ppsl = papPeriodic[scan - SCAN_1ST_PERIODIC];
|
||||
|
||||
if (ppsl)
|
||||
deleteFromList(precord, &ppsl->scan_list);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
double scanPeriod(int scan) {
|
||||
periodic_scan_list *ppsl;
|
||||
|
||||
scan -= SCAN_1ST_PERIODIC;
|
||||
if (scan < 0 || scan >= nPeriodic)
|
||||
return 0.0;
|
||||
return papPeriodic[scan]->period;
|
||||
ppsl = papPeriodic[scan];
|
||||
return ppsl ? ppsl->period : 0.0;
|
||||
}
|
||||
|
||||
int scanppl(double period) /* print periodic list */
|
||||
|
||||
int scanppl(double period) /* print periodic scan list(s) */
|
||||
{
|
||||
periodic_scan_list *ppsl;
|
||||
dbMenu *pmenu = dbFindMenu(pdbbase, "menuScan");
|
||||
char message[80];
|
||||
int i;
|
||||
|
||||
if (!pmenu || !papPeriodic) {
|
||||
printf("scanppl: dbScan subsystem not initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nPeriodic; i++) {
|
||||
ppsl = papPeriodic[i];
|
||||
if (ppsl == NULL) continue;
|
||||
if (period > 0.0 && (fabs(period - ppsl->period) >.05)) continue;
|
||||
periodic_scan_list *ppsl = papPeriodic[i];
|
||||
|
||||
if (!ppsl) {
|
||||
const char *choice = pmenu->papChoiceValue[i + SCAN_1ST_PERIODIC];
|
||||
|
||||
printf("Periodic scan list for SCAN = '%s' not initialized\n",
|
||||
choice);
|
||||
continue;
|
||||
}
|
||||
if (period > 0.0 &&
|
||||
(fabs(period - ppsl->period) > 0.05))
|
||||
continue;
|
||||
|
||||
sprintf(message, "Records with SCAN = '%s' (%lu over-runs):",
|
||||
ppsl->name, ppsl->overruns);
|
||||
printList(&ppsl->scan_list, message);
|
||||
@@ -588,7 +621,7 @@ static void periodicTask(void *arg)
|
||||
if (++overruns >= 10 &&
|
||||
epicsTimeDiffInSeconds(&now, &reported) > report_delay) {
|
||||
errlogPrintf("\ndbScan warning from '%s' scan thread:\n"
|
||||
"\tScan processing averages %.2f seconds (%.2f .. %.2f).\n"
|
||||
"\tScan processing averages %.3f seconds (%.3f .. %.3f).\n"
|
||||
"\tOver-runs have now happened %u times in a row.\n"
|
||||
"\tTo fix this, move some records to a slower scan rate.\n",
|
||||
ppsl->name, ppsl->period + overtime / overruns,
|
||||
@@ -617,25 +650,30 @@ static void periodicTask(void *arg)
|
||||
|
||||
static void initPeriodic(void)
|
||||
{
|
||||
dbMenu *pmenu;
|
||||
periodic_scan_list *ppsl;
|
||||
dbMenu *pmenu = dbFindMenu(pdbbase, "menuScan");
|
||||
int i;
|
||||
|
||||
pmenu = dbFindMenu(pdbbase, "menuScan");
|
||||
if (!pmenu) {
|
||||
epicsPrintf("initPeriodic: menuScan not present\n");
|
||||
errlogPrintf("initPeriodic: menuScan not present\n");
|
||||
return;
|
||||
}
|
||||
nPeriodic = pmenu->nChoice - SCAN_1ST_PERIODIC;
|
||||
papPeriodic = dbCalloc(nPeriodic, sizeof(periodic_scan_list*));
|
||||
periodicTaskId = dbCalloc(nPeriodic, sizeof(void *));
|
||||
for (i = 0; i < nPeriodic; i++) {
|
||||
ppsl = dbCalloc(1, sizeof(periodic_scan_list));
|
||||
periodic_scan_list *ppsl = dbCalloc(1, sizeof(periodic_scan_list));
|
||||
const char *choice = pmenu->papChoiceValue[i + SCAN_1ST_PERIODIC];
|
||||
|
||||
if (!epicsScanDouble(choice, &ppsl->period) ||
|
||||
ppsl->period <= 0) {
|
||||
errlogPrintf("initPeriodic: Bad menuScan choice '%s'\n", choice);
|
||||
free(ppsl);
|
||||
continue;
|
||||
}
|
||||
|
||||
ppsl->scan_list.lock = epicsMutexMustCreate();
|
||||
ellInit(&ppsl->scan_list.list);
|
||||
ppsl->name = pmenu->papChoiceValue[i + SCAN_1ST_PERIODIC];
|
||||
epicsScanDouble(ppsl->name, &ppsl->period);
|
||||
ppsl->name = choice;
|
||||
ppsl->scanCtl = ctlPause;
|
||||
ppsl->loopEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
@@ -645,10 +683,11 @@ static void initPeriodic(void)
|
||||
|
||||
static void spawnPeriodic(int ind)
|
||||
{
|
||||
periodic_scan_list *ppsl;
|
||||
periodic_scan_list *ppsl = papPeriodic[ind];
|
||||
char taskName[20];
|
||||
|
||||
ppsl = papPeriodic[ind];
|
||||
if (!ppsl) return;
|
||||
|
||||
sprintf(taskName, "scan%g", ppsl->period);
|
||||
periodicTaskId[ind] = epicsThreadCreate(
|
||||
taskName, epicsThreadPriorityScanLow + ind,
|
||||
|
||||
Reference in New Issue
Block a user