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*)ringbuffer);
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*)ringbuffer,
83 targetSize);
84
85 if (ringbuffer->writePtr == ringbuffer->readPtr)
86 {
87 /* when no size is used we can realloc() and set the heads at the
88 * beginning of the buffer
89 */
90 newData = (BYTE*)realloc(ringbuffer->buffer, targetSize);
91
92 if (!newData)
93 return FALSE;
94
95 ringbuffer->readPtr = ringbuffer->writePtr = 0;
96 ringbuffer->buffer = newData;
97 }
98 else if ((ringbuffer->writePtr >= ringbuffer->readPtr) && (ringbuffer->writePtr < targetSize))
99 {
100 /* we reallocate only if we're in that case, realloc don't touch read
101 * and write heads
102 *
103 * readPtr writePtr
104 * | |
105 * v v
106 * [............|XXXXXXXXXXXXXX|..........]
107 */
108 newData = (BYTE*)realloc(ringbuffer->buffer, targetSize);
109
110 if (!newData)
111 return FALSE;
112
113 ringbuffer->buffer = newData;
114 }
115 else
116 {
117 /* in case of malloc the read head is moved at the beginning of the new buffer
118 * and the write head is set accordingly
119 */
120 newData = (BYTE*)malloc(targetSize);
121
122 if (!newData)
123 return FALSE;
124
125 if (ringbuffer->readPtr < ringbuffer->writePtr)
126 {
127 /* readPtr writePtr
128 * | |
129 * v v
130 * [............|XXXXXXXXXXXXXX|..........]
131 */
132 memcpy(newData, ringbuffer->buffer + ringbuffer->readPtr, ringbuffer_used(ringbuffer));
133 }
134 else
135 {
136 /* writePtr readPtr
137 * | |
138 * v v
139 * [XXXXXXXXXXXX|..............|XXXXXXXXXX]
140 */
141 BYTE* dst = newData;
142 memcpy(dst, ringbuffer->buffer + ringbuffer->readPtr,
143 ringbuffer->size - ringbuffer->readPtr);
144 dst += (ringbuffer->size - ringbuffer->readPtr);
145
146 if (ringbuffer->writePtr)
147 memcpy(dst, ringbuffer->buffer, ringbuffer->writePtr);
148 }
149
150 ringbuffer->writePtr = ringbuffer->size - ringbuffer->freeSize;
151 ringbuffer->readPtr = 0;
152 free(ringbuffer->buffer);
153 ringbuffer->buffer = newData;
154 }
155
156 ringbuffer->freeSize += (targetSize - ringbuffer->size);
157 ringbuffer->size = targetSize;
158 return TRUE;
159}
160
170BOOL ringbuffer_write(RingBuffer* ringbuffer, const BYTE* ptr, size_t sz)
171{
172 size_t toWrite = 0;
173 size_t remaining = 0;
174
175 WINPR_ASSERT(ringbuffer);
176 DEBUG_RINGBUFFER("ringbuffer_write(%p): sz: %" PRIdz "", (void*)ringbuffer, sz);
177
178 if ((ringbuffer->freeSize <= sz) && !ringbuffer_realloc(ringbuffer, ringbuffer->size + sz))
179 return FALSE;
180
181 /* the write could be split in two
182 * readHead writeHead
183 * | |
184 * v v
185 * [ ################ ]
186 */
187 toWrite = sz;
188 remaining = sz;
189
190 if (ringbuffer->size - ringbuffer->writePtr < sz)
191 toWrite = ringbuffer->size - ringbuffer->writePtr;
192
193 if (toWrite)
194 {
195 memcpy(ringbuffer->buffer + ringbuffer->writePtr, ptr, toWrite);
196 remaining -= toWrite;
197 ptr += toWrite;
198 }
199
200 if (remaining)
201 memcpy(ringbuffer->buffer, ptr, remaining);
202
203 ringbuffer->writePtr = (ringbuffer->writePtr + sz) % ringbuffer->size;
204 ringbuffer->freeSize -= sz;
205 return TRUE;
206}
207
208BYTE* ringbuffer_ensure_linear_write(RingBuffer* ringbuffer, size_t sz)
209{
210 DEBUG_RINGBUFFER("ringbuffer_ensure_linear_write(%p): sz: %" PRIdz "", (void*)ringbuffer, sz);
211
212 WINPR_ASSERT(ringbuffer);
213 if (ringbuffer->freeSize < sz)
214 {
215 if (!ringbuffer_realloc(ringbuffer, ringbuffer->size + sz - ringbuffer->freeSize + 32))
216 return nullptr;
217 }
218
219 if (ringbuffer->writePtr == ringbuffer->readPtr)
220 {
221 ringbuffer->writePtr = ringbuffer->readPtr = 0;
222 }
223
224 if (ringbuffer->writePtr + sz < ringbuffer->size)
225 return ringbuffer->buffer + ringbuffer->writePtr;
226
227 /*
228 * to add: .......
229 * [ XXXXXXXXX ]
230 *
231 * result:
232 * [XXXXXXXXX....... ]
233 */
234 memmove(ringbuffer->buffer, ringbuffer->buffer + ringbuffer->readPtr,
235 ringbuffer->writePtr - ringbuffer->readPtr);
236 ringbuffer->readPtr = 0;
237 ringbuffer->writePtr = ringbuffer->size - ringbuffer->freeSize;
238 return ringbuffer->buffer + ringbuffer->writePtr;
239}
240
241BOOL ringbuffer_commit_written_bytes(RingBuffer* ringbuffer, size_t sz)
242{
243 DEBUG_RINGBUFFER("ringbuffer_commit_written_bytes(%p): sz: %" PRIdz "", (void*)ringbuffer, sz);
244
245 WINPR_ASSERT(ringbuffer);
246 if (sz < 1)
247 return TRUE;
248
249 if (ringbuffer->writePtr + sz > ringbuffer->size)
250 return FALSE;
251
252 ringbuffer->writePtr = (ringbuffer->writePtr + sz) % ringbuffer->size;
253 ringbuffer->freeSize -= sz;
254 return TRUE;
255}
256
257int ringbuffer_peek(const RingBuffer* ringbuffer, DataChunk chunks[2], size_t sz)
258{
259 size_t remaining = sz;
260 size_t toRead = 0;
261 int chunkIndex = 0;
262 int status = 0;
263 DEBUG_RINGBUFFER("ringbuffer_peek(%p): sz: %" PRIdz "", (const void*)ringbuffer, sz);
264
265 WINPR_ASSERT(ringbuffer);
266 if (sz < 1)
267 return 0;
268
269 if ((ringbuffer->size - ringbuffer->freeSize) < sz)
270 remaining = ringbuffer->size - ringbuffer->freeSize;
271
272 toRead = remaining;
273
274 if ((ringbuffer->readPtr + remaining) > ringbuffer->size)
275 toRead = ringbuffer->size - ringbuffer->readPtr;
276
277 if (toRead)
278 {
279 chunks[0].data = ringbuffer->buffer + ringbuffer->readPtr;
280 chunks[0].size = toRead;
281 remaining -= toRead;
282 chunkIndex++;
283 status++;
284 }
285
286 if (remaining)
287 {
288 chunks[chunkIndex].data = ringbuffer->buffer;
289 chunks[chunkIndex].size = remaining;
290 status++;
291 }
292
293 return status;
294}
295
296void ringbuffer_commit_read_bytes(RingBuffer* ringbuffer, size_t sz)
297{
298 DEBUG_RINGBUFFER("ringbuffer_commit_read_bytes(%p): sz: %" PRIdz "", (void*)ringbuffer, sz);
299
300 WINPR_ASSERT(ringbuffer);
301 if (sz < 1)
302 return;
303
304 WINPR_ASSERT(ringbuffer->size - ringbuffer->freeSize >= sz);
305 ringbuffer->readPtr = (ringbuffer->readPtr + sz) % ringbuffer->size;
306 ringbuffer->freeSize += sz;
307
308 /* when we reach a reasonable free size, we can go back to the original size */
309 if ((ringbuffer->size != ringbuffer->initialSize) &&
310 (ringbuffer_used(ringbuffer) < ringbuffer->initialSize / 2))
311 ringbuffer_realloc(ringbuffer, ringbuffer->initialSize);
312}
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