> Another option could be to have the time comsuming task within a coroutine that
> yields periodically. The coroutine would be called and continued in an event
> queue timer. With this you don't have to handle a local event queue loop.
First let me say that I don't have much experience with co-routines... it's a lack
I've been meaning to address, but so far haven't had a need that couldn't be
addressed another way or the time to do it on my own.
But if I'm understanding co-routines correctly, they still require some lua code (or
C code using the lua API) to actually invoke `coroutine.resume` on them for processing
to continue. This won't work for us (at least in the general case) because
the user interface, event queue, and lua interpreter share the main thread --
in Hammerspoon, as long as the lua interpeter is doing something, nothing else on
the main thread can.
I have to agree that using yield / resume is probably the best plan for you. There are a couple of points to consider that may help:
(1) You can use a Lua hook to cause a bit of Lua code to run whenever there's a function call or resume, or after each line of code, or after every N bytecode instructions. Inside this hook, you can call yield. This way you can preempt running Lua code without requiring the Lua code to explicitly yield if you don't want to. (You might need to come up with some sort of serialization primitive to make sure it doesn't leave you in an inconsistent state, but that also might not be a problem depending on how the rest of the system is architected.)
(2) Every event loop system I know of has a way to create synthetic events. If you just want to yield to the event loop and get called right back after the pending events have been processed, just create an event that calls coroutine.resume whenever the Lua code yields.