From 298c8706ece05c977e3db080330d155ef341735b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 30 Apr 2020 22:59:58 -0500 Subject: [PATCH 01/14] osdMessageQueue: Rename freeEventNode() -> destroyEventNode() --- src/libCom/osi/os/default/osdMessageQueue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/os/default/osdMessageQueue.cpp b/src/libCom/osi/os/default/osdMessageQueue.cpp index fc50a36b7..81d0fa015 100644 --- a/src/libCom/osi/os/default/osdMessageQueue.cpp +++ b/src/libCom/osi/os/default/osdMessageQueue.cpp @@ -106,7 +106,7 @@ epicsShareFunc epicsMessageQueueId epicsShareAPI epicsMessageQueueCreate( } static void -freeEventNode(struct eventNode *enode) +destroyEventNode(struct eventNode *enode) { epicsEventDestroy(enode->event); free(enode); @@ -119,7 +119,7 @@ epicsMessageQueueDestroy(epicsMessageQueueId pmsg) while ((evp = reinterpret_cast < struct eventNode * > ( ellGet(&pmsg->eventFreeList) ) ) != NULL) { - freeEventNode(evp); + destroyEventNode(evp); } epicsMutexDestroy(pmsg->mutex); free(pmsg->buf); From cf2fef2405aee3469fd4f9d82ccebc77bd4454e6 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 30 Apr 2020 23:27:43 -0500 Subject: [PATCH 02/14] osdMessageQueue: Return sooner on -ve timeout It appears that previously a negative timeout actually implemented a 'wait forever', but the VxWorks and RTEMS implementations both check for (timeout <= 0) and return immediately if nothing can be done without waiting. --- src/libCom/osi/os/default/osdMessageQueue.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/libCom/osi/os/default/osdMessageQueue.cpp b/src/libCom/osi/os/default/osdMessageQueue.cpp index 81d0fa015..c93be4d97 100644 --- a/src/libCom/osi/os/default/osdMessageQueue.cpp +++ b/src/libCom/osi/os/default/osdMessageQueue.cpp @@ -165,7 +165,7 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size, /* * Return if not allowed to wait */ - if (timeout == 0) { + if (timeout <= 0) { epicsMutexUnlock(pmsg->mutex); return -1; } @@ -186,11 +186,8 @@ 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); + epicsEventStatus status = + epicsEventWaitWithTimeout(threadNode.evp->event, timeout); epicsMutexMustLock(pmsg->mutex); @@ -304,7 +301,7 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size, /* * Return if not allowed to wait */ - if (timeout == 0) { + if (timeout <= 0) { epicsMutexUnlock(pmsg->mutex); return -1; } @@ -335,10 +332,11 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size, ellAdd(&pmsg->receiveQueue, &threadNode.link); epicsMutexUnlock(pmsg->mutex); - if (timeout > 0) + /* + * Wait for a message to arrive + */ + epicsEventStatus status = epicsEventWaitWithTimeout(threadNode.evp->event, timeout); - else - epicsEventWait(threadNode.evp->event); epicsMutexMustLock(pmsg->mutex); From 183c3b2a3e1fa2a55cd918b94ef4d7c486e11bf4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 30 Apr 2020 23:38:51 -0500 Subject: [PATCH 03/14] osdMessageQueue: Clear eventNode before returning it Introduced freeEventNode() which ensures eventNodes don't have a signalled event in them before returning the node to the freeList. Callers pass the status from epicsEventWaitWithTimeout() to indicate whether it was signalled or not. If it timed out we must trigger it and Wait to clear the event state. --- src/libCom/osi/os/default/osdMessageQueue.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/os/default/osdMessageQueue.cpp b/src/libCom/osi/os/default/osdMessageQueue.cpp index c93be4d97..0e1d1fc22 100644 --- a/src/libCom/osi/os/default/osdMessageQueue.cpp +++ b/src/libCom/osi/os/default/osdMessageQueue.cpp @@ -145,6 +145,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) @@ -195,7 +205,7 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size, ellDelete(&pmsg->sendQueue, &threadNode.link); pmsg->numberOfSendersWaiting--; - ellAdd(&pmsg->eventFreeList, &threadNode.evp->link); + freeEventNode(pmsg, threadNode.evp, status); if ((pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL)) || status != epicsEventOK) { @@ -342,7 +352,8 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size, if (!threadNode.eventSent) ellDelete(&pmsg->receiveQueue, &threadNode.link); - ellAdd(&pmsg->eventFreeList, &threadNode.evp->link); + + freeEventNode(pmsg, threadNode.evp, status); epicsMutexUnlock(pmsg->mutex); From aeed7cfbddc979c5bc668d668052ef96cb5d84c5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 30 Apr 2020 23:55:30 -0500 Subject: [PATCH 04/14] osdMessageQueue: This is the mirror of Heinz Junkes' earlier fix When sending a message, if the queue is full so we have to wait, we create a threadNode with an eventNode in it and stick it on the sendQueue, then wait for a receiver to signal that event, waking us. If we awoke due to a timeout but a receiver was actually waking us up anyway (i.e. eventSent was set), we shouldn't give up. --- src/libCom/osi/os/default/osdMessageQueue.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libCom/osi/os/default/osdMessageQueue.cpp b/src/libCom/osi/os/default/osdMessageQueue.cpp index 0e1d1fc22..cdb3afba9 100644 --- a/src/libCom/osi/os/default/osdMessageQueue.cpp +++ b/src/libCom/osi/os/default/osdMessageQueue.cpp @@ -207,8 +207,7 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size, freeEventNode(pmsg, threadNode.evp, status); - if ((pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL)) || - status != epicsEventOK) { + if (pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL)) { epicsMutexUnlock(pmsg->mutex); return -1; } From 084557bd3e6de8795f65b0f6cff7914fa4ec930b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 May 2020 00:12:32 -0500 Subject: [PATCH 05/14] osdMessageQueue: Don't wake our sender until we're ready for it Move the code that wakes up the next sending task to after we've added our threadNode to the receiveQueue. He still has to wait for us to release the Mutex though, so this might make no difference. This commit also changes when we decrement the number of waiting senders so it always happens immediately after a threadNode gets taken off the sendQueue by the code that removed it. --- src/libCom/osi/os/default/osdMessageQueue.cpp | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/libCom/osi/os/default/osdMessageQueue.cpp b/src/libCom/osi/os/default/osdMessageQueue.cpp index cdb3afba9..38e4f764d 100644 --- a/src/libCom/osi/os/default/osdMessageQueue.cpp +++ b/src/libCom/osi/os/default/osdMessageQueue.cpp @@ -201,9 +201,10 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size, epicsMutexMustLock(pmsg->mutex); - if(!threadNode.eventSent) + if (!threadNode.eventSent) { ellDelete(&pmsg->sendQueue, &threadNode.link); - pmsg->numberOfSendersWaiting--; + pmsg->numberOfSendersWaiting--; + } freeEventNode(pmsg, threadNode.evp, status); @@ -300,6 +301,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); } @@ -316,16 +318,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); @@ -339,6 +332,17 @@ 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); /* From ceb13797a600da82bd73d52dded14fd6ee35d423 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 May 2020 00:13:02 -0500 Subject: [PATCH 06/14] Cosmetic --- src/libCom/osi/os/default/osdMessageQueue.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libCom/osi/os/default/osdMessageQueue.cpp b/src/libCom/osi/os/default/osdMessageQueue.cpp index 38e4f764d..3f95c4f40 100644 --- a/src/libCom/osi/os/default/osdMessageQueue.cpp +++ b/src/libCom/osi/os/default/osdMessageQueue.cpp @@ -408,7 +408,8 @@ epicsMessageQueuePending(epicsMessageQueueId pmsg) epicsShareFunc void epicsShareAPI 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"); From 34e0b2f305ecef38f699d150086a76ee962a52cb Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 4 May 2020 11:56:14 -0500 Subject: [PATCH 07/14] osdMessageQueue: Undo change to -ve timeout handling The internal mySend() and myReceive() routines do expect a timeout of -1 to mean wait forever, see the epicsMessageQueueSend() and epicsMessageQueueReceive() API routines. --- src/libCom/osi/os/default/osdMessageQueue.cpp | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/libCom/osi/os/default/osdMessageQueue.cpp b/src/libCom/osi/os/default/osdMessageQueue.cpp index 3f95c4f40..d99e23b70 100644 --- a/src/libCom/osi/os/default/osdMessageQueue.cpp +++ b/src/libCom/osi/os/default/osdMessageQueue.cpp @@ -173,15 +173,15 @@ 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) { + if (timeout == 0) { epicsMutexUnlock(pmsg->mutex); return -1; } /* - * Wait + * Indicate that we're waiting */ struct threadNode threadNode; threadNode.evp = getEventNode(pmsg); @@ -196,12 +196,17 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size, epicsMutexUnlock(pmsg->mutex); - epicsEventStatus status = + /* + * 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) { + /* Receiver didn't take us off the sendQueue, do it ourselves */ ellDelete(&pmsg->sendQueue, &threadNode.link); pmsg->numberOfSendersWaiting--; } @@ -209,6 +214,7 @@ mySend(epicsMessageQueueId pmsg, void *message, unsigned int size, freeEventNode(pmsg, threadNode.evp, status); if (pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL)) { + /* State of the queue didn't change, exit */ epicsMutexUnlock(pmsg->mutex); return -1; } @@ -310,9 +316,9 @@ 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) { + if (timeout == 0) { epicsMutexUnlock(pmsg->mutex); return -1; } @@ -348,7 +354,8 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size, /* * Wait for a message to arrive */ - epicsEventStatus status = + epicsEventStatus status = timeout < 0 ? + epicsEventWait(threadNode.evp->event) : epicsEventWaitWithTimeout(threadNode.evp->event, timeout); epicsMutexMustLock(pmsg->mutex); From 089954aaab0ef6c43da77305bc28b807f1686930 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 7 May 2020 13:12:12 -0500 Subject: [PATCH 08/14] MessageQueue Tests: Extend Mark's sleep tests --- src/libCom/test/epicsMessageQueueTest.cpp | 133 ++++++++++++++++------ 1 file changed, 101 insertions(+), 32 deletions(-) diff --git a/src/libCom/test/epicsMessageQueueTest.cpp b/src/libCom/test/epicsMessageQueueTest.cpp index 1bee13c36..b793ce2cd 100644 --- a/src/libCom/test/epicsMessageQueueTest.cpp +++ b/src/libCom/test/epicsMessageQueueTest.cpp @@ -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,95 @@ 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(epicsMessageQueue *q, double delay) +{ + testDiag("sleepySender: sending every %.3f seconds", delay); + epicsThreadCreate("Fast Receiver", epicsThreadPriorityMedium, + mediumStack, fastReceiver, q); + + numSent = 0; + numReceived = 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(epicsMessageQueue *q, double delay) +{ + testDiag("sleepyReceiver: acquiring every %.3f seconds", delay); + + // 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,7 +243,6 @@ 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); @@ -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(q2, 0.009); + sleepySender(q2, 0.010); + sleepySender(q2, 0.011); + sleepyReceiver(q2, 0.009); + sleepyReceiver(q2, 0.010); + sleepyReceiver(q2, 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); From 2e7ed02a606bbebe3cf961670a8b782fd6915705 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 7 May 2020 13:13:26 -0500 Subject: [PATCH 09/14] Allow/expect MinGW to fail epicsStackTraceTest #5 --- src/libCom/test/epicsStackTraceTest.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/libCom/test/epicsStackTraceTest.c b/src/libCom/test/epicsStackTraceTest.c index 69cb499f2..246abe4d8 100644 --- a/src/libCom/test/epicsStackTraceTest.c +++ b/src/libCom/test/epicsStackTraceTest.c @@ -1,11 +1,11 @@ -/* +/* * Copyright: Stanford University / SLAC National Laboratory. * * EPICS BASE is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. + * in file LICENSE that is included with this distribution. * * Author: Till Straumann , 2014 - */ + */ /* * Check stack trace functionality @@ -135,14 +135,14 @@ findNumOcc(const char *buf) } /* We should find an address close to epicsStackTraceRecurseGbl twice */ for (i=0; i= (char*)epicsStackTraceRecurseGbl && (char*)ptrs[i] < (char*)epicsStackTraceRecurseGbl + WINDOW_SZ ) { - rval ++; + rval ++; if ( test_debug ) testDiag("found address %p again\n", ptrs[i]); } @@ -167,7 +167,7 @@ MAIN(epicsStackTraceTest) testPlan(5); - features = epicsStackTraceGetFeatures(); + features = epicsStackTraceGetFeatures(); all_features = EPICS_STACKTRACE_LCL_SYMBOLS | EPICS_STACKTRACE_GBL_SYMBOLS @@ -217,7 +217,13 @@ MAIN(epicsStackTraceTest) } if ( (features & EPICS_STACKTRACE_ADDRESSES) ) { +#ifdef _MINGW + testTodoBegin("MinGW, might fail"); +#endif testOk( numFound > 0, "dumping addresses" ); +#ifdef _MINGW + testTodoEnd(); +#endif } else { testSkip(1 , "no support for dumping addresses on this platform"); } From 59c68807b6eb3525619bb210897b1520a1a9b96c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 13 May 2020 15:26:34 -0500 Subject: [PATCH 10/14] Heinz Junkes' fix for lp: #1812084 Build failure on RTEMS I reduced some of the code duplication from his original. --- src/libCom/osi/os/RTEMS/osdThread.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c index c19279ecf..8cbfc7086 100644 --- a/src/libCom/osi/os/RTEMS/osdThread.c +++ b/src/libCom/osi/os/RTEMS/osdThread.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -615,6 +616,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. @@ -622,17 +640,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 | From b03e2f376bf8bd126dacc684b34afc35c309fd92 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 13 May 2020 16:11:31 -0500 Subject: [PATCH 11/14] eMQTest: Start each test with a new (empty) queue If fastReceiver() took more than 0.01 seconds to exit, sleepySender() might have pushed a second message onto the queue after setting recvExit, so there would be an extra message in the queue for the next test, which I was seeing on Appveyor. That's my current theory... --- src/libCom/test/epicsMessageQueueTest.cpp | 36 +++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libCom/test/epicsMessageQueueTest.cpp b/src/libCom/test/epicsMessageQueueTest.cpp index b793ce2cd..f23683c84 100644 --- a/src/libCom/test/epicsMessageQueueTest.cpp +++ b/src/libCom/test/epicsMessageQueueTest.cpp @@ -136,16 +136,16 @@ fastReceiver(void *arg) epicsEventSignal(complete); } -void sleepySender(epicsMessageQueue *q, double delay) +void sleepySender(double delay) { testDiag("sleepySender: sending every %.3f seconds", delay); + epicsMessageQueue q(4, 20); epicsThreadCreate("Fast Receiver", epicsThreadPriorityMedium, - mediumStack, fastReceiver, q); + mediumStack, fastReceiver, &q); numSent = 0; - numReceived = 0; for (int i = 0 ; i < SLEEPY_TESTS ; i++) { - if (q->send((void *)msg1, 4) == 0) { + if (q.send((void *)msg1, 4) == 0) { numSent++; } epicsThreadSleep(delay); @@ -157,7 +157,7 @@ void sleepySender(epicsMessageQueue *q, double delay) numReceived, SLEEPY_TESTS); recvExit = 1; - while (q->send((void *)msg1, 4) != 0) + while (q.send((void *)msg1, 4) != 0) epicsThreadSleep(0.01); epicsEventMustWait(complete); } @@ -182,17 +182,18 @@ fastSender(void *arg) epicsEventSignal(complete); } -void sleepyReceiver(epicsMessageQueue *q, double delay) +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); + for (int i = q.pending(); i < 4 ;i++) { + q.send((void *)msg1, 4); } epicsThreadCreate("Fast Sender", epicsThreadPriorityMedium, - mediumStack, fastSender, q); + mediumStack, fastSender, &q); epicsThreadSleep(0.5); char cbuf[80]; @@ -200,7 +201,7 @@ void sleepyReceiver(epicsMessageQueue *q, double delay) numReceived = 0; for (int i = 0 ; i < SLEEPY_TESTS ; i++) { - len = q->receive(cbuf, sizeof cbuf); + len = q.receive(cbuf, sizeof cbuf); if (len > 0) { numReceived++; } @@ -213,7 +214,7 @@ void sleepyReceiver(epicsMessageQueue *q, double delay) numReceived, SLEEPY_TESTS); sendExit = 1; - while (q->receive(cbuf, sizeof cbuf) <= 0) + while (q.receive(cbuf, sizeof cbuf) <= 0) epicsThreadSleep(0.01); epicsEventMustWait(complete); } @@ -245,7 +246,6 @@ extern "C" void messageQueueTest(void *parm) int want; epicsMessageQueue *q1 = new epicsMessageQueue(4, 20); - epicsMessageQueue *q2 = new epicsMessageQueue(4, 20); testDiag("Simple single-thread tests:"); i = 0; @@ -360,12 +360,12 @@ extern "C" void messageQueueTest(void *parm) SLEEPY_TESTS * 0.010); complete = epicsEventMustCreate(epicsEventEmpty); - sleepySender(q2, 0.009); - sleepySender(q2, 0.010); - sleepySender(q2, 0.011); - sleepyReceiver(q2, 0.009); - sleepyReceiver(q2, 0.010); - sleepyReceiver(q2, 0.011); + 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); From 2f28ce94f4c4965f9a887a0e72bcd272f1aefd90 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 15 May 2020 11:36:45 -0500 Subject: [PATCH 12/14] Release Notes changes for 3.15.8 --- documentation/RELEASE_NOTES.md | 45 +++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 6217fa9a2..fbcf72aaa 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -1,10 +1,28 @@ # EPICS Base Release 3.15.8 -This version of EPICS Base has not been released yet. +## Changes made between 3.15.7 and 3.15.8 -## Changes made on the 3.15 branch since 3.15.7 +### 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 @@ -28,6 +46,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 @@ -50,7 +87,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 From c7e42fab3c10f6b0c7464482f507e8ffac502937 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 15 May 2020 12:00:23 -0500 Subject: [PATCH 13/14] Set version number to 3.15.8, clear snapshot --- configure/CONFIG_BASE_VERSION | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index 16a54b1e5..eaeb0f2de 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -4,7 +4,7 @@ # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. # EPICS BASE is distributed subject to a Software License Agreement found -# in the file LICENSE that is included with this distribution. +# in the file LICENSE that is included with this distribution. #************************************************************************* # # EPICS Version information @@ -27,23 +27,19 @@ EPICS_VERSION = 3 EPICS_REVISION = 15 # EPICS_MODIFICATION must be a number >=0 and <256 -EPICS_MODIFICATION = 7 +EPICS_MODIFICATION = 8 # EPICS_PATCH_LEVEL must be a number (win32 resource file requirement) # Not included if zero -EPICS_PATCH_LEVEL = 1 +EPICS_PATCH_LEVEL = 0 # This will end in -DEV between official releases -EPICS_DEV_SNAPSHOT=-DEV +#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 -#EPICS_DEV_SNAPSHOT= +EPICS_DEV_SNAPSHOT= # No changes should be needed below here From e923790c41e208304ea9fba92e5e068c69ce0e4b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 15 May 2020 12:09:24 -0500 Subject: [PATCH 14/14] Update versions after tagging --- configure/CONFIG_BASE_VERSION | 6 +++--- documentation/KnownProblems.html | 8 ++++---- documentation/RELEASE_NOTES.md | 9 ++++++++- documentation/RecordReference.md | 4 ++-- documentation/ReleaseChecklist.html | 16 ++++++++-------- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index eaeb0f2de..f7141a82e 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -31,15 +31,15 @@ EPICS_MODIFICATION = 8 # EPICS_PATCH_LEVEL must be a number (win32 resource file requirement) # Not included if zero -EPICS_PATCH_LEVEL = 0 +EPICS_PATCH_LEVEL = 1 # This will end in -DEV between official releases -#EPICS_DEV_SNAPSHOT=-DEV +EPICS_DEV_SNAPSHOT=-DEV #EPICS_DEV_SNAPSHOT=-pre1 #EPICS_DEV_SNAPSHOT=-pre1-DEV #EPICS_DEV_SNAPSHOT=-rc1 #EPICS_DEV_SNAPSHOT=-rc1-DEV -EPICS_DEV_SNAPSHOT= +#EPICS_DEV_SNAPSHOT= # No changes should be needed below here diff --git a/documentation/KnownProblems.html b/documentation/KnownProblems.html index 307d98d5a..ac5ba3af5 100644 --- a/documentation/KnownProblems.html +++ b/documentation/KnownProblems.html @@ -4,17 +4,17 @@ - Known Problems in R3.15.8 + Known Problems in R3.15.9 -

EPICS Base R3.15.8: Known Problems

+

EPICS Base R3.15.9: Known Problems

Any patch files linked below should be applied at the root of the -base-3.15.8 tree. Download them, then use the GNU Patch program as +base-3.15.9 tree. Download them, then use the GNU Patch program as follows:

-
% cd /path/to/base-3.15.8
+
% cd /path/to/base-3.15.9
 % patch -p1 < /path/to/file.patch

The following significant problems have been reported with this diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index fbcf72aaa..0dfb8866c 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -1,4 +1,11 @@ -# EPICS Base Release 3.15.8 +# EPICS Base Release 3.15.9 + +This version of EPICS Base has not been released yet. + +## Changes made on the 3.15 branch since 3.15.8 + + + ## Changes made between 3.15.7 and 3.15.8 diff --git a/documentation/RecordReference.md b/documentation/RecordReference.md index fbd5c1fe3..a13f83dd2 100644 --- a/documentation/RecordReference.md +++ b/documentation/RecordReference.md @@ -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 diff --git a/documentation/ReleaseChecklist.html b/documentation/ReleaseChecklist.html index af0f1dad2..c4bacbfec 100644 --- a/documentation/ReleaseChecklist.html +++ b/documentation/ReleaseChecklist.html @@ -136,17 +136,17 @@ relevent roles unless the Release Manager designates otherwise:

Tag the module in Git, using these tag conventions:
  • - R3.15.8-pre1 + R3.15.9-pre1 — pre-release tag
  • - R3.15.8-rc1 + R3.15.9-rc1 — release candidate tag
cd base-3.15
- git tag -m 'ANJ: Tagged for 3.15.8-rc1' R3.15.8-rc1 + git tag -m 'ANJ: Tagged for 3.15.9-rc1' R3.15.9-rc1
@@ -158,11 +158,11 @@ relevent roles unless the Release Manager designates otherwise:

files and directories that are only used for continuous integration:
cd base-3.15
- git archive --prefix=base-3.15.8-rc1/ --output=base-3.15.8-rc1.tar.gz R3.15.8-rc1 configure documentation LICENSE Makefile README src startup + git archive --prefix=base-3.15.9-rc1/ --output=base-3.15.9-rc1.tar.gz R3.15.9-rc1 configure documentation LICENSE Makefile README src startup
Create a GPG signature file of the tarfile as follows:
- gpg --armor --sign --detach-sig base-3.15.8-rc1.tar.gz + gpg --armor --sign --detach-sig base-3.15.9-rc1.tar.gz
@@ -274,7 +274,7 @@ relevent roles unless the Release Manager designates otherwise:

Tag the module in Git:
cd base-3.15
- git tag -m 'ANJ: Tagged for 3.15.8' R3.15.8 + git tag -m 'ANJ: Tagged for 3.15.9' R3.15.9
@@ -285,11 +285,11 @@ relevent roles unless the Release Manager designates otherwise:

generates a gzipped tarfile directly from the repository:
cd base-3.15
- git archive --prefix=base-3.15.8/ --output=base-3.15.8.tar.gz R3.15.8 configure documentation LICENSE Makefile README src startup + git archive --prefix=base-3.15.9/ --output=base-3.15.9.tar.gz R3.15.9 configure documentation LICENSE Makefile README src startup
Create a GPG signature file of the tarfile as follows:
- gpg --armor --sign --detach-sig base-3.15.8.tar.gz + gpg --armor --sign --detach-sig base-3.15.9.tar.gz