Преглед изворни кода

Better support in 'ltests' for tracing the GC

Roberto Ierusalimschy пре 9 месеци
родитељ
комит
258355734d
5 измењених фајлова са 67 додато и 30 уклоњено
  1. 10 7
      lgc.c
  2. 49 19
      ltests.c
  3. 4 0
      ltests.h
  4. 1 1
      testes/api.lua
  5. 3 3
      testes/gc.lua

+ 10 - 7
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 */
   }
 }
 

+ 49 - 19
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},

+ 4 - 0
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
 */

+ 1 - 1
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

+ 3 - 3
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)