diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2012-05-31 17:26:14 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2012-05-31 17:26:14 -0300 |
commit | ab2c3d5cdea7812b48127778359849dbc180349a (patch) | |
tree | 14630e5a2b2cdb8ba7cc4653dd734cfd1a755c55 /lgc.c | |
parent | 01e5f358bd58de5c78138575cc09ff7745d4d96d (diff) | |
download | lua-ab2c3d5cdea7812b48127778359849dbc180349a.tar.gz lua-ab2c3d5cdea7812b48127778359849dbc180349a.tar.bz2 lua-ab2c3d5cdea7812b48127778359849dbc180349a.zip |
small bug in error handling of finalizers (cannot call lua_tostring
inside the core) + small bug in luaC_checkfinalizer (when avoiding
remove object being sweeped from sweep list) + small changes in GC
pace control (for the atomic part)
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 72 |
1 files changed, 45 insertions, 27 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.130 2012/05/29 17:52:17 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.131 2012/05/30 16:01:10 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 | */ |
@@ -753,6 +753,18 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
753 | return (*p == NULL) ? NULL : p; | 753 | return (*p == NULL) ? NULL : p; |
754 | } | 754 | } |
755 | 755 | ||
756 | |||
757 | /* | ||
758 | ** sweep a list until a live object (or end of list) | ||
759 | */ | ||
760 | static GCObject **sweeptolive (lua_State *L, GCObject **p) { | ||
761 | GCObject ** old = p; | ||
762 | do { | ||
763 | p = sweeplist(L, p, 1); | ||
764 | } while (p == old); | ||
765 | return p; | ||
766 | } | ||
767 | |||
756 | /* }====================================================== */ | 768 | /* }====================================================== */ |
757 | 769 | ||
758 | 770 | ||
@@ -812,12 +824,14 @@ static void GCTM (lua_State *L, int propagateerrors) { | |||
812 | L->allowhook = oldah; /* restore hooks */ | 824 | L->allowhook = oldah; /* restore hooks */ |
813 | g->gcrunning = running; /* restore state */ | 825 | g->gcrunning = running; /* restore state */ |
814 | if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ | 826 | if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ |
815 | if (status == LUA_ERRRUN) { /* is there an error msg.? */ | 827 | if (status == LUA_ERRRUN) { /* is there an error object? */ |
816 | luaO_pushfstring(L, "error in __gc metamethod (%s)", | 828 | const char *msg = (ttisstring(L->top - 1)) |
817 | lua_tostring(L, -1)); | 829 | ? svalue(L->top - 1) |
830 | : "no message"; | ||
831 | luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); | ||
818 | status = LUA_ERRGCMM; /* error in __gc metamethod */ | 832 | status = LUA_ERRGCMM; /* error in __gc metamethod */ |
819 | } | 833 | } |
820 | luaD_throw(L, status); /* re-send error */ | 834 | luaD_throw(L, status); /* re-throw error */ |
821 | } | 835 | } |
822 | } | 836 | } |
823 | } | 837 | } |
@@ -864,11 +878,9 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
864 | else { /* move 'o' to 'finobj' list */ | 878 | else { /* move 'o' to 'finobj' list */ |
865 | GCObject **p; | 879 | GCObject **p; |
866 | GCheader *ho = gch(o); | 880 | GCheader *ho = gch(o); |
867 | lua_assert(!isdead(g, o)); | 881 | if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ |
868 | /* avoid removing current sweep object */ | 882 | lua_assert(issweepphase(g)); |
869 | if (g->sweepgc == &ho->next) { | 883 | g->sweepgc = sweeptolive(L, g->sweepgc); |
870 | /* step to next object in the list */ | ||
871 | g->sweepgc = sweeplist(L, g->sweepgc, 1); | ||
872 | } | 884 | } |
873 | /* search for pointer pointing to 'o' */ | 885 | /* search for pointer pointing to 'o' */ |
874 | for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } | 886 | for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } |
@@ -899,18 +911,19 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
899 | 911 | ||
900 | /* | 912 | /* |
901 | ** enter first sweep phase (strings) and prepare pointers for other | 913 | ** enter first sweep phase (strings) and prepare pointers for other |
902 | ** sweep phases. The calls to 'sweeplist' attempt to make pointers | 914 | ** sweep phases. The calls to 'sweeptolive' make pointers point to an |
903 | ** point to an object inside the list (instead of to the header), so | 915 | ** object inside the list (instead of to the header), so that the real |
904 | ** that the real sweep do not need to skip objects created between "now" | 916 | ** sweep do not need to skip objects created between "now" and the start |
905 | ** and the start of the real sweep. | 917 | ** of the real sweep. |
906 | */ | 918 | */ |
907 | static void entersweep (lua_State *L) { | 919 | static void entersweep (lua_State *L) { |
908 | global_State *g = G(L); | 920 | global_State *g = G(L); |
909 | g->gcstate = GCSsweepstring; | 921 | g->gcstate = GCSsweepstring; |
910 | lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); | 922 | lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); |
911 | g->sweepstrgc = 0; /* prepare to sweep strings, ... */ | 923 | /* prepare to sweep strings, finalizable objects, and regular objects */ |
912 | g->sweepfin = sweeplist(L, &g->finobj, 1); /* finalizable objects, ... */ | 924 | g->sweepstrgc = 0; |
913 | g->sweepgc = sweeplist(L, &g->allgc, 1); /* and regular objects */ | 925 | g->sweepfin = sweeptolive(L, &g->finobj); |
926 | g->sweepgc = sweeptolive(L, &g->allgc); | ||
914 | } | 927 | } |
915 | 928 | ||
916 | 929 | ||
@@ -966,7 +979,7 @@ void luaC_freeallobjects (lua_State *L) { | |||
966 | 979 | ||
967 | static l_mem atomic (lua_State *L) { | 980 | static l_mem atomic (lua_State *L) { |
968 | global_State *g = G(L); | 981 | global_State *g = G(L); |
969 | l_mem trav = -g->GCmemtrav; /* start counting work */ | 982 | l_mem work = -g->GCmemtrav; /* start counting work */ |
970 | GCObject *origweak, *origall; | 983 | GCObject *origweak, *origall; |
971 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 984 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
972 | markobject(g, L); /* mark running thread */ | 985 | markobject(g, L); /* mark running thread */ |
@@ -976,20 +989,21 @@ static l_mem atomic (lua_State *L) { | |||
976 | /* remark occasional upvalues of (maybe) dead threads */ | 989 | /* remark occasional upvalues of (maybe) dead threads */ |
977 | remarkupvals(g); | 990 | remarkupvals(g); |
978 | propagateall(g); /* propagate changes */ | 991 | propagateall(g); /* propagate changes */ |
979 | trav += g->GCmemtrav; /* count work done til now */ | 992 | work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ |
980 | /* traverse objects caught by write barrier and by 'remarkupvals' */ | 993 | /* traverse objects caught by write barrier and by 'remarkupvals' */ |
981 | retraversegrays(g); | 994 | retraversegrays(g); |
995 | work -= g->GCmemtrav; /* restart counting */ | ||
982 | convergeephemerons(g); | 996 | convergeephemerons(g); |
983 | /* at this point, all strongly accessible objects are marked. */ | 997 | /* at this point, all strongly accessible objects are marked. */ |
984 | /* clear values from weak tables, before checking finalizers */ | 998 | /* clear values from weak tables, before checking finalizers */ |
985 | clearvalues(g, g->weak, NULL); | 999 | clearvalues(g, g->weak, NULL); |
986 | clearvalues(g, g->allweak, NULL); | 1000 | clearvalues(g, g->allweak, NULL); |
987 | origweak = g->weak; origall = g->allweak; | 1001 | origweak = g->weak; origall = g->allweak; |
988 | trav -= g->GCmemtrav; /* restart counting work */ | 1002 | work += g->GCmemtrav; /* stop counting (objects being finalized) */ |
989 | separatetobefnz(L, 0); /* separate objects to be finalized */ | 1003 | separatetobefnz(L, 0); /* separate objects to be finalized */ |
990 | markbeingfnz(g); /* mark objects that will be finalized */ | 1004 | markbeingfnz(g); /* mark objects that will be finalized */ |
991 | propagateall(g); /* remark, to propagate `preserveness' */ | 1005 | propagateall(g); /* remark, to propagate `preserveness' */ |
992 | trav += g->GCmemtrav; /* add work done til now */ | 1006 | work -= g->GCmemtrav; /* restart counting */ |
993 | convergeephemerons(g); | 1007 | convergeephemerons(g); |
994 | /* at this point, all resurrected objects are marked. */ | 1008 | /* at this point, all resurrected objects are marked. */ |
995 | /* remove dead objects from weak tables */ | 1009 | /* remove dead objects from weak tables */ |
@@ -999,8 +1013,8 @@ static l_mem atomic (lua_State *L) { | |||
999 | clearvalues(g, g->weak, origweak); | 1013 | clearvalues(g, g->weak, origweak); |
1000 | clearvalues(g, g->allweak, origall); | 1014 | clearvalues(g, g->allweak, origall); |
1001 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ | 1015 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |
1002 | entersweep(L); /* prepare to sweep strings */ | 1016 | work += g->GCmemtrav; /* complete counting */ |
1003 | return trav; /* estimate of the objects marked by 'atomic' */ | 1017 | return work; /* estimate of memory marked by 'atomic' */ |
1004 | } | 1018 | } |
1005 | 1019 | ||
1006 | 1020 | ||
@@ -1024,9 +1038,13 @@ static lu_mem singlestep (lua_State *L) { | |||
1024 | return g->GCmemtrav - oldtrav; /* memory traversed in this step */ | 1038 | return g->GCmemtrav - oldtrav; /* memory traversed in this step */ |
1025 | } | 1039 | } |
1026 | else { /* no more `gray' objects */ | 1040 | else { /* no more `gray' objects */ |
1041 | lu_mem work; | ||
1027 | g->gcstate = GCSatomic; /* finish mark phase */ | 1042 | g->gcstate = GCSatomic; /* finish mark phase */ |
1028 | g->GCestimate = g->GCmemtrav; /* save what was counted */ | 1043 | g->GCestimate = g->GCmemtrav; /* save what was counted */; |
1029 | return atomic(L); | 1044 | work = atomic(L); /* add what was traversed by 'atomic' */ |
1045 | g->GCestimate += work; /* estimate of total memory traversed */ | ||
1046 | entersweep(L); | ||
1047 | return work + 2 * GCSWEEPCOST; | ||
1030 | } | 1048 | } |
1031 | } | 1049 | } |
1032 | case GCSsweepstring: { | 1050 | case GCSsweepstring: { |
@@ -1095,7 +1113,7 @@ static void generationalcollection (lua_State *L) { | |||
1095 | } | 1113 | } |
1096 | 1114 | ||
1097 | 1115 | ||
1098 | static void step (lua_State *L) { | 1116 | static void incstep (lua_State *L) { |
1099 | global_State *g = G(L); | 1117 | global_State *g = G(L); |
1100 | l_mem debt = g->GCdebt; | 1118 | l_mem debt = g->GCdebt; |
1101 | int stepmul = g->gcstepmul; | 1119 | int stepmul = g->gcstepmul; |
@@ -1122,7 +1140,7 @@ void luaC_forcestep (lua_State *L) { | |||
1122 | global_State *g = G(L); | 1140 | global_State *g = G(L); |
1123 | int i; | 1141 | int i; |
1124 | if (isgenerational(g)) generationalcollection(L); | 1142 | if (isgenerational(g)) generationalcollection(L); |
1125 | else step(L); | 1143 | else incstep(L); |
1126 | /* run a few finalizers (or all of them at the end of a collect cycle) */ | 1144 | /* run a few finalizers (or all of them at the end of a collect cycle) */ |
1127 | for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) | 1145 | for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) |
1128 | GCTM(L, 1); /* call one finalizer */ | 1146 | GCTM(L, 1); /* call one finalizer */ |