Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
Made the SDL event queue dynamically allocated so we don't ever drop …
Browse files Browse the repository at this point in the history
…events.
  • Loading branch information
slouken committed Jun 11, 2013
1 parent 0f67090 commit 6d0a8a6
Showing 1 changed file with 159 additions and 82 deletions.
241 changes: 159 additions & 82 deletions src/events/SDL_events.c
Expand Up @@ -53,17 +53,30 @@ static SDL_DisabledEventBlock *SDL_disabled_events[256];
static Uint32 SDL_userevents = SDL_USEREVENT;

/* Private data -- event queue */
#define MAXEVENTS 128
typedef struct _SDL_EventEntry
{
SDL_Event event;
SDL_SysWMmsg msg;
struct _SDL_EventEntry *prev;
struct _SDL_EventEntry *next;
} SDL_EventEntry;

typedef struct _SDL_SysWMEntry
{
SDL_SysWMmsg msg;
struct _SDL_SysWMEntry *next;
} SDL_SysWMEntry;

static struct
{
SDL_mutex *lock;
int active;
int head;
int tail;
SDL_Event event[MAXEVENTS];
int wmmsg_next;
struct SDL_SysWMmsg wmmsg[MAXEVENTS];
} SDL_EventQ = { NULL, 1 };
volatile SDL_bool active;
SDL_EventEntry *head;
SDL_EventEntry *tail;
SDL_EventEntry *free;
SDL_SysWMEntry *wmmsg_used;
SDL_SysWMEntry *wmmsg_free;
} SDL_EventQ = { NULL, SDL_TRUE };


static __inline__ SDL_bool
Expand All @@ -85,18 +98,41 @@ void
SDL_StopEventLoop(void)
{
int i;

SDL_EventQ.active = 0;
SDL_EventEntry *entry;
SDL_SysWMEntry *wmmsg;

if (SDL_EventQ.lock) {
SDL_DestroyMutex(SDL_EventQ.lock);
SDL_EventQ.lock = NULL;
SDL_LockMutex(SDL_EventQ.lock);
}

SDL_EventQ.active = SDL_FALSE;

/* Clean out EventQ */
SDL_EventQ.head = 0;
SDL_EventQ.tail = 0;
SDL_EventQ.wmmsg_next = 0;
for (entry = SDL_EventQ.head; entry; ) {
SDL_EventEntry *next = entry->next;
SDL_free(entry);
entry = next;
}
for (entry = SDL_EventQ.free; entry; ) {
SDL_EventEntry *next = entry->next;
SDL_free(entry);
entry = next;
}
for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; ) {
SDL_SysWMEntry *next = wmmsg->next;
SDL_free(wmmsg);
wmmsg = next;
}
for (wmmsg = SDL_EventQ.wmmsg_free; wmmsg; ) {
SDL_SysWMEntry *next = wmmsg->next;
SDL_free(wmmsg);
wmmsg = next;
}
SDL_EventQ.head = NULL;
SDL_EventQ.tail = NULL;
SDL_EventQ.free = NULL;
SDL_EventQ.wmmsg_used = NULL;
SDL_EventQ.wmmsg_free = NULL;

/* Clear disabled event state */
for (i = 0; i < SDL_arraysize(SDL_disabled_events); ++i) {
Expand All @@ -112,6 +148,12 @@ SDL_StopEventLoop(void)
SDL_free(tmp);
}
SDL_EventOK = NULL;

if (SDL_EventQ.lock) {
SDL_UnlockMutex(SDL_EventQ.lock);
SDL_DestroyMutex(SDL_EventQ.lock);
SDL_EventQ.lock = NULL;
}
}

/* This function (and associated calls) may be called more than once */
Expand Down Expand Up @@ -139,7 +181,7 @@ SDL_StartEventLoop(void)
SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);

SDL_EventQ.active = 1;
SDL_EventQ.active = SDL_TRUE;

return (0);
}
Expand All @@ -149,55 +191,61 @@ SDL_StartEventLoop(void)
static int
SDL_AddEvent(SDL_Event * event)
{
int tail, added;
SDL_EventEntry *entry;

tail = (SDL_EventQ.tail + 1) % MAXEVENTS;
if (tail == SDL_EventQ.head) {
/* Overflow, drop event */
added = 0;
} else {
SDL_EventQ.event[SDL_EventQ.tail] = *event;
if (event->type == SDL_SYSWMEVENT) {
/* Note that it's possible to lose an event */
int next = SDL_EventQ.wmmsg_next;
SDL_EventQ.wmmsg[next] = *event->syswm.msg;
SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
&SDL_EventQ.wmmsg[next];
SDL_EventQ.wmmsg_next = (next + 1) % MAXEVENTS;
if (SDL_EventQ.free == NULL) {
entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
if (!entry) {
return 0;
}
SDL_EventQ.tail = tail;
added = 1;
} else {
entry = SDL_EventQ.free;
SDL_EventQ.free = entry->next;
}

entry->event = *event;
if (event->type == SDL_SYSWMEVENT) {
entry->msg = *event->syswm.msg;
}
return (added);

if (SDL_EventQ.tail) {
SDL_EventQ.tail->next = entry;
entry->prev = SDL_EventQ.tail;
SDL_EventQ.tail = entry;
entry->next = NULL;
} else {
SDL_assert(!SDL_EventQ.head);
SDL_EventQ.head = entry;
SDL_EventQ.tail = entry;
entry->prev = NULL;
entry->next = NULL;
}

return 1;
}

/* Cut an event, and return the next valid spot, or the tail */
/* -- called with the queue locked */
static int
SDL_CutEvent(int spot)
/* Remove an event from the queue -- called with the queue locked */
static void
SDL_CutEvent(SDL_EventEntry *entry)
{
if (spot == SDL_EventQ.head) {
SDL_EventQ.head = (SDL_EventQ.head + 1) % MAXEVENTS;
return (SDL_EventQ.head);
} else if ((spot + 1) % MAXEVENTS == SDL_EventQ.tail) {
SDL_EventQ.tail = spot;
return (SDL_EventQ.tail);
} else
/* We cut the middle -- shift everything over */
{
int here, next;
if (entry->prev) {
entry->prev->next = entry->next;
}
if (entry->next) {
entry->next->prev = entry->prev;
}

/* This can probably be optimized with SDL_memcpy() -- careful! */
if (--SDL_EventQ.tail < 0) {
SDL_EventQ.tail = MAXEVENTS - 1;
}
for (here = spot; here != SDL_EventQ.tail; here = next) {
next = (here + 1) % MAXEVENTS;
SDL_EventQ.event[here] = SDL_EventQ.event[next];
}
return (spot);
if (entry == SDL_EventQ.head) {
SDL_assert(entry->prev == NULL);
SDL_EventQ.head = entry->next;
}
if (entry == SDL_EventQ.tail) {
SDL_assert(entry->next == NULL);
SDL_EventQ.tail = entry->prev;
}
/* NOTREACHED */

entry->next = SDL_EventQ.free;
SDL_EventQ.free = entry;
}

/* Lock the event queue, take a peep at it, and unlock it */
Expand All @@ -209,6 +257,10 @@ SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,

/* Don't look after we've quit */
if (!SDL_EventQ.active) {
/* We get a few spurious events at shutdown, so don't warn then */
if (action != SDL_ADDEVENT) {
SDL_SetError("The event system has been shut down");
}
return (-1);
}
/* Lock the event queue */
Expand All @@ -219,27 +271,55 @@ SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
used += SDL_AddEvent(&events[i]);
}
} else {
SDL_EventEntry *entry, *next;
SDL_SysWMEntry *wmmsg, *wmmsg_next;
SDL_Event tmpevent;
int spot;
Uint32 type;

/* If 'events' is NULL, just see if they exist */
if (events == NULL) {
action = SDL_PEEKEVENT;
numevents = 1;
events = &tmpevent;
}
spot = SDL_EventQ.head;
while ((used < numevents) && (spot != SDL_EventQ.tail)) {
Uint32 type = SDL_EventQ.event[spot].type;

/* Clean out any used wmmsg data
FIXME: Do we want to retain the data for some period of time?
*/
for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
wmmsg_next = wmmsg->next;
wmmsg->next = SDL_EventQ.wmmsg_free;
SDL_EventQ.wmmsg_free = wmmsg;
}
SDL_EventQ.wmmsg_used = NULL;

for (entry = SDL_EventQ.head; entry && used < numevents; entry = next) {
next = entry->next;
type = entry->event.type;
if (minType <= type && type <= maxType) {
events[used++] = SDL_EventQ.event[spot];
events[used] = entry->event;
if (entry->event.type == SDL_SYSWMEVENT) {
/* We need to copy the wmmsg somewhere safe.
For now we'll guarantee it's valid at least until
the next call to SDL_PeepEvents()
*/
SDL_SysWMEntry *wmmsg;
if (SDL_EventQ.wmmsg_free) {
wmmsg = SDL_EventQ.wmmsg_free;
SDL_EventQ.wmmsg_free = wmmsg->next;
} else {
wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
}
wmmsg->msg = *entry->event.syswm.msg;
wmmsg->next = SDL_EventQ.wmmsg_used;
SDL_EventQ.wmmsg_used = wmmsg;
events[used].syswm.msg = &wmmsg->msg;
}
++used;

if (action == SDL_GETEVENT) {
spot = SDL_CutEvent(spot);
} else {
spot = (spot + 1) % MAXEVENTS;
SDL_CutEvent(entry);
}
} else {
spot = (spot + 1) % MAXEVENTS;
}
}
}
Expand Down Expand Up @@ -286,13 +366,13 @@ SDL_FlushEvents(Uint32 minType, Uint32 maxType)

/* Lock the event queue */
if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
int spot = SDL_EventQ.head;
while (spot != SDL_EventQ.tail) {
Uint32 type = SDL_EventQ.event[spot].type;
SDL_EventEntry *entry, *next;
Uint32 type;
for (entry = SDL_EventQ.head; entry; entry = next) {
next = entry->next;
type = entry->event.type;
if (minType <= type && type <= maxType) {
spot = SDL_CutEvent(spot);
} else {
spot = (spot + 1) % MAXEVENTS;
SDL_CutEvent(entry);
}
}
SDL_UnlockMutex(SDL_EventQ.lock);
Expand Down Expand Up @@ -448,18 +528,15 @@ void
SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
{
if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
int spot;

spot = SDL_EventQ.head;
while (spot != SDL_EventQ.tail) {
if (filter(userdata, &SDL_EventQ.event[spot])) {
spot = (spot + 1) % MAXEVENTS;
} else {
spot = SDL_CutEvent(spot);
SDL_EventEntry *entry, *next;
for (entry = SDL_EventQ.head; entry; entry = next) {
next = entry->next;
if (!filter(userdata, &entry->event)) {
SDL_CutEvent(entry);
}
}
SDL_UnlockMutex(SDL_EventQ.lock);
}
SDL_UnlockMutex(SDL_EventQ.lock);
}

Uint8
Expand Down

0 comments on commit 6d0a8a6

Please sign in to comment.