lua-users home
lua-l archive

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


On Fri, Dec 30, 2005 at 14:39 +0100, Gerhard Sittig wrote:
> 
> On Thu, Dec 29, 2005 at 23:05 -0800, David Andersen wrote:
> > 
> > You want to do this I think:
> > 
> > http://www.icynorth.com/forums/viewtopic.php?p=228&sid=24c427141b80232a86258d2e41c6b0ee#228
> 
> Thank you for the pointer.  [ ... ]

For the record:  The approach referenced above works like this:  A Lua
VM is opened, the script (only defining a function, not running it) is
loaded and pcall() gets called -- i.e. the script gets compiled and run
to introduce the function into the namespace.  Then a new Lua thread
gets created, the count debug hook registered and the script's loop()
function is resume()d, while the debug hook yield()s.  This way control
is returned to the main thread in a regularly scheduled manner.

Since I already wanted to "supervise" the initial pcall (because it
might already run for an infinite time should the script not only define
the loop() function but already call it), I played a little with the
code.  That I did not succeed of course was my own failure. :)  Fixing
my bad after adding some error checking and diagnostic printouts was
easy.

Now I trimmed down everything and things work like expected.  The C code
actually is just this (diagnostics and checks removed).

  L = lua_open();
  lua_sethook(L, count_hook, LUA_MASKCOUNT, 10);
  luaL_loadfile(L, "loop.lua");
  error = lua_pcall(L, 0, 0, 0);  /* here the user provided script is
	  run, count_hook() gets called permanently, while I don't have
	  to know any details about the script and don't have to expect
	  conventions to be obeyed -- the user is absolutely free */
  lua_close(L);

Of course the small count of just ten VM opcodes is only appropriate for
testing.  The hook function need not do anything Lua specific and merely
handles the C application's event stuff or whatever needs to be done in
a "tick".


Now the remaining problem is to handle the situation where the hook
needs to abort the script running in the Lua VM.  This applies when the
user script does not end by itself (endless loop or something, maybe
even finite but time consuming work one wants to interrupt and
terminate).

The hook is called from within src/lvm.c:luaV_execute().  I noticed that
yield() (in Lua) returns from this routine, but I guess it does not end
the thread but merely suspends it to schedule whatever is available to
run now.  While I could not find an appropriate CallInfo state to end a
thread nor could I see an OpCode which ends a thread (short of
permanently issuing "return" opcodes which is rather ugly and I actually
did not plan to fiddle with the lua_State).

What is a clean way to terminate a Lua VM from within luaV_execute()?
Does one have to fiddle with the execution stack and "return from the
main routine" or is there an alternative?  Would it be useful to
introduce a new opcode which "officially" ends a Lua thread and could be
used by regular scripts, too?


Another problem may be that Lua users could clobber the application's
debug hook by registering an own hook or by resetting the value to NULL.
This means that I might want to introduce an "application hook" separate
from the debug hook.  And not export it to the Lua land.  From what I've
seen so far this would be easy to do.

And luaE_newthread() needs to "inherit" set application hooks to newly
created threads.  Otherwise user code may run without the application
being called back when new Lua threads are used exclusively.  This I
think could be implemented as easy as the above change.  Although the
counters are not reliable any longer unless one global application hook
counter is used in common for all threads of a VM -- but I assume the
hook was designed to call back registered routines at all, not to
reliably call the application back for an exact number of opcodes.

BTW did I get the impression that a line hook may not be called from
within traceexec() should a count hook "shadow" it by chance (i.e. when
its counter is 0 at the start of a line).  That means, the callback gets
called, but the reason is "counter hit" while the "line started" reason
is not passed to the callback.  This is in Lua 5.0.2, haven't checked
5.1 yet.

And I wondered why the lua_State is not memset() after malloc() in
mallocstate() or preinit_state() but fields are assigned to
individually.  This means that the optional additional EXTRASPACE is
undefined or may lead to additional lua_State fields which are added in
the future having random content when preinit_state() is not always
adjusted completely.  And I wondered if preinit_state() might need an
additional reference to the "parent's" state (or NULL when called from
the lua_open() routine) to "inherit from" when appropriate.

What cannot be solved is that some C code might unregister the separate
app hook (while the setapphook call needs to be in the C interface so
the app can register its hook).  But neither can be made sure that the
debug hook is called when a user's C library spends too much time
without returning to a Lua script.  I assume that this is OK or just
cannot be solved without running C plugins in a sandbox, too, which
would go way beyond what Lua was designed for.  It might as well be that
I have a wrong impression because I'm abusing the debug hook or the
newly introduced app hook because the OS does not provide ways to run
the app and the Lua VM in parallel, which is not at all Lua's fault. :)


virtually yours
Gerhard Sittig
-- 
     If you don't understand or are scared by any of the above
             ask your parents or an adult to help you.