aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lfunc.c16
-rw-r--r--lfunc.h6
-rw-r--r--lgc.c45
-rw-r--r--lstate.c4
-rw-r--r--lstate.h4
5 files changed, 58 insertions, 17 deletions
diff --git a/lfunc.c b/lfunc.c
index 685d7bdd..9d0703e1 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lfunc.c,v 2.39 2014/02/13 12:11:34 roberto Exp roberto $ 2** $Id: lfunc.c,v 2.40 2014/02/15 13:12:01 roberto Exp roberto $
3** Auxiliary functions to manipulate prototypes and closures 3** Auxiliary functions to manipulate prototypes and closures
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -35,7 +35,9 @@ Closure *luaF_newLclosure (lua_State *L, int n) {
35 return c; 35 return c;
36} 36}
37 37
38 38/*
39** fill a closure with new closed upvalues
40*/
39void luaF_initupvals (lua_State *L, LClosure *cl) { 41void luaF_initupvals (lua_State *L, LClosure *cl) {
40 int i; 42 int i;
41 for (i = 0; i < cl->nupvalues; i++) { 43 for (i = 0; i < cl->nupvalues; i++) {
@@ -52,18 +54,24 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
52 UpVal **pp = &L->openupval; 54 UpVal **pp = &L->openupval;
53 UpVal *p; 55 UpVal *p;
54 UpVal *uv; 56 UpVal *uv;
57 lua_assert(isintwups(L) || L->openupval == NULL);
55 while (*pp != NULL && (p = *pp)->v >= level) { 58 while (*pp != NULL && (p = *pp)->v >= level) {
56 lua_assert(upisopen(p)); 59 lua_assert(upisopen(p));
57 if (p->v == level) /* found a corresponding upvalue? */ 60 if (p->v == level) /* found a corresponding upvalue? */
58 return p; /* return it */ 61 return p; /* return it */
59 pp = &p->u.open.next; 62 pp = &p->u.open.next;
60 } 63 }
61 /* not found: create a new one */ 64 /* not found: create a new upvalue */
62 uv = luaM_new(L, UpVal); 65 uv = luaM_new(L, UpVal);
63 uv->refcount = 0; 66 uv->refcount = 0;
64 uv->u.open.next = *pp; 67 uv->u.open.next = *pp; /* link it to list of open upvalues */
68 uv->u.open.touched = 1;
65 *pp = uv; 69 *pp = uv;
66 uv->v = level; /* current value lives in the stack */ 70 uv->v = level; /* current value lives in the stack */
71 if (!isintwups(L)) { /* thread not in list of threads with upvalues? */
72 L->twups = G(L)->twups; /* link it to the list */
73 G(L)->twups = L;
74 }
67 return uv; 75 return uv;
68} 76}
69 77
diff --git a/lfunc.h b/lfunc.h
index 9ed51767..3ca72075 100644
--- a/lfunc.h
+++ b/lfunc.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lfunc.h,v 2.11 2013/09/11 15:17:00 roberto Exp roberto $ 2** $Id: lfunc.h,v 2.12 2014/02/15 13:12:01 roberto Exp roberto $
3** Auxiliary functions to manipulate prototypes and closures 3** Auxiliary functions to manipulate prototypes and closures
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -18,6 +18,10 @@
18 cast(int, sizeof(TValue *)*((n)-1))) 18 cast(int, sizeof(TValue *)*((n)-1)))
19 19
20 20
21/* test whether thread is in 'twups' list */
22#define isintwups(L) (L->twups != L)
23
24
21/* 25/*
22** Upvalues for Lua closures 26** Upvalues for Lua closures
23*/ 27*/
diff --git a/lgc.c b/lgc.c
index d51c4f5f..9471b894 100644
--- a/lgc.c
+++ b/lgc.c
@@ -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*/
293static void remarkupvals (global_State *g) { 299static 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*/
462static lu_mem traverseLclosure (global_State *g, LClosure *cl) { 479static 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);
diff --git a/lstate.c b/lstate.c
index 4c768c07..bc235941 100644
--- a/lstate.c
+++ b/lstate.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.c,v 2.118 2014/02/13 12:11:34 roberto Exp roberto $ 2** $Id: lstate.c,v 2.119 2014/02/13 14:46:38 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*/
@@ -222,6 +222,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
222 L->stack = NULL; 222 L->stack = NULL;
223 L->ci = NULL; 223 L->ci = NULL;
224 L->stacksize = 0; 224 L->stacksize = 0;
225 L->twups = L; /* thread has no upvalues */
225 L->errorJmp = NULL; 226 L->errorJmp = NULL;
226 L->nCcalls = 0; 227 L->nCcalls = 0;
227 L->hook = NULL; 228 L->hook = NULL;
@@ -317,6 +318,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
317 g->sweepgc = NULL; 318 g->sweepgc = NULL;
318 g->gray = g->grayagain = NULL; 319 g->gray = g->grayagain = NULL;
319 g->weak = g->ephemeron = g->allweak = NULL; 320 g->weak = g->ephemeron = g->allweak = NULL;
321 g->twups = NULL;
320 g->totalbytes = sizeof(LG); 322 g->totalbytes = sizeof(LG);
321 g->GCdebt = 0; 323 g->GCdebt = 0;
322 g->gcfinnum = 0; 324 g->gcfinnum = 0;
diff --git a/lstate.h b/lstate.h
index 4acdee84..9df36f32 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.99 2014/02/13 12:11:34 roberto Exp roberto $ 2** $Id: lstate.h,v 2.100 2014/02/13 14:46:38 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*/
@@ -124,6 +124,7 @@ typedef struct global_State {
124 GCObject *allweak; /* list of all-weak tables */ 124 GCObject *allweak; /* list of all-weak tables */
125 GCObject *tobefnz; /* list of userdata to be GC */ 125 GCObject *tobefnz; /* list of userdata to be GC */
126 GCObject *fixedgc; /* list of objects not to be collected */ 126 GCObject *fixedgc; /* list of objects not to be collected */
127 struct lua_State *twups; /* list of threads with open upvalues */
127 Mbuffer buff; /* temporary buffer for string concatenation */ 128 Mbuffer buff; /* temporary buffer for string concatenation */
128 unsigned int gcfinnum; /* number of finalizers to call in each GC step */ 129 unsigned int gcfinnum; /* number of finalizers to call in each GC step */
129 int gcpause; /* size of pause between successive GCs */ 130 int gcpause; /* size of pause between successive GCs */
@@ -159,6 +160,7 @@ struct lua_State {
159 lua_Hook hook; 160 lua_Hook hook;
160 UpVal *openupval; /* list of open upvalues in this stack */ 161 UpVal *openupval; /* list of open upvalues in this stack */
161 GCObject *gclist; 162 GCObject *gclist;
163 struct lua_State *twups; /* list of threads with open upvalues */
162 struct lua_longjmp *errorJmp; /* current error recover point */ 164 struct lua_longjmp *errorJmp; /* current error recover point */
163 ptrdiff_t errfunc; /* current error handling function (stack index) */ 165 ptrdiff_t errfunc; /* current error handling function (stack index) */
164 CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ 166 CallInfo base_ci; /* CallInfo for first level (C calling Lua) */