diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-02-11 10:18:12 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-02-11 10:18:12 -0200 |
| commit | ba3586cc90d1ab8d499437dd7c504798371b0e4f (patch) | |
| tree | 416f99ec601d48a19a7233f6363a7329989a6fd6 | |
| parent | 68df7c6279421a0a5710afc31e5cd3122e0d3391 (diff) | |
| download | lua-ba3586cc90d1ab8d499437dd7c504798371b0e4f.tar.gz lua-ba3586cc90d1ab8d499437dd7c504798371b0e4f.tar.bz2 lua-ba3586cc90d1ab8d499437dd7c504798371b0e4f.zip | |
keep a single list of objects to be finalized (with local and non-local
objects), to ensure finalization order
| -rw-r--r-- | lgc.c | 47 | ||||
| -rw-r--r-- | lgc.h | 15 | ||||
| -rw-r--r-- | lstate.c | 4 | ||||
| -rw-r--r-- | lstate.h | 6 | ||||
| -rw-r--r-- | ltests.c | 25 |
5 files changed, 37 insertions, 60 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.167 2013/12/13 15:17:00 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.168 2013/12/13 15:42:08 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 | */ |
| @@ -770,16 +770,16 @@ static GCObject *udata2finalize (global_State *g) { | |||
| 770 | lua_assert(tofinalize(o)); | 770 | lua_assert(tofinalize(o)); |
| 771 | g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ | 771 | g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ |
| 772 | if (islocal(o)) { | 772 | if (islocal(o)) { |
| 773 | lua_assert(!testbit(gch(o)->marked, LOCALMARK)); | ||
| 774 | gch(o)->next = g->localgc; /* return it to 'localgc' list */ | 773 | gch(o)->next = g->localgc; /* return it to 'localgc' list */ |
| 775 | g->localgc = o; | 774 | g->localgc = o; |
| 775 | resetbit(gch(o)->marked, LOCALMARK); | ||
| 776 | } | 776 | } |
| 777 | else { /* return it to 'allgc' list */ | 777 | else { /* return it to 'allgc' list */ |
| 778 | gch(o)->next = g->allgc; | 778 | gch(o)->next = g->allgc; |
| 779 | g->allgc = o; | 779 | g->allgc = o; |
| 780 | l_setbit(gch(o)->marked, LOCALMARK); | 780 | l_setbit(gch(o)->marked, LOCALMARK); |
| 781 | } | 781 | } |
| 782 | resetbit(gch(o)->marked, FINALIZEDBIT); /* object is back in 'allgc' */ | 782 | resetbit(gch(o)->marked, FINALIZEDBIT); /* object is "normal" again */ |
| 783 | if (issweepphase(g)) | 783 | if (issweepphase(g)) |
| 784 | makewhite(g, o); /* "sweep" object */ | 784 | makewhite(g, o); /* "sweep" object */ |
| 785 | return o; | 785 | return o; |
| @@ -848,8 +848,9 @@ static GCObject **findlast (GCObject **p) { | |||
| 848 | ** move all unreachable objects (or 'all' objects) that need | 848 | ** move all unreachable objects (or 'all' objects) that need |
| 849 | ** finalization from list 'p' to list 'tobefnz' (to be finalized) | 849 | ** finalization from list 'p' to list 'tobefnz' (to be finalized) |
| 850 | */ | 850 | */ |
| 851 | static void separatetobefnz_aux (global_State *g, GCObject **p, int all) { | 851 | static void separatetobefnz (global_State *g, int all) { |
| 852 | GCObject *curr; | 852 | GCObject *curr; |
| 853 | GCObject **p = &g->finobj; | ||
| 853 | GCObject **lastnext = findlast(&g->tobefnz); | 854 | GCObject **lastnext = findlast(&g->tobefnz); |
| 854 | while ((curr = *p) != NULL) { /* traverse all finalizable objects */ | 855 | while ((curr = *p) != NULL) { /* traverse all finalizable objects */ |
| 855 | lua_assert(tofinalize(curr)); | 856 | lua_assert(tofinalize(curr)); |
| @@ -865,15 +866,9 @@ static void separatetobefnz_aux (global_State *g, GCObject **p, int all) { | |||
| 865 | } | 866 | } |
| 866 | 867 | ||
| 867 | 868 | ||
| 868 | static void separatetobefnz (global_State *g, int all) { | ||
| 869 | separatetobefnz_aux(g, &g->localfin, all); | ||
| 870 | separatetobefnz_aux(g, &g->finobj, all); | ||
| 871 | } | ||
| 872 | |||
| 873 | |||
| 874 | /* | 869 | /* |
| 875 | ** if object 'o' has a finalizer, remove it from 'allgc' list (must | 870 | ** if object 'o' has a finalizer, remove it from 'allgc' list (must |
| 876 | ** search the list to find it) and link it in 'localfin' or 'finobj' list. | 871 | ** search the list to find it) and link it in 'finobj' list. |
| 877 | */ | 872 | */ |
| 878 | void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | 873 | void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { |
| 879 | global_State *g = G(L); | 874 | global_State *g = G(L); |
| @@ -890,9 +885,8 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
| 890 | p = (testbit(o->gch.marked, LOCALMARK)) ? &g->allgc : &g->localgc; | 885 | p = (testbit(o->gch.marked, LOCALMARK)) ? &g->allgc : &g->localgc; |
| 891 | for (; *p != o; p = &gch(*p)->next) { /* empty */ } | 886 | for (; *p != o; p = &gch(*p)->next) { /* empty */ } |
| 892 | *p = o->gch.next; /* remove 'o' from its list */ | 887 | *p = o->gch.next; /* remove 'o' from its list */ |
| 893 | p = (testbit(o->gch.marked, LOCALMARK)) ? &g->finobj : &g->localfin; | 888 | o->gch.next = g->finobj; /* link it in "fin" list */ |
| 894 | o->gch.next = *p; /* link it in a "fin" list */ | 889 | g->finobj = o; |
| 895 | *p = o; | ||
| 896 | l_setbit(o->gch.marked, FINALIZEDBIT); /* mark it as such */ | 890 | l_setbit(o->gch.marked, FINALIZEDBIT); /* mark it as such */ |
| 897 | if (issweepphase(g)) | 891 | if (issweepphase(g)) |
| 898 | makewhite(g, o); /* "sweep" object */ | 892 | makewhite(g, o); /* "sweep" object */ |
| @@ -966,20 +960,15 @@ static void localsweep (lua_State *L, global_State *g) { | |||
| 966 | } | 960 | } |
| 967 | 961 | ||
| 968 | 962 | ||
| 969 | static void separatelocal (global_State *g, int all) { | 963 | static void separatelocal (global_State *g) { |
| 970 | GCObject **p = &g->localfin; | 964 | GCObject **p = &g->finobj; |
| 971 | GCObject **lastnext = findlast(&g->tobefnz); | 965 | GCObject **lastnext = findlast(&g->tobefnz); |
| 972 | while (*p != NULL) { | 966 | while (*p != NULL) { |
| 973 | GCObject *curr = *p; | 967 | GCObject *curr = *p; |
| 974 | if (!islocal(curr)) { /* is 'curr' no more local? */ | 968 | if (!islocal(curr)) /* is 'curr' no more local? */ |
| 975 | *p = curr->gch.next; /* remove 'curr' from list */ | 969 | p = &curr->gch.next; /* go to next element */ |
| 976 | curr->gch.next = g->finobj; /* link 'curr' in 'finobj' list */ | ||
| 977 | g->finobj = curr; | ||
| 978 | /* mark it as out of local list */ | ||
| 979 | l_setbit(curr->gch.marked, LOCALMARK); | ||
| 980 | } | ||
| 981 | else { /* still local */ | 970 | else { /* still local */ |
| 982 | if (testbit(curr->gch.marked, LOCALMARK) && !all) { /* locally alive? */ | 971 | if (testbit(curr->gch.marked, LOCALMARK)) { /* locally alive? */ |
| 983 | resetbit(curr->gch.marked, LOCALMARK); | 972 | resetbit(curr->gch.marked, LOCALMARK); |
| 984 | p = &curr->gch.next; /* go to next element */ | 973 | p = &curr->gch.next; /* go to next element */ |
| 985 | } | 974 | } |
| @@ -999,7 +988,7 @@ static void luaC_localcollection (lua_State *L) { | |||
| 999 | lua_assert(g->gcstate == GCSpause); | 988 | lua_assert(g->gcstate == GCSpause); |
| 1000 | localmark(g); | 989 | localmark(g); |
| 1001 | localsweep(L, g); | 990 | localsweep(L, g); |
| 1002 | separatelocal(g, 0); | 991 | separatelocal(g); |
| 1003 | callallpendingfinalizers(L, 1); | 992 | callallpendingfinalizers(L, 1); |
| 1004 | } | 993 | } |
| 1005 | 994 | ||
| @@ -1050,13 +1039,12 @@ static int entersweep (lua_State *L) { | |||
| 1050 | void luaC_freeallobjects (lua_State *L) { | 1039 | void luaC_freeallobjects (lua_State *L) { |
| 1051 | global_State *g = G(L); | 1040 | global_State *g = G(L); |
| 1052 | separatetobefnz(g, 1); /* separate all objects with finalizers */ | 1041 | separatetobefnz(g, 1); /* separate all objects with finalizers */ |
| 1053 | lua_assert(g->finobj == NULL && g->localfin == NULL); | 1042 | lua_assert(g->finobj == NULL); |
| 1054 | callallpendingfinalizers(L, 0); | 1043 | callallpendingfinalizers(L, 0); |
| 1055 | lua_assert(g->tobefnz == NULL); | 1044 | lua_assert(g->tobefnz == NULL); |
| 1056 | g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ | 1045 | g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ |
| 1057 | g->gckind = KGC_NORMAL; | 1046 | g->gckind = KGC_NORMAL; |
| 1058 | sweepwholelist(L, &g->localgc); | 1047 | sweepwholelist(L, &g->localgc); |
| 1059 | sweepwholelist(L, &g->localfin); /* finalizers can create objs. with fins. */ | ||
| 1060 | sweepwholelist(L, &g->finobj); | 1048 | sweepwholelist(L, &g->finobj); |
| 1061 | sweepwholelist(L, &g->allgc); | 1049 | sweepwholelist(L, &g->allgc); |
| 1062 | sweepwholelist(L, &g->mainthread->next); | 1050 | sweepwholelist(L, &g->mainthread->next); |
| @@ -1155,12 +1143,9 @@ static lu_mem singlestep (lua_State *L) { | |||
| 1155 | return sweepstep(L, g, GCSswpthreads, &g->mainthread->next); | 1143 | return sweepstep(L, g, GCSswpthreads, &g->mainthread->next); |
| 1156 | } | 1144 | } |
| 1157 | case GCSswpthreads: { /* sweep threads */ | 1145 | case GCSswpthreads: { /* sweep threads */ |
| 1158 | return sweepstep(L, g, GCSswplocalfin, &g->localfin); | ||
| 1159 | } | ||
| 1160 | case GCSswplocalfin: { /* sweep local objects with finalizers */ | ||
| 1161 | return sweepstep(L, g, GCSswpfinobj, &g->finobj); | 1146 | return sweepstep(L, g, GCSswpfinobj, &g->finobj); |
| 1162 | } | 1147 | } |
| 1163 | case GCSswpfinobj: { /* sweep non-local objects with finalizers */ | 1148 | case GCSswpfinobj: { /* sweep objects with finalizers */ |
| 1164 | return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); | 1149 | return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); |
| 1165 | } | 1150 | } |
| 1166 | case GCSswptobefnz: { /* sweep objects to be finalized */ | 1151 | case GCSswptobefnz: { /* sweep objects to be finalized */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.75 2013/09/11 14:47:08 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.76 2013/09/11 20:15:31 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 | */ |
| @@ -39,13 +39,12 @@ | |||
| 39 | #define GCSpropagate 0 | 39 | #define GCSpropagate 0 |
| 40 | #define GCSatomic 1 | 40 | #define GCSatomic 1 |
| 41 | #define GCSswplocalgc 2 | 41 | #define GCSswplocalgc 2 |
| 42 | #define GCSswpallgc 4 | 42 | #define GCSswpallgc 3 |
| 43 | #define GCSswpthreads 3 | 43 | #define GCSswpthreads 4 |
| 44 | #define GCSswplocalfin 5 | 44 | #define GCSswpfinobj 5 |
| 45 | #define GCSswpfinobj 6 | 45 | #define GCSswptobefnz 6 |
| 46 | #define GCSswptobefnz 7 | 46 | #define GCSswpend 7 |
| 47 | #define GCSswpend 8 | 47 | #define GCSpause 8 |
| 48 | #define GCSpause 9 | ||
| 49 | 48 | ||
| 50 | 49 | ||
| 51 | #define issweepphase(g) \ | 50 | #define issweepphase(g) \ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.115 2013/09/17 15:40:06 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.116 2013/11/08 17:34:22 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -320,7 +320,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
| 320 | g->panic = NULL; | 320 | g->panic = NULL; |
| 321 | g->version = NULL; | 321 | g->version = NULL; |
| 322 | g->gcstate = GCSpause; | 322 | g->gcstate = GCSpause; |
| 323 | g->localgc = g->localfin = g->allgc = g->finobj = NULL; | 323 | g->localgc = g->allgc = g->finobj = NULL; |
| 324 | g->tobefnz = NULL; | 324 | g->tobefnz = NULL; |
| 325 | g->fixedgc = NULL; | 325 | g->fixedgc = NULL; |
| 326 | g->sweepgc = NULL; | 326 | g->sweepgc = NULL; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.h,v 2.96 2013/09/13 16:21:52 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.97 2013/09/17 15:40:06 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -23,9 +23,8 @@ | |||
| 23 | ** | 23 | ** |
| 24 | ** mainthread->next: all threads; | 24 | ** mainthread->next: all threads; |
| 25 | ** localgc: all local objects not marked for finalization; | 25 | ** localgc: all local objects not marked for finalization; |
| 26 | ** localfin: all local objects marked for finalization; | ||
| 27 | ** allgc: all non local objects not marked for finalization; | 26 | ** allgc: all non local objects not marked for finalization; |
| 28 | ** finobj: all non local objects marked for finalization; | 27 | ** finobj: all objects marked for finalization; |
| 29 | ** tobefnz: all objects ready to be finalized; | 28 | ** tobefnz: all objects ready to be finalized; |
| 30 | ** fixedgc: all objects that are not to be collected (currently | 29 | ** fixedgc: all objects that are not to be collected (currently |
| 31 | ** only small strings, such as reserved words). | 30 | ** only small strings, such as reserved words). |
| @@ -119,7 +118,6 @@ typedef struct global_State { | |||
| 119 | lu_byte gcrunning; /* true if GC is running */ | 118 | lu_byte gcrunning; /* true if GC is running */ |
| 120 | GCObject *allgc; /* list of all collectable objects */ | 119 | GCObject *allgc; /* list of all collectable objects */ |
| 121 | GCObject *localgc; /* list of local objects */ | 120 | GCObject *localgc; /* list of local objects */ |
| 122 | GCObject *localfin; /* list of local objects with finalizers */ | ||
| 123 | GCObject **sweepgc; /* current position of sweep in list */ | 121 | GCObject **sweepgc; /* current position of sweep in list */ |
| 124 | GCObject *finobj; /* list of collectable objects with finalizers */ | 122 | GCObject *finobj; /* list of collectable objects with finalizers */ |
| 125 | GCObject *gray; /* list of gray objects */ | 123 | GCObject *gray; /* list of gray objects */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.c,v 2.161 2013/12/18 14:12:03 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.162 2013/12/30 20:47:58 roberto Exp roberto $ |
| 3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -338,7 +338,6 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) { | |||
| 338 | lua_assert(maybedead); | 338 | lua_assert(maybedead); |
| 339 | else { | 339 | else { |
| 340 | lua_assert(g->gcstate != GCSpause || iswhite(o)); | 340 | lua_assert(g->gcstate != GCSpause || iswhite(o)); |
| 341 | lua_assert(!islocal(o) || !testbit(gch(o)->marked, LOCALMARK)); | ||
| 342 | switch (gch(o)->tt) { | 341 | switch (gch(o)->tt) { |
| 343 | case LUA_TUSERDATA: { | 342 | case LUA_TUSERDATA: { |
| 344 | Table *mt = gco2u(o)->metatable; | 343 | Table *mt = gco2u(o)->metatable; |
| @@ -456,19 +455,12 @@ int lua_checkmemory (lua_State *L) { | |||
| 456 | lua_assert(testbit(o->gch.marked, NOLOCALBIT)); | 455 | lua_assert(testbit(o->gch.marked, NOLOCALBIT)); |
| 457 | lua_assert(gch(o)->tt == LUA_TTHREAD); | 456 | lua_assert(gch(o)->tt == LUA_TTHREAD); |
| 458 | } | 457 | } |
| 459 | /* check 'localfin' list */ | ||
| 460 | checkgray(g, g->localfin); | ||
| 461 | for (o = g->localfin; o != NULL; o = gch(o)->next) { | ||
| 462 | checkobject(g, o, 0); | ||
| 463 | lua_assert(tofinalize(o) && !testbit(o->gch.marked, LOCALMARK)); | ||
| 464 | lua_assert(gch(o)->tt == LUA_TUSERDATA || gch(o)->tt == LUA_TTABLE); | ||
| 465 | } | ||
| 466 | /* check 'finobj' list */ | 458 | /* check 'finobj' list */ |
| 467 | checkgray(g, g->finobj); | 459 | checkgray(g, g->finobj); |
| 468 | for (o = g->finobj; o != NULL; o = gch(o)->next) { | 460 | for (o = g->finobj; o != NULL; o = gch(o)->next) { |
| 469 | checkobject(g, o, 0); | 461 | checkobject(g, o, 0); |
| 470 | lua_assert(tofinalize(o) && testbit(o->gch.marked, LOCALMARK)); | 462 | lua_assert(tofinalize(o)); |
| 471 | lua_assert(testbit(o->gch.marked, NOLOCALBIT)); | 463 | lua_assert(!islocal(o) || !testbit(gch(o)->marked, LOCALMARK)); |
| 472 | lua_assert(gch(o)->tt == LUA_TUSERDATA || gch(o)->tt == LUA_TTABLE); | 464 | lua_assert(gch(o)->tt == LUA_TUSERDATA || gch(o)->tt == LUA_TTABLE); |
| 473 | } | 465 | } |
| 474 | /* check 'tobefnz' list */ | 466 | /* check 'tobefnz' list */ |
| @@ -655,10 +647,13 @@ static int gc_local (lua_State *L) { | |||
| 655 | 647 | ||
| 656 | static int gc_state (lua_State *L) { | 648 | static int gc_state (lua_State *L) { |
| 657 | static const char *statenames[] = {"propagate", "atomic", | 649 | static const char *statenames[] = {"propagate", "atomic", |
| 658 | "sweeplocalgc", "sweepallgc", "sweepthreads", "sweeplocalfin", | 650 | "sweeplocalgc", "sweepallgc", "sweepthreads", "sweepfinobj", |
| 659 | "sweepfinobj", "sweeptobefnz", "sweepend", "pause", ""}; | 651 | "sweeptobefnz", "sweepend", "pause", ""}; |
| 660 | int option = luaL_checkoption(L, 1, "", statenames); | 652 | static const int states[] = {GCSpropagate, GCSatomic, |
| 661 | if (option == GCSpause + 1) { | 653 | GCSswplocalgc, GCSswpallgc, GCSswpthreads, GCSswpfinobj, |
| 654 | GCSswptobefnz, GCSswpend, GCSpause, -1}; | ||
| 655 | int option = states[luaL_checkoption(L, 1, "", statenames)]; | ||
| 656 | if (option == -1) { | ||
| 662 | lua_pushstring(L, statenames[G(L)->gcstate]); | 657 | lua_pushstring(L, statenames[G(L)->gcstate]); |
| 663 | return 1; | 658 | return 1; |
| 664 | } | 659 | } |
