Merge Heinz & Andrew's rtems-osd-event branch into 7.0
This commit is contained in:
@@ -16,6 +16,17 @@ should also be read to understand what has changed since earlier releases.
|
||||
|
||||
<!-- Insert new items immediately below here ... -->
|
||||
|
||||
### Fix embedded implementations of `epicsEvent`
|
||||
|
||||
[GH:202](https://github.com/epics-base/epics-base/issues/202) and
|
||||
[GH:206](https://github.com/epics-base/epics-base/pull/206)
|
||||
|
||||
Heinz Junkes provided a new implementation of the `epicsEvent` API suitable for
|
||||
RTEMS Posix targets (RTEMS 5.1 and later). In review a few issues related to
|
||||
overflow of timeout values surfaced in this and other embedded implementations,
|
||||
and these were also been fixed in this Pull Request. The API documentation for
|
||||
this and some other routines has also been updated.
|
||||
|
||||
|
||||
### Breakpoint Table Names
|
||||
|
||||
|
||||
@@ -559,19 +559,19 @@ LIBCA_API chid epicsStdCall ca_evid_to_chid ( evid id );
|
||||
/*
|
||||
* ca_pend_event()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds
|
||||
* timeout R wait for this delay in seconds
|
||||
*/
|
||||
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeOut);
|
||||
LIBCA_API int epicsStdCall ca_pend_event (ca_real timeout);
|
||||
#define ca_poll() ca_pend_event(1e-12)
|
||||
|
||||
/*
|
||||
* ca_pend_io()
|
||||
*
|
||||
* timeOut R wait for this delay in seconds but return early
|
||||
* timeout R wait for this delay in seconds but return early
|
||||
* if all get requests (or search requests with null
|
||||
* connection handler pointer have completed)
|
||||
*/
|
||||
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeOut);
|
||||
LIBCA_API int epicsStdCall ca_pend_io (ca_real timeout);
|
||||
|
||||
/* calls ca_pend_io() if early is true otherwise ca_pend_event() is called */
|
||||
LIBCA_API int epicsStdCall ca_pend (ca_real timeout, int early);
|
||||
|
||||
@@ -70,9 +70,9 @@ void epicsEvent::wait ()
|
||||
}
|
||||
}
|
||||
|
||||
bool epicsEvent::wait (double timeOut)
|
||||
bool epicsEvent::wait (double timeout)
|
||||
{
|
||||
epicsEventStatus status = epicsEventWaitWithTimeout (this->id, timeOut);
|
||||
epicsEventStatus status = epicsEventWaitWithTimeout (this->id, timeout);
|
||||
|
||||
if (status == epicsEventOK) {
|
||||
return true;
|
||||
|
||||
@@ -99,10 +99,12 @@ public:
|
||||
**/
|
||||
void wait ();
|
||||
/**\brief Wait for the event or until the specified timeout.
|
||||
* \param timeOut The timeout delay in seconds.
|
||||
* \param timeout The timeout delay in seconds. A timeout of zero is
|
||||
* equivalent to calling tryWait(); NaN or any value too large to be
|
||||
* represented to the target OS is equivalent to no timeout.
|
||||
* \return True if the event was triggered, False if it timed out.
|
||||
**/
|
||||
bool wait ( double timeOut );
|
||||
bool wait ( double timeout );
|
||||
/**\brief Similar to wait() except that if the event is currently empty the
|
||||
* call will return immediately.
|
||||
* \return True if the event was full (triggered), False if empty.
|
||||
@@ -190,11 +192,13 @@ LIBCOM_API void epicsEventMustWait(epicsEventId id);
|
||||
/**\brief Wait an the event or until the specified timeout period is over.
|
||||
* \note Blocks until full or timeout.
|
||||
* \param id The event identifier.
|
||||
* \param timeOut The timeout delay in seconds.
|
||||
* \param timeout The timeout delay in seconds. A timeout of zero is
|
||||
* equivalent to calling epicsEventTryWait(); NaN or any value too large
|
||||
* to be represented to the target OS is equivalent to no timeout.
|
||||
* \return Status indicator.
|
||||
**/
|
||||
LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout(
|
||||
epicsEventId id, double timeOut);
|
||||
epicsEventId id, double timeout);
|
||||
|
||||
/**\brief Similar to wait() except that if the event is currently empty the
|
||||
* call will return immediately with status \c epicsEventWaitTimeout.
|
||||
|
||||
@@ -84,6 +84,9 @@ public:
|
||||
|
||||
/**
|
||||
* \brief Send a message or timeout.
|
||||
* \param timeout The timeout delay in seconds. A timeout of zero is
|
||||
* equivalent to calling trySend(); NaN or any value too large to be
|
||||
* represented to the target OS is equivalent to no timeout.
|
||||
* \returns 0 if the message was sent to a receiver or queued for
|
||||
* future delivery.
|
||||
* \returns -1 if the timeout was reached before the
|
||||
@@ -124,12 +127,16 @@ public:
|
||||
int receive ( void *message, unsigned int size );
|
||||
|
||||
/**
|
||||
* \brief Wait for a message to be queued.
|
||||
* Wait up to \p timeout seconds for a message to be sent if the queue
|
||||
* is empty, then move the first message to the specified location.
|
||||
* \brief Wait for and fetch the next message.
|
||||
* \param timeout The timeout delay in seconds. A timeout of zero is
|
||||
* equivalent to calling tryReceive(); NaN or any value too large to
|
||||
* be represented to the target OS is equivalent to no timeout.
|
||||
*
|
||||
* If the received message is larger than the specified
|
||||
* messageBufferSize it may either return -1, or truncate the
|
||||
* Waits up to \p timeout seconds for a message to arrive if the queue
|
||||
* is empty, then moves the first message to the specified location.
|
||||
*
|
||||
* If the received message is larger than the specified message size
|
||||
* the implementation may either return -1, or truncate the
|
||||
* message. It is most efficient if the messageBufferSize is equal
|
||||
* to the maximumMessageSize with which the message queue was
|
||||
* created.
|
||||
|
||||
116
modules/libcom/src/osi/os/RTEMS-posix/osdEvent.c
Normal file
116
modules/libcom/src/osi/os/RTEMS-posix/osdEvent.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2021 Fritz Haber Institute, Berlin
|
||||
* SPDX-License-Identifier: EPICS
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* RTEMS osdEvent.c
|
||||
* Author: H. Junkes
|
||||
* junkes@fhi.mpg.de
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <rtems.h>
|
||||
#include <rtems/error.h>
|
||||
|
||||
#include <rtems/thread.h>
|
||||
|
||||
#include "libComAPI.h"
|
||||
#include "epicsEvent.h"
|
||||
|
||||
typedef struct epicsEventOSD {
|
||||
rtems_binary_semaphore rbs;
|
||||
} epicsEventOSD;
|
||||
|
||||
/*
|
||||
* Create a simple binary semaphore
|
||||
*/
|
||||
LIBCOM_API epicsEventId
|
||||
epicsEventCreate(epicsEventInitialState initialState)
|
||||
{
|
||||
epicsEventOSD *pSem = malloc (sizeof(*pSem));
|
||||
|
||||
if (pSem) {
|
||||
rtems_binary_semaphore_init(&pSem->rbs, NULL);
|
||||
if (initialState)
|
||||
rtems_binary_semaphore_post(&pSem->rbs);
|
||||
}
|
||||
return pSem;
|
||||
}
|
||||
|
||||
LIBCOM_API void
|
||||
epicsEventDestroy(epicsEventId pSem)
|
||||
{
|
||||
rtems_binary_semaphore_destroy(&pSem->rbs);
|
||||
}
|
||||
|
||||
LIBCOM_API epicsEventStatus
|
||||
epicsEventTrigger(epicsEventId pSem)
|
||||
{
|
||||
rtems_binary_semaphore_post(&pSem->rbs);
|
||||
return epicsEventOK;
|
||||
}
|
||||
|
||||
LIBCOM_API epicsEventStatus
|
||||
epicsEventWait(epicsEventId pSem)
|
||||
{
|
||||
rtems_binary_semaphore_wait(&pSem->rbs);
|
||||
return epicsEventOK;
|
||||
}
|
||||
|
||||
LIBCOM_API epicsEventStatus
|
||||
epicsEventWaitWithTimeout(epicsEventId pSem, double timeout)
|
||||
{
|
||||
int sc;
|
||||
rtems_interval delay;
|
||||
rtems_interval rate = rtems_clock_get_ticks_per_second();
|
||||
|
||||
if (!rate)
|
||||
return epicsEventError;
|
||||
|
||||
if (timeout <= 0.0) {
|
||||
sc = rtems_binary_semaphore_try_wait(&pSem->rbs);
|
||||
if (!sc)
|
||||
return epicsEventOK;
|
||||
else
|
||||
return epicsEventWaitTimeout;
|
||||
}
|
||||
else if (timeout < (double) UINT32_MAX / rate) {
|
||||
delay = timeout * rate;
|
||||
if (delay == 0) {
|
||||
/* 0 < timeout < 1/rate; round up */
|
||||
delay = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* timeout is NaN or too big to represent; wait forever */
|
||||
delay = RTEMS_NO_TIMEOUT;
|
||||
}
|
||||
|
||||
sc = rtems_binary_semaphore_wait_timed_ticks(&pSem->rbs, delay);
|
||||
if (!sc)
|
||||
return epicsEventOK;
|
||||
else if (sc == ETIMEDOUT)
|
||||
return epicsEventWaitTimeout;
|
||||
else
|
||||
return epicsEventError;
|
||||
}
|
||||
|
||||
LIBCOM_API epicsEventStatus
|
||||
epicsEventTryWait(epicsEventId pSem)
|
||||
{
|
||||
int sc = rtems_binary_semaphore_try_wait(&pSem->rbs);
|
||||
|
||||
if (!sc)
|
||||
return epicsEventOK;
|
||||
else
|
||||
return epicsEventWaitTimeout;
|
||||
}
|
||||
|
||||
LIBCOM_API void
|
||||
epicsEventShow(epicsEventId pSem, unsigned int level)
|
||||
{
|
||||
}
|
||||
8
modules/libcom/src/osi/os/RTEMS-posix/osdEvent.h
Normal file
8
modules/libcom/src/osi/os/RTEMS-posix/osdEvent.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2021 Fritz Haber Institute, Berlin
|
||||
* SPDX-License-Identifier: EPICS
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/* No definitions are needed for this implementation */
|
||||
@@ -20,6 +20,7 @@
|
||||
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <rtems.h>
|
||||
#include <rtems/error.h>
|
||||
|
||||
@@ -122,19 +123,27 @@ epicsEventWait(epicsEventId id)
|
||||
}
|
||||
|
||||
epicsEventStatus
|
||||
epicsEventWaitWithTimeout(epicsEventId id, double timeOut)
|
||||
epicsEventWaitWithTimeout(epicsEventId id, double timeout)
|
||||
{
|
||||
rtems_id sid = (rtems_id)id;
|
||||
rtems_status_code sc;
|
||||
rtems_interval delay;
|
||||
extern double rtemsTicksPerSecond_double;
|
||||
|
||||
if (timeOut <= 0.0)
|
||||
if (timeout <= 0.0)
|
||||
return epicsEventTryWait(id);
|
||||
SEMSTAT(1)
|
||||
delay = timeOut * rtemsTicksPerSecond_double;
|
||||
if (delay == 0)
|
||||
delay++;
|
||||
if (timeout < (double) UINT32_MAX / rtemsTicksPerSecond_double) {
|
||||
delay = timeout * rtemsTicksPerSecond_double;
|
||||
if (delay == 0) {
|
||||
/* 0 < timeout < 1/rtemsTicksPerSecond, round up */
|
||||
delay++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* timeout is NaN or too big to represent in ticks */
|
||||
delay = RTEMS_NO_TIMEOUT;
|
||||
}
|
||||
sc = rtems_semaphore_obtain (sid, RTEMS_WAIT, delay);
|
||||
if (sc == RTEMS_SUCCESSFUL)
|
||||
return epicsEventOK;
|
||||
|
||||
@@ -90,7 +90,7 @@ LIBCOM_API epicsEventStatus epicsEventWait ( epicsEventId pSem )
|
||||
* epicsEventWaitWithTimeout ()
|
||||
*/
|
||||
LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout (
|
||||
epicsEventId pSem, double timeOut )
|
||||
epicsEventId pSem, double timeout )
|
||||
{
|
||||
/* waitable timers use 100 nanosecond intervals, like FILETIME */
|
||||
static const unsigned ivalPerSec = 10000000u; /* number of 100ns intervals per second */
|
||||
@@ -101,17 +101,17 @@ LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout (
|
||||
HANDLE timer;
|
||||
LONGLONG nIvals; /* number of intervals */
|
||||
|
||||
if ( timeOut <= 0.0 ) {
|
||||
if ( timeout <= 0.0 ) {
|
||||
tmo.QuadPart = 0u;
|
||||
}
|
||||
else if ( timeOut >= INFINITE / mSecPerSec ) {
|
||||
else if ( timeout >= INFINITE / mSecPerSec ) {
|
||||
/* we need to apply a maximum wait time to stop an overflow. We choose (INFINITE - 1) milliseconds,
|
||||
to be compatible with previous WaitForSingleObject() implementation */
|
||||
nIvals = (LONGLONG)(INFINITE - 1) * (ivalPerSec / mSecPerSec);
|
||||
tmo.QuadPart = -nIvals; /* negative value means a relative time offset for timer */
|
||||
}
|
||||
else {
|
||||
nIvals = (LONGLONG)(timeOut * ivalPerSec + 0.999999);
|
||||
nIvals = (LONGLONG)(timeout * ivalPerSec + 0.999999);
|
||||
tmo.QuadPart = -nIvals;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,20 +34,25 @@ void epicsEventDestroy(epicsEventId id)
|
||||
semDelete((SEM_ID)id);
|
||||
}
|
||||
|
||||
epicsEventStatus epicsEventWaitWithTimeout(epicsEventId id, double timeOut)
|
||||
epicsEventStatus epicsEventWaitWithTimeout(epicsEventId id, double timeout)
|
||||
{
|
||||
int rate = sysClkRateGet();
|
||||
int status;
|
||||
int ticks;
|
||||
|
||||
if (timeOut <= 0.0) {
|
||||
if (timeout <= 0.0) {
|
||||
ticks = 0;
|
||||
} else if (timeOut >= (double) INT_MAX / rate) {
|
||||
ticks = WAIT_FOREVER;
|
||||
} else {
|
||||
ticks = timeOut * rate;
|
||||
if (ticks <= 0)
|
||||
}
|
||||
else if (timeout < (double) INT_MAX / rate) {
|
||||
ticks = timeout * rate;
|
||||
if (ticks == 0) {
|
||||
/* 0 < timeout < 1/rate; round up */
|
||||
ticks = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* timeout is NaN or too big to represent in ticks */
|
||||
ticks = WAIT_FOREVER;
|
||||
}
|
||||
status = semTake((SEM_ID)id, ticks);
|
||||
if (status == OK)
|
||||
|
||||
@@ -21,18 +21,28 @@ extern "C" int sysClkRateGet(void);
|
||||
LIBCOM_API int epicsStdCall epicsMessageQueueSendWithTimeout(
|
||||
epicsMessageQueueId id,
|
||||
void *message,
|
||||
unsigned int messageSize,
|
||||
unsigned int size,
|
||||
double timeout)
|
||||
{
|
||||
int ticks;
|
||||
int rate = sysClkRateGet();
|
||||
|
||||
if (timeout<=0.0) {
|
||||
if (timeout <= 0.0) {
|
||||
ticks = 0;
|
||||
} else {
|
||||
ticks = (int)(timeout*sysClkRateGet());
|
||||
if(ticks<=0) ticks = 1;
|
||||
}
|
||||
return msgQSend((MSG_Q_ID)id, (char *)message, messageSize, ticks, MSG_PRI_NORMAL);
|
||||
else if (timeout < (double) INT_MAX / rate) {
|
||||
ticks = timeout * rate;
|
||||
if (ticks == 0) {
|
||||
/* 0 < timeout < 1/rate; round up */
|
||||
ticks = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* timeout is NaN or too big to represent in ticks */
|
||||
ticks = WAIT_FOREVER;
|
||||
}
|
||||
|
||||
return msgQSend((MSG_Q_ID)id, (char *)message, size, ticks, MSG_PRI_NORMAL);
|
||||
}
|
||||
|
||||
LIBCOM_API int epicsStdCall epicsMessageQueueReceiveWithTimeout(
|
||||
@@ -42,12 +52,22 @@ LIBCOM_API int epicsStdCall epicsMessageQueueReceiveWithTimeout(
|
||||
double timeout)
|
||||
{
|
||||
int ticks;
|
||||
int rate = sysClkRateGet();
|
||||
|
||||
if (timeout<=0.0) {
|
||||
if (timeout <= 0.0) {
|
||||
ticks = 0;
|
||||
} else {
|
||||
ticks = (int)(timeout*sysClkRateGet());
|
||||
if(ticks<=0) ticks = 1;
|
||||
}
|
||||
else if (timeout < (double) INT_MAX / rate) {
|
||||
ticks = timeout * rate;
|
||||
if (ticks == 0) {
|
||||
/* 0 < timeout < 1/rate, round up */
|
||||
ticks = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* timeout is NaN or too big to represent in ticks */
|
||||
ticks = WAIT_FOREVER;
|
||||
}
|
||||
|
||||
return msgQReceive((MSG_Q_ID)id, (char *)message, size, ticks);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user