diff options
-rw-r--r-- | lgc.c | 49 | ||||
-rw-r--r-- | lstate.c | 4 | ||||
-rw-r--r-- | lstate.h | 3 |
3 files changed, 31 insertions, 25 deletions
@@ -136,6 +136,8 @@ static void markudet (lua_State *L, GCState *st) { | |||
136 | Udata *u; | 136 | Udata *u; |
137 | for (u = G(L)->rootudata; u; u = u->uv.next) | 137 | for (u = G(L)->rootudata; u; u = u->uv.next) |
138 | marktable(st, u->uv.eventtable); | 138 | marktable(st, u->uv.eventtable); |
139 | for (u = G(L)->tmudata; u; u = u->uv.next) | ||
140 | marktable(st, u->uv.eventtable); | ||
139 | } | 141 | } |
140 | 142 | ||
141 | 143 | ||
@@ -290,27 +292,30 @@ static void collecttable (lua_State *L) { | |||
290 | } | 292 | } |
291 | 293 | ||
292 | 294 | ||
293 | static Udata *collectudata (lua_State *L, int keep) { | 295 | static void collectudata (lua_State *L) { |
294 | Udata **p = &G(L)->rootudata; | 296 | Udata **p = &G(L)->rootudata; |
295 | Udata *curr; | 297 | Udata *curr; |
296 | Udata *collected = NULL; | 298 | Udata *collected = NULL; /* to collect udata with gc event */ |
299 | Udata **lastcollected = &collected; | ||
297 | while ((curr = *p) != NULL) { | 300 | while ((curr = *p) != NULL) { |
298 | if (isudmarked(curr)) { | 301 | if (isudmarked(curr)) { |
299 | unmarkud(curr); | 302 | unmarkud(curr); |
300 | p = &curr->uv.next; | 303 | p = &curr->uv.next; |
301 | } | 304 | } |
302 | else { /* collect */ | 305 | else { |
303 | const TObject *tm = fasttm(L, curr->uv.eventtable, TM_GC); | ||
304 | *p = curr->uv.next; | 306 | *p = curr->uv.next; |
305 | if (keep || tm != NULL) { | 307 | if (fasttm(L, curr->uv.eventtable, TM_GC) != NULL) { /* gc event? */ |
306 | curr->uv.next = collected; | 308 | curr->uv.next = NULL; /* link `curr' at the end of `collected' list */ |
307 | collected = curr; | 309 | *lastcollected = curr; |
310 | lastcollected = &curr->uv.next; | ||
308 | } | 311 | } |
309 | else /* no gc action; delete udata */ | 312 | else /* no gc event; delete udata */ |
310 | luaM_free(L, curr, sizeudata(curr->uv.len)); | 313 | luaM_free(L, curr, sizeudata(curr->uv.len)); |
311 | } | 314 | } |
312 | } | 315 | } |
313 | return collected; | 316 | /* insert collected udata with gc event into `tmudata' list */ |
317 | *lastcollected = G(L)->tmudata; | ||
318 | G(L)->tmudata = collected; | ||
314 | } | 319 | } |
315 | 320 | ||
316 | 321 | ||
@@ -365,12 +370,12 @@ static void callgcTM (lua_State *L, Udata *udata) { | |||
365 | } | 370 | } |
366 | 371 | ||
367 | 372 | ||
368 | static void callgcTMudata (lua_State *L, Udata *c) { | 373 | static void callgcTMudata (lua_State *L) { |
369 | luaD_checkstack(L, 3); | 374 | luaD_checkstack(L, 3); |
370 | L->top++; /* reserve space to keep udata while runs its gc method */ | 375 | L->top++; /* reserve space to keep udata while runs its gc method */ |
371 | while (c != NULL) { | 376 | while (G(L)->tmudata != NULL) { |
372 | Udata *udata = c; | 377 | Udata *udata = G(L)->tmudata; |
373 | c = udata->uv.next; /* remove udata from list */ | 378 | G(L)->tmudata = udata->uv.next; /* remove udata from list */ |
374 | udata->uv.next = G(L)->rootudata; /* resurect it */ | 379 | udata->uv.next = G(L)->rootudata; /* resurect it */ |
375 | G(L)->rootudata = udata; | 380 | G(L)->rootudata = udata; |
376 | setuvalue(L->top - 1, udata); | 381 | setuvalue(L->top - 1, udata); |
@@ -383,34 +388,32 @@ static void callgcTMudata (lua_State *L, Udata *c) { | |||
383 | 388 | ||
384 | 389 | ||
385 | void luaC_callallgcTM (lua_State *L) { | 390 | void luaC_callallgcTM (lua_State *L) { |
386 | if (G(L)->rootudata) { /* avoid problems with incomplete states */ | 391 | lua_assert(G(L)->tmudata == NULL); |
387 | Udata *c = collectudata(L, 1); /* collect all udata */ | 392 | G(L)->tmudata = G(L)->rootudata; /* all udata must be collected */ |
388 | callgcTMudata(L, c); /* call their GC tag methods */ | 393 | G(L)->rootudata = NULL; |
389 | } | 394 | callgcTMudata(L); /* call their GC tag methods */ |
390 | } | 395 | } |
391 | 396 | ||
392 | 397 | ||
393 | Udata *luaC_collect (lua_State *L, int all) { | 398 | void luaC_collect (lua_State *L, int all) { |
394 | Udata *c = collectudata(L, 0); | 399 | collectudata(L); |
395 | collectstrings(L, all); | 400 | collectstrings(L, all); |
396 | collecttable(L); | 401 | collecttable(L); |
397 | collectproto(L); | 402 | collectproto(L); |
398 | collectupval(L); | 403 | collectupval(L); |
399 | collectclosures(L); | 404 | collectclosures(L); |
400 | return c; | ||
401 | } | 405 | } |
402 | 406 | ||
403 | 407 | ||
404 | void luaC_collectgarbage (lua_State *L) { | 408 | void luaC_collectgarbage (lua_State *L) { |
405 | Udata *c; | ||
406 | GCState st; | 409 | GCState st; |
407 | st.tmark = NULL; | 410 | st.tmark = NULL; |
408 | st.toclear = NULL; | 411 | st.toclear = NULL; |
409 | markall(L, &st); | 412 | markall(L, &st); |
410 | cleartables(st.toclear); | 413 | cleartables(st.toclear); |
411 | c = luaC_collect(L, 0); | 414 | luaC_collect(L, 0); |
412 | checkMbuffer(L); | 415 | checkMbuffer(L); |
413 | G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ | 416 | G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ |
414 | callgcTMudata(L, c); | 417 | callgcTMudata(L); |
415 | } | 418 | } |
416 | 419 | ||
@@ -59,8 +59,9 @@ static void f_luaopen (lua_State *L, void *ud) { | |||
59 | G(L)->rootproto = NULL; | 59 | G(L)->rootproto = NULL; |
60 | G(L)->rootcl = NULL; | 60 | G(L)->rootcl = NULL; |
61 | G(L)->roottable = NULL; | 61 | G(L)->roottable = NULL; |
62 | G(L)->rootudata = NULL; | ||
63 | G(L)->rootupval = NULL; | 62 | G(L)->rootupval = NULL; |
63 | G(L)->rootudata = NULL; | ||
64 | G(L)->tmudata = NULL; | ||
64 | G(L)->nblocks = sizeof(lua_State) + sizeof(global_State); | 65 | G(L)->nblocks = sizeof(lua_State) + sizeof(global_State); |
65 | luaD_init(L, so->stacksize); /* init stack */ | 66 | luaD_init(L, so->stacksize); /* init stack */ |
66 | /* create default event table with a dummy table, and then close the loop */ | 67 | /* create default event table with a dummy table, and then close the loop */ |
@@ -118,6 +119,7 @@ static void close_state (lua_State *L, lua_State *OL) { | |||
118 | else if (G(L)) { /* last thread; close global state */ | 119 | else if (G(L)) { /* last thread; close global state */ |
119 | if (G(L)->rootudata) /* (avoid problems with incomplete states) */ | 120 | if (G(L)->rootudata) /* (avoid problems with incomplete states) */ |
120 | luaC_callallgcTM(L); /* call GC tag methods for all udata */ | 121 | luaC_callallgcTM(L); /* call GC tag methods for all udata */ |
122 | lua_assert(G(L)->tmudata == NULL); | ||
121 | luaC_collect(L, 1); /* collect all elements */ | 123 | luaC_collect(L, 1); /* collect all elements */ |
122 | lua_assert(G(L)->rootproto == NULL); | 124 | lua_assert(G(L)->rootproto == NULL); |
123 | lua_assert(G(L)->rootudata == NULL); | 125 | lua_assert(G(L)->rootudata == NULL); |
@@ -81,8 +81,9 @@ typedef struct global_State { | |||
81 | Proto *rootproto; /* list of all prototypes */ | 81 | Proto *rootproto; /* list of all prototypes */ |
82 | Closure *rootcl; /* list of all closures */ | 82 | Closure *rootcl; /* list of all closures */ |
83 | Table *roottable; /* list of all tables */ | 83 | Table *roottable; /* list of all tables */ |
84 | Udata *rootudata; /* list of all userdata */ | ||
85 | UpVal *rootupval; /* list of closed up values */ | 84 | UpVal *rootupval; /* list of closed up values */ |
85 | Udata *rootudata; /* list of all userdata */ | ||
86 | Udata *tmudata; /* list of userdata to be GC */ | ||
86 | TString *tmname[TM_N]; /* array with tag-method names */ | 87 | TString *tmname[TM_N]; /* array with tag-method names */ |
87 | } global_State; | 88 | } global_State; |
88 | 89 | ||