(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.
That might be a reasonable approach if I hadn't just discovered that we have a fundamental issue with coroutines to begin with in Hammerspoon: see https://github.com/Hammerspoon/hammerspoon/issues/2306
, if you want the nitty-gritty, but it boils down to any approach with leverages coroutines will have to wait until that's fixed first...
Ah, yeah, that does look like an issue, but I think you might have an easier solution available to you than the ones you're considering now: replace coroutine.create(). If the problem is that the new state isn't set up in LuaSkin, then just make a function that calls lua_newthread(), sets it up appropriately, and returns it to the caller.
Unfortunately, LuaSkin uses a shared singleton instance which contains a number of references to helper functions (for moving Objective-C data types into and out of lua as userdata) that get added at run time as lua modules are loaded -- in its current incarnation, it's not possible to create a new instance with just the stored reference to the lua_State being different.
I think we've been lucky so far that none of our users have seriously tried to use coroutines; but going forward, I think we need to, so... it's time for some thinking and probably some restructuring and recoding :-)