bc6526b3f7cedc0e4770bdea8d097997136a03e9
[openwrt/svn-archive/archive.git] / package / lua / patches / 040-memory-limits.patch
1 --- a/src/lapi.c
2 +++ b/src/lapi.c
3 @@ -716,14 +716,14 @@
4
5 LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
6 StkId t;
7 - TValue key;
8 lua_lock(L);
9 api_checknelems(L, 1);
10 t = index2adr(L, idx);
11 api_checkvalidindex(L, t);
12 - setsvalue(L, &key, luaS_new(L, k));
13 - luaV_settable(L, t, &key, L->top - 1);
14 - L->top--; /* pop value */
15 + setsvalue2s(L, L->top, luaS_new(L, k));
16 + api_incr_top(L);
17 + luaV_settable(L, t, L->top - 1, L->top - 2);
18 + L->top -= 2; /* pop key and value */
19 lua_unlock(L);
20 }
21
22 @@ -971,7 +971,12 @@
23 break;
24 }
25 case LUA_GCCOLLECT: {
26 - luaC_fullgc(L);
27 + lu_mem old_thres = g->GCthreshold;
28 + if(g->GCthreshold != MAX_LUMEM) {
29 + g->GCthreshold = MAX_LUMEM;
30 + luaC_fullgc(L);
31 + g->GCthreshold = old_thres;
32 + }
33 break;
34 }
35 case LUA_GCCOUNT: {
36 --- a/src/ldo.c
37 +++ b/src/ldo.c
38 @@ -494,6 +494,7 @@
39 struct SParser *p = cast(struct SParser *, ud);
40 int c = luaZ_lookahead(p->z);
41 luaC_checkGC(L);
42 + lua_gc(L, LUA_GCSTOP, 0); /* stop collector during parsing */
43 tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z,
44 &p->buff, p->name);
45 cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L)));
46 @@ -502,6 +503,7 @@
47 cl->l.upvals[i] = luaF_newupval(L);
48 setclvalue(L, L->top, cl);
49 incr_top(L);
50 + lua_gc(L, LUA_GCRESTART, 0);
51 }
52
53
54 --- a/src/lgc.c
55 +++ b/src/lgc.c
56 @@ -437,7 +437,10 @@
57 /* check size of buffer */
58 if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
59 size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
60 - luaZ_resizebuffer(L, &g->buff, newsize);
61 + /* make sure newsize is larger then the buffer's in use size. */
62 + newsize = (luaZ_bufflen(&g->buff) > newsize) ? luaZ_bufflen(&g->buff) : newsize;
63 + if(newsize < luaZ_sizebuffer(&g->buff))
64 + luaZ_resizebuffer(L, &g->buff, newsize);
65 }
66 }
67
68 --- a/src/lstate.c
69 +++ b/src/lstate.c
70 @@ -118,7 +118,6 @@
71
72 lua_State *luaE_newthread (lua_State *L) {
73 lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));
74 - luaC_link(L, obj2gco(L1), LUA_TTHREAD);
75 preinit_state(L1, G(L));
76 stack_init(L1, L); /* init stack */
77 setobj2n(L, gt(L1), gt(L)); /* share table of globals */
78 @@ -126,6 +125,7 @@
79 L1->basehookcount = L->basehookcount;
80 L1->hook = L->hook;
81 resethookcount(L1);
82 + luaC_link(L, obj2gco(L1), LUA_TTHREAD);
83 lua_assert(iswhite(obj2gco(L1)));
84 return L1;
85 }
86 --- a/src/lstring.c
87 +++ b/src/lstring.c
88 @@ -53,6 +53,9 @@
89 stringtable *tb;
90 if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
91 luaM_toobig(L);
92 + tb = &G(L)->strt;
93 + if ((tb->nuse + 1) > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
94 + luaS_resize(L, tb->size*2); /* too crowded */
95 ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString)));
96 ts->tsv.len = l;
97 ts->tsv.hash = h;
98 @@ -61,13 +64,10 @@
99 ts->tsv.reserved = 0;
100 memcpy(ts+1, str, l*sizeof(char));
101 ((char *)(ts+1))[l] = '\0'; /* ending 0 */
102 - tb = &G(L)->strt;
103 h = lmod(h, tb->size);
104 ts->tsv.next = tb->hash[h]; /* chain new entry */
105 tb->hash[h] = obj2gco(ts);
106 tb->nuse++;
107 - if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
108 - luaS_resize(L, tb->size*2); /* too crowded */
109 return ts;
110 }
111
112 --- a/src/ltable.c
113 +++ b/src/ltable.c
114 @@ -371,7 +371,6 @@
115
116 Table *luaH_new (lua_State *L, int narray, int nhash) {
117 Table *t = luaM_new(L, Table);
118 - luaC_link(L, obj2gco(t), LUA_TTABLE);
119 t->metatable = NULL;
120 t->flags = cast_byte(~0);
121 /* temporary values (kept only if some malloc fails) */
122 @@ -381,6 +380,7 @@
123 t->node = cast(Node *, dummynode);
124 setarrayvector(L, t, narray);
125 setnodevector(L, t, nhash);
126 + luaC_link(L, obj2gco(t), LUA_TTABLE);
127 return t;
128 }
129
130 --- a/src/lvm.c
131 +++ b/src/lvm.c
132 @@ -375,6 +375,7 @@
133 if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
134 tl += l;
135 }
136 + G(L)->buff.n = tl;
137 buffer = luaZ_openspace(L, &G(L)->buff, tl);
138 tl = 0;
139 for (i=n; i>0; i--) { /* concat all strings */
140 @@ -383,6 +384,7 @@
141 tl += l;
142 }
143 setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
144 + luaZ_resetbuffer(&G(L)->buff);
145 }
146 total -= n-1; /* got `n' strings to create 1 new */
147 last -= n-1;
148 --- a/src/lua.c
149 +++ b/src/lua.c
150 @@ -19,6 +19,94 @@
151 #include "llimits.h"
152
153
154 +typedef struct {
155 + char *name;
156 + lua_State *L;
157 + size_t memused;
158 + size_t peak_memused;
159 + size_t gc_memused;
160 + size_t max_memused;
161 + int collecting;
162 +} script_info_t;
163 +
164 +
165 +static void *script_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
166 +{
167 + script_info_t *info=(script_info_t *)ud;
168 + size_t old_size = info->memused;
169 +
170 + info->memused -= osize;
171 + if (nsize == 0) {
172 + free(ptr);
173 + return NULL;
174 + }
175 + info->memused += nsize;
176 + if(info->max_memused > 0 && nsize > osize &&
177 + (info->memused >= info->max_memused || info->memused >= info->gc_memused)) {
178 +#ifdef LOW_MEM_DEBUG
179 + printf("LOW MEM: 1 osize=%zd, nsize=%zd, used=%zu, peak=%zu, need=%zd\n", osize, nsize,
180 + info->memused, info->peak_memused, (info->memused - info->max_memused));
181 +#endif
182 + info->memused = old_size;
183 + /* don't allow a recursive garbage collection call. */
184 + if(info->collecting != 0) {
185 + return NULL;
186 + }
187 + info->collecting = 1;
188 + /* try to free memory by collecting garbage. */
189 + lua_gc(info->L, LUA_GCCOLLECT, 0);
190 + info->collecting = 0;
191 +#ifdef LOW_MEM_DEBUG
192 + printf("LOW MEM: 2 used=%zu, peak=%zu\n", info->memused, info->peak_memused);
193 +#endif
194 + /* check memory usage again. */
195 + old_size = info->memused;
196 + info->memused -= osize;
197 + info->memused += nsize;
198 + if(info->memused >= info->max_memused) {
199 + info->memused = old_size;
200 +#ifdef LOW_MEM_DEBUG
201 + printf("OUT OF MEMORY: memused=%zd, osize=%zd, nsize=%zd\n", info->memused, osize, nsize);
202 +#endif
203 + return NULL;
204 + }
205 + }
206 + if(info->memused > info->peak_memused) info->peak_memused = info->memused;
207 + return realloc(ptr, nsize);
208 +}
209 +
210 +static int set_memory_limit(lua_State *L)
211 +{
212 + int hardlimit = luaL_checknumber(L, 1);
213 + int softlimit = luaL_optnumber(L, 2, 0);
214 +
215 + script_info_t *info;
216 + lua_getallocf(L, (void *)(&info));
217 +
218 + if( hardlimit >= 0 )
219 + {
220 + if( softlimit <= 0 )
221 + softlimit = (int)((float)hardlimit * 0.75);
222 +
223 + info->max_memused = hardlimit;
224 + info->gc_memused = softlimit;
225 + }
226 +
227 + lua_pushnumber(L, hardlimit);
228 + lua_pushnumber(L, softlimit);
229 + return 2;
230 +}
231 +
232 +static int get_memory_limit(lua_State *L)
233 +{
234 + script_info_t *info;
235 + lua_getallocf(L, (void *)(&info));
236 + lua_pushnumber(L, info->max_memused);
237 + lua_pushnumber(L, info->gc_memused);
238 + return 2;
239 +}
240 +
241 +
242 static lua_State *globalL = NULL;
243
244 static const char *progname = LUA_PROGNAME;
245 @@ -377,11 +465,28 @@
246 int main (int argc, char **argv) {
247 int status;
248 struct Smain s;
249 - lua_State *L = lua_open(); /* create state */
250 + script_info_t *info;
251 +
252 + info = (script_info_t *)calloc(1, sizeof(script_info_t));
253 + info->max_memused = 0;
254 + info->collecting = 0;
255 + info->name = argv[0];
256 + info->memused = 0;
257 + info->peak_memused = 0;
258 +
259 + lua_State *L = lua_newstate(script_alloc, info);
260 +
261 if (L == NULL) {
262 l_message(argv[0], "cannot create state: not enough memory");
263 return EXIT_FAILURE;
264 }
265 +
266 + info->L = L;
267 +
268 + luaL_openlibs(L);
269 + lua_register(L, "set_memory_limit", set_memory_limit);
270 + lua_register(L, "get_memory_limit", get_memory_limit);
271 +
272 /* Checking 'sizeof(lua_Integer)' cannot be made in preprocessor on all compilers.
273 */
274 #ifdef LNUM_INT16
275 @@ -396,6 +501,14 @@
276 status = lua_cpcall(L, &pmain, &s);
277 report(L, status);
278 lua_close(L);
279 +
280 +#ifdef LOW_MEM_DEBUG
281 + printf("%s: memused=%zd, peak_memused=%zd\n", info->name,
282 + info->memused, info->peak_memused);
283 +#endif
284 +
285 + free(info);
286 +
287 return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
288 }
289