Merge changes from 3.15 branch into 7.0

This commit is contained in:
Andrew Johnson
2020-05-24 23:17:33 -05:00
6 changed files with 222 additions and 76 deletions

View File

@@ -60,12 +60,8 @@ EPICS_PATCH_LEVEL = 2
EPICS_DEV_SNAPSHOT=-DEV
#EPICS_DEV_SNAPSHOT=-pre1
#EPICS_DEV_SNAPSHOT=-pre1-DEV
#EPICS_DEV_SNAPSHOT=-pre2
#EPICS_DEV_SNAPSHOT=-pre2-DEV
#EPICS_DEV_SNAPSHOT=-rc1
#EPICS_DEV_SNAPSHOT=-rc1-DEV
#EPICS_DEV_SNAPSHOT=-rc2
#EPICS_DEV_SNAPSHOT=-rc2-DEV
# No changes should be needed below here

View File

@@ -1290,7 +1290,32 @@ header and removed the need for dbScan.c to reach into the internals of its
`CALLBACK` objects.
## Changes from the 3.15 branch since 3.15.7
# Changes incorporated from the 3.15 branch
## Changes made between 3.15.7 and 3.15.8
### Bug fixes
The following launchpad bugs have fixes included in this release:
- [lp: 1812084](https://bugs.launchpad.net/epics-base/+bug/1812084), Build
failure on RTEMS 4.10.2
- [lp: 1829770](https://bugs.launchpad.net/epics-base/+bug/1829770), event
record device support broken with constant INP
- [lp: 1829919](https://bugs.launchpad.net/epics-base/+bug/1829919), IOC
segfaults when calling dbLoadRecords after iocInit
- [lp: 1838792](https://bugs.launchpad.net/epics-base/+bug/1838792), epicsCalc
bit-wise operators on aarch64
- [lp: 1841608](https://bugs.launchpad.net/epics-base/+bug/1841608), logClient
falsely sends error logs on all connections
- [lp: 1853168](https://bugs.launchpad.net/epics-base/+bug/1853168), undefined
reference to `clock_gettime()`
- [lp: 1862328](https://bugs.launchpad.net/epics-base/+bug/1862328), Race
condition on IOC start leaves rsrv unresponsive
- [lp: 1868486](https://bugs.launchpad.net/epics-base/+bug/1868486),
epicsMessageQueue lost messages
### Improvements to the self-test build targets
@@ -1314,6 +1339,25 @@ jobs that should be allowed so `make -j4 tapfiles` for a system with 4 CPUs say.
Running many more jobs than you have CPUs is likely to be slower and is not
recommended.
### Calc Engine Fixes and Enhancements
The code that implements bit operations for Calc expressions has been reworked
to better handle some CPU architectures and compilers. As part of this work a
new operator has been added: `>>>` performs a logical right-shift, inserting
zero bits into the most significant bits (the operator `>>` is an arithmetic
right-shift which copies the sign bit as it shifts the value rightwards).
### IOC logClient Changes
The IOC's error logging system has been updated significantly to fix a number
of issues including:
- Only send errlog messages to iocLogClient listeners
- Try to minimize lost messages while the log server is down:
+ Detect disconnects sooner
+ Don't discard the buffer on disconnect
+ Flush the buffer immediately after a server reconnects
### epicsThread: Main thread defaults to allow blocking I/O
VxWorks IOCs (and potentially RTEMS IOCs running GeSys) have had problems with
@@ -1336,7 +1380,7 @@ This has now been fixed.
The remaining record types have had their reference pages moved from the Wiki,
and some new reference pages have been written to cover the analog array and
long string input and output record types plus the printf recor type, none of
long string input and output record types plus the printf record type, none of
which were previously documented. The wiki reference pages covering the fields
common to all, input, and output record types have also been added, thanks to
Rolf Keitel. The POD conversion scripts have also been improved and they now

View File

@@ -5,8 +5,8 @@ converted from the old EPICS Wiki pages and updated. This list only includes the
record types supplied with Base.
* [Fields Common to All Record Types](dbCommonRecord.html)
* [Fields Common to Input Record Types](dbCommonInputs.html)
* [Fields Common to Output Record Types](dbCommonOutputs.html)
* [Fields Common to Input Record Types](dbCommonInput.html)
* [Fields Common to Output Record Types](dbCommonOutput.html)
## Record Types

View File

@@ -22,6 +22,7 @@
#include <assert.h>
#include <syslog.h>
#include <limits.h>
#include <pthread.h>
#include <rtems.h>
#include <rtems/error.h>
@@ -736,6 +737,23 @@ showInternalTaskInfo (rtems_id tid)
}
thread = *the_thread;
_Thread_Enable_dispatch();
/* This looks a bit weird, but it has to support RTEMS versions both before
* and after 4.10.2 when threads changed how their priorities are stored.
*/
int policy;
struct sched_param sp;
rtems_task_priority real_priority, current_priority;
rtems_status_code sc = pthread_getschedparam(tid, &policy, &sp);
if (sc == RTEMS_SUCCESSFUL) {
real_priority = sp.sched_priority;
sc = rtems_task_set_priority(tid, RTEMS_CURRENT_PRIORITY, &current_priority);
}
if (sc != RTEMS_SUCCESSFUL) {
fprintf(epicsGetStdout(),"%-30s", " *** RTEMS task gone! ***");
return;
}
/*
* Show both real and current priorities if they differ.
* Note that the epicsThreadGetOsiPriorityValue routine is not used here.
@@ -743,17 +761,17 @@ showInternalTaskInfo (rtems_id tid)
* that priority should be displayed, not the value truncated to
* the EPICS range.
*/
epicsPri = 199-thread.real_priority;
epicsPri = 199-real_priority;
if (epicsPri < 0)
fprintf(epicsGetStdout()," <0");
else if (epicsPri > 99)
fprintf(epicsGetStdout()," >99");
else
fprintf(epicsGetStdout()," %4d", epicsPri);
if (thread.current_priority == thread.real_priority)
fprintf(epicsGetStdout(),"%4d ", (int)thread.current_priority);
if (current_priority == real_priority)
fprintf(epicsGetStdout(),"%4d ", (int)current_priority);
else
fprintf(epicsGetStdout(),"%4d/%-3d", (int)thread.real_priority, (int)thread.current_priority);
fprintf(epicsGetStdout(),"%4d/%-3d", (int)real_priority, (int)current_priority);
showBitmap (bitbuf, thread.current_state, taskState);
fprintf(epicsGetStdout(),"%8.8s", bitbuf);
if (thread.current_state & (STATES_WAITING_FOR_SEMAPHORE |

View File

@@ -15,7 +15,6 @@
#include <stdexcept>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -108,7 +107,7 @@ LIBCOM_API epicsMessageQueueId epicsStdCall epicsMessageQueueCreate(
}
static void
freeEventNode(struct eventNode *enode)
destroyEventNode(struct eventNode *enode)
{
epicsEventDestroy(enode->event);
free(enode);
@@ -121,7 +120,7 @@ epicsMessageQueueDestroy(epicsMessageQueueId pmsg)
while ((evp = reinterpret_cast < struct eventNode * >
( ellGet(&pmsg->eventFreeList) ) ) != NULL) {
freeEventNode(evp);
destroyEventNode(evp);
}
epicsMutexDestroy(pmsg->mutex);
free(pmsg->buf);
@@ -147,6 +146,16 @@ getEventNode(epicsMessageQueueId pmsg)
return evp;
}
static void
freeEventNode(epicsMessageQueueId pmsg, eventNode *evp, epicsEventStatus status)
{
if (status == epicsEventWaitTimeout) {
epicsEventSignal(evp->event);
epicsEventWait(evp->event);
}
ellAdd(&pmsg->eventFreeList, &evp->link);
}
static int
mySend(epicsMessageQueueId pmsg, void *message, unsigned int size,
double timeout)
@@ -165,7 +174,7 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size,
if ((pmsg->numberOfSendersWaiting > 0)
|| (pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL))) {
/*
* Return if not allowed to wait
* Return if not allowed to wait. NB -1 means wait forever.
*/
if (timeout == 0) {
epicsMutexUnlock(pmsg->mutex);
@@ -173,7 +182,7 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size,
}
/*
* Wait
* Indicate that we're waiting
*/
struct threadNode threadNode;
threadNode.evp = getEventNode(pmsg);
@@ -188,22 +197,25 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size,
epicsMutexUnlock(pmsg->mutex);
epicsEventStatus status;
if (timeout > 0)
status = epicsEventWaitWithTimeout(threadNode.evp->event, timeout);
else
status = epicsEventWait(threadNode.evp->event);
/*
* Wait for receiver to wake us
*/
epicsEventStatus status = timeout < 0 ?
epicsEventWait(threadNode.evp->event) :
epicsEventWaitWithTimeout(threadNode.evp->event, timeout);
epicsMutexMustLock(pmsg->mutex);
if(!threadNode.eventSent)
if (!threadNode.eventSent) {
/* Receiver didn't take us off the sendQueue, do it ourselves */
ellDelete(&pmsg->sendQueue, &threadNode.link);
pmsg->numberOfSendersWaiting--;
pmsg->numberOfSendersWaiting--;
}
ellAdd(&pmsg->eventFreeList, &threadNode.evp->link);
freeEventNode(pmsg, threadNode.evp, status);
if ((pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL)) ||
status != epicsEventOK) {
if (pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL)) {
/* State of the queue didn't change, exit */
epicsMutexUnlock(pmsg->mutex);
return -1;
}
@@ -296,6 +308,7 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size,
*/
if ((pthr = reinterpret_cast < struct threadNode * >
( ellGet(&pmsg->sendQueue) ) ) != NULL) {
pmsg->numberOfSendersWaiting--;
pthr->eventSent = true;
epicsEventSignal(pthr->evp->event);
}
@@ -304,7 +317,7 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size,
}
/*
* Return if not allowed to wait
* Return if not allowed to wait. NB -1 means wait forever.
*/
if (timeout == 0) {
epicsMutexUnlock(pmsg->mutex);
@@ -312,16 +325,7 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size,
}
/*
* Wake up the oldest task waiting to send
*/
if ((pthr = reinterpret_cast < struct threadNode * >
( ellGet(&pmsg->sendQueue) ) ) != NULL) {
pthr->eventSent = true;
epicsEventSignal(pthr->evp->event);
}
/*
* Wait for message to arrive
* Indicate that we're waiting
*/
struct threadNode threadNode;
threadNode.evp = getEventNode(pmsg);
@@ -335,18 +339,32 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size,
}
ellAdd(&pmsg->receiveQueue, &threadNode.link);
/*
* Wake up the oldest task waiting to send
*/
if ((pthr = reinterpret_cast < struct threadNode * >
( ellGet(&pmsg->sendQueue) ) ) != NULL) {
pmsg->numberOfSendersWaiting--;
pthr->eventSent = true;
epicsEventSignal(pthr->evp->event);
}
epicsMutexUnlock(pmsg->mutex);
if (timeout > 0)
/*
* Wait for a message to arrive
*/
epicsEventStatus status = timeout < 0 ?
epicsEventWait(threadNode.evp->event) :
epicsEventWaitWithTimeout(threadNode.evp->event, timeout);
else
epicsEventWait(threadNode.evp->event);
epicsMutexMustLock(pmsg->mutex);
if (!threadNode.eventSent)
ellDelete(&pmsg->receiveQueue, &threadNode.link);
ellAdd(&pmsg->eventFreeList, &threadNode.evp->link);
freeEventNode(pmsg, threadNode.evp, status);
epicsMutexUnlock(pmsg->mutex);
@@ -398,7 +416,8 @@ epicsMessageQueuePending(epicsMessageQueueId pmsg)
LIBCOM_API void epicsStdCall
epicsMessageQueueShow(epicsMessageQueueId pmsg, int level)
{
printf("Message Queue Used:%d Slots:%lu", epicsMessageQueuePending(pmsg), pmsg->capacity);
printf("Message Queue Used:%d Slots:%lu",
epicsMessageQueuePending(pmsg), pmsg->capacity);
if (level >= 1)
printf(" Maximum size:%lu", pmsg->maxMessageSize);
printf("\n");

View File

@@ -27,7 +27,10 @@ static volatile int sendExit = 0;
static volatile int recvExit = 0;
static epicsEventId finished;
static unsigned int mediumStack;
static int numReceived;
#define SLEEPY_TESTS 500
static int numSent, numReceived;
static epicsEventId complete;
/*
* In Numerical Recipes in C: The Art of Scientific Computing (William H.
@@ -124,11 +127,96 @@ fastReceiver(void *arg)
int len;
numReceived = 0;
while (!recvExit) {
len = q->receive(cbuf, sizeof cbuf, 0.01);
len = q->receive(cbuf, sizeof cbuf, 0.010);
if (len > 0) {
numReceived++;
}
}
recvExit = 0;
epicsEventSignal(complete);
}
void sleepySender(double delay)
{
testDiag("sleepySender: sending every %.3f seconds", delay);
epicsMessageQueue q(4, 20);
epicsThreadCreate("Fast Receiver", epicsThreadPriorityMedium,
mediumStack, fastReceiver, &q);
numSent = 0;
for (int i = 0 ; i < SLEEPY_TESTS ; i++) {
if (q.send((void *)msg1, 4) == 0) {
numSent++;
}
epicsThreadSleep(delay);
}
epicsThreadSleep(1.0);
testOk(numSent == SLEEPY_TESTS, "Sent %d (should be %d)",
numSent, SLEEPY_TESTS);
testOk(numReceived == SLEEPY_TESTS, "Received %d (should be %d)",
numReceived, SLEEPY_TESTS);
recvExit = 1;
while (q.send((void *)msg1, 4) != 0)
epicsThreadSleep(0.01);
epicsEventMustWait(complete);
}
extern "C" void
fastSender(void *arg)
{
epicsMessageQueue *q = (epicsMessageQueue *)arg;
numSent = 0;
// Send first withough timeout
q->send((void *)msg1, 4);
numSent++;
// The rest have a timeout
while (!sendExit) {
if (q->send((void *)msg1, 4, 0.010) == 0) {
numSent++;
}
}
sendExit = 0;
epicsEventSignal(complete);
}
void sleepyReceiver(double delay)
{
testDiag("sleepyReceiver: acquiring every %.3f seconds", delay);
epicsMessageQueue q(4, 20);
// Fill the queue
for (int i = q.pending(); i < 4 ;i++) {
q.send((void *)msg1, 4);
}
epicsThreadCreate("Fast Sender", epicsThreadPriorityMedium,
mediumStack, fastSender, &q);
epicsThreadSleep(0.5);
char cbuf[80];
int len;
numReceived = 0;
for (int i = 0 ; i < SLEEPY_TESTS ; i++) {
len = q.receive(cbuf, sizeof cbuf);
if (len > 0) {
numReceived++;
}
epicsThreadSleep(delay);
}
testOk(numSent == SLEEPY_TESTS, "Sent %d (should be %d)",
numSent, SLEEPY_TESTS);
testOk(numReceived == SLEEPY_TESTS, "Received %d (should be %d)",
numReceived, SLEEPY_TESTS);
sendExit = 1;
while (q.receive(cbuf, sizeof cbuf) <= 0)
epicsThreadSleep(0.01);
epicsEventMustWait(complete);
}
extern "C" void
@@ -156,10 +244,8 @@ extern "C" void messageQueueTest(void *parm)
int len;
int pass;
int want;
int numSent = 0;
epicsMessageQueue *q1 = new epicsMessageQueue(4, 20);
epicsMessageQueue *q2 = new epicsMessageQueue(4, 20);
testDiag("Simple single-thread tests:");
i = 0;
@@ -269,34 +355,17 @@ extern "C" void messageQueueTest(void *parm)
testOk(q1->send((void *)msg1, 10) == 0, "Send with no receiver");
epicsThreadSleep(2.0);
testDiag("Single receiver with timeout, single sender with sleep tests:");
testDiag("These tests last 20 seconds ...");
epicsThreadCreate("Fast Receiver", epicsThreadPriorityMedium,
mediumStack, fastReceiver, q2);
numSent = 0;
numReceived = 0;
for (i = 0 ; i < 1000 ; i++) {
if (q2->send((void *)msg1, 4) == 0) {
numSent++;
}
epicsThreadSleep(0.011);
}
epicsThreadSleep(1.0);
if (!testOk(numSent == 1000 && numReceived == 1000, "sleep=0.011")) {
testDiag("numSent should be 1000, actual=%d, numReceived should be 1000, actual=%d", numSent, numReceived);
}
numSent = 0;
numReceived = 0;
for (i = 0 ; i < 1000 ; i++) {
if (q2->send((void *)msg1, 4) == 0) {
numSent++;
}
epicsThreadSleep(0.010);
}
epicsThreadSleep(1.0);
if (!testOk(numSent == 1000 && numReceived == 1000, "sleep=0.010")) {
testDiag("numSent should be 1000, actual=%d, numReceived should be 1000, actual=%d", numSent, numReceived);
}
testDiag("6 Single receiver single sender 'Sleepy timeout' tests,");
testDiag(" these should take about %.2f seconds each:",
SLEEPY_TESTS * 0.010);
complete = epicsEventMustCreate(epicsEventEmpty);
sleepySender(0.009);
sleepySender(0.010);
sleepySender(0.011);
sleepyReceiver(0.009);
sleepyReceiver(0.010);
sleepyReceiver(0.011);
testDiag("Single receiver, single sender tests:");
epicsThreadSetPriority(myThreadId, epicsThreadPriorityHigh);
@@ -359,7 +428,7 @@ extern "C" void messageQueueTest(void *parm)
MAIN(epicsMessageQueueTest)
{
testPlan(64);
testPlan(74);
finished = epicsEventMustCreate(epicsEventEmpty);
mediumStack = epicsThreadGetStackSize(epicsThreadStackMedium);