Can I take over the run loop?

The Playdate SDK is obviously designed around the idea that the framework controls the run loop and on events calls into user code. The user code function is expected to return to the run loop quickly (as discussed here).

Can I reverse this, so that the run loop is in my code, and periodically calls into the framework to let it do whatever event handling it needs to? I am specifically interested in doing it in C, but the answer might apply to Lua too.

I did a quick test by just never returning from eventHandler() or from the update() callback and instead calling pd->graphics->display() regularly. But that didn’t work out too well. While it allowed me to animate stuff on the display, the buttons were unresponsive, and after 10 seconds (on the device, not in the simulator) the Run loop stalled for more than 10 seconds watchdog kicked in. So apparently display() really only flushes the display, but doesn’t do the whole usual end-of-frame processing and event handling. Is there anything else I can call to let the framework do its thing, or is this way of operation flat-out unsupported? If it is, could it be supported in the future?

The reason I am asking is that I am planning to try to get MicroPython into a Playdate application in order to run existing games written in Python. These games assume that they control the run loop, they contain an infinite loop that calls out to API functions that update the display, check for button presses, or wait for the next frame time. The MicroPython virtual machine doesn’t help me out either in that regard, running one Python function means one C call that only returns after the Python function returns, there is no way to have it interrupt after a certain number of Python instructions and return to the caller, to resume in a further C call. It does have the ability to call back every so many instructions, though.

I imagine this functionality could also be useful for ports of other existing games or for emulators.

If I am out of luck and there is no way to take over the run loop, I might be able to achieve my goal using this “coroutines for C” library. Lua’s native coroutines were what allowed me to get this to work in a Lua prototype.

Ultimately the answer is going to be no, because there's no way to guarantee that user code will be well-behaved. Your code might play by the rules, but as long as it's possible that someone else's code could crash the system or whatever, it becomes untenable for everyone.

If you do work in web development, you'll be familiar with how thread communications work, and how it's literally impossible for the DOM thread to synchronize on a shared resource (yes, even Atomics.wait() is disallowed from the DOM thread). The industry identified that all it takes is one programmer who doesn't really understand how the system is supposed to work to create a web page that causes the web browser to freeze and ruin the experience for everyone. Imagine if the code that caused that to happen was some third-party advertisement or something you have no control over. So they made sure that could never happen by preventing anyone and everyone from even having the ability.

The same applies to your suggestion for Playdate. Operating system tasks will never be supervised by user software.

1 Like

As you mentioned, the coroutines library will be a good choice here. Of course, I am biased :slight_smile:


I’m not sure I follow. How is the misbehavior enabled by an application-controlled run loop any worse than the misbehavior possible today by stalling in eventHandler() or update() (which seems adequately solved by the 10-second watchdog)?

Well that's just it: what you're proposing is that the application is responsible for making sure the 10-second watchdog runs.

No, that’s not what I am proposing. The watchdog would work in the same way it does today. I don’t know exactly what that is (a separate FreeRTOS task or a timer interrupt or something like that), but it’s obviously not in the main application thread, otherwise it wouldn’t be effective.