From 6a2d1112c3cf64b46f7c60d7878d5cc8101fc5cd Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Fri, 7 Jun 2024 10:07:44 +0200 Subject: Debug code to help track linda gc during keeper operation --- deep_test/deeptest.lua | 52 +++++++++++++++++++++++++++++++++++--------------- src/debug.h | 2 ++ src/linda.cpp | 2 ++ src/linda.h | 32 ++++++++++++++++++++++++++++--- src/lindafactory.cpp | 2 +- 5 files changed, 71 insertions(+), 19 deletions(-) diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua index 99cf1e4..250eb98 100644 --- a/deep_test/deeptest.lua +++ b/deep_test/deeptest.lua @@ -1,6 +1,8 @@ local lanes = require("lanes").configure{ with_timers = false} local l = lanes.linda "my linda" +local table_unpack = table.unpack or unpack -- Lua 5.1 support + -- we will transfer userdata created by this module, so we need to make Lanes aware of it local dt = lanes.require "deep_test" @@ -93,24 +95,44 @@ if DEEP then print "================================================================" print "DEEP" local d = dt.new_deep(nupvals) - if DEEP == "gc" then - local thrasher = function(repeat_, size_) - print "in thrasher" - -- result is a table of repeat_ tables, each containing size_ entries - local result = {} - for i = 1, repeat_ do - local batch_values = {} - for j = 1, size_ do - table.insert(batch_values, j) + if type(DEEP) == "string" then + local gc_tests = { + thrasher = function(repeat_, size_) + print "in thrasher" + -- result is a table of repeat_ tables, each containing size_ entries + local result = {} + for i = 1, repeat_ do + local batch_values = {} + for j = 1, size_ do + table.insert(batch_values, j) + end + table.insert(result, batch_values) + end + print "thrasher done" + return result + end, + stack_abuser = function(repeat_, size_) + print "in stack_abuser" + for i = 1, repeat_ do + local batch_values = {} + for j = 1, size_ do + table.insert(batch_values, j) + end + -- return size_ values + local _ = table_unpack(batch_values) end - table.insert(result, batch_values) + print "stack_abuser done" + return result end - print "thrasher done" - return result - end + } -- have the object call the function from inside one of its functions, to detect if it gets collected from there (while in use!) - local r = d:invoke(thrasher, REPEAT or 10, SIZE or 10) - print("invoke -> ", tostring(r)) + local testf = gc_tests[DEEP] + if testf then + local r = d:invoke(gc_tests[DEEP], REPEAT or 10, SIZE or 10) + print("invoke -> ", tostring(r)) + else + print("unknown test '" .. DEEP .. "'") + end else performTest(d) end diff --git a/src/debug.h b/src/debug.h index a0a4b8d..99fe48a 100644 --- a/src/debug.h +++ b/src/debug.h @@ -15,6 +15,7 @@ inline void LUA_ASSERT_IMPL(lua_State* L_, bool cond_, char const* file_, int co } #define LUA_ASSERT(L_, cond_) LUA_ASSERT_IMPL(L_, cond_, __FILE__, __LINE__, #cond_) +#define LUA_ASSERT_CODE(code_) code_ class StackChecker { @@ -102,6 +103,7 @@ class StackChecker #else // HAVE_LUA_ASSERT() #define LUA_ASSERT(L_, c) nullptr // nothing +#define LUA_ASSERT_CODE(code_) nullptr #define STACK_CHECK_START_REL(L_, offset_) #define STACK_CHECK_START_ABS(L_, offset_) diff --git a/src/linda.cpp b/src/linda.cpp index 8b6df8e..3449f89 100644 --- a/src/linda.cpp +++ b/src/linda.cpp @@ -181,6 +181,8 @@ int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_) lua_State* const _KL{ _K ? _K->L : nullptr }; if (_KL == nullptr) return 0; + + LUA_ASSERT_CODE(auto const _koip{ _linda->startKeeperOperation(L_) }); // if we didn't do anything wrong, the keeper stack should be clean LUA_ASSERT(L_, lua_gettop(_KL) == 0); diff --git a/src/linda.h b/src/linda.h index 8db380a..809ade5 100644 --- a/src/linda.h +++ b/src/linda.h @@ -23,15 +23,39 @@ using LindaGroup = Unique; class Linda : public DeepPrelude // Deep userdata MUST start with this header { + public: + class KeeperOperationInProgress + { + private: + Linda& linda; + [[maybe_unused]] lua_State* const L; // just here for inspection while debugging + + public: + KeeperOperationInProgress(Linda& linda_, lua_State* const L_) + : linda{ linda_ } + , L{ L_ } + { + [[maybe_unused]] int const _prev{ linda.keeperOperationCount.fetch_add(1, std::memory_order_seq_cst) }; + } + + public: + ~KeeperOperationInProgress() + { + [[maybe_unused]] int const _prev{ linda.keeperOperationCount.fetch_sub(1, std::memory_order_seq_cst) }; + } + }; + private: static constexpr size_t kEmbeddedNameLength = 24; using EmbeddedName = std::array; // depending on the name length, it is either embedded inside the Linda, or allocated separately - std::variant nameVariant; + std::variant nameVariant{}; + // counts the keeper operations in progress + std::atomic keeperOperationCount{}; public: - std::condition_variable readHappened; - std::condition_variable writeHappened; + std::condition_variable readHappened{}; + std::condition_variable writeHappened{}; Universe* const U{ nullptr }; // the universe this linda belongs to int const keeperIndex{ -1 }; // the keeper associated to this linda CancelRequest cancelRequest{ CancelRequest::None }; @@ -60,7 +84,9 @@ class Linda public: [[nodiscard]] Keeper* acquireKeeper() const; [[nodiscard]] std::string_view getName() const; + [[nodiscard]] bool inKeeperOperation() const { return keeperOperationCount.load(std::memory_order_seq_cst) != 0; } void releaseKeeper(Keeper* keeper_) const; [[nodiscard]] static int ProtectedCall(lua_State* L_, lua_CFunction f_); + [[nodiscard]] KeeperOperationInProgress startKeeperOperation(lua_State* const L_) { return KeeperOperationInProgress{ *this, L_ }; }; [[nodiscard]] Keeper* whichKeeper() const { return U->keepers.getKeeper(keeperIndex); } }; diff --git a/src/lindafactory.cpp b/src/lindafactory.cpp index 3f4b9b0..6a2b000 100644 --- a/src/lindafactory.cpp +++ b/src/lindafactory.cpp @@ -69,7 +69,7 @@ void LindaFactory::createMetatable(lua_State* L_) const void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) const { Linda* const _linda{ static_cast(o_) }; - LUA_ASSERT(L_, _linda); + LUA_ASSERT(L_, _linda && !_linda->inKeeperOperation()); Keeper* const _myK{ _linda->whichKeeper() }; // if collected after the universe, keepers are already destroyed, and there is nothing to clear if (_myK) { -- cgit v1.2.3-55-g6feb