diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-02-18 10:39:37 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-02-18 10:39:37 -0300 |
commit | d764cc552251fc69207c1bb4b34d3a6a5b7020c6 (patch) | |
tree | 7b1b6532af3d22da36118cc81b8256ab53b887bc /lgc.c | |
parent | ffa96d988d60f31591014fe417c27e44fc3116d1 (diff) | |
download | lua-d764cc552251fc69207c1bb4b34d3a6a5b7020c6.tar.gz lua-d764cc552251fc69207c1bb4b34d3a6a5b7020c6.tar.bz2 lua-d764cc552251fc69207c1bb4b34d3a6a5b7020c6.zip |
new list 'twups' to allow traversal of upvalues from dead threads
(+ fixed some problems with cycles involving those upvalues)
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 45 |
1 files changed, 35 insertions, 10 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.174 2014/02/14 16:43:14 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.175 2014/02/15 13:12:01 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 | */ |
@@ -23,6 +23,11 @@ | |||
23 | #include "ltm.h" | 23 | #include "ltm.h" |
24 | 24 | ||
25 | 25 | ||
26 | /* | ||
27 | ** internal state for collector while inside the atomic phase. The | ||
28 | ** collector should never be in this state while running regular code. | ||
29 | */ | ||
30 | #define GCSinsideatomic (GCSpause + 1) | ||
26 | 31 | ||
27 | /* | 32 | /* |
28 | ** cost of sweeping one element (the size of a small object divided | 33 | ** cost of sweeping one element (the size of a small object divided |
@@ -288,15 +293,21 @@ static void markbeingfnz (global_State *g) { | |||
288 | /* | 293 | /* |
289 | ** Mark all values stored in marked open upvalues from non-marked threads. | 294 | ** Mark all values stored in marked open upvalues from non-marked threads. |
290 | ** (Values from marked threads were already marked when traversing the | 295 | ** (Values from marked threads were already marked when traversing the |
291 | ** thread.) | 296 | ** thread.) Remove from the list threads that no longer have upvalues and |
297 | ** not-marked threads. | ||
292 | */ | 298 | */ |
293 | static void remarkupvals (global_State *g) { | 299 | static void remarkupvals (global_State *g) { |
294 | GCObject *thread = g->mainthread->next; | 300 | lua_State *thread; |
295 | for (; thread != NULL; thread = gch(thread)->next) { | 301 | lua_State **p = &g->twups; |
296 | lua_assert(!isblack(thread)); /* threads are never black */ | 302 | while ((thread = *p) != NULL) { |
297 | if (!isgray(thread)) { /* dead thread? */ | 303 | lua_assert(!isblack(obj2gco(thread))); /* threads are never black */ |
298 | UpVal *uv = gco2th(thread)->openupval; | 304 | if (isgray(obj2gco(thread)) && thread->openupval != NULL) |
299 | for (; uv != NULL; uv = uv->u.open.next) { | 305 | p = &thread->twups; /* keep marked thread with upvalues in the list */ |
306 | else { /* thread is not marked or without upvalues */ | ||
307 | UpVal *uv; | ||
308 | *p = thread->twups; /* remove thread from the list */ | ||
309 | thread->twups = thread; /* mark that it is out of list */ | ||
310 | for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { | ||
300 | if (uv->u.open.touched) { | 311 | if (uv->u.open.touched) { |
301 | markvalue(g, uv->v); /* remark upvalue's value */ | 312 | markvalue(g, uv->v); /* remark upvalue's value */ |
302 | uv->u.open.touched = 0; | 313 | uv->u.open.touched = 0; |
@@ -459,13 +470,19 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) { | |||
459 | return sizeCclosure(cl->nupvalues); | 470 | return sizeCclosure(cl->nupvalues); |
460 | } | 471 | } |
461 | 472 | ||
473 | /* | ||
474 | ** open upvalues point to values in a thread, so those values should | ||
475 | ** be marked when the thread is traversed except in the atomic phase | ||
476 | ** (because then the value cannot be changed by the thread and the | ||
477 | ** thread may not be traversed again) | ||
478 | */ | ||
462 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | 479 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { |
463 | int i; | 480 | int i; |
464 | markobject(g, cl->p); /* mark its prototype */ | 481 | markobject(g, cl->p); /* mark its prototype */ |
465 | for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ | 482 | for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ |
466 | UpVal *uv = cl->upvals[i]; | 483 | UpVal *uv = cl->upvals[i]; |
467 | if (uv != NULL) { | 484 | if (uv != NULL) { |
468 | if (upisopen(uv)) | 485 | if (upisopen(uv) && g->gcstate != GCSinsideatomic) |
469 | uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ | 486 | uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ |
470 | else | 487 | else |
471 | markvalue(g, uv->v); | 488 | markvalue(g, uv->v); |
@@ -480,12 +497,19 @@ static lu_mem traversestack (global_State *g, lua_State *th) { | |||
480 | StkId o = th->stack; | 497 | StkId o = th->stack; |
481 | if (o == NULL) | 498 | if (o == NULL) |
482 | return 1; /* stack not completely built yet */ | 499 | return 1; /* stack not completely built yet */ |
500 | lua_assert(g->gcstate == GCSinsideatomic || | ||
501 | th->openupval == NULL || isintwups(th)); | ||
483 | for (; o < th->top; o++) /* mark live elements in the stack */ | 502 | for (; o < th->top; o++) /* mark live elements in the stack */ |
484 | markvalue(g, o); | 503 | markvalue(g, o); |
485 | if (g->gcstate == GCSatomic) { /* final traversal? */ | 504 | if (g->gcstate == GCSinsideatomic) { /* final traversal? */ |
486 | StkId lim = th->stack + th->stacksize; /* real end of stack */ | 505 | StkId lim = th->stack + th->stacksize; /* real end of stack */ |
487 | for (; o < lim; o++) /* clear not-marked stack slice */ | 506 | for (; o < lim; o++) /* clear not-marked stack slice */ |
488 | setnilvalue(o); | 507 | setnilvalue(o); |
508 | /* 'remarkupvals' may have removed thread from 'twups' list */ | ||
509 | if (!isintwups(th) && th->openupval != NULL) { | ||
510 | th->twups = g->twups; /* link it back to the list */ | ||
511 | g->twups = th; | ||
512 | } | ||
489 | } | 513 | } |
490 | else { | 514 | else { |
491 | CallInfo *ci; | 515 | CallInfo *ci; |
@@ -941,6 +965,7 @@ static l_mem atomic (lua_State *L) { | |||
941 | l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */ | 965 | l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */ |
942 | GCObject *origweak, *origall; | 966 | GCObject *origweak, *origall; |
943 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 967 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
968 | g->gcstate = GCSinsideatomic; | ||
944 | markobject(g, L); /* mark running thread */ | 969 | markobject(g, L); /* mark running thread */ |
945 | /* registry and global metatables may be changed by API */ | 970 | /* registry and global metatables may be changed by API */ |
946 | markvalue(g, &g->l_registry); | 971 | markvalue(g, &g->l_registry); |