Beispiel #1
0
static void generationalcollection (lua_State *L) {
  global_State *g = G(L);
  if (g->lastmajormem == 0) {  /* signal for another major collection? */
    luaC_fullgc(L, 0);  /* perform a full regular collection */
    g->lastmajormem = gettotalbytes(g);  /* update control */
  }
  else {
    luaC_runtilstate(L, ~bitmask(GCSpause));  /* run complete cycle */
    luaC_runtilstate(L, bitmask(GCSpause));
    if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc)
      g->lastmajormem = 0;  /* signal for a major collection */
  }
  luaE_setdebt(g, stddebt(g));
}
Beispiel #2
0
/*
** performs a full GC cycle; if "isemergency", does not call
** finalizers (which could change stack positions)
*/
void luaC_fullgc (lua_State *L, int isemergency) {
	global_State *g = G(L);
	int origkind = g->gckind;
	lua_assert(origkind != KGC_EMERGENCY);
	if (isemergency)  /* do not run finalizers during emergency GC */
	g->gckind = KGC_EMERGENCY;
	else {
	g->gckind = KGC_NORMAL;
	callallpendingfinalizers(L, 1);
	}
	if (keepinvariant(g)) {  /* may there be some black objects? */
	/* must sweep all objects to turn them back to white
	   (as white has not changed, nothing will be collected) */
	entersweep(L);
	}
	/* finish any pending sweep phase to start a new cycle */
	luaC_runtilstate(L, bitmask(GCSpause));
	luaC_runtilstate(L, ~bitmask(GCSpause));  /* start new collection */
	luaC_runtilstate(L, bitmask(GCSpause));  /* run entire collection */
	if (origkind == KGC_GEN) {  /* generational mode? */
	/* generational mode must be kept in propagate phase */
	luaC_runtilstate(L, bitmask(GCSpropagate));
	}
	g->gckind = origkind;
	setpause(g, gettotalbytes(g));
	if (!isemergency)   /* do not run finalizers during emergency GC */
	callallpendingfinalizers(L, 1);
}
Beispiel #3
0
/*
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
** invariant (and avoiding underflows in 'totalbytes')
*/
void luaE_setdebt (global_State *g, l_mem debt) {
  l_mem tb = gettotalbytes(g);
  lua_assert(tb > 0);
  if (debt < tb - MAX_LMEM)
    debt = tb - MAX_LMEM;  /* will make 'totalbytes == MAX_LMEM' */
  g->totalbytes = tb - debt;
  g->GCdebt = debt;
}
Beispiel #4
0
/*
** set a reasonable "time" to wait before starting a new GC cycle;
** cycle will start when memory use hits threshold
*/
static void setpause (global_State *g, l_mem estimate) {
	l_mem debt, threshold;
	estimate = estimate / PAUSEADJ;  /* adjust 'estimate' */
	threshold = (g->gcpause < MAX_LMEM / estimate)  /* overflow? */
			? estimate * g->gcpause  /* no overflow */
			: MAX_LMEM;  /* overflow; truncate to maximum */
	debt = -cast(l_mem, threshold - gettotalbytes(g));
	luaE_setdebt(g, debt);
}
Beispiel #5
0
/*
** set a reasonable "time" to wait before starting a new GC cycle;
** cycle will start when memory use hits threshold
*/
static void setpause (global_State *g) {
  l_mem threshold, debt;
  l_mem estimate = g->GCestimate / PAUSEADJ;  /* adjust 'estimate' */
  threshold = (g->gcpause < MAX_LMEM / estimate)  /* overflow? */
            ? estimate * g->gcpause  /* no overflow */
            : MAX_LMEM;  /* overflow; truncate to maximum */
  debt = gettotalbytes(g) - threshold;
  luaE_setdebt(g, debt);
}
Beispiel #6
0
static lu_mem singlestep (lua_State *L) {
    global_State *g = G(L);
    switch (g->gcstate) {
    case GCSpause: {
        g->GCmemtrav = g->strt.size * sizeof(GCObject*);
        restartcollection(g);
        g->gcstate = GCSpropagate;
        return g->GCmemtrav;
    }
    case GCSpropagate: {
        g->GCmemtrav = 0;
        lua_assert(g->gray);
        propagatemark(g);
        if (g->gray == NULL)  /* no more gray objects? */
            g->gcstate = GCSatomic;  /* finish propagate phase */
        return g->GCmemtrav;  /* memory traversed in this step */
    }
    case GCSatomic: {
        lu_mem work;
        int sw;
        propagateall(g);  /* make sure gray list is empty */
        work = atomic(L);  /* work is what was traversed by 'atomic' */
        sw = entersweep(L);
        g->GCestimate = gettotalbytes(g);  /* first estimate */;
        return work + sw * GCSWEEPCOST;
    }
    case GCSswpallgc: {  /* sweep "regular" objects */
        return sweepstep(L, g, GCSswpfinobj, &g->finobj);
    }
    case GCSswpfinobj: {  /* sweep objects with finalizers */
        return sweepstep(L, g, GCSswptobefnz, &g->tobefnz);
    }
    case GCSswptobefnz: {  /* sweep objects to be finalized */
        return sweepstep(L, g, GCSswpend, NULL);
    }
    case GCSswpend: {  /* finish sweeps */
        makewhite(g, g->mainthread);  /* sweep main thread */
        checkSizes(L, g);
        g->gcstate = GCScallfin;
        return 0;
    }
    case GCScallfin: {  /* call remaining finalizers */
        if (g->tobefnz && g->gckind != KGC_EMERGENCY) {
            int n = runafewfinalizers(L);
            return (n * GCFINALIZECOST);
        }
        else {  /* emergency mode or no more finalizers */
            g->gcstate = GCSpause;  /* finish collection */
            return 0;
        }
    }
    default:
        lua_assert(0);
        return 0;
    }
}
Beispiel #7
0
static void close_state (lua_State *L) {
  global_State *g = G(L);
  luaF_close(L, L->stack);  /* close all upvalues for this thread */
  luaC_freeallobjects(L);  /* collect all objects */
  luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
  luaZ_freebuffer(L, &g->buff);
  freestack(L);
  lua_assert(gettotalbytes(g) == sizeof(LG));
  (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0);  /* free main block */
}
Beispiel #8
0
static void generationalcollection (lua_State *L) {
	global_State *g = G(L);
	lua_assert(g->gcstate == GCSpropagate);
	if (g->GCestimate == 0) {  /* signal for another major collection? */
	luaC_fullgc(L, 0);  /* perform a full regular collection */
	g->GCestimate = gettotalbytes(g);  /* update control */
	}
	else {
	lu_mem estimate = g->GCestimate;
	luaC_runtilstate(L, bitmask(GCSpause));  /* run complete (minor) cycle */
	g->gcstate = GCSpropagate;  /* skip restart */
	if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc)
		g->GCestimate = 0;  /* signal for a major collection */
	else
		g->GCestimate = estimate;  /* keep estimate from last major coll. */

	}
	setpause(g, gettotalbytes(g));
	lua_assert(g->gcstate == GCSpropagate);
}
Beispiel #9
0
static void close_state (lua_State *L) {
  global_State *g = G(L);
  luaF_close(L, L->stack);  /* close all upvalues for this thread */
  luaC_freeallobjects(L);  /* collect all objects */
  if (g->version)  /* closing a fully built state? */
    luai_userstateclose(L);
  luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
  freestack(L);
  lua_assert(gettotalbytes(g) == sizeof(LG));
  (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0);  /* free main block */
}
Beispiel #10
0
/*
** Performs a full GC cycle; if 'isemergency', set a flag to avoid
** some operations which could change the interpreter state in some
** unexpected ways (running finalizers and shrinking some structures).
** Before running the collection, check 'keepinvariant'; if it is true,
** there may be some objects marked as black, so the collector has
** to sweep all objects to turn them back to white (as white has not
** changed, nothing will be collected).
*/
void luaC_fullgc (lua_State *L, int isemergency) {
  global_State *g = G(L);
  lua_assert(g->gckind == KGC_NORMAL);
  if (isemergency) g->gckind = KGC_EMERGENCY;  /* set flag */
  if (keepinvariant(g)) {  /* black objects? */
    entersweep(L); /* sweep everything to turn them back to white */
  }
  /* finish any pending sweep phase to start a new cycle */
  luaC_runtilstate(L, bitmask(GCSpause));
  luaC_runtilstate(L, ~bitmask(GCSpause));  /* start new collection */
  luaC_runtilstate(L, bitmask(GCScallfin));  /* run up to finalizers */
  /* estimate must be correct after a full GC cycle */
  lua_assert(g->GCestimate == gettotalbytes(g));
  luaC_runtilstate(L, bitmask(GCSpause));  /* finish collection */
  g->gckind = KGC_NORMAL;
  setpause(g);
}
Beispiel #11
0
/*
** change GC mode
*/
void luaC_changemode (lua_State *L, int mode) {
	global_State *g = G(L);
	if (mode == g->gckind) return;  /* nothing to change */
	if (mode == KGC_GEN) {  /* change to generational mode */
	/* make sure gray lists are consistent */
	luaC_runtilstate(L, bitmask(GCSpropagate));
	g->GCestimate = gettotalbytes(g);
	g->gckind = KGC_GEN;
	}
	else {  /* change to incremental mode */
	/* sweep all objects to turn them back to white
	   (as white has not changed, nothing extra will be collected) */
	g->gckind = KGC_NORMAL;
	entersweep(L);
	luaC_runtilstate(L, ~sweepphases);
	}
}
Beispiel #12
0
/*
** generic allocation routine.
*/
void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
  void *newblock;
  global_State *g = G(L);
  size_t realosize = (block) ? osize : 0;
  lua_assert((realosize == 0) == (block == NULL));
#if defined(HARDMEMTESTS)
  if (nsize > realosize && g->gcrunning)
    luaC_fullgc(L, 1);  /* force a GC whenever possible */
#endif
  newblock = (*g->frealloc)(g->ud, block, osize, nsize);
  if (newblock == NULL && nsize > 0) {
    api_check(L, nsize > realosize,
                 "realloc cannot fail when shrinking a block");
    if (g->gcrunning) {
      luaC_fullgc(L, 1);  /* try to free some memory... */
      newblock = (*g->frealloc)(g->ud, block, osize, nsize);  /* try again */
    }
    if (newblock == NULL)
      luaD_throw(L, LUA_ERRMEM);
  }
  lua_assert((nsize == 0) == (newblock == NULL));
  g->GCdebt = (g->GCdebt + nsize) - realosize;
#if defined(TRACEMEM)
  { /* auxiliary patch to monitor garbage collection.
    ** To plot, gnuplot with following command:
    ** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines
    */
    static unsigned long total = 0;  /* our "time" */
    static FILE *f = NULL;  /* output file */
    total++;  /* "time" always grows */
    if ((total % 200) == 0) {
      if (f == NULL) f = fopen(TRACEMEM, "w");
      fprintf(f, "%lu %u %d %d\n", total,
              gettotalbytes(g), g->GCdebt, g->gcstate * 10000);
    }
  }
#endif

  return newblock;
}