lua-users home
lua-l archive

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



> -----Message d'origine-----
> De : Luiz Henrique de Figueiredo [mailto:lhf@tecgraf.puc-rio.br]
> Envoyé : jeudi 6 février 2003 18:37
> À : Multiple recipients of list
> Objet : RE: does anyone else miss a coroutine.reset() feature ?
> 
> Perhaps I'm missing a lot here, but in Lua 5.0 you can send "messages"
> (that is, Lua values) in resume and receive them in yield. You can use
> those messages to tell the taks to restart itself or to stop 
> or anything

Yes, but the task is not monolithic: I have a primary entry point called
inside an infinite yielding loop, and this entrypoint can call several
functions, and them in turn some more, before one of them somewhere decides
to yield. It would be somewhat cumbersome for an end-user to explicitly have
to trap the 'abort message' everywhere they use interruptible mechanisms so
that they can propagate it up the call stack back to the top-level infinite
yielding loop.

For example, I'd rather have someone describe a task as:

function task ( params )
	do some stuff
	someSequence:execute()
	do some other stuff
	someSequence:execute()
	...
end

and register the task to some system of mine which will wrap it in my an
infinite yielding loop and handle everything, rather than:

function task ( params )
	do some stuff
	if someSequence:execute() == 'reset' then return 'reset' end
	do some other stuff
	if someSequence:execute() == 'reset' then return 'reset' end
	...
end

and having my sequence yielding loop catching the message and propagate it.
I have however tested the system and it works fine. So, the deed is done,
but not in the user-friendly way I thought about.


> else. I guess this means that tasks that need to restart themselves
> run inside their own infinite loop. Wouldn't that work for you? Do you
> really need taks to restart themselves inside the Lua VM?

Considering that the persons who will use the language are not programmers,
I'd say it is one less source of error if they don't have to know (and
account for) the internals of the tools I provide them.

Anyway, I have implemented a coroutine.reset() call. Here is the code for
anyone that is interested. The only thing I ask in return is to be told
about any bug that my incomplete understanding of the core might have
overlooked :-) More specifically, this works with the current scripts I have
at hand, but I haven't done deep testing regarding different code structures
(yielding deeper inside the call stack, using functions with upvalues,
checking that everything is handled fine by the gc, etc.)

in lua.h, add:
LUA_API int  lua_reset (lua_State *L);

in ldo.c, add:
LUA_API int lua_reset (lua_State *L) {
  /* close upvalues */
  luaF_close (L, L->stack);
  /* unwind call stack */
  L->nCcalls = 0;
  L->ci = L->base_ci;
  L->ci->state = CI_C;
  /* restore stack */
  L->top = L->stack;
  setnilvalue(L->top++);  /* `function' entry for this `ci' */
  L->base = L->ci->base = L->top;
  L->ci->top = L->top + LUA_MINSTACK;
  L->top++; /* keep the entrypoint function active on the stack */
  return 0;
}

in lbaselib.c, add:
static int luaB_coreset (lua_State *L) {
  lua_State *co;
  /* expect either a thread or a coroutine wrapper */
  if (lua_iscfunction(L, 1)) {
    int n=lua_gettop(L);
    lua_getupvalues(L,1);
    luaL_argcheck(L, lua_gettop(L)-n==1, 1, "wrapper expected");
    lua_remove(L,1);
  }
  co = lua_tothread(L, 1);
  luaL_argcheck(L, co, 1, "coroutine expected");
  lua_reset(co);
  /* NOTE: lua_reset assumes that a valid object was pushed
  on the stack of the thread, and it is there now, as after
  a coroutine.create() call */
  return 0;
}

static const luaL_reg co_funcs[] = {
  {"create", luaB_cocreate},
  {"wrap", luaB_cowrap},
  {"resume", luaB_coresume},
  {"reset", luaB_coreset}, /* do not for to register the reset function too
*/
  {"yield", luaB_yield},
  {"status", luaB_costatus},
  {NULL, NULL}
};


Cheers,


Benoit.