[Date Prev][Date Next][Thread Prev][Thread Next]
- Subject: Re: Newbie: Cooperative Multitasking
- From: Bret Mogilefsky <mogul@...>
- Date: Thu, 4 Nov 1999 11:20:22 -0800
On Thu, Nov 04, 1999 at 04:41:06AM -0200, Derek Wong wrote:
> Any pointers on where I should try to start/stop the scripts? Should it be
> at the level of the virtual machine, maybe make a new opcode or some kind
> of flag that gets checked? Or should it be higher up like in the function
> luaD_protectedrun? Or is it somewhere in between?
I put it in luaD_protectedrun(). I registered an empty "sleep" function, then
checked for the pointer to that function when a C function is being called
from Lua. I haven't checked into the interpreter lately, but if it's laid out
like it was for 2.5, the key thing to remember is this... If you have a string
of function calls that go back and forth between the script environment and
the host, eg:
C -> Lua -> C -> Lua -> Lua -> C
The host recurses into a new stack frame EACH TIME a function is called,
whether C or Lua. This causes problems because if you sleep in one task and
then resume in another, the stack of the host may be at a completely different
depth than it was when the resumed thread originally went to sleep... Major
mayhem ensues. So the first thing to do if you're going to make this
modification is to have protectedrun push a stack frame structure for the
function being called onto a stack of stack frame structures (confused yet?).
In other words, manage the Lua stack frame explicitly.
The easiest way for me to do this was with a little bit of C++ to coalesce the
local variables in a bunch of the functions into a class I could pass
around... Your mileage may vary.
After you've made that change, you can create a stack of stack frames for each
task that starts up... (Again, C++ helped me encapsulate this pretty well, but
you could just as easily do it with a liberal application of object-oriented
C.) Keep a list of all the task-stacks that you've created. Then look for
the sleep function in protectedrun, and at that point simply switch which
task-stack you're looking at and dive right back into the return from the
sleep that the next task-stack last ran. Keeping the various local variables
in the structure makes it pretty easy to sneak right back into the "returning
from function" chain of events.
One caveat: You can't sleep if you've recursed on the host side. Luckily this
is easy to detect and you can just error() when it happens rather than
switching task-stacks. In other words (pseudo code):
When you do this, the sleep() in A is ok, as is the sleep() in B that's called
without looping through the host. However, the sleep that gets called as a
result of reg_func_that_calls_lua_B_func() is not allowed because we've
recursed a stack frame on the host in order to get there, so you'd see an
error() thrown and stay in that task.
"Why, that's the second biggest monkey head I've ever seen!" --Guybrush
"LeChuck's dead. I blew him into a million gooey pieces." --Guybrush
Bret Mogilefsky ** email@example.com ** Programmer, SCEA R&D