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* rb, size_t initialSize)
43{
44 WINPR_ASSERT(rb);
45 rb->buffer = malloc(initialSize);
46
47 if (!rb->buffer)
48 return FALSE;
49
50 rb->readPtr = rb->writePtr = 0;
51 rb->initialSize = rb->size = rb->freeSize = initialSize;
52 DEBUG_RINGBUFFER("ringbuffer_init(%p)", (void*)rb);
53 return TRUE;
54}
55
56size_t ringbuffer_used(const RingBuffer* rb)
57{
58 WINPR_ASSERT(rb);
59 return rb->size - rb->freeSize;
60}
61
62size_t ringbuffer_capacity(const RingBuffer* rb)
63{
64 WINPR_ASSERT(rb);
65 return rb->size;
66}
67
68void ringbuffer_destroy(RingBuffer* rb)
69{
70 DEBUG_RINGBUFFER("ringbuffer_destroy(%p)", (void*)rb);
71 if (!rb)
72 return;
73
74 free(rb->buffer);
75 rb->buffer = NULL;
76}
77
78static BOOL ringbuffer_realloc(RingBuffer* rb, size_t targetSize)
79{
80 WINPR_ASSERT(rb);
81 BYTE* newData = NULL;
82 DEBUG_RINGBUFFER("ringbuffer_realloc(%p): targetSize: %" PRIdz "", (void*)rb, targetSize);
83
84 if (rb->writePtr == rb->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(rb->buffer, targetSize);
90
91 if (!newData)
92 return FALSE;
93
94 rb->readPtr = rb->writePtr = 0;
95 rb->buffer = newData;
96 }
97 else if ((rb->writePtr >= rb->readPtr) && (rb->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(rb->buffer, targetSize);
108
109 if (!newData)
110 return FALSE;
111
112 rb->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 (rb->readPtr < rb->writePtr)
125 {
126 /* readPtr writePtr
127 * | |
128 * v v
129 * [............|XXXXXXXXXXXXXX|..........]
130 */
131 memcpy(newData, rb->buffer + rb->readPtr, ringbuffer_used(rb));
132 }
133 else
134 {
135 /* writePtr readPtr
136 * | |
137 * v v
138 * [XXXXXXXXXXXX|..............|XXXXXXXXXX]
139 */
140 BYTE* dst = newData;
141 memcpy(dst, rb->buffer + rb->readPtr, rb->size - rb->readPtr);
142 dst += (rb->size - rb->readPtr);
143
144 if (rb->writePtr)
145 memcpy(dst, rb->buffer, rb->writePtr);
146 }
147
148 rb->writePtr = rb->size - rb->freeSize;
149 rb->readPtr = 0;
150 free(rb->buffer);
151 rb->buffer = newData;
152 }
153
154 rb->freeSize += (targetSize - rb->size);
155 rb->size = targetSize;
156 return TRUE;
157}
158
168BOOL ringbuffer_write(RingBuffer* rb, const BYTE* ptr, size_t sz)
169{
170 size_t toWrite = 0;
171 size_t remaining = 0;
172
173 WINPR_ASSERT(rb);
174 DEBUG_RINGBUFFER("ringbuffer_write(%p): sz: %" PRIdz "", (void*)rb, sz);
175
176 if ((rb->freeSize <= sz) && !ringbuffer_realloc(rb, rb->size + sz))
177 return FALSE;
178
179 /* the write could be split in two
180 * readHead writeHead
181 * | |
182 * v v
183 * [ ################ ]
184 */
185 toWrite = sz;
186 remaining = sz;
187
188 if (rb->size - rb->writePtr < sz)
189 toWrite = rb->size - rb->writePtr;
190
191 if (toWrite)
192 {
193 memcpy(rb->buffer + rb->writePtr, ptr, toWrite);
194 remaining -= toWrite;
195 ptr += toWrite;
196 }
197
198 if (remaining)
199 memcpy(rb->buffer, ptr, remaining);
200
201 rb->writePtr = (rb->writePtr + sz) % rb->size;
202 rb->freeSize -= sz;
203 return TRUE;
204}
205
206BYTE* ringbuffer_ensure_linear_write(RingBuffer* rb, size_t sz)
207{
208 DEBUG_RINGBUFFER("ringbuffer_ensure_linear_write(%p): sz: %" PRIdz "", (void*)rb, sz);
209
210 WINPR_ASSERT(rb);
211 if (rb->freeSize < sz)
212 {
213 if (!ringbuffer_realloc(rb, rb->size + sz - rb->freeSize + 32))
214 return NULL;
215 }
216
217 if (rb->writePtr == rb->readPtr)
218 {
219 rb->writePtr = rb->readPtr = 0;
220 }
221
222 if (rb->writePtr + sz < rb->size)
223 return rb->buffer + rb->writePtr;
224
225 /*
226 * to add: .......
227 * [ XXXXXXXXX ]
228 *
229 * result:
230 * [XXXXXXXXX....... ]
231 */
232 memmove(rb->buffer, rb->buffer + rb->readPtr, rb->writePtr - rb->readPtr);
233 rb->readPtr = 0;
234 rb->writePtr = rb->size - rb->freeSize;
235 return rb->buffer + rb->writePtr;
236}
237
238BOOL ringbuffer_commit_written_bytes(RingBuffer* rb, size_t sz)
239{
240 DEBUG_RINGBUFFER("ringbuffer_commit_written_bytes(%p): sz: %" PRIdz "", (void*)rb, sz);
241
242 WINPR_ASSERT(rb);
243 if (sz < 1)
244 return TRUE;
245
246 if (rb->writePtr + sz > rb->size)
247 return FALSE;
248
249 rb->writePtr = (rb->writePtr + sz) % rb->size;
250 rb->freeSize -= sz;
251 return TRUE;
252}
253
254int ringbuffer_peek(const RingBuffer* rb, DataChunk chunks[2], size_t sz)
255{
256 size_t remaining = sz;
257 size_t toRead = 0;
258 int chunkIndex = 0;
259 int status = 0;
260 DEBUG_RINGBUFFER("ringbuffer_peek(%p): sz: %" PRIdz "", (const void*)rb, sz);
261
262 WINPR_ASSERT(rb);
263 if (sz < 1)
264 return 0;
265
266 if ((rb->size - rb->freeSize) < sz)
267 remaining = rb->size - rb->freeSize;
268
269 toRead = remaining;
270
271 if ((rb->readPtr + remaining) > rb->size)
272 toRead = rb->size - rb->readPtr;
273
274 if (toRead)
275 {
276 chunks[0].data = rb->buffer + rb->readPtr;
277 chunks[0].size = toRead;
278 remaining -= toRead;
279 chunkIndex++;
280 status++;
281 }
282
283 if (remaining)
284 {
285 chunks[chunkIndex].data = rb->buffer;
286 chunks[chunkIndex].size = remaining;
287 status++;
288 }
289
290 return status;
291}
292
293void ringbuffer_commit_read_bytes(RingBuffer* rb, size_t sz)
294{
295 DEBUG_RINGBUFFER("ringbuffer_commit_read_bytes(%p): sz: %" PRIdz "", (void*)rb, sz);
296
297 WINPR_ASSERT(rb);
298 if (sz < 1)
299 return;
300
301 WINPR_ASSERT(rb->size - rb->freeSize >= sz);
302 rb->readPtr = (rb->readPtr + sz) % rb->size;
303 rb->freeSize += sz;
304
305 /* when we reach a reasonable free size, we can go back to the original size */
306 if ((rb->size != rb->initialSize) && (ringbuffer_used(rb) < rb->initialSize / 2))
307 ringbuffer_realloc(rb, rb->initialSize);
308}
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