EPICS Base  7.0.8.1
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 */
LIBCOM_API void epicsSpinLock(epicsSpinId lockId)
Acquires the spin lock.
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 epicsSpinId epicsSpinCreate(void)
Creates a spin lock.
int getFree() const
Get how much free space remains in the ring.
LIBCOM_API int epicsStdCall epicsRingPointerPush(epicsRingPointerId id, void *p)
Push pointer into the ring buffer.
struct epicsSpin * epicsSpinId
Definition: epicsSpin.h:29
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.
LIBCOM_API void epicsSpinDestroy(epicsSpinId lockId)
Destroys spin lock.
LIBCOM_API void epicsStdCall epicsRingPointerResetHighWaterMark(epicsRingPointerId id)
Reset the Highwater mark of the ring buffer.
OS independent interface for creating spin locks.
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.
LIBCOM_API void epicsSpinUnlock(epicsSpinId lockId)
Releases spin lock.
int getHighWaterMark() const
See how full the ring has got since it was last checked.
~epicsRingPointer()
Destructor.
void resetHighWaterMark()
Reset high water mark.
int getSize() const
Get the size of the ring.
LIBCOM_API epicsRingPointerId epicsStdCall epicsRingPointerCreate(int size)
Create a new ring buffer.
int getUsed() const
Get how many elements are stored on the ring.
bool isFull() const
Test if the ring is currently full.
void * epicsRingPointerId
An identifier for the C API to a ring buffer storing pointers.
bool isEmpty() const
Test if the ring is currently empty.
void flush()
Remove all elements from the ring.