aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2009-07-09 17:45:23 +0000
committerJo-Philipp Wich <jow@openwrt.org>2009-07-09 17:45:23 +0000
commit03db00a803c8c8b78c7aa2880ab05f149da72815 (patch)
tree0e7e03b7d4ab188b06a54b58dffcf01784a92167
parentb8a97ca5c51f04b5fb32446c0d1df9186781b231 (diff)
downloadupstream-03db00a803c8c8b78c7aa2880ab05f149da72815.tar.gz
upstream-03db00a803c8c8b78c7aa2880ab05f149da72815.tar.bz2
upstream-03db00a803c8c8b78c7aa2880ab05f149da72815.zip
package/lua: implement memory limits, scripts can use get_memory_limit() and set_memory_limit() to cap the maximum ram usage
SVN-Revision: 16753
-rw-r--r--package/lua/Makefile2
-rw-r--r--package/lua/patches/040-memory-limits.patch277
-rw-r--r--package/lua/patches/300-opcode_performance.patch32
3 files changed, 294 insertions, 17 deletions
diff --git a/package/lua/Makefile b/package/lua/Makefile
index c7e1814f92..f5fca7b8f8 100644
--- a/package/lua/Makefile
+++ b/package/lua/Makefile
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=lua
PKG_VERSION:=5.1.4
-PKG_RELEASE:=3
+PKG_RELEASE:=4
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=http://www.lua.org/ftp/ \
diff --git a/package/lua/patches/040-memory-limits.patch b/package/lua/patches/040-memory-limits.patch
new file mode 100644
index 0000000000..52bae6ae85
--- /dev/null
+++ b/package/lua/patches/040-memory-limits.patch
@@ -0,0 +1,277 @@
+--- a/src/lapi.c
++++ b/src/lapi.c
+@@ -716,14 +716,14 @@
+
+ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
+ StkId t;
+- TValue key;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ t = index2adr(L, idx);
+ api_checkvalidindex(L, t);
+- setsvalue(L, &key, luaS_new(L, k));
+- luaV_settable(L, t, &key, L->top - 1);
+- L->top--; /* pop value */
++ setsvalue2s(L, L->top, luaS_new(L, k));
++ api_incr_top(L);
++ luaV_settable(L, t, L->top - 1, L->top - 2);
++ L->top -= 2; /* pop key and value */
+ lua_unlock(L);
+ }
+
+@@ -971,7 +971,12 @@
+ break;
+ }
+ case LUA_GCCOLLECT: {
+- luaC_fullgc(L);
++ lu_mem old_thres = g->GCthreshold;
++ if(g->GCthreshold != MAX_LUMEM) {
++ g->GCthreshold = MAX_LUMEM;
++ luaC_fullgc(L);
++ g->GCthreshold = old_thres;
++ }
+ break;
+ }
+ case LUA_GCCOUNT: {
+--- a/src/ldo.c
++++ b/src/ldo.c
+@@ -494,6 +494,7 @@
+ struct SParser *p = cast(struct SParser *, ud);
+ int c = luaZ_lookahead(p->z);
+ luaC_checkGC(L);
++ lua_gc(L, LUA_GCSTOP, 0); /* stop collector during parsing */
+ tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
+ &p->buff, p->name);
+ cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
+@@ -502,6 +503,7 @@
+ cl->l.upvals[i] = luaF_newupval(L);
+ setclvalue(L, L->top, cl);
+ incr_top(L);
++ lua_gc(L, LUA_GCRESTART, 0);
+ }
+
+
+--- a/src/lgc.c
++++ b/src/lgc.c
+@@ -437,7 +437,10 @@
+ /* check size of buffer */
+ if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
+ size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
+- luaZ_resizebuffer(L, &g->buff, newsize);
++ /* make sure newsize is larger then the buffer's in use size. */
++ newsize = (luaZ_bufflen(&g->buff) > newsize) ? luaZ_bufflen(&g->buff) : newsize;
++ if(newsize < luaZ_sizebuffer(&g->buff))
++ luaZ_resizebuffer(L, &g->buff, newsize);
+ }
+ }
+
+--- a/src/lstate.c
++++ b/src/lstate.c
+@@ -118,7 +118,6 @@
+
+ lua_State *luaE_newthread (lua_State *L) {
+ lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
+- luaC_link(L, obj2gco(L1), LUA_TTHREAD);
+ preinit_state(L1, G(L));
+ stack_init(L1, L); /* init stack */
+ setobj2n(L, gt(L1), gt(L)); /* share table of globals */
+@@ -126,6 +125,7 @@
+ L1->basehookcount = L->basehookcount;
+ L1->hook = L->hook;
+ resethookcount(L1);
++ luaC_link(L, obj2gco(L1), LUA_TTHREAD);
+ lua_assert(iswhite(obj2gco(L1)));
+ return L1;
+ }
+--- a/src/lstring.c
++++ b/src/lstring.c
+@@ -53,6 +53,9 @@
+ stringtable *tb;
+ if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
+ luaM_toobig(L);
++ tb = &G(L)->strt;
++ if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
++ luaS_resize(L, tb->size*2); /* too crowded */
+ ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
+ ts->tsv.len = l;
+ ts->tsv.hash = h;
+@@ -61,13 +64,10 @@
+ ts->tsv.reserved = 0;
+ memcpy(ts+1, str, l*sizeof(char));
+ ((char *)(ts+1))[l] = '\0'; /* ending 0 */
+- tb = &G(L)->strt;
+ h = lmod(h, tb->size);
+ ts->tsv.next = tb->hash[h]; /* chain new entry */
+ tb->hash[h] = obj2gco(ts);
+ tb->nuse++;
+- if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
+- luaS_resize(L, tb->size*2); /* too crowded */
+ return ts;
+ }
+
+--- a/src/ltable.c
++++ b/src/ltable.c
+@@ -371,7 +371,6 @@
+
+ Table *luaH_new (lua_State *L, int narray, int nhash) {
+ Table *t = luaM_new(L, Table);
+- luaC_link(L, obj2gco(t), LUA_TTABLE);
+ t->metatable = NULL;
+ t->flags = cast_byte(~0);
+ /* temporary values (kept only if some malloc fails) */
+@@ -381,6 +380,7 @@
+ t->node = cast(Node *, dummynode);
+ setarrayvector(L, t, narray);
+ setnodevector(L, t, nhash);
++ luaC_link(L, obj2gco(t), LUA_TTABLE);
+ return t;
+ }
+
+--- a/src/lvm.c
++++ b/src/lvm.c
+@@ -375,6 +375,7 @@
+ if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
+ tl += l;
+ }
++ G(L)->buff.n = tl;
+ buffer = luaZ_openspace(L, &G(L)->buff, tl);
+ tl = 0;
+ for (i=n; i>0; i--) { /* concat all strings */
+@@ -383,6 +384,7 @@
+ tl += l;
+ }
+ setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
++ luaZ_resetbuffer(&G(L)->buff);
+ }
+ total -= n-1; /* got `n' strings to create 1 new */
+ last -= n-1;
+--- a/src/lua.c
++++ b/src/lua.c
+@@ -19,6 +19,82 @@
+ #include "llimits.h"
+
+
++typedef struct {
++ char *name;
++ lua_State *L;
++ size_t memused;
++ size_t peak_memused;
++ size_t max_memused;
++ int collecting;
++} script_info_t;
++
++
++static void *script_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
++{
++ script_info_t *info=(script_info_t *)ud;
++ size_t old_size = info->memused;
++
++ info->memused -= osize;
++ if (nsize == 0) {
++ free(ptr);
++ return NULL;
++ }
++ info->memused += nsize;
++ if(info->max_memused > 0 && nsize > osize && info->memused >= info->max_memused) {
++#ifdef LOW_MEM_DEBUG
++ printf("LOW MEM: 1 osize=%zd, nsize=%zd, used=%zu, peak=%zu, need=%zd\n", osize, nsize,
++ info->memused, info->peak_memused, (info->memused - info->max_memused));
++#endif
++ info->memused = old_size;
++ /* don't allow a recursive garbage collection call. */
++ if(info->collecting != 0) {
++ return NULL;
++ }
++ info->collecting = 1;
++ /* try to free memory by collecting garbage. */
++ lua_gc(info->L, LUA_GCCOLLECT, 0);
++ info->collecting = 0;
++#ifdef LOW_MEM_DEBUG
++ printf("LOW MEM: 2 used=%zu, peak=%zu\n", info->memused, info->peak_memused);
++#endif
++ /* check memory usage again. */
++ old_size = info->memused;
++ info->memused -= osize;
++ info->memused += nsize;
++ if(info->memused >= info->max_memused) {
++ info->memused = old_size;
++#ifdef LOW_MEM_DEBUG
++ printf("OUT OF MEMORY: memused=%zd, osize=%zd, nsize=%zd\n", info->memused, osize, nsize);
++#endif
++ return NULL;
++ }
++ }
++ if(info->memused > info->peak_memused) info->peak_memused = info->memused;
++ return realloc(ptr, nsize);
++}
++
++static int set_memory_limit(lua_State *L)
++{
++ int limit = luaL_checknumber(L, 1);
++ script_info_t *info;
++ lua_getallocf(L, (void *)(&info));
++
++ if( limit >= 0 )
++ info->max_memused = limit;
++
++ lua_pushnumber(L, limit);
++ return 1;
++}
++
++static int get_memory_limit(lua_State *L)
++{
++ script_info_t *info;
++ lua_getallocf(L, (void *)(&info));
++ lua_pushnumber(L, info->max_memused);
++ return 1;
++}
++
++
+ static lua_State *globalL = NULL;
+
+ static const char *progname = LUA_PROGNAME;
+@@ -377,11 +453,28 @@
+ int main (int argc, char **argv) {
+ int status;
+ struct Smain s;
+- lua_State *L = lua_open(); /* create state */
++ script_info_t *info;
++
++ info = (script_info_t *)calloc(1, sizeof(script_info_t));
++ info->max_memused = 0;
++ info->collecting = 0;
++ info->name = argv[0];
++ info->memused = 0;
++ info->peak_memused = 0;
++
++ lua_State *L = lua_newstate(script_alloc, info);
++
+ if (L == NULL) {
+ l_message(argv[0], "cannot create state: not enough memory");
+ return EXIT_FAILURE;
+ }
++
++ info->L = L;
++
++ luaL_openlibs(L);
++ lua_register(L, "set_memory_limit", set_memory_limit);
++ lua_register(L, "get_memory_limit", get_memory_limit);
++
+ /* Checking 'sizeof(lua_Integer)' cannot be made in preprocessor on all compilers.
+ */
+ #ifdef LNUM_INT16
+@@ -396,6 +489,14 @@
+ status = lua_cpcall(L, &pmain, &s);
+ report(L, status);
+ lua_close(L);
++
++#ifdef LOW_MEM_DEBUG
++ printf("%s: memused=%zd, peak_memused=%zd\n", info->name,
++ info->memused, info->peak_memused);
++#endif
++
++ free(info);
++
+ return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
+ }
+
diff --git a/package/lua/patches/300-opcode_performance.patch b/package/lua/patches/300-opcode_performance.patch
index f6204ae19b..fb1f9a1ea7 100644
--- a/package/lua/patches/300-opcode_performance.patch
+++ b/package/lua/patches/300-opcode_performance.patch
@@ -10,7 +10,7 @@
/*
* If 'obj' is a string, it is tried to be interpreted as a number.
-@@ -562,12 +565,63 @@
+@@ -564,12 +567,63 @@
ARITH_OP1_END
#endif
@@ -74,7 +74,7 @@
reentry: /* entry point */
lua_assert(isLua(L->ci));
pc = L->savedpc;
-@@ -592,33 +646,33 @@
+@@ -594,33 +648,33 @@
lua_assert(base == L->base && L->base == L->ci->base);
lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
lua_assert(L->top == L->ci->top || luaG_checkopenop(i));
@@ -115,7 +115,7 @@
TValue g;
TValue *rb = KBx(i);
sethvalue(L, &g, cl->env);
-@@ -626,88 +680,88 @@
+@@ -628,88 +682,88 @@
Protect(luaV_gettable(L, &g, rb, ra));
continue;
}
@@ -219,7 +219,7 @@
const TValue *rb = RB(i);
switch (ttype(rb)) {
case LUA_TTABLE: {
-@@ -727,18 +781,18 @@
+@@ -729,18 +783,18 @@
}
continue;
}
@@ -241,7 +241,7 @@
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
-@@ -748,7 +802,7 @@
+@@ -750,7 +804,7 @@
pc++;
continue;
}
@@ -250,7 +250,7 @@
Protect(
if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i))
dojump(L, pc, GETARG_sBx(*pc));
-@@ -756,7 +810,7 @@
+@@ -758,7 +812,7 @@
pc++;
continue;
}
@@ -259,7 +259,7 @@
Protect(
if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i))
dojump(L, pc, GETARG_sBx(*pc));
-@@ -764,13 +818,13 @@
+@@ -766,13 +820,13 @@
pc++;
continue;
}
@@ -275,7 +275,7 @@
TValue *rb = RB(i);
if (l_isfalse(rb) != GETARG_C(i)) {
setobjs2s(L, ra, rb);
-@@ -779,7 +833,7 @@
+@@ -781,7 +835,7 @@
pc++;
continue;
}
@@ -284,7 +284,7 @@
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0) L->top = ra+b; /* else previous instruction set top */
-@@ -800,7 +854,7 @@
+@@ -802,7 +856,7 @@
}
}
}
@@ -293,7 +293,7 @@
int b = GETARG_B(i);
if (b != 0) L->top = ra+b; /* else previous instruction set top */
L->savedpc = pc;
-@@ -832,7 +886,7 @@
+@@ -834,7 +888,7 @@
}
}
}
@@ -302,7 +302,7 @@
int b = GETARG_B(i);
if (b != 0) L->top = ra+b-1;
if (L->openupval) luaF_close(L, base);
-@@ -847,7 +901,7 @@
+@@ -849,7 +903,7 @@
goto reentry;
}
}
@@ -311,7 +311,7 @@
/* If start,step and limit are all integers, we don't need to check
* against overflow in the looping.
*/
-@@ -875,7 +929,7 @@
+@@ -877,7 +931,7 @@
}
continue;
}
@@ -320,7 +320,7 @@
const TValue *init = ra;
const TValue *plimit = ra+1;
const TValue *pstep = ra+2;
-@@ -898,7 +952,7 @@
+@@ -900,7 +954,7 @@
dojump(L, pc, GETARG_sBx(i));
continue;
}
@@ -329,7 +329,7 @@
StkId cb = ra + 3; /* call base */
setobjs2s(L, cb+2, ra+2);
setobjs2s(L, cb+1, ra+1);
-@@ -914,7 +968,7 @@
+@@ -916,7 +970,7 @@
pc++;
continue;
}
@@ -338,7 +338,7 @@
int n = GETARG_B(i);
int c = GETARG_C(i);
int last;
-@@ -936,11 +990,11 @@
+@@ -938,11 +992,11 @@
}
continue;
}
@@ -352,7 +352,7 @@
Proto *p;
Closure *ncl;
int nup, j;
-@@ -960,7 +1014,7 @@
+@@ -962,7 +1016,7 @@
Protect(luaC_checkGC(L));
continue;
}