aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deep_test/deeptest.lua52
-rw-r--r--src/debug.h2
-rw-r--r--src/linda.cpp2
-rw-r--r--src/linda.h32
-rw-r--r--src/lindafactory.cpp2
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 @@
1local lanes = require("lanes").configure{ with_timers = false} 1local lanes = require("lanes").configure{ with_timers = false}
2local l = lanes.linda "my linda" 2local l = lanes.linda "my linda"
3 3
4local table_unpack = table.unpack or unpack -- Lua 5.1 support
5
4-- we will transfer userdata created by this module, so we need to make Lanes aware of it 6-- we will transfer userdata created by this module, so we need to make Lanes aware of it
5local dt = lanes.require "deep_test" 7local dt = lanes.require "deep_test"
6 8
@@ -93,24 +95,44 @@ if DEEP then
93 print "================================================================" 95 print "================================================================"
94 print "DEEP" 96 print "DEEP"
95 local d = dt.new_deep(nupvals) 97 local d = dt.new_deep(nupvals)
96 if DEEP == "gc" then 98 if type(DEEP) == "string" then
97 local thrasher = function(repeat_, size_) 99 local gc_tests = {
98 print "in thrasher" 100 thrasher = function(repeat_, size_)
99 -- result is a table of repeat_ tables, each containing size_ entries 101 print "in thrasher"
100 local result = {} 102 -- result is a table of repeat_ tables, each containing size_ entries
101 for i = 1, repeat_ do 103 local result = {}
102 local batch_values = {} 104 for i = 1, repeat_ do
103 for j = 1, size_ do 105 local batch_values = {}
104 table.insert(batch_values, j) 106 for j = 1, size_ do
107 table.insert(batch_values, j)
108 end
109 table.insert(result, batch_values)
110 end
111 print "thrasher done"
112 return result
113 end,
114 stack_abuser = function(repeat_, size_)
115 print "in stack_abuser"
116 for i = 1, repeat_ do
117 local batch_values = {}
118 for j = 1, size_ do
119 table.insert(batch_values, j)
120 end
121 -- return size_ values
122 local _ = table_unpack(batch_values)
105 end 123 end
106 table.insert(result, batch_values) 124 print "stack_abuser done"
125 return result
107 end 126 end
108 print "thrasher done" 127 }
109 return result
110 end
111 -- have the object call the function from inside one of its functions, to detect if it gets collected from there (while in use!) 128 -- have the object call the function from inside one of its functions, to detect if it gets collected from there (while in use!)
112 local r = d:invoke(thrasher, REPEAT or 10, SIZE or 10) 129 local testf = gc_tests[DEEP]
113 print("invoke -> ", tostring(r)) 130 if testf then
131 local r = d:invoke(gc_tests[DEEP], REPEAT or 10, SIZE or 10)
132 print("invoke -> ", tostring(r))
133 else
134 print("unknown test '" .. DEEP .. "'")
135 end
114 else 136 else
115 performTest(d) 137 performTest(d)
116 end 138 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
15} 15}
16 16
17#define LUA_ASSERT(L_, cond_) LUA_ASSERT_IMPL(L_, cond_, __FILE__, __LINE__, #cond_) 17#define LUA_ASSERT(L_, cond_) LUA_ASSERT_IMPL(L_, cond_, __FILE__, __LINE__, #cond_)
18#define LUA_ASSERT_CODE(code_) code_
18 19
19class StackChecker 20class StackChecker
20{ 21{
@@ -102,6 +103,7 @@ class StackChecker
102#else // HAVE_LUA_ASSERT() 103#else // HAVE_LUA_ASSERT()
103 104
104#define LUA_ASSERT(L_, c) nullptr // nothing 105#define LUA_ASSERT(L_, c) nullptr // nothing
106#define LUA_ASSERT_CODE(code_) nullptr
105 107
106#define STACK_CHECK_START_REL(L_, offset_) 108#define STACK_CHECK_START_REL(L_, offset_)
107#define STACK_CHECK_START_ABS(L_, offset_) 109#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_)
181 lua_State* const _KL{ _K ? _K->L : nullptr }; 181 lua_State* const _KL{ _K ? _K->L : nullptr };
182 if (_KL == nullptr) 182 if (_KL == nullptr)
183 return 0; 183 return 0;
184
185 LUA_ASSERT_CODE(auto const _koip{ _linda->startKeeperOperation(L_) });
184 // if we didn't do anything wrong, the keeper stack should be clean 186 // if we didn't do anything wrong, the keeper stack should be clean
185 LUA_ASSERT(L_, lua_gettop(_KL) == 0); 187 LUA_ASSERT(L_, lua_gettop(_KL) == 0);
186 188
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<int>;
23class Linda 23class Linda
24: public DeepPrelude // Deep userdata MUST start with this header 24: public DeepPrelude // Deep userdata MUST start with this header
25{ 25{
26 public:
27 class KeeperOperationInProgress
28 {
29 private:
30 Linda& linda;
31 [[maybe_unused]] lua_State* const L; // just here for inspection while debugging
32
33 public:
34 KeeperOperationInProgress(Linda& linda_, lua_State* const L_)
35 : linda{ linda_ }
36 , L{ L_ }
37 {
38 [[maybe_unused]] int const _prev{ linda.keeperOperationCount.fetch_add(1, std::memory_order_seq_cst) };
39 }
40
41 public:
42 ~KeeperOperationInProgress()
43 {
44 [[maybe_unused]] int const _prev{ linda.keeperOperationCount.fetch_sub(1, std::memory_order_seq_cst) };
45 }
46 };
47
26 private: 48 private:
27 static constexpr size_t kEmbeddedNameLength = 24; 49 static constexpr size_t kEmbeddedNameLength = 24;
28 using EmbeddedName = std::array<char, kEmbeddedNameLength>; 50 using EmbeddedName = std::array<char, kEmbeddedNameLength>;
29 // depending on the name length, it is either embedded inside the Linda, or allocated separately 51 // depending on the name length, it is either embedded inside the Linda, or allocated separately
30 std::variant<std::string_view, EmbeddedName> nameVariant; 52 std::variant<std::string_view, EmbeddedName> nameVariant{};
53 // counts the keeper operations in progress
54 std::atomic<int> keeperOperationCount{};
31 55
32 public: 56 public:
33 std::condition_variable readHappened; 57 std::condition_variable readHappened{};
34 std::condition_variable writeHappened; 58 std::condition_variable writeHappened{};
35 Universe* const U{ nullptr }; // the universe this linda belongs to 59 Universe* const U{ nullptr }; // the universe this linda belongs to
36 int const keeperIndex{ -1 }; // the keeper associated to this linda 60 int const keeperIndex{ -1 }; // the keeper associated to this linda
37 CancelRequest cancelRequest{ CancelRequest::None }; 61 CancelRequest cancelRequest{ CancelRequest::None };
@@ -60,7 +84,9 @@ class Linda
60 public: 84 public:
61 [[nodiscard]] Keeper* acquireKeeper() const; 85 [[nodiscard]] Keeper* acquireKeeper() const;
62 [[nodiscard]] std::string_view getName() const; 86 [[nodiscard]] std::string_view getName() const;
87 [[nodiscard]] bool inKeeperOperation() const { return keeperOperationCount.load(std::memory_order_seq_cst) != 0; }
63 void releaseKeeper(Keeper* keeper_) const; 88 void releaseKeeper(Keeper* keeper_) const;
64 [[nodiscard]] static int ProtectedCall(lua_State* L_, lua_CFunction f_); 89 [[nodiscard]] static int ProtectedCall(lua_State* L_, lua_CFunction f_);
90 [[nodiscard]] KeeperOperationInProgress startKeeperOperation(lua_State* const L_) { return KeeperOperationInProgress{ *this, L_ }; };
65 [[nodiscard]] Keeper* whichKeeper() const { return U->keepers.getKeeper(keeperIndex); } 91 [[nodiscard]] Keeper* whichKeeper() const { return U->keepers.getKeeper(keeperIndex); }
66}; 92};
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
69void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) const 69void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) const
70{ 70{
71 Linda* const _linda{ static_cast<Linda*>(o_) }; 71 Linda* const _linda{ static_cast<Linda*>(o_) };
72 LUA_ASSERT(L_, _linda); 72 LUA_ASSERT(L_, _linda && !_linda->inKeeperOperation());
73 Keeper* const _myK{ _linda->whichKeeper() }; 73 Keeper* const _myK{ _linda->whichKeeper() };
74 // if collected after the universe, keepers are already destroyed, and there is nothing to clear 74 // if collected after the universe, keepers are already destroyed, and there is nothing to clear
75 if (_myK) { 75 if (_myK) {