EPICS Base  7.0.5.1
epicsRingPointer.h
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * Copyright (c) 2012 ITER Organization.
7 * SPDX-License-Identifier: EPICS
8 * EPICS BASE is distributed subject to a Software License Agreement found
9 * in file LICENSE that is included with this distribution.
10 \*************************************************************************/
28 #ifndef INCepicsRingPointerh
29 #define INCepicsRingPointerh
30 
31 
32 #include "epicsSpin.h"
33 #include "libComAPI.h"
34 
35 #ifdef __cplusplus
36 
41 template <class T>
43 public: /* Functions */
48  epicsRingPointer(int size, bool locked);
55  bool push(T *p);
59  T* pop();
64  void flush();
68  int getFree() const;
72  int getUsed() const;
76  int getSize() const;
80  bool isEmpty() const;
84  bool isFull() const;
92  int getHighWaterMark() const;
97  void resetHighWaterMark();
98 
99 private: /* Prevent compiler-generated member functions */
100  /* default constructor, copy constructor, assignment operator */
103  epicsRingPointer& operator=(const epicsRingPointer &);
104  int getUsedNoLock() const;
105 
106 private: /* Data */
107  epicsSpinId lock;
108  volatile int nextPush;
109  volatile int nextPop;
110  int size;
111  int highWaterMark;
112  T * volatile * buffer;
113 };
114 
115 extern "C" {
116 #endif /*__cplusplus */
117 
119 typedef void *epicsRingPointerId;
120 typedef void const *epicsRingPointerIdConst;
126 LIBCOM_API epicsRingPointerId epicsStdCall epicsRingPointerCreate(int size);
132 LIBCOM_API epicsRingPointerId epicsStdCall epicsRingPointerLockedCreate(int size);
137 LIBCOM_API void epicsStdCall epicsRingPointerDelete(epicsRingPointerId id);
144 LIBCOM_API int epicsStdCall epicsRingPointerPush(epicsRingPointerId id,void *p);
150 LIBCOM_API void* epicsStdCall epicsRingPointerPop(epicsRingPointerId id) ;
157 LIBCOM_API void epicsStdCall epicsRingPointerFlush(epicsRingPointerId id);
163 LIBCOM_API int epicsStdCall epicsRingPointerGetFree(epicsRingPointerId id);
169 LIBCOM_API int epicsStdCall epicsRingPointerGetUsed(epicsRingPointerId id);
176 LIBCOM_API int epicsStdCall epicsRingPointerGetSize(epicsRingPointerId id);
182 LIBCOM_API int epicsStdCall epicsRingPointerIsEmpty(epicsRingPointerId id);
188 LIBCOM_API int epicsStdCall epicsRingPointerIsFull(epicsRingPointerId id);
198 LIBCOM_API int epicsStdCall epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id);
205 LIBCOM_API void epicsStdCall epicsRingPointerResetHighWaterMark(epicsRingPointerId id);
206 
207 /* This routine was incorrectly named in previous releases */
208 #define epicsRingPointerSize epicsRingPointerGetSize
209 
210 #ifdef __cplusplus
211 }
212 #endif
213 /* END OF DECLARATIONS */
214 
215 /* INLINE FUNCTIONS */
216 
217 #ifdef __cplusplus
218 
219 template <class T>
220 inline epicsRingPointer<T>::epicsRingPointer(int sz, bool locked) :
221  lock(0), nextPush(0), nextPop(0), size(sz+1), highWaterMark(0),
222  buffer(new T* [sz+1])
223 {
224  if (locked)
225  lock = epicsSpinCreate();
226 }
227 
228 template <class T>
230 {
231  if (lock) epicsSpinDestroy(lock);
232  delete [] buffer;
233 }
234 
235 template <class T>
236 inline bool epicsRingPointer<T>::push(T *p)
237 {
238  if (lock) epicsSpinLock(lock);
239  int next = nextPush;
240  int newNext = next + 1;
241  if(newNext>=size) newNext=0;
242  if (newNext == nextPop) {
243  if (lock) epicsSpinUnlock(lock);
244  return(false);
245  }
246  buffer[next] = p;
247  nextPush = newNext;
248  int used = getUsedNoLock();
249  if (used > highWaterMark) highWaterMark = used;
250  if (lock) epicsSpinUnlock(lock);
251  return(true);
252 }
253 
254 template <class T>
256 {
257  if (lock) epicsSpinLock(lock);
258  int next = nextPop;
259  if (next == nextPush) {
260  if (lock) epicsSpinUnlock(lock);
261  return(0);
262  }
263  T*p = buffer[next];
264  ++next;
265  if(next >=size) next = 0;
266  nextPop = next;
267  if (lock) epicsSpinUnlock(lock);
268  return(p);
269 }
270 
271 template <class T>
273 {
274  if (lock) epicsSpinLock(lock);
275  nextPop = 0;
276  nextPush = 0;
277  if (lock) epicsSpinUnlock(lock);
278 }
279 
280 template <class T>
282 {
283  if (lock) epicsSpinLock(lock);
284  int n = nextPop - nextPush - 1;
285  if (n < 0) n += size;
286  if (lock) epicsSpinUnlock(lock);
287  return n;
288 }
289 
290 template <class T>
291 inline int epicsRingPointer<T>::getUsedNoLock() const
292 {
293  int n = nextPush - nextPop;
294  if (n < 0) n += size;
295  return n;
296 }
297 
298 template <class T>
300 {
301  if (lock) epicsSpinLock(lock);
302  int n = getUsedNoLock();
303  if (lock) epicsSpinUnlock(lock);
304  return n;
305 }
306 
307 template <class T>
309 {
310  return(size-1);
311 }
312 
313 template <class T>
314 inline bool epicsRingPointer<T>::isEmpty() const
315 {
316  bool isEmpty;
317  if (lock) epicsSpinLock(lock);
318  isEmpty = (nextPush == nextPop);
319  if (lock) epicsSpinUnlock(lock);
320  return isEmpty;
321 }
322 
323 template <class T>
324 inline bool epicsRingPointer<T>::isFull() const
325 {
326  if (lock) epicsSpinLock(lock);
327  int count = nextPush - nextPop +1;
328  if (lock) epicsSpinUnlock(lock);
329  return((count == 0) || (count == size));
330 }
331 
332 template <class T>
334 {
335  return highWaterMark;
336 }
337 
338 template <class T>
340 {
341  if (lock) epicsSpinLock(lock);
342  highWaterMark = getUsedNoLock();
343  if (lock) epicsSpinUnlock(lock);
344 }
345 
346 #endif /* __cplusplus */
347 
348 #endif /* INCepicsRingPointerh */
T * pop()
Take an element off the ring.
LIBCOM_API int epicsStdCall epicsRingPointerGetFree(epicsRingPointerId id)
Return the amount of empty space in the ring buffer.
LIBCOM_API void epicsStdCall epicsRingPointerFlush(epicsRingPointerId id)
Remove all elements from the ring.
LIBCOM_API epicsRingPointerId epicsStdCall epicsRingPointerLockedCreate(int size)
Create a new ring buffer, secured by a spinlock.
LIBCOM_API void epicsStdCall epicsRingPointerDelete(epicsRingPointerId id)
Delete the ring buffer and free any associated memory.
LIBCOM_API int epicsStdCall epicsRingPointerIsEmpty(epicsRingPointerId id)
Check if the ring buffer is currently empty.
LIBCOM_API int epicsStdCall epicsRingPointerGetUsed(epicsRingPointerId id)
Return the number of elements stored in the ring buffer.
LIBCOM_API int epicsStdCall epicsRingPointerPush(epicsRingPointerId id, void *p)
Push pointer into the ring buffer.
int getHighWaterMark() const
See how full the ring has got since it was last checked.
bool push(T *p)
Push a new entry on the ring.
A C++ template class providing methods for creating and using a ring buffer (a first in...
LIBCOM_API int epicsStdCall epicsRingPointerIsFull(epicsRingPointerId id)
Check if the ring buffer is currently full.
LIBCOM_API void *epicsStdCall epicsRingPointerPop(epicsRingPointerId id)
Take an element off the ring.
bool isFull() const
Test if the ring is currently full.
LIBCOM_API void epicsStdCall epicsRingPointerResetHighWaterMark(epicsRingPointerId id)
Reset the Highwater mark of the ring buffer.
int getFree() const
Get how much free space remains in the ring.
LIBCOM_API int epicsStdCall epicsRingPointerGetHighWaterMark(epicsRingPointerIdConst id)
Get the Highwater mark of the ring buffer.
LIBCOM_API int epicsStdCall epicsRingPointerGetSize(epicsRingPointerId id)
Return the size of the ring.
bool isEmpty() const
Test if the ring is currently empty.
int getUsed() const
Get how many elements are stored on the ring.
~epicsRingPointer()
Destructor.
void resetHighWaterMark()
Reset high water mark.
LIBCOM_API epicsRingPointerId epicsStdCall epicsRingPointerCreate(int size)
Create a new ring buffer.
void * epicsRingPointerId
An identifier for the C API to a ring buffer storing pointers.
void flush()
Remove all elements from the ring.
int getSize() const
Get the size of the ring.