From d94e0097a6bab4a39113a5beb5c2cd5ccacfff7d Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 12 May 2020 12:12:40 +0200 Subject: [PATCH] Got ring buffers from EPICS 7.0 for use in callbacks --- src/libCom/ring/epicsRingBytes.c | 125 +++++++++++++++++++++------ src/libCom/ring/epicsRingBytes.h | 20 +++-- src/libCom/ring/epicsRingPointer.cpp | 29 ++++++- src/libCom/ring/epicsRingPointer.h | 95 +++++++++++++++++--- 4 files changed, 225 insertions(+), 44 deletions(-) diff --git a/src/libCom/ring/epicsRingBytes.c b/src/libCom/ring/epicsRingBytes.c index 4ab883fd7..ab048e467 100644 --- a/src/libCom/ring/epicsRingBytes.c +++ b/src/libCom/ring/epicsRingBytes.c @@ -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 + */ #include #include @@ -18,8 +21,8 @@ #include #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); +} diff --git a/src/libCom/ring/epicsRingBytes.h b/src/libCom/ring/epicsRingBytes.h index 9e5220513..3dc0081ad 100644 --- a/src/libCom/ring/epicsRingBytes.h +++ b/src/libCom/ring/epicsRingBytes.h @@ -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 + */ #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 */ diff --git a/src/libCom/ring/epicsRingPointer.cpp b/src/libCom/ring/epicsRingPointer.cpp index 3a5cc8c72..709ab6509 100644 --- a/src/libCom/ring/epicsRingPointer.cpp +++ b/src/libCom/ring/epicsRingPointer.cpp @@ -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 + */ + #include #include @@ -22,7 +27,13 @@ typedef epicsRingPointer voidPointer; epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerCreate(int size) { - voidPointer *pvoidPointer = new voidPointer(size); + voidPointer *pvoidPointer = new voidPointer(size, false); + return(reinterpret_cast(pvoidPointer)); +} + +epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerLockedCreate(int size) +{ + voidPointer *pvoidPointer = new voidPointer(size, true); return(reinterpret_cast(pvoidPointer)); } @@ -79,3 +90,15 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id) voidPointer *pvoidPointer = reinterpret_cast(id); return((pvoidPointer->isFull()) ? 1 : 0); } + +epicsShareFunc int epicsShareAPI epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id) +{ + voidPointer const *pvoidPointer = reinterpret_cast(id); + return(pvoidPointer->getHighWaterMark()); +} + +epicsShareFunc void epicsShareAPI epicsRingPointerResetHighWaterMark(epicsRingPointerId id) +{ + voidPointer *pvoidPointer = reinterpret_cast(id); + pvoidPointer->resetHighWaterMark(); +} diff --git a/src/libCom/ring/epicsRingPointer.h b/src/libCom/ring/epicsRingPointer.h index 3332782a4..68bf8f5a6 100644 --- a/src/libCom/ring/epicsRingPointer.h +++ b/src/libCom/ring/epicsRingPointer.h @@ -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 + */ #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 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 -inline epicsRingPointer::epicsRingPointer(int sz) : - nextPush(0), nextPop(0), size(sz+1), buffer(new T* [sz+1]) {} +inline epicsRingPointer::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 inline epicsRingPointer::~epicsRingPointer() -{ delete [] buffer;} +{ + if (lock) epicsSpinDestroy(lock); + delete [] buffer; +} template inline bool epicsRingPointer::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 inline T* epicsRingPointer::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 inline void epicsRingPointer::flush() { + if (lock) epicsSpinLock(lock); nextPop = 0; nextPush = 0; + if (lock) epicsSpinUnlock(lock); } template inline int epicsRingPointer::getFree() const { + if (lock) epicsSpinLock(lock); int n = nextPop - nextPush - 1; if (n < 0) n += size; + if (lock) epicsSpinUnlock(lock); return n; } template -inline int epicsRingPointer::getUsed() const +inline int epicsRingPointer::getUsedNoLock() const { int n = nextPush - nextPop; if (n < 0) n += size; return n; } +template +inline int epicsRingPointer::getUsed() const +{ + if (lock) epicsSpinLock(lock); + int n = getUsedNoLock(); + if (lock) epicsSpinUnlock(lock); + return n; +} + template inline int epicsRingPointer::getSize() const -{ return(size-1);} +{ + return(size-1); +} template inline bool epicsRingPointer::isEmpty() const -{ return(nextPush==nextPop);} +{ + bool isEmpty; + if (lock) epicsSpinLock(lock); + isEmpty = (nextPush == nextPop); + if (lock) epicsSpinUnlock(lock); + return isEmpty; +} template inline bool epicsRingPointer::isFull() const { + if (lock) epicsSpinLock(lock); int count = nextPush - nextPop +1; + if (lock) epicsSpinUnlock(lock); return((count == 0) || (count == size)); } +template +inline int epicsRingPointer::getHighWaterMark() const +{ + return highWaterMark; +} + +template +inline void epicsRingPointer::resetHighWaterMark() +{ + if (lock) epicsSpinLock(lock); + highWaterMark = getUsedNoLock(); + if (lock) epicsSpinUnlock(lock); +} + #endif /* __cplusplus */ #endif /* INCepicsRingPointerh */