diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2006-07-11 12:53:29 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2006-07-11 12:53:29 -0300 |
commit | 3ca9af51a4f060cf2178901a67a21f8269af3224 (patch) | |
tree | 4f1bb541280aa8b4960b16d0925eca60adb2b1a8 /lgc.c | |
parent | c7b89dd28097296bbc14d9b47b4cea72514b2b76 (diff) | |
download | lua-3ca9af51a4f060cf2178901a67a21f8269af3224.tar.gz lua-3ca9af51a4f060cf2178901a67a21f8269af3224.tar.bz2 lua-3ca9af51a4f060cf2178901a67a21f8269af3224.zip |
emergency garbage collector (core forces a GC when allocation fails)
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 76 |
1 files changed, 46 insertions, 30 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.37 2005/12/22 16:19:56 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.38 2006/05/24 14:34:06 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -52,7 +52,7 @@ | |||
52 | #define markvalue(g,o) { checkconsistency(o); \ | 52 | #define markvalue(g,o) { checkconsistency(o); \ |
53 | if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } | 53 | if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } |
54 | 54 | ||
55 | #define markobject(g,t) { if (iswhite(obj2gco(t))) \ | 55 | #define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ |
56 | reallymarkobject(g, obj2gco(t)); } | 56 | reallymarkobject(g, obj2gco(t)); } |
57 | 57 | ||
58 | 58 | ||
@@ -76,7 +76,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
76 | case LUA_TUSERDATA: { | 76 | case LUA_TUSERDATA: { |
77 | Table *mt = gco2u(o)->metatable; | 77 | Table *mt = gco2u(o)->metatable; |
78 | gray2black(o); /* udata are never gray */ | 78 | gray2black(o); /* udata are never gray */ |
79 | if (mt) markobject(g, mt); | 79 | markobject(g, mt); |
80 | markobject(g, gco2u(o)->env); | 80 | markobject(g, gco2u(o)->env); |
81 | return; | 81 | return; |
82 | } | 82 | } |
@@ -160,8 +160,7 @@ static int traversetable (global_State *g, Table *h) { | |||
160 | int weakkey = 0; | 160 | int weakkey = 0; |
161 | int weakvalue = 0; | 161 | int weakvalue = 0; |
162 | const TValue *mode; | 162 | const TValue *mode; |
163 | if (h->metatable) | 163 | markobject(g, h->metatable); |
164 | markobject(g, h->metatable); | ||
165 | mode = gfasttm(g, h->metatable, TM_MODE); | 164 | mode = gfasttm(g, h->metatable, TM_MODE); |
166 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ | 165 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ |
167 | weakkey = (strchr(svalue(mode), 'k') != NULL); | 166 | weakkey = (strchr(svalue(mode), 'k') != NULL); |
@@ -209,10 +208,8 @@ static void traverseproto (global_State *g, Proto *f) { | |||
209 | if (f->upvalues[i]) | 208 | if (f->upvalues[i]) |
210 | stringmark(f->upvalues[i]); | 209 | stringmark(f->upvalues[i]); |
211 | } | 210 | } |
212 | for (i=0; i<f->sizep; i++) { /* mark nested protos */ | 211 | for (i=0; i<f->sizep; i++) /* mark nested protos */ |
213 | if (f->p[i]) | 212 | markobject(g, f->p[i]); |
214 | markobject(g, f->p[i]); | ||
215 | } | ||
216 | for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ | 213 | for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ |
217 | if (f->locvars[i].varname) | 214 | if (f->locvars[i].varname) |
218 | stringmark(f->locvars[i].varname); | 215 | stringmark(f->locvars[i].varname); |
@@ -256,6 +253,8 @@ static void checkstacksizes (lua_State *L, StkId max) { | |||
256 | static void traversestack (global_State *g, lua_State *l) { | 253 | static void traversestack (global_State *g, lua_State *l) { |
257 | StkId o, lim; | 254 | StkId o, lim; |
258 | CallInfo *ci; | 255 | CallInfo *ci; |
256 | if (l->stack == NULL || l->base_ci == NULL) | ||
257 | return; /* stack not completely built yet */ | ||
259 | markvalue(g, gt(l)); | 258 | markvalue(g, gt(l)); |
260 | lim = l->top; | 259 | lim = l->top; |
261 | for (ci = l->base_ci; ci <= l->ci; ci++) { | 260 | for (ci = l->base_ci; ci <= l->ci; ci++) { |
@@ -266,7 +265,8 @@ static void traversestack (global_State *g, lua_State *l) { | |||
266 | markvalue(g, o); | 265 | markvalue(g, o); |
267 | for (; o <= lim; o++) | 266 | for (; o <= lim; o++) |
268 | setnilvalue(o); | 267 | setnilvalue(o); |
269 | checkstacksizes(l, lim); | 268 | if (!g->emergencygc) /* cannot change stack in emergency... */ |
269 | checkstacksizes(l, lim); /* ...(interpreter does not expect that change) */ | ||
270 | } | 270 | } |
271 | 271 | ||
272 | 272 | ||
@@ -442,11 +442,9 @@ static void checkSizes (lua_State *L) { | |||
442 | } | 442 | } |
443 | 443 | ||
444 | 444 | ||
445 | static void GCTM (lua_State *L) { | 445 | static Udata *udata2finalize (global_State *g) { |
446 | global_State *g = G(L); | ||
447 | GCObject *o = g->tmudata->gch.next; /* get first element */ | 446 | GCObject *o = g->tmudata->gch.next; /* get first element */ |
448 | Udata *udata = rawgco2u(o); | 447 | Udata *udata = rawgco2u(o); |
449 | const TValue *tm; | ||
450 | /* remove udata from `tmudata' */ | 448 | /* remove udata from `tmudata' */ |
451 | if (o == g->tmudata) /* last element? */ | 449 | if (o == g->tmudata) /* last element? */ |
452 | g->tmudata = NULL; | 450 | g->tmudata = NULL; |
@@ -455,7 +453,14 @@ static void GCTM (lua_State *L) { | |||
455 | udata->uv.next = g->mainthread->next; /* return it to `root' list */ | 453 | udata->uv.next = g->mainthread->next; /* return it to `root' list */ |
456 | g->mainthread->next = o; | 454 | g->mainthread->next = o; |
457 | makewhite(g, o); | 455 | makewhite(g, o); |
458 | tm = fasttm(L, udata->uv.metatable, TM_GC); | 456 | return udata; |
457 | } | ||
458 | |||
459 | |||
460 | static void GCTM (lua_State *L) { | ||
461 | global_State *g = G(L); | ||
462 | Udata *udata = udata2finalize(g); | ||
463 | const TValue *tm = fasttm(L, udata->uv.metatable, TM_GC); | ||
459 | if (tm != NULL) { | 464 | if (tm != NULL) { |
460 | lu_byte oldah = L->allowhook; | 465 | lu_byte oldah = L->allowhook; |
461 | lu_mem oldt = g->GCthreshold; | 466 | lu_mem oldt = g->GCthreshold; |
@@ -475,8 +480,17 @@ static void GCTM (lua_State *L) { | |||
475 | ** Call all GC tag methods | 480 | ** Call all GC tag methods |
476 | */ | 481 | */ |
477 | void luaC_callGCTM (lua_State *L) { | 482 | void luaC_callGCTM (lua_State *L) { |
478 | while (G(L)->tmudata) | 483 | global_State *g = G(L); |
484 | GCObject *last = g->tmudata; | ||
485 | GCObject *curr; | ||
486 | if (last == NULL) return; /* empty list? */ | ||
487 | do { | ||
488 | curr = g->tmudata->gch.next; /* element to be collected */ | ||
479 | GCTM(L); | 489 | GCTM(L); |
490 | } while (curr != last); /* go only until original last */ | ||
491 | /* do not finalize new udata created during previous finalizations */ | ||
492 | while (g->tmudata) | ||
493 | udata2finalize(g); /* simply remove them from list */ | ||
480 | } | 494 | } |
481 | 495 | ||
482 | 496 | ||
@@ -493,7 +507,7 @@ void luaC_freeall (lua_State *L) { | |||
493 | static void markmt (global_State *g) { | 507 | static void markmt (global_State *g) { |
494 | int i; | 508 | int i; |
495 | for (i=0; i<NUM_TAGS; i++) | 509 | for (i=0; i<NUM_TAGS; i++) |
496 | if (g->mt[i]) markobject(g, g->mt[i]); | 510 | markobject(g, g->mt[i]); |
497 | } | 511 | } |
498 | 512 | ||
499 | 513 | ||
@@ -553,6 +567,10 @@ static void atomic (lua_State *L) { | |||
553 | } | 567 | } |
554 | 568 | ||
555 | 569 | ||
570 | #define correctestimate(g,s) {lu_mem old = g->totalbytes; s; \ | ||
571 | lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes;} | ||
572 | |||
573 | |||
556 | static l_mem singlestep (lua_State *L) { | 574 | static l_mem singlestep (lua_State *L) { |
557 | global_State *g = G(L); | 575 | global_State *g = G(L); |
558 | /*lua_checkmemory(L);*/ | 576 | /*lua_checkmemory(L);*/ |
@@ -570,23 +588,15 @@ static l_mem singlestep (lua_State *L) { | |||
570 | } | 588 | } |
571 | } | 589 | } |
572 | case GCSsweepstring: { | 590 | case GCSsweepstring: { |
573 | lu_mem old = g->totalbytes; | 591 | correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++])); |
574 | sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); | ||
575 | if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ | 592 | if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ |
576 | g->gcstate = GCSsweep; /* end sweep-string phase */ | 593 | g->gcstate = GCSsweep; /* end sweep-string phase */ |
577 | lua_assert(old >= g->totalbytes); | ||
578 | g->estimate -= old - g->totalbytes; | ||
579 | return GCSWEEPCOST; | 594 | return GCSWEEPCOST; |
580 | } | 595 | } |
581 | case GCSsweep: { | 596 | case GCSsweep: { |
582 | lu_mem old = g->totalbytes; | 597 | correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX)); |
583 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); | 598 | if (*g->sweepgc == NULL) /* nothing more to sweep? */ |
584 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | ||
585 | checkSizes(L); | ||
586 | g->gcstate = GCSfinalize; /* end sweep phase */ | 599 | g->gcstate = GCSfinalize; /* end sweep phase */ |
587 | } | ||
588 | lua_assert(old >= g->totalbytes); | ||
589 | g->estimate -= old - g->totalbytes; | ||
590 | return GCSWEEPMAX*GCSWEEPCOST; | 600 | return GCSWEEPMAX*GCSWEEPCOST; |
591 | } | 601 | } |
592 | case GCSfinalize: { | 602 | case GCSfinalize: { |
@@ -597,6 +607,7 @@ static l_mem singlestep (lua_State *L) { | |||
597 | return GCFINALIZECOST; | 607 | return GCFINALIZECOST; |
598 | } | 608 | } |
599 | else { | 609 | else { |
610 | correctestimate(g, checkSizes(L)); | ||
600 | g->gcstate = GCSpause; /* end collection */ | 611 | g->gcstate = GCSpause; /* end collection */ |
601 | g->gcdept = 0; | 612 | g->gcdept = 0; |
602 | return 0; | 613 | return 0; |
@@ -610,6 +621,7 @@ static l_mem singlestep (lua_State *L) { | |||
610 | void luaC_step (lua_State *L) { | 621 | void luaC_step (lua_State *L) { |
611 | global_State *g = G(L); | 622 | global_State *g = G(L); |
612 | l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; | 623 | l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; |
624 | lua_assert(!g->emergencygc); | ||
613 | if (lim == 0) | 625 | if (lim == 0) |
614 | lim = (MAX_LUMEM-1)/2; /* no limit */ | 626 | lim = (MAX_LUMEM-1)/2; /* no limit */ |
615 | g->gcdept += g->totalbytes - g->GCthreshold; | 627 | g->gcdept += g->totalbytes - g->GCthreshold; |
@@ -633,8 +645,10 @@ void luaC_step (lua_State *L) { | |||
633 | } | 645 | } |
634 | 646 | ||
635 | 647 | ||
636 | void luaC_fullgc (lua_State *L) { | 648 | void luaC_fullgc (lua_State *L, int isemergency) { |
649 | int stopstate; | ||
637 | global_State *g = G(L); | 650 | global_State *g = G(L); |
651 | g->emergencygc = isemergency; | ||
638 | if (g->gcstate <= GCSpropagate) { | 652 | if (g->gcstate <= GCSpropagate) { |
639 | /* reset sweep marks to sweep all elements (returning them to white) */ | 653 | /* reset sweep marks to sweep all elements (returning them to white) */ |
640 | g->sweepstrgc = 0; | 654 | g->sweepstrgc = 0; |
@@ -652,10 +666,12 @@ void luaC_fullgc (lua_State *L) { | |||
652 | singlestep(L); | 666 | singlestep(L); |
653 | } | 667 | } |
654 | markroot(L); | 668 | markroot(L); |
655 | while (g->gcstate != GCSpause) { | 669 | /* do not run finalizers during emergency GC */ |
670 | stopstate = isemergency ? GCSfinalize : GCSpause; | ||
671 | while (g->gcstate != stopstate) | ||
656 | singlestep(L); | 672 | singlestep(L); |
657 | } | ||
658 | setthreshold(g); | 673 | setthreshold(g); |
674 | g->emergencygc = 0; | ||
659 | } | 675 | } |
660 | 676 | ||
661 | 677 | ||