Expose callback queue status

This allows tools like iocStats to monitor the queue status of
the callback queues. This fixes lp:1786540.
This commit is contained in:
Martin Konrad
2018-10-26 18:49:34 -04:00
parent 94ebd0fe48
commit 59ec8d897d
9 changed files with 205 additions and 7 deletions
+27 -2
View File
@@ -21,6 +21,7 @@
#include <stdio.h>
#define epicsExportSharedSymbols
#include "epicsAtomic.h"
#include "epicsSpin.h"
#include "dbDefs.h"
#include "epicsRingBytes.h"
@@ -38,6 +39,7 @@ typedef struct ringPvt {
volatile int nextPut;
volatile int nextGet;
int size;
int highWaterMark;
volatile char buffer[1]; /* actually larger */
}ringPvt;
@@ -47,6 +49,7 @@ epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int size)
if(!pring)
return NULL;
pring->size = size + SLOP;
pring->highWaterMark = 0;
pring->nextGet = 0;
pring->nextPut = 0;
pring->lock = 0;
@@ -131,8 +134,13 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
if (pring->lock) epicsSpinUnlock(pring->lock);
return 0;
}
if (nbytes)
if (nbytes) {
memcpy ((void *)&pring->buffer[nextPut], value, nbytes);
int curUsed = pring->size - SLOP - freeCount;
if (curUsed > epicsAtomicGetIntT(&pring->highWaterMark)) {
epicsAtomicSetIntT(&pring->highWaterMark, curUsed);
}
}
nextPut += nbytes;
}
else {
@@ -143,8 +151,13 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
}
topCount = size - nextPut;
copyCount = (nbytes > topCount) ? topCount : nbytes;
if (copyCount)
if (copyCount) {
memcpy ((void *)&pring->buffer[nextPut], value, copyCount);
int curUsed = pring->size - SLOP - freeCount;
if (curUsed > epicsAtomicGetIntT(&pring->highWaterMark)) {
epicsAtomicSetIntT(&pring->highWaterMark, curUsed);
}
}
nextPut += copyCount;
if (nextPut == size) {
int nLeft = nbytes - copyCount;
@@ -224,3 +237,15 @@ epicsShareFunc int epicsShareAPI epicsRingBytesIsFull(epicsRingBytesId id)
{
return (epicsRingBytesFreeBytes(id) <= 0);
}
epicsShareFunc int epicsShareAPI epicsRingBytesHighWaterMark(epicsRingBytesIdConst id)
{
ringPvt *pring = (ringPvt *)id;
return epicsAtomicGetIntT(&pring->highWaterMark);
}
epicsShareFunc void epicsShareAPI epicsRingBytesResetHighWaterMark(epicsRingBytesId id)
{
ringPvt *pring = (ringPvt *)id;
epicsAtomicSetIntT(&pring->highWaterMark, epicsRingBytesUsedBytes(id));
}
+3
View File
@@ -24,6 +24,7 @@ extern "C" {
#include "shareLib.h"
typedef void *epicsRingBytesId;
typedef void const *epicsRingBytesIdConst;
epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int nbytes);
/* Same, but secured by a spinlock */
@@ -39,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
}
+12
View File
@@ -90,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();
}
+35 -3
View File
@@ -23,6 +23,7 @@
* epicsRingPointerLocked uses a spinlock.
*/
#include "epicsAtomic.h"
#include "epicsSpin.h"
#include "shareLib.h"
@@ -40,18 +41,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;
};
@@ -59,6 +64,7 @@ extern "C" {
#endif /*__cplusplus */
typedef void *epicsRingPointerId;
typedef void const *epicsRingPointerIdConst;
epicsShareFunc epicsRingPointerId epicsShareAPI epicsRingPointerCreate(int size);
/* Same, but secured by a spinlock */
@@ -74,6 +80,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
@@ -95,7 +103,8 @@ epicsShareFunc int epicsShareAPI epicsRingPointerIsFull(epicsRingPointerId id);
template <class T>
inline epicsRingPointer<T>::epicsRingPointer(int sz, bool locked) :
lock(0), nextPush(0), nextPop(0), size(sz+1), buffer(new T* [sz+1])
lock(0), nextPush(0), nextPop(0), size(sz+1), highWaterMark(0),
buffer(new T* [sz+1])
{
if (locked)
lock = epicsSpinCreate();
@@ -121,6 +130,10 @@ inline bool epicsRingPointer<T>::push(T *p)
}
buffer[next] = p;
nextPush = newNext;
int used = getUsedNoLock();
if (used > epicsAtomicGetIntT(&highWaterMark)) {
epicsAtomicSetIntT(&highWaterMark, used);
}
if (lock) epicsSpinUnlock(lock);
return(true);
}
@@ -161,12 +174,19 @@ inline int epicsRingPointer<T>::getFree() const
return n;
}
template <class T>
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 = nextPush - nextPop;
if (n < 0) n += size;
int n = getUsedNoLock();
if (lock) epicsSpinUnlock(lock);
return n;
}
@@ -196,6 +216,18 @@ inline bool epicsRingPointer<T>::isFull() const
return((count == 0) || (count == size));
}
template <class T>
inline int epicsRingPointer<T>::getHighWaterMark() const
{
return epicsAtomicGetIntT(&highWaterMark);
}
template <class T>
inline void epicsRingPointer<T>::resetHighWaterMark()
{
epicsAtomicSetIntT(&highWaterMark, getUsed());
}
#endif /* __cplusplus */
#endif /* INCepicsRingPointerh */