diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/keeper.cpp | 55 | ||||
-rw-r--r-- | src/keeper.hpp | 5 | ||||
-rw-r--r-- | src/lanes.cpp | 1 | ||||
-rw-r--r-- | src/lanes.lua | 1 | ||||
-rw-r--r-- | src/linda.cpp | 24 |
5 files changed, 86 insertions, 0 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp index e7b02e6..2d9d800 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
@@ -337,6 +337,16 @@ static void PushKeysDB(KeeperState const K_, StackIndex const idx_) | |||
337 | // ################################################################################################# | 337 | // ################################################################################################# |
338 | // ################################################################################################# | 338 | // ################################################################################################# |
339 | 339 | ||
340 | // in: linda | ||
341 | // out: nothing | ||
342 | int keepercall_collectgarbage(lua_State* const L_) | ||
343 | { | ||
344 | lua_gc(L_, LUA_GCCOLLECT, 0); | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | // ################################################################################################# | ||
349 | |||
340 | // in: linda [, key [, ...]] | 350 | // in: linda [, key [, ...]] |
341 | int keepercall_count(lua_State* const L_) | 351 | int keepercall_count(lua_State* const L_) |
342 | { | 352 | { |
@@ -926,6 +936,42 @@ void Keepers::DeleteKV::operator()(Keeper* const k_) const | |||
926 | 936 | ||
927 | // ################################################################################################# | 937 | // ################################################################################################# |
928 | 938 | ||
939 | void Keepers::collectGarbage() | ||
940 | { | ||
941 | if (isClosing.test(std::memory_order_acquire)) { | ||
942 | assert(false); // should never close more than once in practice | ||
943 | return; | ||
944 | } | ||
945 | |||
946 | if (std::holds_alternative<std::monostate>(keeper_array)) { | ||
947 | return; | ||
948 | } | ||
949 | |||
950 | auto _gcOneKeeper = [](Keeper& keeper_) { | ||
951 | std::lock_guard<std::mutex> _guard(keeper_.mutex); | ||
952 | if (keeper_.K) { | ||
953 | lua_gc(keeper_.K, LUA_GCCOLLECT, 0); | ||
954 | } | ||
955 | }; | ||
956 | |||
957 | if (std::holds_alternative<Keeper>(keeper_array)) { | ||
958 | _gcOneKeeper(std::get<Keeper>(keeper_array)); | ||
959 | } else { | ||
960 | KV& _kv = std::get<KV>(keeper_array); | ||
961 | |||
962 | // NOTE: imagine some keeper state N+1 currently holds a linda that uses another keeper N, and a _gc that will make use of it | ||
963 | // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists | ||
964 | // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success | ||
965 | // which is early-outed with a keepers->nbKeepers null-check | ||
966 | for (size_t const _i : std::ranges::iota_view{ size_t{ 0 }, _kv.nbKeepers }) { | ||
967 | _gcOneKeeper(_kv.keepers[_i]); | ||
968 | } | ||
969 | } | ||
970 | } | ||
971 | |||
972 | // ################################################################################################# | ||
973 | |||
974 | |||
929 | void Keepers::close() | 975 | void Keepers::close() |
930 | { | 976 | { |
931 | if (isClosing.test_and_set(std::memory_order_release)) { | 977 | if (isClosing.test_and_set(std::memory_order_release)) { |
@@ -1103,3 +1149,12 @@ void Keepers::initialize(Universe& U_, lua_State* L_, size_t const nbKeepers_, i | |||
1103 | } | 1149 | } |
1104 | } | 1150 | } |
1105 | } | 1151 | } |
1152 | |||
1153 | // ################################################################################################# | ||
1154 | |||
1155 | LUAG_FUNC(collectgarbage) | ||
1156 | { | ||
1157 | Universe* const _U{ Universe::Get(L_) }; | ||
1158 | _U->keepers.collectGarbage(); | ||
1159 | return 0; | ||
1160 | } | ||
diff --git a/src/keeper.hpp b/src/keeper.hpp index e2ad445..c0a8dc5 100644 --- a/src/keeper.hpp +++ b/src/keeper.hpp | |||
@@ -73,6 +73,7 @@ struct Keepers | |||
73 | static void* operator new(size_t size_) = delete; | 73 | static void* operator new(size_t size_) = delete; |
74 | 74 | ||
75 | Keepers() = default; | 75 | Keepers() = default; |
76 | void collectGarbage(); | ||
76 | void close(); | 77 | void close(); |
77 | [[nodiscard]] | 78 | [[nodiscard]] |
78 | Keeper* getKeeper(KeeperIndex idx_); | 79 | Keeper* getKeeper(KeeperIndex idx_); |
@@ -96,6 +97,8 @@ using keeper_api_t = lua_CFunction; | |||
96 | 97 | ||
97 | // lua_Cfunctions to run inside a keeper state | 98 | // lua_Cfunctions to run inside a keeper state |
98 | [[nodiscard]] | 99 | [[nodiscard]] |
100 | int keepercall_collectgarbage(lua_State* L_); | ||
101 | [[nodiscard]] | ||
99 | int keepercall_count(lua_State* L_); | 102 | int keepercall_count(lua_State* L_); |
100 | [[nodiscard]] | 103 | [[nodiscard]] |
101 | int keepercall_destruct(lua_State* L_); | 104 | int keepercall_destruct(lua_State* L_); |
@@ -116,3 +119,5 @@ int keepercall_set(lua_State* L_); | |||
116 | 119 | ||
117 | [[nodiscard]] | 120 | [[nodiscard]] |
118 | KeeperCallResult keeper_call(KeeperState K_, keeper_api_t func_, lua_State* L_, Linda* linda_, StackIndex starting_index_); | 121 | KeeperCallResult keeper_call(KeeperState K_, keeper_api_t func_, lua_State* L_, Linda* linda_, StackIndex starting_index_); |
122 | |||
123 | LUAG_FUNC(collectgarbage); | ||
diff --git a/src/lanes.cpp b/src/lanes.cpp index 83d01fb..f32e7af 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp | |||
@@ -649,6 +649,7 @@ extern LUAG_FUNC(linda); | |||
649 | namespace { | 649 | namespace { |
650 | namespace local { | 650 | namespace local { |
651 | static struct luaL_Reg const sLanesFunctions[] = { | 651 | static struct luaL_Reg const sLanesFunctions[] = { |
652 | { "collectgarbage", LG_collectgarbage }, | ||
652 | { Universe::kFinally, Universe::InitializeFinalizer }, | 653 | { Universe::kFinally, Universe::InitializeFinalizer }, |
653 | { "linda", LG_linda }, | 654 | { "linda", LG_linda }, |
654 | { "nameof", LG_nameof }, | 655 | { "nameof", LG_nameof }, |
diff --git a/src/lanes.lua b/src/lanes.lua index 8d8f25d..4df1f64 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
@@ -851,6 +851,7 @@ local configure = function(settings_) | |||
851 | 851 | ||
852 | -- activate full interface | 852 | -- activate full interface |
853 | lanes.cancel_error = core.cancel_error | 853 | lanes.cancel_error = core.cancel_error |
854 | lanes.collectgarbage = core.collectgarbage | ||
854 | lanes.finally = core.finally | 855 | lanes.finally = core.finally |
855 | lanes.linda = core.linda | 856 | lanes.linda = core.linda |
856 | lanes.nameof = core.nameof | 857 | lanes.nameof = core.nameof |
diff --git a/src/linda.cpp b/src/linda.cpp index 7af387f..4f33899 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
@@ -450,6 +450,29 @@ static LUAG_FUNC(linda_index) | |||
450 | // ################################################################################################# | 450 | // ################################################################################################# |
451 | 451 | ||
452 | /* | 452 | /* |
453 | * (void) = linda_collectgarbage( linda_ud) | ||
454 | * | ||
455 | * Force a GC cycle in the keeper assigned to the Linda | ||
456 | */ | ||
457 | LUAG_FUNC(linda_collectgarbage) | ||
458 | { | ||
459 | static constexpr lua_CFunction _collectgarbage{ | ||
460 | +[](lua_State* const L_) { | ||
461 | Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; | ||
462 | if (lua_gettop(L_) > 1) { | ||
463 | raise_luaL_argerror(L_, StackIndex{ 2 }, "Unexpected extra argument"); | ||
464 | } | ||
465 | Keeper* const _keeper{ _linda->whichKeeper() }; | ||
466 | KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(collectgarbage), L_, _linda, StackIndex{ 0 }) }; | ||
467 | return OptionalValue(_pushed, L_, "Unexpected error"); | ||
468 | } | ||
469 | }; | ||
470 | return Linda::ProtectedCall(L_, _collectgarbage); | ||
471 | } | ||
472 | |||
473 | // ################################################################################################# | ||
474 | |||
475 | /* | ||
453 | * [val] = linda_count( linda_ud, [slot [, ...]]) | 476 | * [val] = linda_count( linda_ud, [slot [, ...]]) |
454 | * | 477 | * |
455 | * Get a count of the pending elements in the specified keys | 478 | * Get a count of the pending elements in the specified keys |
@@ -1075,6 +1098,7 @@ namespace { | |||
1075 | { "__towatch", LG_linda_towatch }, // Decoda __towatch support | 1098 | { "__towatch", LG_linda_towatch }, // Decoda __towatch support |
1076 | #endif // HAVE_DECODA_SUPPORT() | 1099 | #endif // HAVE_DECODA_SUPPORT() |
1077 | { "cancel", LG_linda_cancel }, | 1100 | { "cancel", LG_linda_cancel }, |
1101 | { "collectgarbage", LG_linda_collectgarbage }, | ||
1078 | { "count", LG_linda_count }, | 1102 | { "count", LG_linda_count }, |
1079 | { "deep", LG_linda_deep }, | 1103 | { "deep", LG_linda_deep }, |
1080 | { "dump", LG_linda_dump }, | 1104 | { "dump", LG_linda_dump }, |