Got ring buffers from EPICS 7.0 for use in callbacks

This commit is contained in:
2020-05-12 12:12:40 +02:00
parent c951229511
commit d94e0097a6
4 changed files with 225 additions and 44 deletions

View File

@@ -3,13 +3,16 @@
* 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.
* Copyright (c) 2012 ITER Organization.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* epicsRingBytes.cd */
/* Author: Eric Norum & Marty Kraimer Date: 15JUL99 */
/*
* Author: Marty Kraimer Date: 15JUL99
* Eric Norum
* Ralph Lange <Ralph.Lange@gmx.de>
*/
#include <stddef.h>
#include <string.h>
@@ -18,8 +21,8 @@
#include <stdio.h>
#define epicsExportSharedSymbols
#include "epicsSpin.h"
#include "dbDefs.h"
#include "cantProceed.h"
#include "epicsRingBytes.h"
/*
@@ -31,26 +34,40 @@
#define SLOP 16
typedef struct ringPvt {
epicsSpinId lock;
volatile int nextPut;
volatile int nextGet;
int size;
volatile char *buffer;
int highWaterMark;
volatile char buffer[1]; /* actually larger */
}ringPvt;
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int size)
{
ringPvt *pring = mallocMustSucceed(sizeof(ringPvt),"epicsRingBytesCreate");
ringPvt *pring = malloc(sizeof(ringPvt) + size + SLOP);
if(!pring)
return NULL;
pring->size = size + SLOP;
pring->buffer = mallocMustSucceed(pring->size,"ringCreate");
pring->highWaterMark = 0;
pring->nextGet = 0;
pring->nextPut = 0;
pring->lock = 0;
return((void *)pring);
}
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesLockedCreate(int size)
{
ringPvt *pring = (ringPvt *)epicsRingBytesCreate(size);
if(!pring)
return NULL;
pring->lock = epicsSpinCreate();
return((void *)pring);
}
epicsShareFunc void epicsShareAPI epicsRingBytesDelete(epicsRingBytesId id)
{
ringPvt *pring = (ringPvt *)id;
free((void *)pring->buffer);
if (pring->lock) epicsSpinDestroy(pring->lock);
free((void *)pring);
}
@@ -58,11 +75,14 @@ epicsShareFunc int epicsShareAPI epicsRingBytesGet(
epicsRingBytesId id, char *value,int nbytes)
{
ringPvt *pring = (ringPvt *)id;
int nextGet = pring->nextGet;
int nextPut = pring->nextPut;
int size = pring->size;
int nextGet, nextPut, size;
int count;
if (pring->lock) epicsSpinLock(pring->lock);
nextGet = pring->nextGet;
nextPut = pring->nextPut;
size = pring->size;
if (nextGet <= nextPut) {
count = nextPut - nextGet;
if (count < nbytes)
@@ -90,6 +110,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesGet(
}
}
pring->nextGet = nextGet;
if (pring->lock) epicsSpinUnlock(pring->lock);
return nbytes;
}
@@ -97,27 +119,36 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
epicsRingBytesId id, char *value,int nbytes)
{
ringPvt *pring = (ringPvt *)id;
int nextGet = pring->nextGet;
int nextPut = pring->nextPut;
int size = pring->size;
int freeCount, copyCount, topCount;
int nextGet, nextPut, size;
int freeCount, copyCount, topCount, used;
if (pring->lock) epicsSpinLock(pring->lock);
nextGet = pring->nextGet;
nextPut = pring->nextPut;
size = pring->size;
if (nextPut < nextGet) {
freeCount = nextGet - nextPut - SLOP;
if (nbytes > freeCount)
if (nbytes > freeCount) {
if (pring->lock) epicsSpinUnlock(pring->lock);
return 0;
if (nbytes)
}
if (nbytes) {
memcpy ((void *)&pring->buffer[nextPut], value, nbytes);
}
nextPut += nbytes;
}
else {
freeCount = size - nextPut + nextGet - SLOP;
if (nbytes > freeCount)
if (nbytes > freeCount) {
if (pring->lock) epicsSpinUnlock(pring->lock);
return 0;
}
topCount = size - nextPut;
copyCount = (nbytes > topCount) ? topCount : nbytes;
if (copyCount)
if (copyCount) {
memcpy ((void *)&pring->buffer[nextPut], value, copyCount);
}
nextPut += copyCount;
if (nextPut == size) {
int nLeft = nbytes - copyCount;
@@ -127,6 +158,12 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
}
}
pring->nextPut = nextPut;
used = nextPut - nextGet;
if (used < 0) used += pring->size;
if (used > pring->highWaterMark) pring->highWaterMark = used;
if (pring->lock) epicsSpinUnlock(pring->lock);
return nbytes;
}
@@ -134,14 +171,20 @@ epicsShareFunc void epicsShareAPI epicsRingBytesFlush(epicsRingBytesId id)
{
ringPvt *pring = (ringPvt *)id;
if (pring->lock) epicsSpinLock(pring->lock);
pring->nextGet = pring->nextPut;
if (pring->lock) epicsSpinUnlock(pring->lock);
}
epicsShareFunc int epicsShareAPI epicsRingBytesFreeBytes(epicsRingBytesId id)
{
ringPvt *pring = (ringPvt *)id;
int nextGet = pring->nextGet;
int nextPut = pring->nextPut;
int nextGet, nextPut;
if (pring->lock) epicsSpinLock(pring->lock);
nextGet = pring->nextGet;
nextPut = pring->nextPut;
if (pring->lock) epicsSpinUnlock(pring->lock);
if (nextPut < nextGet)
return nextGet - nextPut - SLOP;
@@ -152,8 +195,18 @@ epicsShareFunc int epicsShareAPI epicsRingBytesFreeBytes(epicsRingBytesId id)
epicsShareFunc int epicsShareAPI epicsRingBytesUsedBytes(epicsRingBytesId id)
{
ringPvt *pring = (ringPvt *)id;
int nextGet, nextPut;
int used;
return pring->size - epicsRingBytesFreeBytes(id) - SLOP;
if (pring->lock) epicsSpinLock(pring->lock);
nextGet = pring->nextGet;
nextPut = pring->nextPut;
if (pring->lock) epicsSpinUnlock(pring->lock);
used = nextPut - nextGet;
if (used < 0) used += pring->size;
return used;
}
epicsShareFunc int epicsShareAPI epicsRingBytesSize(epicsRingBytesId id)
@@ -166,11 +219,33 @@ epicsShareFunc int epicsShareAPI epicsRingBytesSize(epicsRingBytesId id)
epicsShareFunc int epicsShareAPI epicsRingBytesIsEmpty(epicsRingBytesId id)
{
ringPvt *pring = (ringPvt *)id;
int isEmpty;
return (pring->nextPut == pring->nextGet);
if (pring->lock) epicsSpinLock(pring->lock);
isEmpty = (pring->nextPut == pring->nextGet);
if (pring->lock) epicsSpinUnlock(pring->lock);
return isEmpty;
}
epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id)
{
return (epicsRingBytesFreeBytes(id) <= 0);
}
epicsShareFunc int epicsShareAPI epicsRingBytesHighWaterMark(epicsRingBytesIdConst id)
{
ringPvt *pring = (ringPvt *)id;
return pring->highWaterMark;
}
epicsShareFunc void epicsShareAPI epicsRingBytesResetHighWaterMark(epicsRingBytesId id)
{
ringPvt *pring = (ringPvt *)id;
int used;
if (pring->lock) epicsSpinLock(pring->lock);
used = pring->nextGet - pring->nextPut;
if (used < 0) used += pring->size;
pring->highWaterMark = used;
if (pring->lock) epicsSpinUnlock(pring->lock);
}

View File

@@ -3,13 +3,16 @@
* 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.
* Copyright (c) 2012 ITER Organization.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*epicsRingBytes.h */
/* Author: Eric Norum & Marty Kraimer Date: 15JUL99 */
/*
* Author: Marty Kraimer Date: 15JUL99
* Eric Norum
* Ralph Lange <Ralph.Lange@gmx.de>
*/
#ifndef INCepicsRingBytesh
#define INCepicsRingBytesh
@@ -21,8 +24,11 @@ extern "C" {
#include "shareLib.h"
typedef void *epicsRingBytesId;
typedef void const *epicsRingBytesIdConst;
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int nbytes);
/* Same, but secured by a spinlock */
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesLockedCreate(int nbytes);
epicsShareFunc void epicsShareAPI epicsRingBytesDelete(epicsRingBytesId id);
epicsShareFunc int epicsShareAPI epicsRingBytesGet(
epicsRingBytesId id, char *value,int nbytes);
@@ -34,6 +40,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesUsedBytes(epicsRingBytesId id);
epicsShareFunc int epicsShareAPI epicsRingBytesSize(epicsRingBytesId id);
epicsShareFunc int epicsShareAPI epicsRingBytesIsEmpty(epicsRingBytesId id);
epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id);
epicsShareFunc int epicsShareAPI epicsRingBytesHighWaterMark(epicsRingBytesIdConst id);
epicsShareFunc void epicsShareAPI epicsRingBytesResetHighWaterMark(epicsRingBytesId id);
#ifdef __cplusplus
}
@@ -42,6 +50,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id);
/* NOTES
If there is only one writer it is not necessary to lock for put
If there is a single reader it is not necessary to lock for puts
epicsRingBytesLocked uses a spinlock.
*/
#endif /* INCepicsRingBytesh */

View File

@@ -3,11 +3,16 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* Copyright (c) 2012 ITER Organization.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*epicsRingPointer.cpp*/
/* Author: Marty Kraimer Date: 13OCT2000 */
/*
* Author: Marty Kraimer Date: 13OCT2000
* Ralph Lange <Ralph.Lange@gmx.de>
*/
#include <stddef.h>
#include <string.h>
@@ -22,7 +27,13 @@ typedef epicsRingPointer<void> voidPointer;
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerCreate(int size)
{
voidPointer *pvoidPointer = new voidPointer(size);
voidPointer *pvoidPointer = new voidPointer(size, false);
return(reinterpret_cast<void *>(pvoidPointer));
}
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerLockedCreate(int size)
{
voidPointer *pvoidPointer = new voidPointer(size, true);
return(reinterpret_cast<void *>(pvoidPointer));
}
@@ -79,3 +90,15 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id)
voidPointer *pvoidPointer = reinterpret_cast<voidPointer*>(id);
return((pvoidPointer->isFull()) ? 1 : 0);
}
epicsShareFunc int epicsShareAPI epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id)
{
voidPointer const *pvoidPointer = reinterpret_cast<voidPointer const*>(id);
return(pvoidPointer->getHighWaterMark());
}
epicsShareFunc void epicsShareAPI epicsRingPointerResetHighWaterMark(epicsRingPointerId id)
{
voidPointer *pvoidPointer = reinterpret_cast<voidPointer*>(id);
pvoidPointer->resetHighWaterMark();
}

View File

@@ -3,12 +3,15 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* Copyright (c) 2012 ITER Organization.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*epicsRingPointer.h */
/* Author: Marty Kraimer Date: 15JUL99 */
/*
* Author: Marty Kraimer Date: 15JUL99
* Ralph Lange <Ralph.Lange@gmx.de>
*/
#ifndef INCepicsRingPointerh
#define INCepicsRingPointerh
@@ -16,15 +19,18 @@
/* NOTES
* If there is only one writer it is not necessary to lock push
* If there is a single reader it is not necessary to lock pop
*
* epicsRingPointerLocked uses a spinlock.
*/
#include "epicsSpin.h"
#include "shareLib.h"
#ifdef __cplusplus
template <class T>
class epicsRingPointer {
public: /* Functions */
epicsRingPointer(int size);
epicsRingPointer(int size, bool locked);
~epicsRingPointer();
bool push(T *p);
T* pop();
@@ -34,17 +40,22 @@ public: /* Functions */
int getSize() const;
bool isEmpty() const;
bool isFull() const;
int getHighWaterMark() const;
void resetHighWaterMark();
private: /* Prevent compiler-generated member functions */
/* default constructor, copy constructor, assignment operator */
epicsRingPointer();
epicsRingPointer(const epicsRingPointer &);
epicsRingPointer& operator=(const epicsRingPointer &);
int getUsedNoLock() const;
private: /* Data */
epicsSpinId lock;
volatile int nextPush;
volatile int nextPop;
int size;
int highWaterMark;
T * volatile * buffer;
};
@@ -52,8 +63,11 @@ extern "C" {
#endif /*__cplusplus */
typedef void *epicsRingPointerId;
typedef void const *epicsRingPointerIdConst;
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerCreate(int size);
/* Same, but secured by a spinlock */
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerLockedCreate(int size);
epicsShareFunc void epicsShareAPI epicsRingPointerDelete(epicsRingPointerId id);
/*ringPointerPush returns (0,1) if p (was not, was) put on ring*/
epicsShareFunc int epicsShareAPI epicsRingPointerPush(epicsRingPointerId id,void *p);
@@ -65,6 +79,8 @@ epicsShareFunc int epicsShareAPI epicsRingPointerGetUsed(epicsRingPointerId id)
epicsShareFunc int epicsShareAPI epicsRingPointerGetSize(epicsRingPointerId id);
epicsShareFunc int epicsShareAPI epicsRingPointerIsEmpty(epicsRingPointerId id);
epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id);
epicsShareFunc int epicsShareAPI epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id);
epicsShareFunc void epicsShareAPI epicsRingPointerResetHighWaterMark(epicsRingPointerId id);
/* This routine was incorrectly named in previous releases */
#define epicsRingPointerSize epicsRingPointerGetSize
@@ -85,75 +101,132 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id);
#ifdef __cplusplus
template <class T>
inline epicsRingPointer<T>::epicsRingPointer(int sz) :
nextPush(0), nextPop(0), size(sz+1), buffer(new T* [sz+1]) {}
inline epicsRingPointer<T>::epicsRingPointer(int sz, bool locked) :
lock(0), nextPush(0), nextPop(0), size(sz+1), highWaterMark(0),
buffer(new T* [sz+1])
{
if (locked)
lock = epicsSpinCreate();
}
template <class T>
inline epicsRingPointer<T>::~epicsRingPointer()
{ delete [] buffer;}
{
if (lock) epicsSpinDestroy(lock);
delete [] buffer;
}
template <class T>
inline bool epicsRingPointer<T>::push(T *p)
{
if (lock) epicsSpinLock(lock);
int next = nextPush;
int newNext = next + 1;
if(newNext>=size) newNext=0;
if(newNext==nextPop) return(false);
if (newNext == nextPop) {
if (lock) epicsSpinUnlock(lock);
return(false);
}
buffer[next] = p;
nextPush = newNext;
int used = getUsedNoLock();
if (used > highWaterMark) highWaterMark = used;
if (lock) epicsSpinUnlock(lock);
return(true);
}
template <class T>
inline T* epicsRingPointer<T>::pop()
{
if (lock) epicsSpinLock(lock);
int next = nextPop;
if(next == nextPush) return(0);
if (next == nextPush) {
if (lock) epicsSpinUnlock(lock);
return(0);
}
T*p = buffer[next];
++next;
if(next >=size) next = 0;
nextPop = next;
if (lock) epicsSpinUnlock(lock);
return(p);
}
template <class T>
inline void epicsRingPointer<T>::flush()
{
if (lock) epicsSpinLock(lock);
nextPop = 0;
nextPush = 0;
if (lock) epicsSpinUnlock(lock);
}
template <class T>
inline int epicsRingPointer<T>::getFree() const
{
if (lock) epicsSpinLock(lock);
int n = nextPop - nextPush - 1;
if (n < 0) n += size;
if (lock) epicsSpinUnlock(lock);
return n;
}
template <class T>
inline int epicsRingPointer<T>::getUsed() const
inline int epicsRingPointer<T>::getUsedNoLock() const
{
int n = nextPush - nextPop;
if (n < 0) n += size;
return n;
}
template <class T>
inline int epicsRingPointer<T>::getUsed() const
{
if (lock) epicsSpinLock(lock);
int n = getUsedNoLock();
if (lock) epicsSpinUnlock(lock);
return n;
}
template <class T>
inline int epicsRingPointer<T>::getSize() const
{ return(size-1);}
{
return(size-1);
}
template <class T>
inline bool epicsRingPointer<T>::isEmpty() const
{ return(nextPush==nextPop);}
{
bool isEmpty;
if (lock) epicsSpinLock(lock);
isEmpty = (nextPush == nextPop);
if (lock) epicsSpinUnlock(lock);
return isEmpty;
}
template <class T>
inline bool epicsRingPointer<T>::isFull() const
{
if (lock) epicsSpinLock(lock);
int count = nextPush - nextPop +1;
if (lock) epicsSpinUnlock(lock);
return((count == 0) || (count == size));
}
template <class T>
inline int epicsRingPointer<T>::getHighWaterMark() const
{
return highWaterMark;
}
template <class T>
inline void epicsRingPointer<T>::resetHighWaterMark()
{
if (lock) epicsSpinLock(lock);
highWaterMark = getUsedNoLock();
if (lock) epicsSpinUnlock(lock);
}
#endif /* __cplusplus */
#endif /* INCepicsRingPointerh */