I've got a pretty decent little macOS/Linux cross-platform app working with SDL2 now, but I just ran into an issue where using DispatchQueue.main.async {} doesn't work on Linux; the block never executes. It does, however, execute on macOS.
The main part of my program is a loop that waits on the SDL event queue at the start of each loop. It then handles the events (which are mostly timers firing) that usually initiate network requests.
My guess is SDL’s macOS implementation of SDL_WaitEvent() is allowing the main queue to run other blocks, but not the Linux implementation. Is there a call I can make to let my main loop yield to GCD so other blocks can run? Any suggestion on how to go idle until an SDL event is available?
Any suggestion on how to go idle until an SDL event is available?
On Apple platforms, the main thread’s run loop services the main dispatch queue. Search swift-corelibs-foundation for _dispatch_main_queue_callback_4CF to see how this works. Looking at the code, it seems to be set up to function on Linux, leaving you with one of two possibilities:
There’s some sort of bug.
SDL’s main loop is not running the run loop on Linux
It’s seems likely it’s the latter.
As to how you fix this, there’s a bunch of potential approaches you can take, but the most important thing is how you integrate with SDL’s abstractions. I think you should dig into SDL_WaitEvent to see how it works on Apple platforms. Given that Swift’s Foundation brings run loop along with it, it’s possible you could just switch it over to using run loops on Linux.
I haven’t been able to figure out what SDL does on macOS if you don’t instantiate SDLApplication (a subclass of NSApplication), which I don’t. Grepping through the code I haven’t been able to find calls to dispatchMain() or an obvious NSRunLoop setup (there are run loops in some HID and audio code, and calls to get the global dispatch queue, but nothing obvious).
The event handling for Cocoa (which I’m not at all sure is what’s at play in a macOS build) calls [NSApp nextEventMatchingMask:…], and [NSApp sendEvent:], but since I'm not instantiating NSApplication, I don't think that’s involved. Not at all sure, though.
I’ve thought of a way to just call dispatchMain() in Linux-only portions of my code, looping on SDL_WaitEvent() on a separate queue and dispatching those back to the main queue. I haven’t tried it yet, but I think it’ll work.
I haven’t been able to figure out what SDL does on macOS if you don’t
instantiate SDLApplication …. Grepping through the code I haven’t
been able to find calls to dispatchMain or an obvious NSRunLoop
setup
One trick for uncovering this mechanism is to set a breakpoint on one of your event handlers and then look at the backtrace.
Alas, one typically calls into SDL to request the next event. However, there is an event watcher mechanism that might shed light on the situation. Thanks!