lua-users home
lua-l archive

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

On Wed, Dec 02, 2009 at 11:03:39AM -0800, Chris Gagnon wrote:
>    On Wed, Dec 2, 2009 at 10:16 AM, Jim Pryor <[1]>
>    wrote:
>     On Wed, Dec 02, 2009 at 09:33:47AM -0800, Chris Gagnon wrote:
>     > M = thread/co routine manager
>     > S = some system that has registered a C interface for lua scriptsto use
>     > This may yield, i'll use the specific example of a system that
>     > impliments a Delay(fTime) function for scripts to use.
>     > L = a co routine
>     > M creates L and could create MyStateWrapper then starts L
>     >
>     > L calls Delay(1.0) S gets a call to its registered function of signature
>     > int function(lua_State *L) and yields L
>     > ...1 second later...
>     > S wants to Resume L however the resume requires MyStateWrapper so that is
>     > can properly clean up if the L ends or errors.
>     > Now i must look up in a map that associates L with MyStateWrapper.
>     Are you using pre-emptive threads? If so, are you using one of the
>     existing Lua frameworks for this or have you rolled your own?
>    This is a completely homegrown framework, using pretty much vanilla Lua.
>    Completely cooperative threading, I then to use "thread" and "coroutine"
>    interchangeably which probably doesn't help when I'm explaining things,
>    but I blame Lua itself for this since it's confused as to what it wants to
>    call them ;o)
>     If you're only using cooperative threads, then would the model be that S
>     yields the thread that called it back to a parent Lua thread, such as M,
>     and that later someone (looks from this model like it should be M, but
>     that doesn't sound like what you have in mind) decides that the
>     suspended thread should be resumed. So other cooperative Lua threads can
>     be run in the meantime. In that case are you using some patch (RVM?
>     Coco? to enable you to yield across the C-call boundary?
>     Or is the model that S suspends the whole Lua universe for one second
>     (other Lua universes rooted in other parent lua_States can run, but the
>     two universes wouldn't share any memory). In that case you wouldn't need
>     to be doing any yielding inside the Lua universe that's being suspended,
>     you just don't return from the C-call to S until you're ready to go on.
>    When any System( S )� Yields it only Yields the calling L.
>    At anytime there could be hundreds of L's yielded waiting on things like
>    delays, loads or others things each implemented by a different system.
>    Each of these systems manage when they should resume any L that they
>    yielded.
>    So there are multiple entry points for resuming, as well as the entry
>    points for creating new L's. ( new L's are created by M)
>    All resumes go through the M->Resume(L) such that there isn't any code
>    duplication for the resume and cleanup code but once again somehow i need
>    to get at MyStateWrapper to be able to cleanup.

It's still opaque to me. Can you write down the simplest possible prototype?

I'm assuming something like the following is involved, though in C
instead, and you're relying on the built-in luaL_ref, luaL_unref...

ThreadTable = {[0]=0}

function luaL_ref(tbl, val)
    local ref = tbl[0]
    if ref == 0 then
		-- no free slots, grow table
        ref = #tbl + 1
        -- use free slot, move free slot it pointed to to tbl[0]
        tbl[0] = tbl[ref]
    tbl[ref] = val
    return ref

function luaL_unref(tbl, ref)
    local val = tbl[ref]
	-- mark ref as first free slot
	tbl[ref],tbl[0] = tbl[0],ref
	return val

function makethread(funct, args)
    local L = coroutine.create(funct)
    local ref = luaL_ref(ThreadTable, L)
    return ref, coroutine.resume(L, args)

local function L1(args)
    local retval = call_c_sleep_function(10)
    print("good morning", args)

local function L2(args)
    local retval = call_a_different_c_sleep_function(10)
    print("good morning", args)

local ok, retval1, retval2, ref1, ref2

ref1, ok, retval1 = makethread(L1, 100)
if ok then
    ref2, ok, retval2 = makethread(L2, 200)
    if ok then
        -- use retval1 to decide when it's ok to resume thread1 again
        -- and whether to resume thread1 before thread2, etc.
        ok, retval1 = coroutine.resume(ThreadTable[ref1])
        if ok then ...

Is that the flow control? If it's cooperative threading then there's
some kind of round-robin manager that the c functions are yielding to,
and it has to decide, based on the retvalues they yield, when to resume
thread1, whether to resume thread1 before thread2, and so on. This is
also the manager that decides when the threads have crashed or finished,
and when to make them GC-able. Right? Does that represent your basic
flow control?

Jim Pryor