src/SDL_dataqueue.c
author Sam Lantinga
Mon, 09 Jan 2017 11:58:01 -0800
changeset 10802 6afc9b833867
parent 10743 8ccdeceaae6d
child 11582 cc0b1273a381
permissions -rw-r--r--
We only need the first few keymaps corresponding to the following constants:
K_NORMTAB, K_SHIFTTAB, K_ALTTAB, K_ALTSHIFTTAB

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