Made the SDL event queue dynamically allocated so we don't ever drop events.
--- a/src/events/SDL_events.c Sun Jun 09 11:58:31 2013 +0200
+++ b/src/events/SDL_events.c Mon Jun 10 23:24:02 2013 -0700
@@ -53,17 +53,30 @@
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
@@ -85,18 +98,41 @@
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) {
@@ -112,6 +148,12 @@
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 */
@@ -139,7 +181,7 @@
SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
- SDL_EventQ.active = 1;
+ SDL_EventQ.active = SDL_TRUE;
return (0);
}
@@ -149,55 +191,61 @@
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;
+ if (SDL_EventQ.free == NULL) {
+ entry = (SDL_EventEntry *)SDL_malloc(sizeof(*entry));
+ if (!entry) {
+ return 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;
- }
- SDL_EventQ.tail = tail;
- added = 1;
+ 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;
}
- /* NOTREACHED */
+ if (entry == SDL_EventQ.tail) {
+ SDL_assert(entry->next == NULL);
+ SDL_EventQ.tail = entry->prev;
+ }
+
+ entry->next = SDL_EventQ.free;
+ SDL_EventQ.free = entry;
}
/* Lock the event queue, take a peep at it, and unlock it */
@@ -209,6 +257,10 @@
/* 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 */
@@ -219,8 +271,10 @@
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) {
@@ -228,18 +282,44 @@
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;
}
}
}
@@ -286,13 +366,13 @@
/* 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);
@@ -448,18 +528,15 @@
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