FreeRDP
Loading...
Searching...
No Matches
ringbuffer.c
1
20#include <freerdp/config.h>
21
22#include <freerdp/utils/ringbuffer.h>
23
24#include <stdlib.h>
25#include <string.h>
26#include <winpr/assert.h>
27
28#include <winpr/crt.h>
29#include <freerdp/log.h>
30
31#ifdef WITH_DEBUG_RINGBUFFER
32#define TAG FREERDP_TAG("utils.ringbuffer")
33
34#define DEBUG_RINGBUFFER(...) WLog_DBG(TAG, __VA_ARGS__)
35#else
36#define DEBUG_RINGBUFFER(...) \
37 do \
38 { \
39 } while (0)
40#endif
41
42BOOL ringbuffer_init(RingBuffer* ringbuffer, size_t initialSize)
43{
44 WINPR_ASSERT(ringbuffer);
45 ringbuffer->buffer = malloc(initialSize);
46
47 if (!ringbuffer->buffer)
48 return FALSE;
49
50 ringbuffer->readPtr = ringbuffer->writePtr = 0;
51 ringbuffer->initialSize = ringbuffer->size = ringbuffer->freeSize = initialSize;
52 DEBUG_RINGBUFFER("ringbuffer_init(%p)", (void*)rb);
53 return TRUE;
54}
55
56size_t ringbuffer_used(const RingBuffer* ringbuffer)
57{
58 WINPR_ASSERT(ringbuffer);
59 return ringbuffer->size - ringbuffer->freeSize;
60}
61
62size_t ringbuffer_capacity(const RingBuffer* ringbuffer)
63{
64 WINPR_ASSERT(ringbuffer);
65 return ringbuffer->size;
66}
67
68void ringbuffer_destroy(RingBuffer* ringbuffer)
69{
70 DEBUG_RINGBUFFER("ringbuffer_destroy(%p)", (void*)ringbuffer);
71 if (!ringbuffer)
72 return;
73
74 free(ringbuffer->buffer);
75 ringbuffer->buffer = nullptr;
76}
77
78static BOOL ringbuffer_realloc(RingBuffer* ringbuffer, size_t targetSize)
79{
80 WINPR_ASSERT(ringbuffer);
81 BYTE* newData = nullptr;
82 DEBUG_RINGBUFFER("ringbuffer_realloc(%p): targetSize: %" PRIdz "", (void*)rb, targetSize);
83
84 if (ringbuffer->writePtr == ringbuffer->readPtr)
85 {
86 /* when no size is used we can realloc() and set the heads at the
87 * beginning of the buffer
88 */
89 newData = (BYTE*)realloc(ringbuffer->buffer, targetSize);
90
91 if (!newData)
92 return FALSE;
93
94 ringbuffer->readPtr = ringbuffer->writePtr = 0;
95 ringbuffer->buffer = newData;
96 }
97 else if ((ringbuffer->writePtr >= ringbuffer->readPtr) && (ringbuffer->writePtr < targetSize))
98 {
99 /* we reallocate only if we're in that case, realloc don't touch read
100 * and write heads
101 *
102 * readPtr writePtr
103 * | |
104 * v v
105 * [............|XXXXXXXXXXXXXX|..........]
106 */
107 newData = (BYTE*)realloc(ringbuffer->buffer, targetSize);
108
109 if (!newData)
110 return FALSE;
111
112 ringbuffer->buffer = newData;
113 }
114 else
115 {
116 /* in case of malloc the read head is moved at the beginning of the new buffer
117 * and the write head is set accordingly
118 */
119 newData = (BYTE*)malloc(targetSize);
120
121 if (!newData)
122 return FALSE;
123
124 if (ringbuffer->readPtr < ringbuffer->writePtr)
125 {
126 /* readPtr writePtr
127 * | |
128 * v v
129 * [............|XXXXXXXXXXXXXX|..........]
130 */
131 memcpy(newData, ringbuffer->buffer + ringbuffer->readPtr, ringbuffer_used(ringbuffer));
132 }
133 else
134 {
135 /* writePtr readPtr
136 * | |
137 * v v
138 * [XXXXXXXXXXXX|..............|XXXXXXXXXX]
139 */
140 BYTE* dst = newData;
141 memcpy(dst, ringbuffer->buffer + ringbuffer->readPtr,
142 ringbuffer->size - ringbuffer->readPtr);
143 dst += (ringbuffer->size - ringbuffer->readPtr);
144
145 if (ringbuffer->writePtr)
146 memcpy(dst, ringbuffer->buffer, ringbuffer->writePtr);
147 }
148
149 ringbuffer->writePtr = ringbuffer->size - ringbuffer->freeSize;
150 ringbuffer->readPtr = 0;
151 free(ringbuffer->buffer);
152 ringbuffer->buffer = newData;
153 }
154
155 ringbuffer->freeSize += (targetSize - ringbuffer->size);
156 ringbuffer->size = targetSize;
157 return TRUE;
158}
159
169BOOL ringbuffer_write(RingBuffer* ringbuffer, const BYTE* ptr, size_t sz)
170{
171 size_t toWrite = 0;
172 size_t remaining = 0;
173
174 WINPR_ASSERT(ringbuffer);
175 DEBUG_RINGBUFFER("ringbuffer_write(%p): sz: %" PRIdz "", (void*)rb, sz);
176
177 if ((ringbuffer->freeSize <= sz) && !ringbuffer_realloc(ringbuffer, ringbuffer->size + sz))
178 return FALSE;
179
180 /* the write could be split in two
181 * readHead writeHead
182 * | |
183 * v v
184 * [ ################ ]
185 */
186 toWrite = sz;
187 remaining = sz;
188
189 if (ringbuffer->size - ringbuffer->writePtr < sz)
190 toWrite = ringbuffer->size - ringbuffer->writePtr;
191
192 if (toWrite)
193 {
194 memcpy(ringbuffer->buffer + ringbuffer->writePtr, ptr, toWrite);
195 remaining -= toWrite;
196 ptr += toWrite;
197 }
198
199 if (remaining)
200 memcpy(ringbuffer->buffer, ptr, remaining);
201
202 ringbuffer->writePtr = (ringbuffer->writePtr + sz) % ringbuffer->size;
203 ringbuffer->freeSize -= sz;
204 return TRUE;
205}
206
207BYTE* ringbuffer_ensure_linear_write(RingBuffer* ringbuffer, size_t sz)
208{
209 DEBUG_RINGBUFFER("ringbuffer_ensure_linear_write(%p): sz: %" PRIdz "", (void*)rb, sz);
210
211 WINPR_ASSERT(ringbuffer);
212 if (ringbuffer->freeSize < sz)
213 {
214 if (!ringbuffer_realloc(ringbuffer, ringbuffer->size + sz - ringbuffer->freeSize + 32))
215 return nullptr;
216 }
217
218 if (ringbuffer->writePtr == ringbuffer->readPtr)
219 {
220 ringbuffer->writePtr = ringbuffer->readPtr = 0;
221 }
222
223 if (ringbuffer->writePtr + sz < ringbuffer->size)
224 return ringbuffer->buffer + ringbuffer->writePtr;
225
226 /*
227 * to add: .......
228 * [ XXXXXXXXX ]
229 *
230 * result:
231 * [XXXXXXXXX....... ]
232 */
233 memmove(ringbuffer->buffer, ringbuffer->buffer + ringbuffer->readPtr,
234 ringbuffer->writePtr - ringbuffer->readPtr);
235 ringbuffer->readPtr = 0;
236 ringbuffer->writePtr = ringbuffer->size - ringbuffer->freeSize;
237 return ringbuffer->buffer + ringbuffer->writePtr;
238}
239
240BOOL ringbuffer_commit_written_bytes(RingBuffer* ringbuffer, size_t sz)
241{
242 DEBUG_RINGBUFFER("ringbuffer_commit_written_bytes(%p): sz: %" PRIdz "", (void*)rb, sz);
243
244 WINPR_ASSERT(ringbuffer);
245 if (sz < 1)
246 return TRUE;
247
248 if (ringbuffer->writePtr + sz > ringbuffer->size)
249 return FALSE;
250
251 ringbuffer->writePtr = (ringbuffer->writePtr + sz) % ringbuffer->size;
252 ringbuffer->freeSize -= sz;
253 return TRUE;
254}
255
256int ringbuffer_peek(const RingBuffer* ringbuffer, DataChunk chunks[2], size_t sz)
257{
258 size_t remaining = sz;
259 size_t toRead = 0;
260 int chunkIndex = 0;
261 int status = 0;
262 DEBUG_RINGBUFFER("ringbuffer_peek(%p): sz: %" PRIdz "", (const void*)rb, sz);
263
264 WINPR_ASSERT(ringbuffer);
265 if (sz < 1)
266 return 0;
267
268 if ((ringbuffer->size - ringbuffer->freeSize) < sz)
269 remaining = ringbuffer->size - ringbuffer->freeSize;
270
271 toRead = remaining;
272
273 if ((ringbuffer->readPtr + remaining) > ringbuffer->size)
274 toRead = ringbuffer->size - ringbuffer->readPtr;
275
276 if (toRead)
277 {
278 chunks[0].data = ringbuffer->buffer + ringbuffer->readPtr;
279 chunks[0].size = toRead;
280 remaining -= toRead;
281 chunkIndex++;
282 status++;
283 }
284
285 if (remaining)
286 {
287 chunks[chunkIndex].data = ringbuffer->buffer;
288 chunks[chunkIndex].size = remaining;
289 status++;
290 }
291
292 return status;
293}
294
295void ringbuffer_commit_read_bytes(RingBuffer* ringbuffer, size_t sz)
296{
297 DEBUG_RINGBUFFER("ringbuffer_commit_read_bytes(%p): sz: %" PRIdz "", (void*)ringbuffer, sz);
298
299 WINPR_ASSERT(ringbuffer);
300 if (sz < 1)
301 return;
302
303 WINPR_ASSERT(ringbuffer->size - ringbuffer->freeSize >= sz);
304 ringbuffer->readPtr = (ringbuffer->readPtr + sz) % ringbuffer->size;
305 ringbuffer->freeSize += sz;
306
307 /* when we reach a reasonable free size, we can go back to the original size */
308 if ((ringbuffer->size != ringbuffer->initialSize) &&
309 (ringbuffer_used(ringbuffer) < ringbuffer->initialSize / 2))
310 ringbuffer_realloc(ringbuffer, ringbuffer->initialSize);
311}
a piece of data in the ring buffer, exactly like a glibc iovec
Definition ringbuffer.h:44
ring buffer meta data
Definition ringbuffer.h:33