aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-03-20 15:37:28 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-03-20 15:37:28 -0300
commitca2ceef659ed013277485acd0b6058a536649730 (patch)
tree1ff31ece632f1d6da84bc90c96255c3377b5d28f /lgc.c
parent5023aaee0aa7cb741dc112deec7dc9469d804cd5 (diff)
downloadlua-ca2ceef659ed013277485acd0b6058a536649730.tar.gz
lua-ca2ceef659ed013277485acd0b6058a536649730.tar.bz2
lua-ca2ceef659ed013277485acd0b6058a536649730.zip
simpler solution for finalizing udata
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c101
1 files changed, 54 insertions, 47 deletions
diff --git a/lgc.c b/lgc.c
index 1088cb23..264af24d 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 1.129 2002/03/05 16:22:54 roberto Exp roberto $ 2** $Id: lgc.c,v 1.130 2002/03/07 18:14:29 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*/
@@ -27,7 +27,6 @@ typedef struct GCState {
27} GCState; 27} GCState;
28 28
29 29
30
31/* mark a string; marks larger than 1 cannot be changed */ 30/* mark a string; marks larger than 1 cannot be changed */
32#define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;} 31#define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;}
33 32
@@ -37,6 +36,9 @@ typedef struct GCState {
37#define markud(u) (u->uv.len |= 1) 36#define markud(u) (u->uv.len |= 1)
38#define unmarkud(u) (u->uv.len &= (~(size_t)1)) 37#define unmarkud(u) (u->uv.len &= (~(size_t)1))
39 38
39#define isfinalized(u) (u->uv.len & 2)
40#define markfinalized(u) (u->uv.len |= 2)
41
40 42
41/* mark tricks for upvalues (assume that open upvalues are always marked) */ 43/* mark tricks for upvalues (assume that open upvalues are always marked) */
42#define isupvalmarked(uv) ((uv)->v != &(uv)->value) 44#define isupvalmarked(uv) ((uv)->v != &(uv)->value)
@@ -97,10 +99,17 @@ static void marktable (GCState *st, Table *h) {
97 if (!ismarked(h)) { 99 if (!ismarked(h)) {
98 h->mark = st->tmark; /* chain it for later traversal */ 100 h->mark = st->tmark; /* chain it for later traversal */
99 st->tmark = h; 101 st->tmark = h;
102 marktable(st, h->metatable);
100 } 103 }
101} 104}
102 105
103 106
107static void markudata (GCState *st, Udata *u) {
108 markud(u);
109 marktable(st, u->uv.metatable);
110}
111
112
104static void reallymarkobject (GCState *st, TObject *o) { 113static void reallymarkobject (GCState *st, TObject *o) {
105 switch (ttype(o)) { 114 switch (ttype(o)) {
106 case LUA_TSTRING: 115 case LUA_TSTRING:
@@ -108,7 +117,7 @@ static void reallymarkobject (GCState *st, TObject *o) {
108 break; 117 break;
109 case LUA_TUSERDATA: 118 case LUA_TUSERDATA:
110 if (!isudmarked(uvalue(o))) 119 if (!isudmarked(uvalue(o)))
111 markud(uvalue(o)); 120 markudata(st, uvalue(o));
112 break; 121 break;
113 case LUA_TFUNCTION: 122 case LUA_TFUNCTION:
114 markclosure(st, clvalue(o)); 123 markclosure(st, clvalue(o));
@@ -156,12 +165,33 @@ static void markstacks (GCState *st) {
156} 165}
157 166
158 167
159static void markudet (GCState *st) { 168static void marktmu (GCState *st) {
160 Udata *u; 169 Udata *u;
161 for (u = G(st->L)->rootudata; u; u = u->uv.next)
162 marktable(st, u->uv.metatable);
163 for (u = G(st->L)->tmudata; u; u = u->uv.next) 170 for (u = G(st->L)->tmudata; u; u = u->uv.next)
164 marktable(st, u->uv.metatable); 171 markudata(st, u);
172}
173
174
175/* move `dead' udata that need finalization to list `tmudata' */
176static void separateudata (lua_State *L) {
177 Udata **p = &G(L)->rootudata;
178 Udata *curr;
179 Udata *collected = NULL; /* to collect udata with gc event */
180 Udata **lastcollected = &collected;
181 while ((curr = *p) != NULL) {
182 if (isudmarked(curr) || isfinalized(curr) ||
183 (fasttm(L, curr->uv.metatable, TM_GC) == NULL))
184 p = &curr->uv.next;
185 else { /* must call its gc method */
186 *p = curr->uv.next;
187 curr->uv.next = NULL; /* link `curr' at the end of `collected' list */
188 *lastcollected = curr;
189 lastcollected = &curr->uv.next;
190 }
191 }
192 /* insert collected udata with gc event into `tmudata' list */
193 *lastcollected = G(L)->tmudata;
194 G(L)->tmudata = collected;
165} 195}
166 196
167 197
@@ -208,7 +238,6 @@ static void markall (GCState *st) {
208 lua_assert(hvalue(defaultmeta(st->L))->flags == cast(unsigned short, ~0)); 238 lua_assert(hvalue(defaultmeta(st->L))->flags == cast(unsigned short, ~0));
209 /* table is unchanged */ 239 /* table is unchanged */
210 markstacks(st); /* mark all stacks */ 240 markstacks(st); /* mark all stacks */
211 markudet(st); /* mark userdata's meta tables */
212 while (st->tmark) { /* traverse marked tables */ 241 while (st->tmark) { /* traverse marked tables */
213 Table *h = st->tmark; /* get first table from list */ 242 Table *h = st->tmark; /* get first table from list */
214 st->tmark = h->mark; /* remove it from list */ 243 st->tmark = h->mark; /* remove it from list */
@@ -322,11 +351,10 @@ static void collecttable (lua_State *L) {
322} 351}
323 352
324 353
354
325static void collectudata (lua_State *L) { 355static void collectudata (lua_State *L) {
326 Udata **p = &G(L)->rootudata; 356 Udata **p = &G(L)->rootudata;
327 Udata *curr; 357 Udata *curr;
328 Udata *collected = NULL; /* to collect udata with gc event */
329 Udata **lastcollected = &collected;
330 while ((curr = *p) != NULL) { 358 while ((curr = *p) != NULL) {
331 if (isudmarked(curr)) { 359 if (isudmarked(curr)) {
332 unmarkud(curr); 360 unmarkud(curr);
@@ -334,18 +362,11 @@ static void collectudata (lua_State *L) {
334 } 362 }
335 else { 363 else {
336 *p = curr->uv.next; 364 *p = curr->uv.next;
337 if (fasttm(L, curr->uv.metatable, TM_GC) != NULL) { /* gc event? */ 365 lua_assert(isfinalized(curr) ||
338 curr->uv.next = NULL; /* link `curr' at the end of `collected' list */ 366 fasttm(L, curr->uv.metatable, TM_GC) == NULL);
339 *lastcollected = curr; 367 luaM_free(L, curr, sizeudata(curr->uv.len & (~(size_t)3)));
340 lastcollected = &curr->uv.next;
341 }
342 else /* no gc event; delete udata */
343 luaM_free(L, curr, sizeudata(curr->uv.len));
344 } 368 }
345 } 369 }
346 /* insert collected udata with gc event into `tmudata' list */
347 *lastcollected = G(L)->tmudata;
348 G(L)->tmudata = collected;
349} 370}
350 371
351 372
@@ -395,44 +416,27 @@ static void do1gcTM (lua_State *L, Udata *udata) {
395} 416}
396 417
397 418
398static void unprotectedcallGCTM (lua_State *L, void *pu) { 419static void callGCTM (lua_State *L) {
399 luaD_checkstack(L, 3); 420 int oldah = L->allowhooks;
421 L->allowhooks = 0; /* stop debug hooks during GC tag methods */
400 L->top++; /* reserve space to keep udata while runs its gc method */ 422 L->top++; /* reserve space to keep udata while runs its gc method */
401 while (G(L)->tmudata != NULL) { 423 while (G(L)->tmudata != NULL) {
402 Udata *udata = G(L)->tmudata; 424 Udata *udata = G(L)->tmudata;
403 G(L)->tmudata = udata->uv.next; /* remove udata from list */ 425 G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */
404 *(Udata **)pu = udata; /* keep a reference to it (in case of errors) */ 426 udata->uv.next = G(L)->rootudata; /* return it to `root' list */
405 setuvalue(L->top - 1, udata); /* and on stack (in case of recursive GC) */
406 udata->uv.next = G(L)->rootudata; /* resurect it */
407 G(L)->rootudata = udata; 427 G(L)->rootudata = udata;
428 setuvalue(L->top - 1, udata); /* keep a reference to it */
429 unmarkud(udata);
430 markfinalized(udata);
408 do1gcTM(L, udata); 431 do1gcTM(L, udata);
409 /* mark udata as finalized (default meta table) */
410 uvalue(L->top-1)->uv.metatable = hvalue(defaultmeta(L));
411 unmarkud(uvalue(L->top-1));
412 } 432 }
413 L->top--; 433 L->top--;
414}
415
416
417static void callGCTM (lua_State *L) {
418 int oldah = L->allowhooks;
419 L->allowhooks = 0; /* stop debug hooks during GC tag methods */
420 while (G(L)->tmudata != NULL) {
421 Udata *udata;
422 if (luaD_runprotected(L, unprotectedcallGCTM, &udata) != 0) {
423 /* `udata' generated an error during its gc */
424 /* mark it as finalized (default meta table) */
425 udata->uv.metatable = hvalue(defaultmeta(L));
426 }
427 }
428 L->allowhooks = oldah; /* restore hooks */ 434 L->allowhooks = oldah; /* restore hooks */
429} 435}
430 436
431 437
432void luaC_callallgcTM (lua_State *L) { 438void luaC_callallgcTM (lua_State *L) {
433 lua_assert(G(L)->tmudata == NULL); 439 separateudata(L);
434 G(L)->tmudata = G(L)->rootudata; /* all udata must be collected */
435 G(L)->rootudata = NULL;
436 callGCTM(L); /* call their GC tag methods */ 440 callGCTM(L); /* call their GC tag methods */
437} 441}
438 442
@@ -452,7 +456,10 @@ void luaC_collectgarbage (lua_State *L) {
452 st.L = L; 456 st.L = L;
453 st.tmark = NULL; 457 st.tmark = NULL;
454 st.toclear = NULL; 458 st.toclear = NULL;
455 markall(&st); 459 markall(&st); /* mark all reachable objects */
460 separateudata(L); /* separate userdata to be preserved */
461 marktmu(&st); /* mark `preserved' userdata */
462 markall(&st); /* remark */
456 cleartables(st.toclear); 463 cleartables(st.toclear);
457 luaC_collect(L, 0); 464 luaC_collect(L, 0);
458 checkMbuffer(L); 465 checkMbuffer(L);