SDL  2.0
SDL_dataqueue.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 
27 typedef 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. */
32  Uint8 data[SDL_VARIABLE_LENGTH_ARRAY]; /* packet data */
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 
44 static 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 
58 SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
59 {
60  SDL_DataQueue *queue = (SDL_DataQueue *) SDL_malloc(sizeof (SDL_DataQueue));
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++) {
74  SDL_DataQueuePacket *packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + packetlen);
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 
87 void
89 {
90  if (queue) {
93  SDL_free(queue);
94  }
95 }
96 
97 void
98 SDL_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;
103  SDL_DataQueuePacket *prev = NULL;
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 
140 static 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 
174 int
175 SDL_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 
228 size_t
229 SDL_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 
253 size_t
254 SDL_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 
293 size_t
295 {
296  return queue ? queue->queued_bytes : 0;
297 }
298 
299 void *
301 {
302  SDL_DataQueuePacket *packet;
303 
304  if (!queue) {
305  SDL_InvalidParamError("queue");
306  return NULL;
307  } else if (len == 0) {
308  SDL_InvalidParamError("len");
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) {
329  SDL_OutOfMemory();
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 
SDL_DataQueuePacket * head
Definition: SDL_dataqueue.c:37
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
size_t queued_bytes
Definition: SDL_dataqueue.c:41
SDL_DataQueuePacket * pool
Definition: SDL_dataqueue.c:39
SDL_DataQueue * SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
Definition: SDL_dataqueue.c:58
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
static void SDL_FreeDataQueueList(SDL_DataQueuePacket *packet)
Definition: SDL_dataqueue.c:45
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:54
Uint8 data[SDL_VARIABLE_LENGTH_ARRAY]
Definition: SDL_dataqueue.c:32
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
GLenum GLsizei len
SDL_bool retval
struct SDL_DataQueuePacket * next
Definition: SDL_dataqueue.c:31
#define SDL_memcpy
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
size_t SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
void * SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len)
SDL_DataQueuePacket * tail
Definition: SDL_dataqueue.c:38
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
static SDL_DataQueuePacket * AllocateDataQueuePacket(SDL_DataQueue *queue)
GLenum GLuint GLenum GLsizei const GLchar * buf
#define SDL_VARIABLE_LENGTH_ARRAY
Definition: SDL_internal.h:35
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 SDL_assert(condition)
Definition: SDL_assert.h:169
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
Definition: SDL_dataqueue.c:98
size_t SDL_CountDataQueue(SDL_DataQueue *queue)
#define SDL_malloc
void SDL_FreeDataQueue(SDL_DataQueue *queue)
Definition: SDL_dataqueue.c:88
size_t packet_size
Definition: SDL_dataqueue.c:40