lua-users home
lua-l archive

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


This patch, based on a description of a feature invented by Mark Tomczak of
Sim Ops Studios, allows an outside thread to impose a limit on the runtime
of Lua instances (states).  Mark's very clever approach is to introduce a
"must exit" bit in the Lua state; when that bit is set, the Lua VM starts
seeing all instructions as unconditional returns.  Within a few microseconds,
you should be *pop* back out of your lua_(p)call.

This is a complete feature patch, including documentation.
I hope this feature, or something like it, can be introduced for Lua 5.2.


commit 2161539260ca5229f9d9fcfd7c3575145478d627
Author: Chip Salzenberg <chip@tytlal.topaz.cx>
Date:   Tue Jul 15 17:02:07 2008 -0700

    new API feature lua_forcereturn() to limit embedded runtime

diff --git a/doc/manual.html b/doc/manual.html
index b125c13..c940c80 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -2555,6 +2555,31 @@ The panic function can access the error message at the top of the stack.
 
 
 
+<hr><h3><a name="lua_forcereturn"><code>lua_forcereturn</code></a></h3><p>
+<span class="apii">[-0, +0, <em>-</em>]</span>
+<pre>void lua_forcereturn (lua_State *L, int force);</pre>
+
+<p>
+Sets or clears the force-return flag.
+
+
+<p>
+If this flag is set, then all threads attached to the given global state
+will be force to return immediately to their callers.  This is a Big Hammer
+intended for use in embedded environments where runtime must be strictly
+limited.
+
+
+<p>
+It is expected that this function will be called from another OS-level
+thread or a signal handler.  Systems with unusual memory models, such as
+explicit cache coherency management, may break this feature.  On such
+systems, it may be necessary to modify the definitions
+of <code>lua_AtomicBool</code>, <code>lua_setatomicbool</code>, and
+<code>lua_getatomicbool</code> in <code>llimits.h</code>.
+
+
+
 <hr><h3><a name="lua_call"><code>lua_call</code></a></h3><p>
 <span class="apii">[-(nargs + 1), +nresults, <em>e</em>]</span>
 <pre>void lua_call (lua_State *L, int nargs, int nresults);</pre>
diff --git a/src/lapi.c b/src/lapi.c
index d7e8931..98f8a91 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -151,6 +151,13 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
 }
 
 
+LUA_API void lua_forcereturn(lua_State *L, int force) {
+  lua_lock(L);
+  lua_setatomicbool(&G(L)->mustreturn, force);
+  lua_unlock(L);
+}
+
+
 
 /*
 ** basic stack manipulation
diff --git a/src/llimits.h b/src/llimits.h
index ca8dcb7..117a7cb 100644
--- a/src/llimits.h
+++ b/src/llimits.h
@@ -117,6 +117,18 @@ typedef lu_int32 Instruction;
 
 
 /*
+** cross-thread atomic flag - unusual memory models may require modification
+*/
+typedef union {
+    unsigned flag :1;
+    int align_dummy;
+} lua_AtomicBool;
+
+#define lua_setatomicbool(F,B) ((F)->flag = (B) ? 1 : 0)
+#define lua_getatomicbool(F)   ((F)->flag)
+
+
+/*
 ** macro to control inclusion of some hard tests on stack reallocation
 */ 
 #ifndef HARDSTACKTESTS
diff --git a/src/lstate.c b/src/lstate.c
index 4313b83..afa6c7b 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -156,6 +156,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   preinit_state(L, g);
   g->frealloc = f;
   g->ud = ud;
+  lua_setatomicbool(&g->mustreturn, 0);
   g->mainthread = L;
   g->uvhead.u.l.prev = &g->uvhead;
   g->uvhead.u.l.next = &g->uvhead;
diff --git a/src/lstate.h b/src/lstate.h
index 3bc575b..b2aae72 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -69,6 +69,7 @@ typedef struct global_State {
   stringtable strt;  /* hash table for strings */
   lua_Alloc frealloc;  /* function to reallocate memory */
   void *ud;         /* auxiliary data to `frealloc' */
+  lua_AtomicBool mustreturn;  /* all opcodes become "return" */
   lu_byte currentwhite;
   lu_byte gcstate;  /* state of garbage collector */
   int sweepstrgc;  /* position of sweep in `strt' */
diff --git a/src/lua.h b/src/lua.h
index 5bc97b7..581c21f 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -113,6 +113,8 @@ LUA_API lua_State *(lua_newthread) (lua_State *L);
 
 LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
 
+LUA_API void lua_forcereturn(lua_State *L, int force);
+
 
 /*
 ** basic stack manipulation
diff --git a/src/lvm.c b/src/lvm.c
index ee3256a..ee7a6b5 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -374,6 +374,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
   LClosure *cl;
   StkId base;
   TValue *k;
+  lua_AtomicBool *mr = &G(L)->mustreturn;
   const Instruction *pc;
  reentry:  /* entry point */
   lua_assert(isLua(L->ci));
@@ -383,7 +384,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
   k = cl->p->k;
   /* main loop of interpreter */
   for (;;) {
-    const Instruction i = *pc++;
+    const Instruction i = lua_getatomicbool(mr) ? CREATE_ABC(OP_RETURN,0,1,0) : *pc++;
     StkId ra;
     if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
         (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {

-- 
Chip Salzenberg <chip@pobox.com>