lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Thatcher Ulrich, you're my hero.  =)

I haven't tried it, but parts of the patch look eerily familiar.  This is
exactly the minimal behavior we need added to Lua proper to enable all the
other wacky things people will want to do.  Let me be the first to raise my
hand and ask that this patch be added to the core distribution.  This is
the final piece (on top of the original rewrite to use lua_State) that
gives programmers all the thread/task/coroutine meta-mechanisms they might
want.

>From here it is but a short hop to the absolutely dead simple frame-based
cooperative multitasking that game developers crave: Your program simply
keeps a list of lua_States and calls lua_resume() on them in order each
frame.  Put in a call to DrawMyEntireWorldAndSwapBuffers() after reaching
the end of the list and before jumping back to the front and you're all
set!

Further steps to enhance your use of this patch immediately suggest
themselves, and all are done with no modification to Lua itself:

Register functions for traversing the list of lua_States (similar to
next()).  Then you can replace or wrap the functions in the reflexive debug
interface (section 7.4 of the manual) such that they take an extra
parameter to indicate the lua_State you're asking about, just as the C
versions of these functions have.  Now you have the minimal interface
necessary to write a debugger in Lua that's capable of enumerating and
describing all of the other lua_States as well as its own!

Register a function called fork() that takes a function and its parameters
and adds a new lua_State ready to run it to the end of the list.

Register a function called kill() that terminates a given lua_State.

Register a function called join() that waits for a given lua_State to
terminate and inspects its return values.

Register a function called nice() that takes a given lua_State and moves it
around in the list, or adds it into the list multiple times.  Now you can set
both how often and in what order a lua_State gets resumed relative to its
peers.

Hopefully more possibilities spring to mind when you see these.  If someone
does all of these as a library and posts it, game developers all over will
rejoice...


Thanks,
Bret




On Mon, Dec 10, 2001 at 11:27:22AM -0500, Thatcher Ulrich wrote:
> I've created a patch for Lua 4.0 that makes calls from Lua to Lua
> non-recursive (i.e. "stackless").  This allows the implementation of a
> "sleep()" call, which exits from the host program's lua_do* call with
> a LUA_SLEEP code, and leaves the lua_State in a condition where the
> script can be resumed later via a call to a new API function,
> lua_resume(lua_State*).
> 
> The patch is on the "Power Patches" page at lua-users.org :
> 
> http://lua-users.org/wiki/LuaPowerPatches
> 
> This is the core functionality that Bret Mogilefsky has described in
> the "sleep()/yield() for Lua" thread, and has been much bandied about
> in the archives.
> 
> As part of the VM changes, I also made it so OP_TAILCALL is properly
> non-recursive.  This lets you implement long iteration-like
> computations using recursive syntax (provided the compiler emits an
> OP_TAILCALL for the tail call -- I'm not totally sure what the right
> conditions for that are).  See the test program below for a contrived
> example.
> 
> The patched lua correctly executes all the test scripts in the 4.0
> distribution, but it's very possible there's a bug somewhere,
> especially with error handling and such.
> 
> Also, these changes need to be ported to 4.1, to take advantage of Lua
> threads.  I started with 4.0 in order to have a stable platform to
> work in.
> 
> The biggest known problem with this patch is that sleep() will not
> actually succeed if it's called from a tag method, or from a recursive
> call to lua_do* (i.e. script calls a C function, which then calls
> lua_do*).  Instead you get an error message and the script continues
> execution.  So the semantics of sleep() depend somewhat on the
> internal workings of the interpreter.  For practical use in a game
> scripting language, this shouldn't be a problem.
> 
> Feedback welcome!
> 
> -- 
> Thatcher Ulrich <tu@tulrich.com>
> http://tulrich.com
> 
> 
> 
> ------ test/sleep.lua -------
> -- test the sleep patch.  The sleep patch adds a sleep() function,
> -- which suspends script execution in a restartable state (via the API
> -- function lua_resume(L)).  The sleep patch also implements true tail
> -- recursion for the OP_TAILCALL opcode.
> 
> 
> function donothing_tailrec(x)
> 	return x
> end
> 
> function donothing_rec1(x)
> 	return donothing_tailrec(x)
> end
> 
> function donothing_rec2(x)
> 	for i = 1,1000 do
> 		donothing_rec1(x)
> 	end
> 	return donothing_rec1(x)
> end
> 
> function donothing_rec3(x)
> 	for i = 1,1000 do
> 		donothing_rec2(x)
> 
> 		-- exit script execution, returning LUA_SLEEP to the caller.
> 		-- The caller can resume the script via lua_resume(L).
> 		sleep()
> 	end
> 	return donothing_rec2(x)
> end
> 
> c = clock()
> r = donothing_rec3(10)
> t = clock() - c
> print("time = " .. t .. ", result = " .. r);
> 
> 
> count = 0
> 
> function increment_tailrec(ct)
> -- stupid recursive function to increment 'count'
> 	if ct <= 0 then
> 		return 0
> 	else
> 		count = count + 1
> 		return increment_tailrec(ct-1)	-- for some reason, we must return a value for OP_TAILCALL to be generated.
> 	end
> end
> 
> 
> function test(x)
> 	count = 0
> 	increment_tailrec(x)
> 	if count == x then
> 		print("success --> count = " .. x);
> 	else
> 		print("failure --> count = " .. count .. " but x = " .. x);
> 	end
> end
> 
> 
> -- The sleep patch also implements proper tail recursion for the
> -- OP_TAILCALL opcode.  In unpatched Lua 4.0, one of the following
> -- calls will probably cause a stack overflow error.
> test(1)
> test(10)
> test(100)
> test(1000)
> test(10000)
> test(100000)
> test(1000000)

-- 
Bret Mogilefsky * Mgr. SCEA Developer Support * mogul@gelatinous.com