diff options
-rw-r--r-- | lgc.c | 104 |
1 files changed, 47 insertions, 57 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.181 2014/04/02 16:44:42 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.182 2014/04/04 17:01:04 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 | */ |
@@ -495,8 +495,7 @@ static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | |||
495 | } | 495 | } |
496 | 496 | ||
497 | 497 | ||
498 | static lu_mem traversestack (global_State *g, lua_State *th) { | 498 | static lu_mem traversethread (global_State *g, lua_State *th) { |
499 | int n = 0; | ||
500 | StkId o = th->stack; | 499 | StkId o = th->stack; |
501 | if (o == NULL) | 500 | if (o == NULL) |
502 | return 1; /* stack not completely built yet */ | 501 | return 1; /* stack not completely built yet */ |
@@ -514,16 +513,9 @@ static lu_mem traversestack (global_State *g, lua_State *th) { | |||
514 | g->twups = th; | 513 | g->twups = th; |
515 | } | 514 | } |
516 | } | 515 | } |
517 | else { | 516 | else if (g->gckind != KGC_EMERGENCY) |
518 | CallInfo *ci; | 517 | luaD_shrinkstack(th); /* do not change stack in emergency cycle */ |
519 | for (ci = &th->base_ci; ci != th->ci; ci = ci->next) | 518 | return (sizeof(lua_State) + sizeof(TValue) * th->stacksize); |
520 | n++; /* count call infos to compute size */ | ||
521 | /* should not change the stack during an emergency gc cycle */ | ||
522 | if (g->gckind != KGC_EMERGENCY) | ||
523 | luaD_shrinkstack(th); | ||
524 | } | ||
525 | return sizeof(lua_State) + sizeof(TValue) * th->stacksize + | ||
526 | sizeof(CallInfo) * n; | ||
527 | } | 519 | } |
528 | 520 | ||
529 | 521 | ||
@@ -561,7 +553,7 @@ static void propagatemark (global_State *g) { | |||
561 | th->gclist = g->grayagain; | 553 | th->gclist = g->grayagain; |
562 | g->grayagain = o; /* insert into 'grayagain' list */ | 554 | g->grayagain = o; /* insert into 'grayagain' list */ |
563 | black2gray(o); | 555 | black2gray(o); |
564 | size = traversestack(g, th); | 556 | size = traversethread(g, th); |
565 | break; | 557 | break; |
566 | } | 558 | } |
567 | case LUA_TPROTO: { | 559 | case LUA_TPROTO: { |
@@ -838,6 +830,21 @@ static void GCTM (lua_State *L, int propagateerrors) { | |||
838 | 830 | ||
839 | 831 | ||
840 | /* | 832 | /* |
833 | ** call a few (up to 'g->gcfinnum') finalizers | ||
834 | */ | ||
835 | static int runafewfinalizers (lua_State *L) { | ||
836 | global_State *g = G(L); | ||
837 | unsigned int i; | ||
838 | lua_assert(!g->tobefnz || g->gcfinnum > 0); | ||
839 | for (i = 0; g->tobefnz && i < g->gcfinnum; i++) | ||
840 | GCTM(L, 1); /* call one finalizer */ | ||
841 | g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ | ||
842 | : g->gcfinnum * 2; /* else call a few more next time */ | ||
843 | return i; | ||
844 | } | ||
845 | |||
846 | |||
847 | /* | ||
841 | ** call all pending finalizers | 848 | ** call all pending finalizers |
842 | */ | 849 | */ |
843 | static void callallpendingfinalizers (lua_State *L, int propagateerrors) { | 850 | static void callallpendingfinalizers (lua_State *L, int propagateerrors) { |
@@ -1064,10 +1071,15 @@ static lu_mem singlestep (lua_State *L) { | |||
1064 | g->gcstate = GCScallfin; | 1071 | g->gcstate = GCScallfin; |
1065 | return 0; | 1072 | return 0; |
1066 | } | 1073 | } |
1067 | case GCScallfin: { /* state to finish calling finalizers */ | 1074 | case GCScallfin: { /* call remaining finalizers */ |
1068 | /* do nothing here; this state is handled by 'luaC_step' */ | 1075 | if (g->tobefnz && g->gckind != KGC_EMERGENCY) { |
1069 | g->gcstate = GCSpause; /* finish collection */ | 1076 | int n = runafewfinalizers(L); |
1070 | return 0; | 1077 | return (n * GCFINALIZECOST); |
1078 | } | ||
1079 | else { /* emergency mode or no more finalizers */ | ||
1080 | g->gcstate = GCSpause; /* finish collection */ | ||
1081 | return 0; | ||
1082 | } | ||
1071 | } | 1083 | } |
1072 | default: lua_assert(0); return 0; | 1084 | default: lua_assert(0); return 0; |
1073 | } | 1085 | } |
@@ -1086,21 +1098,6 @@ void luaC_runtilstate (lua_State *L, int statesmask) { | |||
1086 | 1098 | ||
1087 | 1099 | ||
1088 | /* | 1100 | /* |
1089 | ** run a few (up to 'g->gcfinnum') finalizers | ||
1090 | */ | ||
1091 | static int runafewfinalizers (lua_State *L) { | ||
1092 | global_State *g = G(L); | ||
1093 | unsigned int i; | ||
1094 | lua_assert(!g->tobefnz || g->gcfinnum > 0); | ||
1095 | for (i = 0; g->tobefnz && i < g->gcfinnum; i++) | ||
1096 | GCTM(L, 1); /* call one finalizer */ | ||
1097 | g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ | ||
1098 | : g->gcfinnum * 2; /* else call a few more next time */ | ||
1099 | return i; | ||
1100 | } | ||
1101 | |||
1102 | |||
1103 | /* | ||
1104 | ** get GC debt and convert it from Kb to 'work units' (avoid zero debt | 1101 | ** get GC debt and convert it from Kb to 'work units' (avoid zero debt |
1105 | ** and overflows) | 1102 | ** and overflows) |
1106 | */ | 1103 | */ |
@@ -1117,20 +1114,14 @@ static l_mem getdebt (global_State *g) { | |||
1117 | */ | 1114 | */ |
1118 | void luaC_step (lua_State *L) { | 1115 | void luaC_step (lua_State *L) { |
1119 | global_State *g = G(L); | 1116 | global_State *g = G(L); |
1120 | l_mem debt = getdebt(g); | 1117 | l_mem debt = getdebt(g); /* GC deficit (be paid now) */ |
1121 | if (!g->gcrunning) { /* not running? */ | 1118 | if (!g->gcrunning) { /* not running? */ |
1122 | luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ | 1119 | luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ |
1123 | return; | 1120 | return; |
1124 | } | 1121 | } |
1125 | do { | 1122 | do { /* repeat until pause or enough "credit" (negative debt) */ |
1126 | if (g->gcstate == GCScallfin && g->tobefnz) { | 1123 | lu_mem work = singlestep(L); /* perform one single step */ |
1127 | unsigned int n = runafewfinalizers(L); | 1124 | debt -= work; |
1128 | debt -= (n * GCFINALIZECOST); | ||
1129 | } | ||
1130 | else { /* perform one single step */ | ||
1131 | lu_mem work = singlestep(L); | ||
1132 | debt -= work; | ||
1133 | } | ||
1134 | } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); | 1125 | } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); |
1135 | if (g->gcstate == GCSpause) | 1126 | if (g->gcstate == GCSpause) |
1136 | setpause(g); /* pause until next cycle */ | 1127 | setpause(g); /* pause until next cycle */ |
@@ -1143,31 +1134,30 @@ void luaC_step (lua_State *L) { | |||
1143 | 1134 | ||
1144 | 1135 | ||
1145 | /* | 1136 | /* |
1146 | ** performs a full GC cycle; if "isemergency", does not call | 1137 | ** Performs a full GC cycle; if "isemergency", set a flag to avoid |
1147 | ** finalizers (which could change stack positions) | 1138 | ** some operations which could change the interpreter state in some |
1139 | ** unexpected ways (running finalizers and shrinking some structures). | ||
1140 | ** Before running the collection, check 'keepinvariant'; if it is true, | ||
1141 | ** there may be some objects marked as black, so the collector has | ||
1142 | ** to sweep all objects to turn them back to white (as white has not | ||
1143 | ** changed, nothing will be collected). | ||
1148 | */ | 1144 | */ |
1149 | void luaC_fullgc (lua_State *L, int isemergency) { | 1145 | void luaC_fullgc (lua_State *L, int isemergency) { |
1150 | global_State *g = G(L); | 1146 | global_State *g = G(L); |
1151 | lua_assert(g->gckind == KGC_NORMAL); | 1147 | lua_assert(g->gckind == KGC_NORMAL); |
1152 | if (isemergency) /* do not run finalizers during emergency GC */ | 1148 | if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ |
1153 | g->gckind = KGC_EMERGENCY; | 1149 | if (keepinvariant(g)) { /* black objects? */ |
1154 | else | 1150 | entersweep(L); /* sweep everything to turn them back to white */ |
1155 | callallpendingfinalizers(L, 1); | ||
1156 | if (keepinvariant(g)) { /* may there be some black objects? */ | ||
1157 | /* must sweep all objects to turn them back to white | ||
1158 | (as white has not changed, nothing will be collected) */ | ||
1159 | entersweep(L); | ||
1160 | } | 1151 | } |
1161 | /* finish any pending sweep phase to start a new cycle */ | 1152 | /* finish any pending sweep phase to start a new cycle */ |
1162 | luaC_runtilstate(L, bitmask(GCSpause)); | 1153 | luaC_runtilstate(L, bitmask(GCSpause)); |
1163 | luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ | 1154 | luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ |
1164 | luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collection */ | 1155 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ |
1165 | /* estimate must be correct after full GC cycles */ | 1156 | /* estimate must be correct after a full GC cycle */ |
1166 | lua_assert(g->GCestimate == gettotalbytes(g)); | 1157 | lua_assert(g->GCestimate == gettotalbytes(g)); |
1158 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | ||
1167 | g->gckind = KGC_NORMAL; | 1159 | g->gckind = KGC_NORMAL; |
1168 | setpause(g); | 1160 | setpause(g); |
1169 | if (!isemergency) /* do not run finalizers during emergency GC */ | ||
1170 | callallpendingfinalizers(L, 1); | ||
1171 | } | 1161 | } |
1172 | 1162 | ||
1173 | /* }====================================================== */ | 1163 | /* }====================================================== */ |