This is Unofficial EPICS BASE Doxygen Site
epicsRingBytes.c
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 * EPICS BASE is distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 
11 /*
12  * Author: Marty Kraimer Date: 15JUL99
13  * Eric Norum
14  * Ralph Lange <Ralph.Lange@gmx.de>
15  */
16 
17 #include <stddef.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <stddef.h>
21 #include <stdio.h>
22 
23 #include "epicsSpin.h"
24 #include "dbDefs.h"
25 #include "epicsRingBytes.h"
26 
27 /*
28  * Need at least one extra byte to be able to distinguish a completely
29  * full buffer from a completely empty one. Allow for a little extra
30  * space to try and keep good alignment and avoid multiple calls to
31  * memcpy for a single put/get operation.
32  */
33 #define SLOP 16
34 
35 typedef struct ringPvt {
37  volatile int nextPut;
38  volatile int nextGet;
39  int size;
41  volatile char buffer[1]; /* actually larger */
42 }ringPvt;
43 
44 LIBCOM_API epicsRingBytesId epicsStdCall epicsRingBytesCreate(int size)
45 {
46  ringPvt *pring = malloc(sizeof(ringPvt) + size + SLOP);
47  if(!pring)
48  return NULL;
49  pring->size = size + SLOP;
50  pring->highWaterMark = 0;
51  pring->nextGet = 0;
52  pring->nextPut = 0;
53  pring->lock = 0;
54  return((void *)pring);
55 }
56 
57 LIBCOM_API epicsRingBytesId epicsStdCall epicsRingBytesLockedCreate(int size)
58 {
59  ringPvt *pring = (ringPvt *)epicsRingBytesCreate(size);
60  if(!pring)
61  return NULL;
62  pring->lock = epicsSpinCreate();
63  return((void *)pring);
64 }
65 
66 LIBCOM_API void epicsStdCall epicsRingBytesDelete(epicsRingBytesId id)
67 {
68  ringPvt *pring = (ringPvt *)id;
69  if (pring->lock) epicsSpinDestroy(pring->lock);
70  free((void *)pring);
71 }
72 
73 LIBCOM_API int epicsStdCall epicsRingBytesGet(
74  epicsRingBytesId id, char *value,int nbytes)
75 {
76  ringPvt *pring = (ringPvt *)id;
77  int nextGet, nextPut, size;
78  int count;
79 
80  if (pring->lock) epicsSpinLock(pring->lock);
81  nextGet = pring->nextGet;
82  nextPut = pring->nextPut;
83  size = pring->size;
84 
85  if (nextGet <= nextPut) {
86  count = nextPut - nextGet;
87  if (count < nbytes)
88  nbytes = count;
89  if (nbytes)
90  memcpy (value, (void *)&pring->buffer[nextGet], nbytes);
91  nextGet += nbytes;
92  }
93  else {
94  count = size - nextGet;
95  if (count > nbytes)
96  count = nbytes;
97  memcpy (value, (void *)&pring->buffer[nextGet], count);
98  nextGet += count;
99  if (nextGet == size) {
100  int nLeft = nbytes - count;
101  if (nLeft > nextPut)
102  nLeft = nextPut;
103  memcpy (value+count, (void *)&pring->buffer[0], nLeft);
104  nextGet = nLeft;
105  nbytes = count + nLeft;
106  }
107  else {
108  nbytes = count;
109  }
110  }
111  pring->nextGet = nextGet;
112 
113  if (pring->lock) epicsSpinUnlock(pring->lock);
114  return nbytes;
115 }
116 
117 LIBCOM_API int epicsStdCall epicsRingBytesPut(
118  epicsRingBytesId id, char *value,int nbytes)
119 {
120  ringPvt *pring = (ringPvt *)id;
121  int nextGet, nextPut, size;
122  int freeCount, copyCount, topCount, used;
123 
124  if (pring->lock) epicsSpinLock(pring->lock);
125  nextGet = pring->nextGet;
126  nextPut = pring->nextPut;
127  size = pring->size;
128 
129  if (nextPut < nextGet) {
130  freeCount = nextGet - nextPut - SLOP;
131  if (nbytes > freeCount) {
132  if (pring->lock) epicsSpinUnlock(pring->lock);
133  return 0;
134  }
135  if (nbytes) {
136  memcpy ((void *)&pring->buffer[nextPut], value, nbytes);
137  }
138  nextPut += nbytes;
139  }
140  else {
141  freeCount = size - nextPut + nextGet - SLOP;
142  if (nbytes > freeCount) {
143  if (pring->lock) epicsSpinUnlock(pring->lock);
144  return 0;
145  }
146  topCount = size - nextPut;
147  copyCount = (nbytes > topCount) ? topCount : nbytes;
148  if (copyCount) {
149  memcpy ((void *)&pring->buffer[nextPut], value, copyCount);
150  }
151  nextPut += copyCount;
152  if (nextPut == size) {
153  int nLeft = nbytes - copyCount;
154  if (nLeft)
155  memcpy ((void *)&pring->buffer[0], value+copyCount, nLeft);
156  nextPut = nLeft;
157  }
158  }
159  pring->nextPut = nextPut;
160 
161  used = nextPut - nextGet;
162  if (used < 0) used += pring->size;
163  if (used > pring->highWaterMark) pring->highWaterMark = used;
164 
165  if (pring->lock) epicsSpinUnlock(pring->lock);
166  return nbytes;
167 }
168 
169 LIBCOM_API void epicsStdCall epicsRingBytesFlush(epicsRingBytesId id)
170 {
171  ringPvt *pring = (ringPvt *)id;
172 
173  if (pring->lock) epicsSpinLock(pring->lock);
174  pring->nextGet = pring->nextPut;
175  if (pring->lock) epicsSpinUnlock(pring->lock);
176 }
177 
178 LIBCOM_API int epicsStdCall epicsRingBytesFreeBytes(epicsRingBytesId id)
179 {
180  ringPvt *pring = (ringPvt *)id;
181  int nextGet, nextPut;
182 
183  if (pring->lock) epicsSpinLock(pring->lock);
184  nextGet = pring->nextGet;
185  nextPut = pring->nextPut;
186  if (pring->lock) epicsSpinUnlock(pring->lock);
187 
188  if (nextPut < nextGet)
189  return nextGet - nextPut - SLOP;
190  else
191  return pring->size - nextPut + nextGet - SLOP;
192 }
193 
194 LIBCOM_API int epicsStdCall epicsRingBytesUsedBytes(epicsRingBytesId id)
195 {
196  ringPvt *pring = (ringPvt *)id;
197  int nextGet, nextPut;
198  int used;
199 
200  if (pring->lock) epicsSpinLock(pring->lock);
201  nextGet = pring->nextGet;
202  nextPut = pring->nextPut;
203  if (pring->lock) epicsSpinUnlock(pring->lock);
204 
205  used = nextPut - nextGet;
206  if (used < 0) used += pring->size;
207 
208  return used;
209 }
210 
211 LIBCOM_API int epicsStdCall epicsRingBytesSize(epicsRingBytesId id)
212 {
213  ringPvt *pring = (ringPvt *)id;
214 
215  return pring->size - SLOP;
216 }
217 
218 LIBCOM_API int epicsStdCall epicsRingBytesIsEmpty(epicsRingBytesId id)
219 {
220  ringPvt *pring = (ringPvt *)id;
221  int isEmpty;
222 
223  if (pring->lock) epicsSpinLock(pring->lock);
224  isEmpty = (pring->nextPut == pring->nextGet);
225  if (pring->lock) epicsSpinUnlock(pring->lock);
226 
227  return isEmpty;
228 }
229 
230 LIBCOM_API int epicsStdCall epicsRingBytesIsFull(epicsRingBytesId id)
231 {
232  return (epicsRingBytesFreeBytes(id) <= 0);
233 }
234 
235 LIBCOM_API int epicsStdCall epicsRingBytesHighWaterMark(epicsRingBytesIdConst id)
236 {
237  ringPvt *pring = (ringPvt *)id;
238  return pring->highWaterMark;
239 }
240 
241 LIBCOM_API void epicsStdCall epicsRingBytesResetHighWaterMark(epicsRingBytesId id)
242 {
243  ringPvt *pring = (ringPvt *)id;
244  int used;
245  if (pring->lock) epicsSpinLock(pring->lock);
246  used = pring->nextGet - pring->nextPut;
247  if (used < 0) used += pring->size;
248  pring->highWaterMark = used;
249  if (pring->lock) epicsSpinUnlock(pring->lock);
250 }
LIBCOM_API void epicsStdCall epicsRingBytesFlush(epicsRingBytesId id)
Make the ring buffer empty.
LIBCOM_API int epicsStdCall epicsRingBytesSize(epicsRingBytesId id)
Return the size of the ring buffer.
Definition: link.h:174
LIBCOM_API int epicsStdCall epicsRingBytesUsedBytes(epicsRingBytesId id)
Return the number of bytes currently stored in the ring buffer.
#define SLOP
void const * epicsRingBytesIdConst
#define NULL
Definition: catime.c:38
Miscellaneous macro definitions.
LIBCOM_API epicsRingBytesId epicsStdCall epicsRingBytesCreate(int size)
Create a new ring buffer.
LIBCOM_API void epicsStdCall epicsRingBytesDelete(epicsRingBytesId id)
Delete the ring buffer and free any associated memory.
LIBCOM_API int epicsStdCall epicsRingBytesHighWaterMark(epicsRingBytesIdConst id)
See how full a ring buffer has been since it was last checked.
LIBCOM_API int epicsStdCall epicsRingBytesFreeBytes(epicsRingBytesId id)
Return the number of free bytes in the ring buffer.
LIBCOM_API epicsRingBytesId epicsStdCall epicsRingBytesLockedCreate(int size)
Create a new ring buffer, secured by a spinlock.
struct ringPvt ringPvt
A circular buffer to store bytes.
LIBCOM_API int epicsStdCall epicsRingBytesIsFull(epicsRingBytesId id)
Test if the ring buffer is currently full.
LIBCOM_API int epicsStdCall epicsRingBytesPut(epicsRingBytesId id, char *value, int nbytes)
Write data into the ring buffer.
LIBCOM_API void epicsStdCall epicsRingBytesResetHighWaterMark(epicsRingBytesId id)
Reset the Highwater mark of the ring buffer.
LIBCOM_API void epicsSpinDestroy(epicsSpinId)
Definition: osdSpin.c:54
LIBCOM_API int epicsStdCall epicsRingBytesGet(epicsRingBytesId id, char *value, int nbytes)
Read data out of the ring buffer.
volatile char buffer[1]
volatile int nextPut
void * epicsRingBytesId
An identifier for a ring buffer.
volatile int nextGet
LIBCOM_API void epicsSpinLock(epicsSpinId)
Definition: osdSpin.c:59
LIBCOM_API epicsSpinId epicsSpinCreate(void)
Definition: osdSpin.c:28
LIBCOM_API void epicsSpinUnlock(epicsSpinId)
Definition: osdSpin.c:81
LIBCOM_API int epicsStdCall epicsRingBytesIsEmpty(epicsRingBytesId id)
Test if the ring buffer is currently empty.
epicsSpinId lock
int highWaterMark