diff --git a/lgc.c b/lgc.c index 58d0bf7d..a43cc6a8 100644 --- a/lgc.c +++ b/lgc.c @@ -1695,21 +1695,23 @@ static void incstep (lua_State *L, global_State *g) { #if !defined(luai_tracegc) -#define luai_tracegc(L) ((void)0) +#define luai_tracegc(L,f) ((void)0) #endif /* -** Performs a basic GC step if collector is running. (If collector is -** not running, set a reasonable debt to avoid it being called at -** every single check.) +** Performs a basic GC step if collector is running. (If collector was +** stopped by the user, set a reasonable debt to avoid it being called +** at every single check.) */ void luaC_step (lua_State *L) { global_State *g = G(L); lua_assert(!g->gcemergency); - if (!gcrunning(g)) /* not running? */ - luaE_setdebt(g, 20000); + if (!gcrunning(g)) { /* not running? */ + if (g->gcstp & GCSTPUSR) /* stopped by the user? */ + luaE_setdebt(g, 20000); + } else { - luai_tracegc(L); /* for internal debugging */ + luai_tracegc(L, 1); /* for internal debugging */ switch (g->gckind) { case KGC_INC: case KGC_GENMAJOR: incstep(L, g); @@ -1719,6 +1721,7 @@ void luaC_step (lua_State *L) { setminordebt(g); break; } + luai_tracegc(L, 0); /* for internal debugging */ } } diff --git a/ltests.c b/ltests.c index 91bce2a1..3534d8d5 100644 --- a/ltests.c +++ b/ltests.c @@ -944,34 +944,63 @@ static int gc_printobj (lua_State *L) { } +static const char *statenames[] = { + "propagate", "enteratomic", "atomic", "sweepallgc", "sweepfinobj", + "sweeptobefnz", "sweepend", "callfin", "pause", ""}; + static int gc_state (lua_State *L) { - static const char *statenames[] = { - "propagate", "atomic", "sweepallgc", "sweepfinobj", - "sweeptobefnz", "sweepend", "callfin", "pause", ""}; static const int states[] = { - GCSpropagate, GCSenteratomic, GCSswpallgc, GCSswpfinobj, + GCSpropagate, GCSenteratomic, GCSatomic, GCSswpallgc, GCSswpfinobj, GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1}; int option = states[luaL_checkoption(L, 1, "", statenames)]; + global_State *g = G(L); if (option == -1) { - lua_pushstring(L, statenames[G(L)->gcstate]); + lua_pushstring(L, statenames[g->gcstate]); return 1; } else { - global_State *g = G(L); - if (G(L)->gckind != KGC_INC) + if (g->gckind != KGC_INC) luaL_error(L, "cannot change states in generational mode"); lua_lock(L); if (option < g->gcstate) { /* must cross 'pause'? */ luaC_runtilstate(L, GCSpause, 1); /* run until pause */ } luaC_runtilstate(L, option, 0); /* do not skip propagation state */ - lua_assert(G(L)->gcstate == option); + lua_assert(g->gcstate == option); lua_unlock(L); return 0; } } +static int tracinggc = 0; +void luai_tracegctest (lua_State *L, int first) { + if (!tracinggc) return; + else { + global_State *g = G(L); + lua_unlock(L); + g->gcstp = GCSTPGC; + lua_checkstack(L, 10); + lua_getfield(L, LUA_REGISTRYINDEX, "tracegc"); + lua_pushboolean(L, first); + lua_call(L, 1, 0); + g->gcstp = 0; + lua_lock(L); + } +} + + +static int tracegc (lua_State *L) { + if (lua_isnil(L, 1)) + tracinggc = 0; + else { + tracinggc = 1; + lua_setfield(L, LUA_REGISTRYINDEX, "tracegc"); + } + return 0; +} + + static int hash_query (lua_State *L) { if (lua_isnone(L, 2)) { luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); @@ -1038,17 +1067,17 @@ static int table_query (lua_State *L) { } -static int query_GCparams (lua_State *L) { +static int gc_query (lua_State *L) { global_State *g = G(L); - lua_pushinteger(L, cast(lua_Integer, gettotalbytes(g))); - lua_pushinteger(L, cast(lua_Integer, g->GCdebt)); - lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MINORMUL, 100))); - lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MAJORMINOR, 100))); - lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MINORMAJOR, 100))); - lua_pushinteger(L, cast(lua_Integer, applygcparam(g, PAUSE, 100))); - lua_pushinteger(L, cast(lua_Integer, applygcparam(g, STEPMUL, 100))); - lua_pushinteger(L, cast(lua_Integer, applygcparam(g, STEPSIZE, 100))); - return 8; + lua_pushstring(L, g->gckind == KGC_INC ? "inc" + : g->gckind == KGC_GENMAJOR ? "genmajor" + : "genminor"); + lua_pushstring(L, statenames[g->gcstate]); + lua_pushinteger(L, cast_st2S(gettotalbytes(g))); + lua_pushinteger(L, cast_st2S(g->GCdebt)); + lua_pushinteger(L, cast_st2S(g->GCmarked)); + lua_pushinteger(L, cast_st2S(g->GCmajorminor)); + return 6; } @@ -2009,6 +2038,7 @@ static const struct luaL_Reg tests_funcs[] = { {"gccolor", gc_color}, {"gcage", gc_age}, {"gcstate", gc_state}, + {"tracegc", tracegc}, {"pobj", gc_printobj}, {"getref", getref}, {"hash", hash_query}, @@ -2026,9 +2056,9 @@ static const struct luaL_Reg tests_funcs[] = { {"num2int", num2int}, {"makeseed", makeseed}, {"pushuserdata", pushuserdata}, + {"gcquery", gc_query}, {"querystr", string_query}, {"querytab", table_query}, - {"queryGCparams", query_GCparams}, {"codeparam", test_codeparam}, {"applyparam", test_applyparam}, {"ref", tref}, diff --git a/ltests.h b/ltests.h index 078c9fc3..906fae33 100644 --- a/ltests.h +++ b/ltests.h @@ -58,6 +58,10 @@ typedef struct Memcontrol { LUA_API Memcontrol l_memcontrol; +#define luai_tracegc(L,f) luai_tracegctest(L, f) +LUAI_FUNC void luai_tracegctest (lua_State *L, int first); + + /* ** generic variable for debug tricks */ diff --git a/testes/api.lua b/testes/api.lua index ae2f82dd..b7e34f7f 100644 --- a/testes/api.lua +++ b/testes/api.lua @@ -799,7 +799,7 @@ assert(debug.getuservalue(b) == 134) -- test barrier for uservalues do local oldmode = collectgarbage("incremental") - T.gcstate("atomic") + T.gcstate("enteratomic") assert(T.gccolor(b) == "black") debug.setuservalue(b, {x = 100}) T.gcstate("pause") -- complete collection diff --git a/testes/gc.lua b/testes/gc.lua index 3f8143b1..09bfe09a 100644 --- a/testes/gc.lua +++ b/testes/gc.lua @@ -560,8 +560,8 @@ if T then -- tests for weird cases collecting upvalues -- create coroutine in a weak table, so it will never be marked t.co = coroutine.wrap(foo) local f = t.co() -- create function to access local 'a' - T.gcstate("atomic") -- ensure all objects are traversed - assert(T.gcstate() == "atomic") + T.gcstate("enteratomic") -- ensure all objects are traversed + assert(T.gcstate() == "enteratomic") assert(t.co() == 100) -- resume coroutine, creating new table for 'a' assert(T.gccolor(t.co) == "white") -- thread was not traversed T.gcstate("pause") -- collect thread, but should mark 'a' before that @@ -574,7 +574,7 @@ if T then -- tests for weird cases collecting upvalues collectgarbage() collectgarbage"stop" local a = {} -- avoid 'u' as first element in 'allgc' - T.gcstate"atomic" + T.gcstate"enteratomic" T.gcstate"sweepallgc" local x = {} assert(T.gccolor(u) == "black") -- userdata is "old" (black)