SDL  2.0
SDL_dataqueue.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 #include "./SDL_internal.h"
22 
23 #include "SDL.h"
24 #include "./SDL_dataqueue.h"
25 
26 typedef struct SDL_DataQueuePacket
27 {
28  size_t datalen; /* bytes currently in use in this packet. */
29  size_t startpos; /* bytes currently consumed in this packet. */
30  struct SDL_DataQueuePacket *next; /* next item in linked list. */
31  Uint8 data[SDL_VARIABLE_LENGTH_ARRAY]; /* packet data */
33 
35 {
36  SDL_DataQueuePacket *head; /* device fed from here. */
37  SDL_DataQueuePacket *tail; /* queue fills to here. */
38  SDL_DataQueuePacket *pool; /* these are unused packets. */
39  size_t packet_size; /* size of new packets */
40  size_t queued_bytes; /* number of bytes of data in the queue. */
41 };
42 
43 static void
45 {
46  while (packet) {
47  SDL_DataQueuePacket *next = packet->next;
48  SDL_free(packet);
49  packet = next;
50  }
51 }
52 
53 
54 /* this all expects that you managed thread safety elsewhere. */
55 
57 SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
58 {
59  SDL_DataQueue *queue = (SDL_DataQueue *) SDL_malloc(sizeof (SDL_DataQueue));
60 
61  if (!queue) {
63  return NULL;
64  } else {
65  const size_t packetlen = _packetlen ? _packetlen : 1024;
66  const size_t wantpackets = (initialslack + (packetlen - 1)) / packetlen;
67  size_t i;
68 
69  SDL_zerop(queue);
70  queue->packet_size = packetlen;
71 
72  for (i = 0; i < wantpackets; i++) {
73  SDL_DataQueuePacket *packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + packetlen);
74  if (packet) { /* don't care if this fails, we'll deal later. */
75  packet->datalen = 0;
76  packet->startpos = 0;
77  packet->next = queue->pool;
78  queue->pool = packet;
79  }
80  }
81  }
82 
83  return queue;
84 }
85 
86 void
88 {
89  if (queue) {
92  SDL_free(queue);
93  }
94 }
95 
96 void
97 SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
98 {
99  const size_t packet_size = queue ? queue->packet_size : 1;
100  const size_t slackpackets = (slack + (packet_size-1)) / packet_size;
101  SDL_DataQueuePacket *packet;
102  SDL_DataQueuePacket *prev = NULL;
103  size_t i;
104 
105  if (!queue) {
106  return;
107  }
108 
109  packet = queue->head;
110 
111  /* merge the available pool and the current queue into one list. */
112  if (packet) {
113  queue->tail->next = queue->pool;
114  } else {
115  packet = queue->pool;
116  }
117 
118  /* Remove the queued packets from the device. */
119  queue->tail = NULL;
120  queue->head = NULL;
121  queue->queued_bytes = 0;
122  queue->pool = packet;
123 
124  /* Optionally keep some slack in the pool to reduce malloc pressure. */
125  for (i = 0; packet && (i < slackpackets); i++) {
126  prev = packet;
127  packet = packet->next;
128  }
129 
130  if (prev) {
131  prev->next = NULL;
132  } else {
133  queue->pool = NULL;
134  }
135 
136  SDL_FreeDataQueueList(packet); /* free extra packets */
137 }
138 
139 static SDL_DataQueuePacket *
141 {
142  SDL_DataQueuePacket *packet;
143 
144  SDL_assert(queue != NULL);
145 
146  packet = queue->pool;
147  if (packet != NULL) {
148  /* we have one available in the pool. */
149  queue->pool = packet->next;
150  } else {
151  /* Have to allocate a new one! */
152  packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + queue->packet_size);
153  if (packet == NULL) {
154  return NULL;
155  }
156  }
157 
158  packet->datalen = 0;
159  packet->startpos = 0;
160  packet->next = NULL;
161 
162  SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
163  if (queue->tail == NULL) {
164  queue->head = packet;
165  } else {
166  queue->tail->next = packet;
167  }
168  queue->tail = packet;
169  return packet;
170 }
171 
172 
173 int
174 SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
175 {
176  size_t len = _len;
177  const Uint8 *data = (const Uint8 *) _data;
178  const size_t packet_size = queue ? queue->packet_size : 0;
179  SDL_DataQueuePacket *orighead;
180  SDL_DataQueuePacket *origtail;
181  size_t origlen;
182  size_t datalen;
183 
184  if (!queue) {
185  return SDL_InvalidParamError("queue");
186  }
187 
188  orighead = queue->head;
189  origtail = queue->tail;
190  origlen = origtail ? origtail->datalen : 0;
191 
192  while (len > 0) {
193  SDL_DataQueuePacket *packet = queue->tail;
194  SDL_assert(!packet || (packet->datalen <= packet_size));
195  if (!packet || (packet->datalen >= packet_size)) {
196  /* tail packet missing or completely full; we need a new packet. */
197  packet = AllocateDataQueuePacket(queue);
198  if (!packet) {
199  /* uhoh, reset so we've queued nothing new, free what we can. */
200  if (!origtail) {
201  packet = queue->head; /* whole queue. */
202  } else {
203  packet = origtail->next; /* what we added to existing queue. */
204  origtail->next = NULL;
205  origtail->datalen = origlen;
206  }
207  queue->head = orighead;
208  queue->tail = origtail;
209  queue->pool = NULL;
210 
211  SDL_FreeDataQueueList(packet); /* give back what we can. */
212  return SDL_OutOfMemory();
213  }
214  }
215 
216  datalen = SDL_min(len, packet_size - packet->datalen);
217  SDL_memcpy(packet->data + packet->datalen, data, datalen);
218  data += datalen;
219  len -= datalen;
220  packet->datalen += datalen;
221  queue->queued_bytes += datalen;
222  }
223 
224  return 0;
225 }
226 
227 size_t
228 SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
229 {
230  size_t len = _len;
231  Uint8 *buf = (Uint8 *) _buf;
232  Uint8 *ptr = buf;
233  SDL_DataQueuePacket *packet;
234 
235  if (!queue) {
236  return 0;
237  }
238 
239  for (packet = queue->head; len && packet; packet = packet->next) {
240  const size_t avail = packet->datalen - packet->startpos;
241  const size_t cpy = SDL_min(len, avail);
242  SDL_assert(queue->queued_bytes >= avail);
243 
244  SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
245  ptr += cpy;
246  len -= cpy;
247  }
248 
249  return (size_t) (ptr - buf);
250 }
251 
252 size_t
253 SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
254 {
255  size_t len = _len;
256  Uint8 *buf = (Uint8 *) _buf;
257  Uint8 *ptr = buf;
258  SDL_DataQueuePacket *packet;
259 
260  if (!queue) {
261  return 0;
262  }
263 
264  while ((len > 0) && ((packet = queue->head) != NULL)) {
265  const size_t avail = packet->datalen - packet->startpos;
266  const size_t cpy = SDL_min(len, avail);
267  SDL_assert(queue->queued_bytes >= avail);
268 
269  SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
270  packet->startpos += cpy;
271  ptr += cpy;
272  queue->queued_bytes -= cpy;
273  len -= cpy;
274 
275  if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */
276  queue->head = packet->next;
277  SDL_assert((packet->next != NULL) || (packet == queue->tail));
278  packet->next = queue->pool;
279  queue->pool = packet;
280  }
281  }
282 
283  SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
284 
285  if (queue->head == NULL) {
286  queue->tail = NULL; /* in case we drained the queue entirely. */
287  }
288 
289  return (size_t) (ptr - buf);
290 }
291 
292 size_t
294 {
295  return queue ? queue->queued_bytes : 0;
296 }
297 
298 void *
300 {
301  SDL_DataQueuePacket *packet;
302 
303  if (!queue) {
304  SDL_InvalidParamError("queue");
305  return NULL;
306  } else if (len == 0) {
307  SDL_InvalidParamError("len");
308  return NULL;
309  } else if (len > queue->packet_size) {
310  SDL_SetError("len is larger than packet size");
311  return NULL;
312  }
313 
314  packet = queue->head;
315  if (packet) {
316  const size_t avail = queue->packet_size - packet->datalen;
317  if (len <= avail) { /* we can use the space at end of this packet. */
318  void *retval = packet->data + packet->datalen;
319  packet->datalen += len;
320  queue->queued_bytes += len;
321  return retval;
322  }
323  }
324 
325  /* Need a fresh packet. */
326  packet = AllocateDataQueuePacket(queue);
327  if (!packet) {
328  SDL_OutOfMemory();
329  return NULL;
330  }
331 
332  packet->datalen = len;
333  queue->queued_bytes += len;
334  return packet->data;
335 }
336 
337 /* vi: set ts=4 sw=4 expandtab: */
338 
#define SDL_assert(condition)
Definition: SDL_assert.h:171
SDL_DataQueue * SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
Definition: SDL_dataqueue.c:57
size_t SDL_CountDataQueue(SDL_DataQueue *queue)
void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
Definition: SDL_dataqueue.c:97
static SDL_DataQueuePacket * AllocateDataQueuePacket(SDL_DataQueue *queue)
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)
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
static void SDL_FreeDataQueueList(SDL_DataQueuePacket *packet)
Definition: SDL_dataqueue.c:44
void * SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len)
void SDL_FreeDataQueue(SDL_DataQueue *queue)
Definition: SDL_dataqueue.c:87
#define SDL_SetError
#define SDL_malloc
#define SDL_free
#define SDL_memcpy
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:90
#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
uint8_t Uint8
Definition: SDL_stdinc.h:185
#define SDL_zerop(x)
Definition: SDL_stdinc.h:427
#define SDL_min(x, y)
Definition: SDL_stdinc.h:412
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:163
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF ptr
SDL_DataQueuePacket * pool
Definition: SDL_dataqueue.c:38
size_t queued_bytes
Definition: SDL_dataqueue.c:40
SDL_DataQueuePacket * tail
Definition: SDL_dataqueue.c:37
size_t packet_size
Definition: SDL_dataqueue.c:39
SDL_DataQueuePacket * head
Definition: SDL_dataqueue.c:36
struct SDL_DataQueuePacket * next
Definition: SDL_dataqueue.c:30
Uint8 data[SDL_VARIABLE_LENGTH_ARRAY]
Definition: SDL_dataqueue.c:31
SDL_bool retval