Simple implementation of SDL_Events

Hi, I’m programming an embedded system. Porting the entire SDL library to this system is more than intimidating, but there are certain things I’m used to thinking like SDL_Events and I was wondering if someone with more experience than I have, can offer some tips on how to simply implement a kind of SDL_Event queue… It’s the queue itself I’m not sure about… Should I just google ‘queue C’ ?

But the rest I can handle… like I understand that I would be adding to the queue when certain events happen low level (like a button released), and in the main loop I will check the queue to parse to process the events like I would in SDL…

After some thought, I think my bigger issue comes from the fact that a lot of influence on me that malloc() is not good to utilize in bare metal embedded applications, and not using malloc() would cause me to have to limit my queue size to a statically declared size in the code… That bothers me… Bite the bullet and start using malloc() ?? … My issue is not amount of RAM, this system has 32MB RAM… I’ll figure it out…

Is cross compiling not a reasonable option for the platform? What embedded
platform are you targeting?On 25 Mar 2015 06:30, “bazz” wrote:

After some thought, I think my bigger issue comes from the fact that a
lot of influence on me that malloc() is not good to utilize in bare metal
embedded applications, and not using malloc() would cause me to have to
limit my queue size to a statically declared size in the code… That
bothers me… Bite the bullet and start using malloc() ?? … My issue is
not amount of RAM, this system has 32MB RAM… I’ll figure it out…


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

It’s not. The platform is undisclosed

Are you able to disclose the CPU architecture?On 25 Mar 2015 09:02, “bazz” wrote:

It’s not. The platform is undisclosed


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

As I understand it, the SDL event queue is not dynamically sized. You
would be alright with a static buffer as long as it is big enough (see SDL
source).

Jonny DOn Wednesday, March 25, 2015, Alex Barry <alex.barry at gmail.com> wrote:

Are you able to disclose the CPU architecture?
On 25 Mar 2015 09:02, “bazz” <mbazzinotti at gmail.com <javascript:_e(%7B%7D,‘cvml’,‘mbazzinotti at gmail.com’);>> wrote:

It’s not. The platform is undisclosed


SDL mailing list
SDL at lists.libsdl.org
<javascript:_e(%7B%7D,‘cvml’,‘SDL at lists.libsdl.org’);>
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

FWIW, SDL’s event queue used to be statically allocated for the longest
time, but Sam
changed it to a dynamically allocated linked list some time after he joined
Valve
(supposedly they were hitting cases of dropped events).

2015-03-25 11:30 GMT+01:00 bazz :> After some thought, I think my bigger issue comes from the fact that a

lot of influence on me that malloc() is not good to utilize in bare metal
embedded applications, and not using malloc() would cause me to have to
limit my queue size to a statically declared size in the code… That
bothers me… Bite the bullet and start using malloc() ?? … My issue is
not amount of RAM, this system has 32MB RAM… I’ll figure it out…


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

(Even on embedded systems, malloc() isn’t as bad as you think, in my
opinion. Some times you need it! You have to have more discipline than
on a desktop machine, and you have to be smart about what and when you
allocate. Bonus points for letting allocators isolate to a block of
memory that you can remove wholesale when you finish a piece of work, to
prevent fragmentation across the whole address space, but that can add a
lot of complexity. As always, it depends on your needs.)

Here’s what SDL does. You might be surprised.

SDL 2.0 uses a doubly-linked list for the event queue, and keeps a pool
of SDL_Event objects for reuse. That is, every time we need to add an
event to the queue, we look for an event that’s not in use and reuse it,
and if there aren’t any available, we malloc() a new one. When the event
is processed, it isn’t freed, but rather put in the reuse pool for the
next event to come through. Basically once they are malloc()'d, they
just move back and forth between two linked lists (the event queue and
the queue of free events).

In practice, we have a small pile of allocations near the start of the
program, and then never again. We do have an upper bound of 64k
events, to stop a massive spamming of events on an app that isn’t
reading the event queue in a timely manner (or at all). If we have that
many events and another is added, we drop it immediately. This is a
failsafe; I don’t have statistics on this, but I can’t imagine any
reasonable app uses more than a few dozen events at once.

SDL_AddEvent() is pretty illustrative of the details:

https://hg.libsdl.org/SDL/file/0af69dab9bb6/src/events/SDL_events.c#l180

…the whole file is only 650 lines of C code, and somewhat
self-contained, so you could write this from scratch, or probably just
modify it for your project, without much drama.

SDL 1.2 was much simpler: it was a static array of 128 events, and if it
filled up, we dropped any further events until you drained some from the
queue. I never saw this event queue overflow, even on high-end, complex
games. In practice, I bet you could get away with an array of 32 events.
Measure and sprinkle some assert() calls around and see what you can get
away with.

If you ignore the SYSWMEVENT special case, the 1.2 version of
SDL_AddEvent() is 10 lines of C code.

https://hg.libsdl.org/SDL/file/c238763e1228/src/events/SDL_events.c#l264

For a really tiny system like you describe, the 1.2 way is probably more
than sufficient for your needs, dirt-simple to implement, and doesn’t
take much memory and needs no malloc at all. I’d aim for that.

–ryan.On 3/25/15 6:30 AM, bazz wrote:

After some thought, I think my bigger issue comes from the fact that a
lot of influence on me that malloc() is not good to utilize in bare
metal embedded applications, and not using malloc() would cause me to
have to limit my queue size to a statically declared size in the code…
That bothers me… Bite the bullet and start using malloc() ?? … My
issue is not amount of RAM, this system has 32MB RAM… I’ll figure it out…

I don’t have statistics on this,

Now I do!

The latest in revision control will track the maximum events in-flight
at a time (so if you have 5 events in the queue, drain it, and later
have 7 events before you drain, and later 3, at the end of the program,
this number is seven).

To use it, export an enviroment variable:

SDL_EVENT_QUEUE_STATISTICS=1 ./testsprite2

And when you call SDL_Quit(), you’ll get a line that looks something
like this to stdout:

2015-03-25 10:18:11.413 testsprite2[77754:507] INFO: SDL EVENT QUEUE:
Maximum events in-flight: 4

4 was about as high as I could get testsprite2 to go; I’m sure other
things go higher, especially if you’re pounding on the keyboard of a
game that’s blocking to load game data.

Feel free to try it and see what sort of queue usage your app uses.

–ryan.

Let’s focus on implementing a queue in C. Is it as easy as lemon pie?
I was just going to find a “linked-list” queue implementation and cap the size at run-time.

I wanted to ask, does anyone have recommendations on handling a “queue full” situation?

Well, Ryan has the definitive suggestion for when the queue is full. You
might as well mimic SDL’s behavior in this case and just drop new events.

Implementing a simple linked list queue is much easier than lemon pie. :wink:

Jonny DOn Wed, Mar 25, 2015 at 10:50 AM, bazz wrote:

Let’s focus on implementing a queue in C. Is it as easy as lemon pie?
I was just going to find a “linked-list” queue implementation and cap the
size at run-time.

I wanted to ask, does anyone have recommendations on handling a “queue
full” situation?


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

I deleted my last post given I just read Ryan C. Gordon’s excellent first post answer. It’s golden. Thank you.

The bonus points for malloc() avoidance of defragmentation sounds awesome but I have enough on my plate already. See you in at least 4 months to discuss that. heheh.

I had some desires to learn whether SDL2 would ever free from its pool of malloc’d events over time if the volume of active events was reduced substantially. But if you’re not interested in answering, don’t bother, I really do have enough on my plate. hehe

Thanks for the answer and the confidence and all the good vibes

Man… I just spent the past couple hours just getting assert() to work!! I had to learn how to override the _write() syscall in newlib. It’s probably time to confess I am coding for an ARM processor. hehe that’s all I’ll say.
but oddly enough, I could only get assert() to work if it was set to stdout, rather than stderr… If I use stderr, the format string doesn’t get interpreted… so think of it as printing a raw format string… for instance :
while this works:

Code:
printf(“hi %d”, 5); -> hi 5

this won’t

Code:
fprintf(stderr, “hi %d”, 5); -> hi

I did some backtracing in GDB and I noticed that the call in regular printf (or an fprintf call with stdout ) reaches the final _write() call with the string formatted “hi 5” as expected, while stderr version shows the string coming into _write as “hi %d” – I couldn’t tell for the life of me why this is happening… My newlib implementation is otherwise pretty stock… Meaning I’m not getting the bang for my buck out of it… I’m doing a lot of things the hard way… but temporarily as far as assert() goes, I set it to use stdout… but I would really like to know if anyone has a clue what’s going on here so that stderr does not remain broken…

I’m not including my _write() routine since it was proven to NOT be the problem.

Thanks!

newlib 2.1.0

I realize I am asking newlib question on SDL forum. :3 but you are smart guys <3 :smiley: I will consider heading to another forum :slight_smile:

I had some desires to learn whether SDL2 would ever free from its pool
of malloc’d events over time if the volume of active events was reduced
substantially.

SDL doesn’t do this at the moment, but we could probably do something
like: if X frames (or milliseconds) have passed with Y events being
unused, free up to Z events per frame.

–ryan.

2015-03-25 20:53 GMT-03:00, Ryan C. Gordon :

SDL doesn’t do this at the moment, but we could probably do something
like: if X frames (or milliseconds) have passed with Y events being
unused, free up to Z events per frame.

How do you determine this? Especially since the timer subsystem may
not be initialized yet. Maybe it’s better to do the check only when
already messing with the event list (e.g. when removing an event from
the list, check if the list had gone too empty for many events or
something).

How do you determine this? Especially since the timer subsystem may
not be initialized yet.

Oh, I meant check SDL_GetTicks() when messing with the queue, not using
an actual timer event.

–ryan.

2015-03-26 3:50 GMT-03:00, Ryan C. Gordon :

Oh, I meant check SDL_GetTicks() when messing with the queue, not using
an actual timer event.

I thought that also required timers to be initialized (or is that not
the case for this specific function?).

Sorry I misinterpretted what you were trying to do, oops. Good luck with
the project, though!On Wed, Mar 25, 2015 at 6:12 AM, bazz wrote:

Hi, I’m programming an embedded system. Porting the entire SDL library
to this system is more than intimidating, but there are certain things I’m
used to thinking like SDL_Events and I was wondering if someone with more
experience than I have, can offer some tips on how to simply implement a
kind of SDL_Event queue… It’s the queue itself I’m not sure about… Should
I just google ‘queue C’ ?

But the rest I can handle… like I understand that I would be adding to
the queue when certain events happen low level (like a button released),
and in the main loop I will check the queue to parse to process the events
like I would in SDL…


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org