aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-10-21 15:18:20 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-10-21 15:18:20 -0300
commit258355734d3aceb34eb6288ece37d9bbd7f2bc6d (patch)
tree692b2f43cffa8255f6221704af29fb94c6bbd323
parentd0815046d003f8f24efcdb03d35dd125ddd3b5f9 (diff)
downloadlua-258355734d3aceb34eb6288ece37d9bbd7f2bc6d.tar.gz
lua-258355734d3aceb34eb6288ece37d9bbd7f2bc6d.tar.bz2
lua-258355734d3aceb34eb6288ece37d9bbd7f2bc6d.zip
Better support in 'ltests' for tracing the GC
-rw-r--r--lgc.c17
-rw-r--r--ltests.c68
-rw-r--r--ltests.h4
-rw-r--r--testes/api.lua2
-rw-r--r--testes/gc.lua6
5 files changed, 67 insertions, 30 deletions
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) {
1695 1695
1696 1696
1697#if !defined(luai_tracegc) 1697#if !defined(luai_tracegc)
1698#define luai_tracegc(L) ((void)0) 1698#define luai_tracegc(L,f) ((void)0)
1699#endif 1699#endif
1700 1700
1701/* 1701/*
1702** Performs a basic GC step if collector is running. (If collector is 1702** Performs a basic GC step if collector is running. (If collector was
1703** not running, set a reasonable debt to avoid it being called at 1703** stopped by the user, set a reasonable debt to avoid it being called
1704** every single check.) 1704** at every single check.)
1705*/ 1705*/
1706void luaC_step (lua_State *L) { 1706void luaC_step (lua_State *L) {
1707 global_State *g = G(L); 1707 global_State *g = G(L);
1708 lua_assert(!g->gcemergency); 1708 lua_assert(!g->gcemergency);
1709 if (!gcrunning(g)) /* not running? */ 1709 if (!gcrunning(g)) { /* not running? */
1710 luaE_setdebt(g, 20000); 1710 if (g->gcstp & GCSTPUSR) /* stopped by the user? */
1711 luaE_setdebt(g, 20000);
1712 }
1711 else { 1713 else {
1712 luai_tracegc(L); /* for internal debugging */ 1714 luai_tracegc(L, 1); /* for internal debugging */
1713 switch (g->gckind) { 1715 switch (g->gckind) {
1714 case KGC_INC: case KGC_GENMAJOR: 1716 case KGC_INC: case KGC_GENMAJOR:
1715 incstep(L, g); 1717 incstep(L, g);
@@ -1719,6 +1721,7 @@ void luaC_step (lua_State *L) {
1719 setminordebt(g); 1721 setminordebt(g);
1720 break; 1722 break;
1721 } 1723 }
1724 luai_tracegc(L, 0); /* for internal debugging */
1722 } 1725 }
1723} 1726}
1724 1727
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) {
944} 944}
945 945
946 946
947static const char *statenames[] = {
948 "propagate", "enteratomic", "atomic", "sweepallgc", "sweepfinobj",
949 "sweeptobefnz", "sweepend", "callfin", "pause", ""};
950
947static int gc_state (lua_State *L) { 951static int gc_state (lua_State *L) {
948 static const char *statenames[] = {
949 "propagate", "atomic", "sweepallgc", "sweepfinobj",
950 "sweeptobefnz", "sweepend", "callfin", "pause", ""};
951 static const int states[] = { 952 static const int states[] = {
952 GCSpropagate, GCSenteratomic, GCSswpallgc, GCSswpfinobj, 953 GCSpropagate, GCSenteratomic, GCSatomic, GCSswpallgc, GCSswpfinobj,
953 GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1}; 954 GCSswptobefnz, GCSswpend, GCScallfin, GCSpause, -1};
954 int option = states[luaL_checkoption(L, 1, "", statenames)]; 955 int option = states[luaL_checkoption(L, 1, "", statenames)];
956 global_State *g = G(L);
955 if (option == -1) { 957 if (option == -1) {
956 lua_pushstring(L, statenames[G(L)->gcstate]); 958 lua_pushstring(L, statenames[g->gcstate]);
957 return 1; 959 return 1;
958 } 960 }
959 else { 961 else {
960 global_State *g = G(L); 962 if (g->gckind != KGC_INC)
961 if (G(L)->gckind != KGC_INC)
962 luaL_error(L, "cannot change states in generational mode"); 963 luaL_error(L, "cannot change states in generational mode");
963 lua_lock(L); 964 lua_lock(L);
964 if (option < g->gcstate) { /* must cross 'pause'? */ 965 if (option < g->gcstate) { /* must cross 'pause'? */
965 luaC_runtilstate(L, GCSpause, 1); /* run until pause */ 966 luaC_runtilstate(L, GCSpause, 1); /* run until pause */
966 } 967 }
967 luaC_runtilstate(L, option, 0); /* do not skip propagation state */ 968 luaC_runtilstate(L, option, 0); /* do not skip propagation state */
968 lua_assert(G(L)->gcstate == option); 969 lua_assert(g->gcstate == option);
969 lua_unlock(L); 970 lua_unlock(L);
970 return 0; 971 return 0;
971 } 972 }
972} 973}
973 974
974 975
976static int tracinggc = 0;
977void luai_tracegctest (lua_State *L, int first) {
978 if (!tracinggc) return;
979 else {
980 global_State *g = G(L);
981 lua_unlock(L);
982 g->gcstp = GCSTPGC;
983 lua_checkstack(L, 10);
984 lua_getfield(L, LUA_REGISTRYINDEX, "tracegc");
985 lua_pushboolean(L, first);
986 lua_call(L, 1, 0);
987 g->gcstp = 0;
988 lua_lock(L);
989 }
990}
991
992
993static int tracegc (lua_State *L) {
994 if (lua_isnil(L, 1))
995 tracinggc = 0;
996 else {
997 tracinggc = 1;
998 lua_setfield(L, LUA_REGISTRYINDEX, "tracegc");
999 }
1000 return 0;
1001}
1002
1003
975static int hash_query (lua_State *L) { 1004static int hash_query (lua_State *L) {
976 if (lua_isnone(L, 2)) { 1005 if (lua_isnone(L, 2)) {
977 luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); 1006 luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected");
@@ -1038,17 +1067,17 @@ static int table_query (lua_State *L) {
1038} 1067}
1039 1068
1040 1069
1041static int query_GCparams (lua_State *L) { 1070static int gc_query (lua_State *L) {
1042 global_State *g = G(L); 1071 global_State *g = G(L);
1043 lua_pushinteger(L, cast(lua_Integer, gettotalbytes(g))); 1072 lua_pushstring(L, g->gckind == KGC_INC ? "inc"
1044 lua_pushinteger(L, cast(lua_Integer, g->GCdebt)); 1073 : g->gckind == KGC_GENMAJOR ? "genmajor"
1045 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MINORMUL, 100))); 1074 : "genminor");
1046 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MAJORMINOR, 100))); 1075 lua_pushstring(L, statenames[g->gcstate]);
1047 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, MINORMAJOR, 100))); 1076 lua_pushinteger(L, cast_st2S(gettotalbytes(g)));
1048 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, PAUSE, 100))); 1077 lua_pushinteger(L, cast_st2S(g->GCdebt));
1049 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, STEPMUL, 100))); 1078 lua_pushinteger(L, cast_st2S(g->GCmarked));
1050 lua_pushinteger(L, cast(lua_Integer, applygcparam(g, STEPSIZE, 100))); 1079 lua_pushinteger(L, cast_st2S(g->GCmajorminor));
1051 return 8; 1080 return 6;
1052} 1081}
1053 1082
1054 1083
@@ -2009,6 +2038,7 @@ static const struct luaL_Reg tests_funcs[] = {
2009 {"gccolor", gc_color}, 2038 {"gccolor", gc_color},
2010 {"gcage", gc_age}, 2039 {"gcage", gc_age},
2011 {"gcstate", gc_state}, 2040 {"gcstate", gc_state},
2041 {"tracegc", tracegc},
2012 {"pobj", gc_printobj}, 2042 {"pobj", gc_printobj},
2013 {"getref", getref}, 2043 {"getref", getref},
2014 {"hash", hash_query}, 2044 {"hash", hash_query},
@@ -2026,9 +2056,9 @@ static const struct luaL_Reg tests_funcs[] = {
2026 {"num2int", num2int}, 2056 {"num2int", num2int},
2027 {"makeseed", makeseed}, 2057 {"makeseed", makeseed},
2028 {"pushuserdata", pushuserdata}, 2058 {"pushuserdata", pushuserdata},
2059 {"gcquery", gc_query},
2029 {"querystr", string_query}, 2060 {"querystr", string_query},
2030 {"querytab", table_query}, 2061 {"querytab", table_query},
2031 {"queryGCparams", query_GCparams},
2032 {"codeparam", test_codeparam}, 2062 {"codeparam", test_codeparam},
2033 {"applyparam", test_applyparam}, 2063 {"applyparam", test_applyparam},
2034 {"ref", tref}, 2064 {"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 {
58LUA_API Memcontrol l_memcontrol; 58LUA_API Memcontrol l_memcontrol;
59 59
60 60
61#define luai_tracegc(L,f) luai_tracegctest(L, f)
62LUAI_FUNC void luai_tracegctest (lua_State *L, int first);
63
64
61/* 65/*
62** generic variable for debug tricks 66** generic variable for debug tricks
63*/ 67*/
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)
799-- test barrier for uservalues 799-- test barrier for uservalues
800do 800do
801 local oldmode = collectgarbage("incremental") 801 local oldmode = collectgarbage("incremental")
802 T.gcstate("atomic") 802 T.gcstate("enteratomic")
803 assert(T.gccolor(b) == "black") 803 assert(T.gccolor(b) == "black")
804 debug.setuservalue(b, {x = 100}) 804 debug.setuservalue(b, {x = 100})
805 T.gcstate("pause") -- complete collection 805 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
560 -- create coroutine in a weak table, so it will never be marked 560 -- create coroutine in a weak table, so it will never be marked
561 t.co = coroutine.wrap(foo) 561 t.co = coroutine.wrap(foo)
562 local f = t.co() -- create function to access local 'a' 562 local f = t.co() -- create function to access local 'a'
563 T.gcstate("atomic") -- ensure all objects are traversed 563 T.gcstate("enteratomic") -- ensure all objects are traversed
564 assert(T.gcstate() == "atomic") 564 assert(T.gcstate() == "enteratomic")
565 assert(t.co() == 100) -- resume coroutine, creating new table for 'a' 565 assert(t.co() == 100) -- resume coroutine, creating new table for 'a'
566 assert(T.gccolor(t.co) == "white") -- thread was not traversed 566 assert(T.gccolor(t.co) == "white") -- thread was not traversed
567 T.gcstate("pause") -- collect thread, but should mark 'a' before that 567 T.gcstate("pause") -- collect thread, but should mark 'a' before that
@@ -574,7 +574,7 @@ if T then -- tests for weird cases collecting upvalues
574 collectgarbage() 574 collectgarbage()
575 collectgarbage"stop" 575 collectgarbage"stop"
576 local a = {} -- avoid 'u' as first element in 'allgc' 576 local a = {} -- avoid 'u' as first element in 'allgc'
577 T.gcstate"atomic" 577 T.gcstate"enteratomic"
578 T.gcstate"sweepallgc" 578 T.gcstate"sweepallgc"
579 local x = {} 579 local x = {}
580 assert(T.gccolor(u) == "black") -- userdata is "old" (black) 580 assert(T.gccolor(u) == "black") -- userdata is "old" (black)