libCom/ring: add thread safe versions of ring buffers (using spinlocks)

This commit is contained in:
Ralph Lange
2013-03-29 17:23:24 +01:00
parent 3718cfa673
commit d6f5b50550
4 changed files with 146 additions and 35 deletions
+68 -17
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,6 +21,7 @@
#include <stdio.h>
#define epicsExportSharedSymbols
#include "epicsSpin.h"
#include "dbDefs.h"
#include "epicsRingBytes.h"
@@ -30,6 +34,7 @@
#define SLOP 16
typedef struct ringPvt {
epicsSpinId lock;
volatile int nextPut;
volatile int nextGet;
int size;
@@ -44,12 +49,23 @@ epicsShareFunc epicsRingBytesId epicsShareAPI epicsRingBytesCreate(int size)
pring->size = size + SLOP;
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;
if (pring->lock) epicsSpinDestroy(pring->lock);
free((void *)pring);
}
@@ -57,11 +73,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)
@@ -89,6 +108,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesGet(
}
}
pring->nextGet = nextGet;
if (pring->lock) epicsSpinUnlock(pring->lock);
return nbytes;
}
@@ -96,23 +117,30 @@ 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 nextGet, nextPut, size;
int freeCount, copyCount, topCount;
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)
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)
@@ -126,6 +154,8 @@ epicsShareFunc int epicsShareAPI epicsRingBytesPut(
}
}
pring->nextPut = nextPut;
if (pring->lock) epicsSpinUnlock(pring->lock);
return nbytes;
}
@@ -133,14 +163,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;
@@ -151,8 +187,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)
@@ -165,8 +211,13 @@ 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)
+12 -5
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
@@ -23,6 +26,8 @@ extern "C" {
typedef void *epicsRingBytesId;
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);
@@ -42,6 +47,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 */
+14 -3
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));
}
+52 -10
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();
@@ -42,6 +48,7 @@ private: /* Prevent compiler-generated member functions */
epicsRingPointer& operator=(const epicsRingPointer &);
private: /* Data */
epicsSpinId lock;
volatile int nextPush;
volatile int nextPop;
int size;
@@ -54,6 +61,8 @@ extern "C" {
typedef void *epicsRingPointerId;
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);
@@ -85,72 +94,105 @@ 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), 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;
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
{
if (lock) epicsSpinLock(lock);
int n = nextPush - nextPop;
if (n < 0) n += size;
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));
}