SDL 2.0
SDL_dataqueue.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22#include "./SDL_internal.h"
23#include "SDL.h"
24#include "./SDL_dataqueue.h"
25#include "SDL_assert.h"
26
27typedef struct SDL_DataQueuePacket
28{
29 size_t datalen; /* bytes currently in use in this packet. */
30 size_t startpos; /* bytes currently consumed in this packet. */
31 struct SDL_DataQueuePacket *next; /* next item in linked list. */
34
36{
37 SDL_DataQueuePacket *head; /* device fed from here. */
38 SDL_DataQueuePacket *tail; /* queue fills to here. */
39 SDL_DataQueuePacket *pool; /* these are unused packets. */
40 size_t packet_size; /* size of new packets */
41 size_t queued_bytes; /* number of bytes of data in the queue. */
42};
43
44static void
46{
47 while (packet) {
48 SDL_DataQueuePacket *next = packet->next;
49 SDL_free(packet);
50 packet = next;
51 }
52}
53
54
55/* this all expects that you managed thread safety elsewhere. */
56
58SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
59{
61
62 if (!queue) {
64 return NULL;
65 } else {
66 const size_t packetlen = _packetlen ? _packetlen : 1024;
67 const size_t wantpackets = (initialslack + (packetlen - 1)) / packetlen;
68 size_t i;
69
70 SDL_zerop(queue);
71 queue->packet_size = packetlen;
72
73 for (i = 0; i < wantpackets; i++) {
75 if (packet) { /* don't care if this fails, we'll deal later. */
76 packet->datalen = 0;
77 packet->startpos = 0;
78 packet->next = queue->pool;
79 queue->pool = packet;
80 }
81 }
82 }
83
84 return queue;
85}
86
87void
89{
90 if (queue) {
93 SDL_free(queue);
94 }
95}
96
97void
98SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
99{
100 const size_t packet_size = queue ? queue->packet_size : 1;
101 const size_t slackpackets = (slack + (packet_size-1)) / packet_size;
102 SDL_DataQueuePacket *packet;
104 size_t i;
105
106 if (!queue) {
107 return;
108 }
109
110 packet = queue->head;
111
112 /* merge the available pool and the current queue into one list. */
113 if (packet) {
114 queue->tail->next = queue->pool;
115 } else {
116 packet = queue->pool;
117 }
118
119 /* Remove the queued packets from the device. */
120 queue->tail = NULL;
121 queue->head = NULL;
122 queue->queued_bytes = 0;
123 queue->pool = packet;
124
125 /* Optionally keep some slack in the pool to reduce malloc pressure. */
126 for (i = 0; packet && (i < slackpackets); i++) {
127 prev = packet;
128 packet = packet->next;
129 }
130
131 if (prev) {
132 prev->next = NULL;
133 } else {
134 queue->pool = NULL;
135 }
136
137 SDL_FreeDataQueueList(packet); /* free extra packets */
138}
139
140static SDL_DataQueuePacket *
142{
143 SDL_DataQueuePacket *packet;
144
145 SDL_assert(queue != NULL);
146
147 packet = queue->pool;
148 if (packet != NULL) {
149 /* we have one available in the pool. */
150 queue->pool = packet->next;
151 } else {
152 /* Have to allocate a new one! */
153 packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + queue->packet_size);
154 if (packet == NULL) {
155 return NULL;
156 }
157 }
158
159 packet->datalen = 0;
160 packet->startpos = 0;
161 packet->next = NULL;
162
163 SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
164 if (queue->tail == NULL) {
165 queue->head = packet;
166 } else {
167 queue->tail->next = packet;
168 }
169 queue->tail = packet;
170 return packet;
171}
172
173
174int
175SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
176{
177 size_t len = _len;
178 const Uint8 *data = (const Uint8 *) _data;
179 const size_t packet_size = queue ? queue->packet_size : 0;
180 SDL_DataQueuePacket *orighead;
181 SDL_DataQueuePacket *origtail;
182 size_t origlen;
183 size_t datalen;
184
185 if (!queue) {
186 return SDL_InvalidParamError("queue");
187 }
188
189 orighead = queue->head;
190 origtail = queue->tail;
191 origlen = origtail ? origtail->datalen : 0;
192
193 while (len > 0) {
194 SDL_DataQueuePacket *packet = queue->tail;
195 SDL_assert(!packet || (packet->datalen <= packet_size));
196 if (!packet || (packet->datalen >= packet_size)) {
197 /* tail packet missing or completely full; we need a new packet. */
198 packet = AllocateDataQueuePacket(queue);
199 if (!packet) {
200 /* uhoh, reset so we've queued nothing new, free what we can. */
201 if (!origtail) {
202 packet = queue->head; /* whole queue. */
203 } else {
204 packet = origtail->next; /* what we added to existing queue. */
205 origtail->next = NULL;
206 origtail->datalen = origlen;
207 }
208 queue->head = orighead;
209 queue->tail = origtail;
210 queue->pool = NULL;
211
212 SDL_FreeDataQueueList(packet); /* give back what we can. */
213 return SDL_OutOfMemory();
214 }
215 }
216
217 datalen = SDL_min(len, packet_size - packet->datalen);
218 SDL_memcpy(packet->data + packet->datalen, data, datalen);
219 data += datalen;
220 len -= datalen;
221 packet->datalen += datalen;
222 queue->queued_bytes += datalen;
223 }
224
225 return 0;
226}
227
228size_t
229SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
230{
231 size_t len = _len;
232 Uint8 *buf = (Uint8 *) _buf;
233 Uint8 *ptr = buf;
234 SDL_DataQueuePacket *packet;
235
236 if (!queue) {
237 return 0;
238 }
239
240 for (packet = queue->head; len && packet; packet = packet->next) {
241 const size_t avail = packet->datalen - packet->startpos;
242 const size_t cpy = SDL_min(len, avail);
243 SDL_assert(queue->queued_bytes >= avail);
244
245 SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
246 ptr += cpy;
247 len -= cpy;
248 }
249
250 return (size_t) (ptr - buf);
251}
252
253size_t
254SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
255{
256 size_t len = _len;
257 Uint8 *buf = (Uint8 *) _buf;
258 Uint8 *ptr = buf;
259 SDL_DataQueuePacket *packet;
260
261 if (!queue) {
262 return 0;
263 }
264
265 while ((len > 0) && ((packet = queue->head) != NULL)) {
266 const size_t avail = packet->datalen - packet->startpos;
267 const size_t cpy = SDL_min(len, avail);
268 SDL_assert(queue->queued_bytes >= avail);
269
270 SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
271 packet->startpos += cpy;
272 ptr += cpy;
273 queue->queued_bytes -= cpy;
274 len -= cpy;
275
276 if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */
277 queue->head = packet->next;
278 SDL_assert((packet->next != NULL) || (packet == queue->tail));
279 packet->next = queue->pool;
280 queue->pool = packet;
281 }
282 }
283
284 SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
285
286 if (queue->head == NULL) {
287 queue->tail = NULL; /* in case we drained the queue entirely. */
288 }
289
290 return (size_t) (ptr - buf);
291}
292
293size_t
295{
296 return queue ? queue->queued_bytes : 0;
297}
298
299void *
301{
302 SDL_DataQueuePacket *packet;
303
304 if (!queue) {
305 SDL_InvalidParamError("queue");
306 return NULL;
307 } else if (len == 0) {
309 return NULL;
310 } else if (len > queue->packet_size) {
311 SDL_SetError("len is larger than packet size");
312 return NULL;
313 }
314
315 packet = queue->head;
316 if (packet) {
317 const size_t avail = queue->packet_size - packet->datalen;
318 if (len <= avail) { /* we can use the space at end of this packet. */
319 void *retval = packet->data + packet->datalen;
320 packet->datalen += len;
321 queue->queued_bytes += len;
322 return retval;
323 }
324 }
325
326 /* Need a fresh packet. */
327 packet = AllocateDataQueuePacket(queue);
328 if (!packet) {
330 return NULL;
331 }
332
333 packet->datalen = len;
334 queue->queued_bytes += len;
335 return packet->data;
336}
337
338/* vi: set ts=4 sw=4 expandtab: */
339
#define SDL_assert(condition)
Definition: SDL_assert.h:169
size_t SDL_CountDataQueue(SDL_DataQueue *queue)
static SDL_DataQueuePacket * AllocateDataQueuePacket(SDL_DataQueue *queue)
void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
Definition: SDL_dataqueue.c:98
size_t SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
void * SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len)
SDL_DataQueue * SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
Definition: SDL_dataqueue.c:58
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
static void SDL_FreeDataQueueList(SDL_DataQueuePacket *packet)
Definition: SDL_dataqueue.c:45
void SDL_FreeDataQueue(SDL_DataQueue *queue)
Definition: SDL_dataqueue.c:88
#define SDL_SetError
#define SDL_malloc
#define SDL_free
#define SDL_memcpy
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
#define SDL_VARIABLE_LENGTH_ARRAY
Definition: SDL_internal.h:35
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLenum GLsizei len
GLenum GLuint GLenum GLsizei const GLchar * buf
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
uint8_t Uint8
Definition: SDL_stdinc.h:179
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
SDL_DataQueuePacket * pool
Definition: SDL_dataqueue.c:39
size_t queued_bytes
Definition: SDL_dataqueue.c:41
SDL_DataQueuePacket * tail
Definition: SDL_dataqueue.c:38
size_t packet_size
Definition: SDL_dataqueue.c:40
SDL_DataQueuePacket * head
Definition: SDL_dataqueue.c:37
struct SDL_DataQueuePacket * next
Definition: SDL_dataqueue.c:31
Uint8 data[SDL_VARIABLE_LENGTH_ARRAY]
Definition: SDL_dataqueue.c:32
SDL_bool retval