EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: RTEMS/osdMessageQueue.c
From: Heinz Junkes via Core-talk <core-talk at aps.anl.gov>
To: Michael Davidsaver <mdavidsaver at gmail.com>
Cc: EPICS core-talk <core-talk at aps.anl.gov>
Date: Mon, 25 May 2020 21:31:56 +0200
I just had a quick look at my RTEMS5 implementation of the Message Queue.

I use the Posix-mq there. Maybe one could switch the default mq story to posix in general?

Just an idea. I don't want to complicate things.

Heinz

RTEMS-posix/osdMessageQueue.h

/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
*     National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
*     Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution. 
\*************************************************************************/
/*
 *      Author  W. Eric Norum
 *              norume at aps.anl.gov
 *              630 252 4793
 */

/*
 * Very thin shims around RTEMS routines
 */
#include <rtems.h>
#include <mqueue.h>

struct epicsMessageQueueOSD {
    mqd_t   id;
    char    name[24];
    int     idCnt;

};
#define epicsMessageQueueSend(q,m,l) (mq_send((q)->id, (const char*)(m), (l), 0))
#define epicsMessageQueueReceive(q,m,s) (mq_receive((q)->id, (char*)(m), (s), N

RTEMS-posix/osdMessageQueue.c

/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
*     National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
*     Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution. 
\*************************************************************************/
/*
 *      Author  W. Eric Norum
 *              norume at aps.anl.gov
 *              630 252 4793
 */

/*
 * We want to access information which is
 * normally hidden from application programs.
 */
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1

#define epicsExportSharedSymbols
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rtems.h>
#include <rtems/error.h>
#include "epicsMessageQueue.h"
#include "errlog.h"
#include <epicsAtomic.h>

#include <errno.h>
#include <mqueue.h>
#include <fcntl.h>

epicsShareFunc epicsMessageQueueId epicsShareAPI
epicsMessageQueueCreate(unsigned int capacity, unsigned int maximumMessageSize)
{
    struct mq_attr the_attr;
    epicsMessageQueueId id = (epicsMessageQueueId)calloc(1, sizeof(*id));
    
    epicsAtomicIncrIntT(&id->idCnt);
    sprintf(id->name, "MQ_%01d", epicsAtomicGetIntT(&id->idCnt));
    the_attr.mq_maxmsg = capacity;
    the_attr.mq_msgsize = maximumMessageSize;
    id->id = mq_open(id->name, O_RDWR | O_CREAT | O_EXCL, 0644, &the_attr);
    if (id->id <0) {
        fprintf (stderr, "Can't create message queue: %s\n", strerror (errno));
        return NULL;
    }
    return id;
}

epicsShareFunc void epicsShareAPI epicsMessageQueueDestroy(
    epicsMessageQueueId id)
{
  int rv;
  rv = mq_close(id->id);
  if( rv ) { 
    fprintf(stderr, "epicsMessageQueueDestroy mq_close failed: %s\n",
                         strerror(rv));
  }
  rv = mq_unlink(id->name);
  if( rv ) { 
    fprintf(stderr,"epicsMessageQueueDestroy mq_unlink %s failed: %s\n",
                         id->name, strerror(rv));
  }
  free(id);
}


epicsShareFunc int epicsShareAPI epicsMessageQueueTrySend(
    epicsMessageQueueId id,
    void *message,
    unsigned int messageSize)
{
  struct timespec ts;
  clock_gettime(CLOCK_REALTIME, &ts);
  return mq_timedsend(id->id, (char const *)message, messageSize, 0, &ts);
}

epicsShareFunc int epicsShareAPI epicsMessageQueueSendWithTimeout(
    epicsMessageQueueId id,
    void *message,
    unsigned int messageSize,
    double timeout)
{
  struct timespec ts;
  unsigned long micros;

  // assume timeout in sec
  micros = (unsigned long)(timeout * 1000000.0);
  clock_gettime(CLOCK_REALTIME, &ts);
  ts.tv_sec += micros / 1000000L;
  ts.tv_nsec += (micros % 1000000L) * 1000L;

  return  mq_timedsend (id->id, (const char *)message, messageSize, 0, &ts);
}

epicsShareFunc int epicsShareAPI epicsMessageQueueTryReceive(
    epicsMessageQueueId id,
    void *message,
    unsigned int size)
{
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    return mq_timedreceive(id->id, (char *)message, size, NULL, &ts);
}

epicsShareFunc int epicsShareAPI epicsMessageQueueReceiveWithTimeout(
    epicsMessageQueueId id,
    void *message,
    unsigned int size,
    double timeout)
{
    unsigned long micros;
    struct timespec ts;

    micros = (unsigned long)(timeout * 1000000.0);
    clock_gettime(CLOCK_REALTIME, &ts);
    ts.tv_sec += micros / 1000000L;
    ts.tv_nsec += (micros % 1000000L) * 1000L;

    return mq_timedreceive(id->id, (char *)message, size, NULL, &ts);
}

epicsShareFunc int epicsShareAPI epicsMessageQueuePending(
            epicsMessageQueueId id)
{
  int rv;
  struct mq_attr the_attr;

  rv = mq_getattr(id->id, &the_attr);
  if (rv) {
    fprintf(stderr, "Epics Message queue %x (%s) get attr failed: %s\n",
                         (unsigned int)id->id, id->name, strerror(rv));
        return -1;
    }
    return the_attr.mq_curmsgs;
}
epicsShareFunc void epicsShareAPI epicsMessageQueueShow(
            epicsMessageQueueId id,
                int level)
{
  int rv;
  struct mq_attr the_attr;

  rv = mq_getattr(id->id, &the_attr);
  if (rv) {
    fprintf(stderr, "Epics Message queue %x (%s) get attr failed: %s\n",
                         (unsigned int)id->id, id->name, strerror(rv));
    }

    printf("Message Queue Used:%ld  Max Msg:%lu", the_attr.mq_curmsgs, the_attr.mq_maxmsg);
    if (level >= 1)
       printf("  Maximum size:%lu", the_attr.mq_msgsize);

    printf("\n");
}
------------------------------------------------------------------------------
Fritz-Haber-Institut    | Phone:         (+49 30) 8413-4270
Heinz Junkes             | Fax (G3+G4):   (+49 30) 8413-5900
Faradayweg 4-6        | VC: 102220181216 at bjn.vc
D - 14195 Berlin        | E-Mail:        junkes at fhi-berlin.mpg.de
------------------------------------------------------------------------------

> On 25. May 2020, at 20:37, Michael Davidsaver via Core-talk <core-talk at aps.anl.gov> wrote:
> 
> A couple of things.
> 
> It looks like the switch to ci-scripts for Base added TEST=NO for the RTEMS builds.
> This needs to be removed.
> 
> On 5/25/20 10:49 AM, Johnson, Andrew N. via Core-talk wrote:
>> tl;dr:  I propose that we delete the RTEMS implementation of osdMessageQueue before making the 7.0.3.2 release, it has bugs which the default implementation doesn’t show.
> 
> I don't have a strong objection to this.  Although, I'm not enthused to be
> making this change days before a release, when it will go out the door with
> very little testing.  Whatever is going on, I suspect that it isn't a
> regression (the bugs in the default impl weren't).
> 
> How about marking your new test as a skip until after the release?
> 
> 
>> The long version:
>> 
>> While merging 3.15 into 7.0 last night I ran the tests on RTEMS (qemu) and discovered that the implementation of the epicsMessageQueue fails the additional tests that I wrote for this API. I was expecting the Travis-CI builds to fail but
> 
>> I forgot that they don’t actually run the tests at all.
> 
> I guess there is something to be said for developing on the development branch.
> 
> 
>> In the RTEMS implementation of the epicsMessageQueue Eric added an rtems_message_queue_send_timeout() routine which the rtems_message_queue type doesn’t come with. These were the results I saw for these tests:
>> 
>>> # 6 Single receiver single sender 'Sleepy timeout' tests,
>>> #     these should take about 5.00 seconds each:
>>> # sleepySender: sending every 0.009 seconds
>>> ok 57 - Sent 500 (should be 500)
>>> ok 58 - Received 500 (should be 500)
>>> # sleepySender: sending every 0.010 seconds
>>> ok 59 - Sent 500 (should be 500)
>>> ok 60 - Received 500 (should be 500)
>>> # sleepySender: sending every 0.011 seconds
>>> ok 61 - Sent 500 (should be 500)
>>> ok 62 - Received 500 (should be 500)
>>> # sleepyReceiver: acquiring every 0.009 seconds
>>> not ok 63 - Sent 420 (should be 500)
>>> ok 64 - Received 500 (should be 500)
>>> # sleepyReceiver: acquiring every 0.010 seconds
>>> not ok 65 - Sent 420 (should be 500)
>>> ok 66 - Received 500 (should be 500)
>>> # sleepyReceiver: acquiring every 0.011 seconds
>>> not ok 67 - Sent 420 (should be 500)
>>> ok 68 - Received 500 (should be 500)
>> 
>> So far every time I have run this test the numSent counter has always come back as 420 instead of 500. The fastSender() code looks like this:
>> 
>>> extern"C"void
>>> fastSender(void*arg)
>>> {
>>>     epicsMessageQueue *q = (epicsMessageQueue *)arg;
>>>     numSent= 0;
>>> 
>>>     // Send first without 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);
>>> }
>> 
>> The epicsMessageQueueSendWithTimeout() routine must sometimes be returning an error (non-zero value) even though it has successfully queued the message; I confirmed that by incrementing a local numFailed counter on the else branch, which always counted to 580. This was the output from a normal run on linux, which is about what I would expect:
>> 
>>> # sleepyReceiver: acquiring every 0.009 seconds
>>> ok 63 - Sent 500 (should be 500)
>>> ok 64 - Received 500 (should be 500)
>>> # numFailed = 0
>>> # sleepyReceiver: acquiring every 0.010 seconds
>>> ok 65 - Sent 500 (should be 500)
>>> ok 66 - Received 500 (should be 500)
>>> # numFailed = 204
>>> # sleepyReceiver: acquiring every 0.011 seconds
>>> ok 67 - Sent 500 (should be 500)
>>> ok 68 - Received 500 (should be 500)
>>> # numFailed = 500
>> 
>> Instead of trying to fix the RTEMS code I propose that we delete the RTEMS implementation completely, causing RTEMS to use the default implementation which gives me these test results when run on qemu:
>> 
>>> # 6 Single receiver single sender 'Sleepy timeout' tests,
>>> #     these should take about 5.00 seconds each:
>>> # sleepySender: sending every 0.009 seconds
>>> ok 57 - Sent 500 (should be 500)
>>> ok 58 - Received 500 (should be 500)
>>> # sleepySender: sending every 0.010 seconds
>>> ok 59 - Sent 500 (should be 500)
>>> ok 60 - Received 500 (should be 500)
>>> # sleepySender: sending every 0.011 seconds
>>> ok 61 - Sent 500 (should be 500)
>>> ok 62 - Received 500 (should be 500)
>>> # sleepyReceiver: acquiring every 0.009 seconds
>>> ok 63 - Sent 500 (should be 500)
>>> ok 64 - Received 500 (should be 500)
>>> # numFailed = 80
>>> # sleepyReceiver: acquiring every 0.010 seconds
>>> ok 65 - Sent 500 (should be 500)
>>> ok 66 - Received 500 (should be 500)
>>> # numFailed = 80
>>> # sleepyReceiver: acquiring every 0.011 seconds
>>> ok 67 - Sent 500 (should be 500)
>>> ok 68 - Received 500 (should be 500)
>>> # numFailed = 80
>> 
>> Any objections? Discussion?
>> 
>> - Andrew
>> 
>> -- 
>> Complexity comes for free, simplicity you have to work for.
>> 
> 

Attachment: smime.p7s
Description: S/MIME cryptographic signature


References:
RTEMS/osdMessageQueue.c Johnson, Andrew N. via Core-talk
Re: RTEMS/osdMessageQueue.c Michael Davidsaver via Core-talk

Navigate by Date:
Prev: Re: RTEMS/osdMessageQueue.c Michael Davidsaver via Core-talk
Next: Re: RTEMS/osdMessageQueue.c Michael Davidsaver via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024 
Navigate by Thread:
Prev: Re: RTEMS/osdMessageQueue.c Michael Davidsaver via Core-talk
Next: Re: RTEMS/osdMessageQueue.c Michael Davidsaver via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024 
ANJ, 25 May 2020 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·