aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-08-03 14:28:13 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-08-03 14:28:13 -0300
commit9cf3299fafa41718e3cb260cc94d1d29bba6335b (patch)
treea72a84591540a4a92889472a80f5029c9d9a07a1
parentb9b554e0f68726b19274209ea6ce910b7e9f5fbf (diff)
downloadlua-9cf3299fafa41718e3cb260cc94d1d29bba6335b.tar.gz
lua-9cf3299fafa41718e3cb260cc94d1d29bba6335b.tar.bz2
lua-9cf3299fafa41718e3cb260cc94d1d29bba6335b.zip
Threads don't need to always go to 'grayagain'
In incremental mode, threads don't need to be visited again once visited in the atomic phase. In generational mode (where all visits are in the atomic phase), only old threads need to be kept in the 'grayagain' list for the next cycle.
-rw-r--r--lgc.c47
1 files changed, 29 insertions, 18 deletions
diff --git a/lgc.c b/lgc.c
index 5e8c02d3..717f80e8 100644
--- a/lgc.c
+++ b/lgc.c
@@ -348,8 +348,7 @@ static int remarkupvals (global_State *g) {
348 int work = 0; /* estimate of how much work was done here */ 348 int work = 0; /* estimate of how much work was done here */
349 while ((thread = *p) != NULL) { 349 while ((thread = *p) != NULL) {
350 work++; 350 work++;
351 lua_assert(!isblack(thread)); /* threads are never black */ 351 if (!iswhite(thread) && thread->openupval != NULL)
352 if (isgray(thread) && thread->openupval != NULL)
353 p = &thread->twups; /* keep marked thread with upvalues in the list */ 352 p = &thread->twups; /* keep marked thread with upvalues in the list */
354 else { /* thread is not marked or without upvalues */ 353 else { /* thread is not marked or without upvalues */
355 UpVal *uv; 354 UpVal *uv;
@@ -600,12 +599,23 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
600 599
601/* 600/*
602** Traverse a thread, marking the elements in the stack up to its top 601** Traverse a thread, marking the elements in the stack up to its top
603** and cleaning the rest of the stack in the final traversal. 602** and cleaning the rest of the stack in the final traversal. That
604** That ensures that the entire stack have valid (non-dead) objects. 603** ensures that the entire stack have valid (non-dead) objects.
604** Threads have no barriers. In gen. mode, old threads must be visited
605** at every cycle, because they might point to young objects. In inc.
606** mode, the thread can still be modified before the end of the cycle,
607** and therefore it must be visited again in the atomic phase. To ensure
608** these visits, threads must return to a gray list if they are not new
609** (which can only happen in generational mode) or if the traverse is in
610** the propagate phase (which can only happen in incremental mode).
605*/ 611*/
606static int traversethread (global_State *g, lua_State *th) { 612static int traversethread (global_State *g, lua_State *th) {
607 UpVal *uv; 613 UpVal *uv;
608 StkId o = th->stack; 614 StkId o = th->stack;
615 if (isold(th) || g->gcstate == GCSpropagate) {
616 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
617 black2gray(th);
618 }
609 if (o == NULL) 619 if (o == NULL)
610 return 1; /* stack not completely built yet */ 620 return 1; /* stack not completely built yet */
611 lua_assert(g->gcstate == GCSatomic || 621 lua_assert(g->gcstate == GCSatomic ||
@@ -644,12 +654,7 @@ static lu_mem propagatemark (global_State *g) {
644 case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); 654 case LUA_VLCL: return traverseLclosure(g, gco2lcl(o));
645 case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); 655 case LUA_VCCL: return traverseCclosure(g, gco2ccl(o));
646 case LUA_VPROTO: return traverseproto(g, gco2p(o)); 656 case LUA_VPROTO: return traverseproto(g, gco2p(o));
647 case LUA_VTHREAD: { 657 case LUA_VTHREAD: return traversethread(g, gco2th(o));
648 lua_State *th = gco2th(o);
649 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
650 black2gray(o);
651 return traversethread(g, th);
652 }
653 default: lua_assert(0); return 0; 658 default: lua_assert(0); return 0;
654 } 659 }
655} 660}
@@ -1028,7 +1033,6 @@ static void setpause (global_State *g);
1028** objects and turns the non dead to old. All non-dead threads---which 1033** objects and turns the non dead to old. All non-dead threads---which
1029** are now old---must be in a gray list. Everything else is not in a 1034** are now old---must be in a gray list. Everything else is not in a
1030** gray list. 1035** gray list.
1031**
1032*/ 1036*/
1033static void sweep2old (lua_State *L, GCObject **p) { 1037static void sweep2old (lua_State *L, GCObject **p) {
1034 GCObject *curr; 1038 GCObject *curr;
@@ -1139,10 +1143,16 @@ static GCObject **correctgraylist (GCObject **p) {
1139 goto remain; /* keep non-white threads on the list */ 1143 goto remain; /* keep non-white threads on the list */
1140 } 1144 }
1141 else { /* everything else is removed */ 1145 else { /* everything else is removed */
1142 lua_assert(isold(curr)); /* young objects should be white */ 1146 lua_assert(isold(curr)); /* young objects should be white here */
1143 if (getage(curr) == G_TOUCHED2) /* advance from G_TOUCHED2... */ 1147 if (getage(curr) == G_TOUCHED2) { /* advance from TOUCHED2... */
1144 changeage(curr, G_TOUCHED2, G_OLD); /* ... to G_OLD */ 1148 changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */
1145 gray2black(curr); /* make object black */ 1149 lua_assert(isblack(curr)); /* TOUCHED2 objects are always black */
1150 }
1151 else {
1152 /* everything else in a gray list should be gray */
1153 lua_assert(isgray(curr));
1154 gray2black(curr); /* make object black (to be removed) */
1155 }
1146 goto remove; 1156 goto remove;
1147 } 1157 }
1148 remove: *p = *next; continue; 1158 remove: *p = *next; continue;
@@ -1207,11 +1217,12 @@ static void youngcollection (lua_State *L, global_State *g) {
1207 GCObject **psurvival; /* to point to first non-dead survival object */ 1217 GCObject **psurvival; /* to point to first non-dead survival object */
1208 GCObject *dummy; /* dummy out parameter to 'sweepgen' */ 1218 GCObject *dummy; /* dummy out parameter to 'sweepgen' */
1209 lua_assert(g->gcstate == GCSpropagate); 1219 lua_assert(g->gcstate == GCSpropagate);
1210 if (g->firstold1) { /* are there OLD1 objects? */ 1220 if (g->firstold1) { /* are there regular OLD1 objects? */
1211 markold(g, g->firstold1, g->reallyold); /* mark them */ 1221 markold(g, g->firstold1, g->reallyold); /* mark them */
1212 g->firstold1 = NULL; /* no more OLD1 objects (for now) */ 1222 g->firstold1 = NULL; /* no more OLD1 objects (for now) */
1213 } 1223 }
1214 markold(g, g->finobj, g->finobjrold); 1224 markold(g, g->finobj, g->finobjrold);
1225 markold(g, g->tobefnz, NULL);
1215 atomic(L); 1226 atomic(L);
1216 1227
1217 /* sweep nursery and get a pointer to its last live element */ 1228 /* sweep nursery and get a pointer to its last live element */
@@ -1268,8 +1279,8 @@ static void atomic2gen (lua_State *L, global_State *g) {
1268/* 1279/*
1269** Enter generational mode. Must go until the end of an atomic cycle 1280** Enter generational mode. Must go until the end of an atomic cycle
1270** to ensure that all objects are correctly marked and weak tables 1281** to ensure that all objects are correctly marked and weak tables
1271** are cleared. 1282** are cleared. Then, turn all objects into old and finishes the
1272** Then, turn all objects into old and finishes the collection. 1283** collection.
1273*/ 1284*/
1274static lu_mem entergen (lua_State *L, global_State *g) { 1285static lu_mem entergen (lua_State *L, global_State *g) {
1275 lu_mem numobjs; 1286 lu_mem numobjs;