[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: [PATCH] lua_forcereturn()
- From: Chip Salzenberg <chip@...>
- Date: Wed, 16 Jul 2008 13:47:49 -0700
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>