Atlas - SDL_dataqueue.c
Home / ext / SDL2 / src Lines: 1 | Size: 9669 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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. */ 32 Uint8 data[SDL_VARIABLE_LENGTH_ARRAY]; /* packet data */ 33} SDL_DataQueuePacket; 34 35struct SDL_DataQueue 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 45SDL_FreeDataQueueList(SDL_DataQueuePacket *packet) 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 57SDL_DataQueue * 58SDL_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) { 63 SDL_OutOfMemory(); 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 87void 88SDL_FreeDataQueue(SDL_DataQueue *queue) 89{ 90 if (queue) { 91 SDL_FreeDataQueueList(queue->head); 92 SDL_FreeDataQueueList(queue->pool); 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; 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 140static SDL_DataQueuePacket * 141AllocateDataQueuePacket(SDL_DataQueue *queue) 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 294SDL_CountDataQueue(SDL_DataQueue *queue) 295{ 296 return queue ? queue->queued_bytes : 0; 297} 298 299void * 300SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len) 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 340[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.