Merge changes from 3.15 branch into 7.0
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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, ¤t_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 |
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user