lgc.c
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:9k
源码类别:

模拟服务器

开发平台:

C/C++

  1. /*
  2. ** $Id: lgc.c,v 1.72 2000/10/26 12:47:05 roberto Exp $
  3. ** Garbage Collector
  4. ** See Copyright Notice in lua.h
  5. */
  6. #include "lua.h"
  7. #include "ldo.h"
  8. #include "lfunc.h"
  9. #include "lgc.h"
  10. #include "lmem.h"
  11. #include "lobject.h"
  12. #include "lstate.h"
  13. #include "lstring.h"
  14. #include "ltable.h"
  15. #include "ltm.h"
  16. typedef struct GCState {
  17.   Hash *tmark;  /* list of marked tables to be visited */
  18.   Closure *cmark;  /* list of marked closures to be visited */
  19. } GCState;
  20. static void markobject (GCState *st, TObject *o);
  21. /* mark a string; marks larger than 1 cannot be changed */
  22. #define strmark(s)    {if ((s)->marked == 0) (s)->marked = 1;}
  23. static void protomark (Proto *f) {
  24.   if (!f->marked) {
  25.     int i;
  26.     f->marked = 1;
  27.     strmark(f->source);
  28.     for (i=0; i<f->nkstr; i++)
  29.       strmark(f->kstr[i]);
  30.     for (i=0; i<f->nkproto; i++)
  31.       protomark(f->kproto[i]);
  32.     for (i=0; i<f->nlocvars; i++)  /* mark local-variable names */
  33.       strmark(f->locvars[i].varname);
  34.   }
  35. }
  36. static void markstack (lua_State *L, GCState *st) {
  37.   StkId o;
  38.   for (o=L->stack; o<L->top; o++)
  39.     markobject(st, o);
  40. }
  41. static void marklock (lua_State *L, GCState *st) {
  42.   int i;
  43.   for (i=0; i<L->refSize; i++) {
  44.     if (L->refArray[i].st == LOCK)
  45.       markobject(st, &L->refArray[i].o);
  46.   }
  47. }
  48. static void markclosure (GCState *st, Closure *cl) {
  49.   if (!ismarked(cl)) {
  50.     if (!cl->isC)
  51.       protomark(cl->f.l);
  52.     cl->mark = st->cmark;  /* chain it for later traversal */
  53.     st->cmark = cl;
  54.   }
  55. }
  56. static void marktagmethods (lua_State *L, GCState *st) {
  57.   int e;
  58.   for (e=0; e<TM_N; e++) {
  59.     int t;
  60.     for (t=0; t<=L->last_tag; t++) {
  61.       Closure *cl = luaT_gettm(L, t, e);
  62.       if (cl) markclosure(st, cl);
  63.     }
  64.   }
  65. }
  66. static void markobject (GCState *st, TObject *o) {
  67.   switch (ttype(o)) {
  68.     case LUA_TUSERDATA:  case LUA_TSTRING:
  69.       strmark(tsvalue(o));
  70.       break;
  71.     case LUA_TMARK:
  72.       markclosure(st, infovalue(o)->func);
  73.       break;
  74.     case LUA_TFUNCTION:
  75.       markclosure(st, clvalue(o));
  76.       break;
  77.     case LUA_TTABLE: {
  78.       if (!ismarked(hvalue(o))) {
  79.         hvalue(o)->mark = st->tmark;  /* chain it in list of marked */
  80.         st->tmark = hvalue(o);
  81.       }
  82.       break;
  83.     }
  84.     default: break;  /* numbers, etc */
  85.   }
  86. }
  87. static void markall (lua_State *L) {
  88.   GCState st;
  89.   st.cmark = NULL;
  90.   st.tmark = L->gt;  /* put table of globals in mark list */
  91.   L->gt->mark = NULL;
  92.   marktagmethods(L, &st);  /* mark tag methods */
  93.   markstack(L, &st); /* mark stack objects */
  94.   marklock(L, &st); /* mark locked objects */
  95.   for (;;) {  /* mark tables and closures */
  96.     if (st.cmark) {
  97.       int i;
  98.       Closure *f = st.cmark;  /* get first closure from list */
  99.       st.cmark = f->mark;  /* remove it from list */
  100.       for (i=0; i<f->nupvalues; i++)  /* mark its upvalues */
  101.         markobject(&st, &f->upvalue[i]);
  102.     }
  103.     else if (st.tmark) {
  104.       int i;
  105.       Hash *h = st.tmark;  /* get first table from list */
  106.       st.tmark = h->mark;  /* remove it from list */
  107.       for (i=0; i<h->size; i++) {
  108.         Node *n = node(h, i);
  109.         if (ttype(key(n)) != LUA_TNIL) {
  110.           if (ttype(val(n)) == LUA_TNIL)
  111.             luaH_remove(h, key(n));  /* dead element; try to remove it */
  112.           markobject(&st, &n->key);
  113.           markobject(&st, &n->val);
  114.         }
  115.       }
  116.     }
  117.     else break;  /* nothing else to mark */
  118.   }
  119. }
  120. static int hasmark (const TObject *o) {
  121.   /* valid only for locked objects */
  122.   switch (o->ttype) {
  123.     case LUA_TSTRING: case LUA_TUSERDATA:
  124.       return tsvalue(o)->marked;
  125.     case LUA_TTABLE:
  126.       return ismarked(hvalue(o));
  127.     case LUA_TFUNCTION:
  128.       return ismarked(clvalue(o));
  129.     default:  /* number */
  130.       return 1;
  131.   }
  132. }
  133. /* macro for internal debugging; check if a link of free refs is valid */
  134. #define VALIDLINK(L, st,n)      (NONEXT <= (st) && (st) < (n))
  135. static void invalidaterefs (lua_State *L) {
  136.   int n = L->refSize;
  137.   int i;
  138.   for (i=0; i<n; i++) {
  139.     struct Ref *r = &L->refArray[i];
  140.     if (r->st == HOLD && !hasmark(&r->o))
  141.       r->st = COLLECTED;
  142.     LUA_ASSERT((r->st == LOCK && hasmark(&r->o)) ||
  143.                (r->st == HOLD && hasmark(&r->o)) ||
  144.                 r->st == COLLECTED ||
  145.                 r->st == NONEXT ||
  146.                (r->st < n && VALIDLINK(L, L->refArray[r->st].st, n)),
  147.                "inconsistent ref table");
  148.   }
  149.   LUA_ASSERT(VALIDLINK(L, L->refFree, n), "inconsistent ref table");
  150. }
  151. static void collectproto (lua_State *L) {
  152.   Proto **p = &L->rootproto;
  153.   Proto *next;
  154.   while ((next = *p) != NULL) {
  155.     if (next->marked) {
  156.       next->marked = 0;
  157.       p = &next->next;
  158.     }
  159.     else {
  160.       *p = next->next;
  161.       luaF_freeproto(L, next);
  162.     }
  163.   }
  164. }
  165. static void collectclosure (lua_State *L) {
  166.   Closure **p = &L->rootcl;
  167.   Closure *next;
  168.   while ((next = *p) != NULL) {
  169.     if (ismarked(next)) {
  170.       next->mark = next;  /* unmark */
  171.       p = &next->next;
  172.     }
  173.     else {
  174.       *p = next->next;
  175.       luaF_freeclosure(L, next);
  176.     }
  177.   }
  178. }
  179. static void collecttable (lua_State *L) {
  180.   Hash **p = &L->roottable;
  181.   Hash *next;
  182.   while ((next = *p) != NULL) {
  183.     if (ismarked(next)) {
  184.       next->mark = next;  /* unmark */
  185.       p = &next->next;
  186.     }
  187.     else {
  188.       *p = next->next;
  189.       luaH_free(L, next);
  190.     }
  191.   }
  192. }
  193. static void checktab (lua_State *L, stringtable *tb) {
  194.   if (tb->nuse < (lint32)(tb->size/4) && tb->size > 10)
  195.     luaS_resize(L, tb, tb->size/2);  /* table is too big */
  196. }
  197. static void collectstrings (lua_State *L, int all) {
  198.   int i;
  199.   for (i=0; i<L->strt.size; i++) {  /* for each list */
  200.     TString **p = &L->strt.hash[i];
  201.     TString *next;
  202.     while ((next = *p) != NULL) {
  203.       if (next->marked && !all) {  /* preserve? */
  204.         if (next->marked < FIXMARK)  /* does not change FIXMARKs */
  205.           next->marked = 0;
  206.         p = &next->nexthash;
  207.       } 
  208.       else {  /* collect */
  209.         *p = next->nexthash;
  210.         L->strt.nuse--;
  211.         L->nblocks -= sizestring(next->len);
  212.         luaM_free(L, next);
  213.       }
  214.     }
  215.   }
  216.   checktab(L, &L->strt);
  217. }
  218. static void collectudata (lua_State *L, int all) {
  219.   int i;
  220.   for (i=0; i<L->udt.size; i++) {  /* for each list */
  221.     TString **p = &L->udt.hash[i];
  222.     TString *next;
  223.     while ((next = *p) != NULL) {
  224.       LUA_ASSERT(next->marked <= 1, "udata cannot be fixed");
  225.       if (next->marked && !all) {  /* preserve? */
  226.         next->marked = 0;
  227.         p = &next->nexthash;
  228.       } 
  229.       else {  /* collect */
  230.         int tag = next->u.d.tag;
  231.         *p = next->nexthash;
  232.         next->nexthash = L->TMtable[tag].collected;  /* chain udata */
  233.         L->TMtable[tag].collected = next;
  234.         L->nblocks -= sizestring(next->len);
  235.         L->udt.nuse--;
  236.       }
  237.     }
  238.   }
  239.   checktab(L, &L->udt);
  240. }
  241. #define MINBUFFER 256
  242. static void checkMbuffer (lua_State *L) {
  243.   if (L->Mbuffsize > MINBUFFER*2) {  /* is buffer too big? */
  244.     size_t newsize = L->Mbuffsize/2;  /* still larger than MINBUFFER */
  245.     L->nblocks += (newsize - L->Mbuffsize)*sizeof(char);
  246.     L->Mbuffsize = newsize;
  247.     luaM_reallocvector(L, L->Mbuffer, newsize, char);
  248.   }
  249. }
  250. static void callgcTM (lua_State *L, const TObject *o) {
  251.   Closure *tm = luaT_gettmbyObj(L, o, TM_GC);
  252.   if (tm != NULL) {
  253.     int oldah = L->allowhooks;
  254.     L->allowhooks = 0;  /* stop debug hooks during GC tag methods */
  255.     luaD_checkstack(L, 2);
  256.     clvalue(L->top) = tm;
  257.     ttype(L->top) = LUA_TFUNCTION;
  258.     *(L->top+1) = *o;
  259.     L->top += 2;
  260.     luaD_call(L, L->top-2, 0);
  261.     L->allowhooks = oldah;  /* restore hooks */
  262.   }
  263. }
  264. static void callgcTMudata (lua_State *L) {
  265.   int tag;
  266.   TObject o;
  267.   ttype(&o) = LUA_TUSERDATA;
  268.   L->GCthreshold = 2*L->nblocks;  /* avoid GC during tag methods */
  269.   for (tag=L->last_tag; tag>=0; tag--) {  /* for each tag (in reverse order) */
  270.     TString *udata;
  271.     while ((udata = L->TMtable[tag].collected) != NULL) {
  272.       L->TMtable[tag].collected = udata->nexthash;  /* remove it from list */
  273.       tsvalue(&o) = udata;
  274.       callgcTM(L, &o);
  275.       luaM_free(L, udata);
  276.     }
  277.   }
  278. }
  279. void luaC_collect (lua_State *L, int all) {
  280.   collectudata(L, all);
  281.   callgcTMudata(L);
  282.   collectstrings(L, all);
  283.   collecttable(L);
  284.   collectproto(L);
  285.   collectclosure(L);
  286. }
  287. static void luaC_collectgarbage (lua_State *L) {
  288.   markall(L);
  289.   invalidaterefs(L);  /* check unlocked references */
  290.   luaC_collect(L, 0);
  291.   checkMbuffer(L);
  292.   L->GCthreshold = 2*L->nblocks;  /* set new threshold */
  293.   callgcTM(L, &luaO_nilobject);
  294. }
  295. void luaC_checkGC (lua_State *L) {
  296.   if (L->nblocks >= L->GCthreshold)
  297.     luaC_collectgarbage(L);
  298. }