Can there ever be so many events in the event queue that the game loop never gets completed?

The typical SDL event handling code looks somewhat like this:

while (SDL_PollEvent(&event)) {
    switch (game_event.type) {
    case SDL_QUIT:
        game_running = SDL_FALSE;
        break;
    case SDL_KEYDOWN:
        // Keypresses get processed here
        break;
    case SDL_MOUSEMOTION:
        // More stuff are handled here
        break;
    // ...
    }
}

// Rendering, custom game logic, etc goes here

I’ve been wondering if it is possible that the user inputs so many events into the event queue that SDL_PollEvent doesn’t have a chance to return 0 (a.k.a. all events have been processed and the while loop should terminate), and thus the above while loop can’t be broken out of, consequently freezing the game, though I may be misunderstanding how the event handling system actually works under the hood.

It can happen if the events are generated at a faster pace than you handle them. With a high DPI mouse you can generate many hundreds of mouse motion events per second. This is not necessarily a problem but you probably don’t want to do very time consuming operations (e.g. calling SDL_Delay or SDL_RenderPresent) for each event.

Under the hood, we get all the events once and then each one is returned from SDL_PollEvent() and it returns 0 once they’re all processed.

You have more control over this process by calling SDL_PumpEvents() and SDL_PeepEvents() yourself, but the default behavior should work for applications even when there are high DPI mice sending hundreds of mouse motion events.

If I’m understanding correctly, does it then follow that if my event handling while loop (everything inside while (SDL_PollEvent(&event))'s brackets) has a bottleneck, either accidentally or deliberately (by using SDL_Delay(500) for example) while simultaneously being bombarded with events, my game would then be stuck trying to process them?

Edit: Sorry, I could’ve tested this myself. Adding SDL_Delay(500) does make the game register events at a really slow rate (the frame rate drops from 60 to around 4 FPS).

If I understand correctly you’re saying the loop will essentially process all the events that had happened before the loop started but not the events that happens while the loop is running. This behaviour seems to be relativly new (January 2022?). I have a relatively old version of SDL2 installed and I can certainly make it stay within the event poll loop for seemingly forever if I just make handling the events slow enough.

As slouken pointed out above, it might not be stuck forever but it would still lead to problems if you cannot keep up with the pace. If you don’t handle all events now it just means you have more events to handle next time.

If it’s just a temporary bottleneck (e.g. a mouse click that triggers some action that takes a long time to execute but it only happens once in a while) then it’s probably not an issue because you will be able to catch up pretty quickly.

But if you’re constantly too slow then the unhandled events will just keep accumulating. Under normal circumstances you would not end up in this situation (unless you do something “wrong”) so I don’t think you should worry too much about it.

500 ms is a long time. It’s half a second. I’m surprised you even get 4 FPS.

If we are going “Ad absurdum” as it were:

There is a hard limit set at 65535 events.
In the SDL_events.c file, they have this line #define SDL_MAX_QUEUED_EVENTS 65535
At that point, attempts to add events to the queue will just be ignored (evidence found in that same file). When the queue is saturated and you do poll the events, it will start giving you the oldest event all the way up to the 65535th event, but not be able to give any of the newer events from before you started polling as they are lost.
As you poll the events in the queue the size of the queue is reduced, so space is made available and the queue can start taking events again.

In SDL3:

  1. I wrote a program to push 300,000 events, it only kept 65535 on the queue.

  2. I wrote a program that set a game loop delay of a full minute and wiggled my mouse for that entire time on the window. I was only able to generate about 8000 events in that whole minute.

  3. I wrote a program with a good delay in the event poll loop and console output to confirm when a game loop occurred. I was able to stall the game loop indefinitely by wiggling the mouse: in while(SDL_PollEvent(event)) the queue can be considered to be growing and shrinking as events are created and polled, even as the events are being processed.

To be safe, events that may occur more than couple times per frame and events requiring a lot of processing should set state flags so they can be processed and interacted with outside of the event polling loop (game logic section as shown in your original post).
As a final note, these tests I wrote are indeed absurd. On a modern machine it would be very difficult to produce actually sane code that would reach those limits.

With a 16 000 dpi mouse I was able to generate almost 60 000 events in one minute. This was on my laptop. On my desktop computer I was only able to generate half of that with the same mouse for some reason.

This comes pretty close to the queue limit but under normal circumstances you would not run the poll loop once per minute. You would instead run it perhaps 60 times per second in which case you would only have to handle about 16 events each time. If your game freezes for more than one minute, and the user keeps moving the mouse so that the queue gets filled up, then the most frustrating thing is probably not that you lost some events…

This is a good advice in general but sometimes you might want to take the intermediate steps into account. For example, if you’re creating a graphics editor you probably want the lines to follow the mouse movement (perhaps with some “smoothing”) and not take shortcuts between frames.

Is that so? I’ve always thought that the event queue gets pushed into at any time an event is initiated by the user, meaning that events added while the current event handling loop is running will just get handled at the next game loop’s event handling loop.

1 Like