Big Bucket Software you like to use
WaitUntil/Yielding
March 10th, 2006

Well, I’ve been racking my brain (as well as the brains of my work colleagues) for a couple of days now in an effort to come up with a solution to my sleep/yield problem. See my previous post for more information. My idea of:

“make the waitFor function register a callback with isIdle, process the main loop continuously itself and unregister with isIdle when it receives the callback…”

Was utter nonsense, here’s why: If another callback was triggered while a Lua function was processing the main loop and that function needed to waitFor an event, then we’d have to recurse. If the waitFor in the recursed function took longer than the original function, then the original function would be blocked. Badness ensues. I only gave this option a little more thought before scrapping it entirely.

So I start looking for information in the Lua mailing list archives and soon found all this stuff on co-operative multitasking. As it turns out, Lua nowadays has built-in support for coroutines. This means that I can do something like:

lua_State* new_thread = lua_newthread (main_thread);

Which is, well, fantastic! The thing about cooperative multitasking though is that it isn’t preemptive, it is necessary that the threads actually yield at some point. So how does this work in Mage?

Well, first of all, there’s a new MessageColleague; the ScriptHandler. This is capable of responding to two Signals; Signal_Run and Signal_Yield. The parameter to Signal_Run is the function name and the parameter to Signal_Yield is the thread ID. Now then, in order to run a function, the ScriptHandler creates a new thread, pushes the function onto that thread’s stack, and resumes it, (lua_resume). If that function yields, (by using a YieldUntil function) then the ScriptHandler will stash the thread in a map so that it can be resumed later. So the question is, “how does it get resumed?”

Before lua_yield-ing, each YieldUntil function first of all establishes a message link. That is, it links a Signal to a Slot. The Signal being what we are waiting to happen and the Slot being Signal_Yield on the ScriptHandler. Neat huh?

I might try and clarify this information at a later date, it does require a bit of previous knowledge of the innards of Mage, but hopefully it’s enlightening.

I really need to get a new binary up on the net some time soon, though I probably won’t do that until I’ve got all the game logic out into Lua… not long to go.