aboutsummaryrefslogtreecommitdiff
path: root/src/linda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/linda.cpp')
-rw-r--r--src/linda.cpp164
1 files changed, 25 insertions, 139 deletions
diff --git a/src/linda.cpp b/src/linda.cpp
index 590b487..bc931ac 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -7,7 +7,7 @@
7/* 7/*
8=============================================================================== 8===============================================================================
9 9
10Copyright (C) 2018 benoit Germain <bnt.germain@gmail.com> 10Copyright (C) 2018-2024 benoit Germain <bnt.germain@gmail.com>
11 11
12Permission is hereby granted, free of charge, to any person obtaining a copy 12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files (the "Software"), to deal 13of this software and associated documentation files (the "Software"), to deal
@@ -35,29 +35,13 @@ THE SOFTWARE.
35#include "compat.h" 35#include "compat.h"
36#include "keeper.h" 36#include "keeper.h"
37#include "lanes_private.h" 37#include "lanes_private.h"
38#include "lindafactory.h"
38#include "threading.h" 39#include "threading.h"
39#include "tools.h" 40#include "tools.h"
40#include "universe.h" 41#include "universe.h"
41 42
42#include <functional> 43#include <functional>
43 44
44// xxh64 of string "kLindaBatched" generated at https://www.pelock.com/products/hash-calculator
45static constexpr UniqueKey kLindaBatched{ 0xB8234DF772646567ull, "linda.batched" };
46
47// #################################################################################################
48
49class LindaFactory : public DeepFactory
50{
51 private:
52
53 DeepPrelude* newDeepObjectInternal(lua_State* L) const override;
54 void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const override;
55 void createMetatable(lua_State* L) const override;
56 char const* moduleName() const override;
57};
58// I'm not totally happy with having a global variable. But since it's stateless, it will do for the time being.
59static LindaFactory g_LindaFactory;
60
61// ################################################################################################# 45// #################################################################################################
62// ################################################################################################# 46// #################################################################################################
63 47
@@ -67,7 +51,7 @@ static LindaFactory g_LindaFactory;
67static constexpr uintptr_t kPointerMagicShift{ 3 }; 51static constexpr uintptr_t kPointerMagicShift{ 3 };
68 52
69Linda::Linda(Universe* U_, LindaGroup group_, char const* name_, size_t len_) 53Linda::Linda(Universe* U_, LindaGroup group_, char const* name_, size_t len_)
70: DeepPrelude{ g_LindaFactory } 54: DeepPrelude{ LindaFactory::Instance }
71, U{ U_ } 55, U{ U_ }
72, m_keeper_index{ (group_ ? group_ : static_cast<int>(std::bit_cast<uintptr_t>(this) >> kPointerMagicShift)) % U_->keepers->nb_keepers } 56, m_keeper_index{ (group_ ? group_ : static_cast<int>(std::bit_cast<uintptr_t>(this) >> kPointerMagicShift)) % U_->keepers->nb_keepers }
73{ 57{
@@ -132,7 +116,7 @@ char const* Linda::getName() const
132template <bool OPT> 116template <bool OPT>
133[[nodiscard]] static inline Linda* ToLinda(lua_State* L_, int idx_) 117[[nodiscard]] static inline Linda* ToLinda(lua_State* L_, int idx_)
134{ 118{
135 Linda* const linda{ static_cast<Linda*>(g_LindaFactory.toDeep(L_, idx_)) }; 119 Linda* const linda{ static_cast<Linda*>(LindaFactory::Instance.toDeep(L_, idx_)) };
136 if constexpr (!OPT) 120 if constexpr (!OPT)
137 { 121 {
138 luaL_argcheck(L_, linda != nullptr, idx_, "expecting a linda object"); // doesn't return if linda is nullptr 122 luaL_argcheck(L_, linda != nullptr, idx_, "expecting a linda object"); // doesn't return if linda is nullptr
@@ -856,124 +840,26 @@ LUAG_FUNC(linda_towatch)
856 840
857// ################################################################################################# 841// #################################################################################################
858 842
859DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L) const 843namespace global {
860{ 844 static luaL_Reg const sLindaMT[] = {
861 size_t name_len = 0; 845 { "__concat", LG_linda_concat },
862 char const* linda_name = nullptr; 846 { "__tostring", LG_linda_tostring },
863 LindaGroup linda_group{ 0 }; 847 { "__towatch", LG_linda_towatch }, // Decoda __towatch support
864 // should have a string and/or a number of the stack as parameters (name and group) 848 { "cancel", LG_linda_cancel },
865 switch (lua_gettop(L)) 849 { "count", LG_linda_count },
866 { 850 { "deep", LG_linda_deep },
867 default: // 0 851 { "dump", LG_linda_dump },
868 break; 852 { "get", LG_linda_get },
869 853 { "limit", LG_linda_limit },
870 case 1: // 1 parameter, either a name or a group 854 { "receive", LG_linda_receive },
871 if (lua_type(L, -1) == LUA_TSTRING) 855 { "send", LG_linda_send },
872 { 856 { "set", LG_linda_set },
873 linda_name = lua_tolstring(L, -1, &name_len); 857 { nullptr, nullptr }
874 } 858 };
875 else 859} // namespace global
876 { 860// it's somewhat awkward to instanciate the LindaFactory here instead of lindafactory.cpp,
877 linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L, -1)) }; 861// but that's necessary to provide s_LindaMT without exposing it outside linda.cpp.
878 } 862/*static*/ LindaFactory LindaFactory::Instance{ global::sLindaMT };
879 break;
880
881 case 2: // 2 parameters, a name and group, in that order
882 linda_name = lua_tolstring(L, -2, &name_len);
883 linda_group = LindaGroup{ static_cast<int>(lua_tointeger(L, -1)) };
884 break;
885 }
886
887 /* The deep data is allocated separately of Lua stack; we might no
888 * longer be around when last reference to it is being released.
889 * One can use any memory allocation scheme.
890 * just don't use L's allocF because we don't know which state will get the honor of GCing the linda
891 */
892 Universe* const U{ universe_get(L) };
893 Linda* linda{ new (U) Linda{ U, linda_group, linda_name, name_len } };
894 return linda;
895}
896
897// #################################################################################################
898
899void LindaFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const
900{
901 Linda* const linda{ static_cast<Linda*>(o_) };
902 LUA_ASSERT(L, linda);
903 Keeper* const myK{ linda->whichKeeper() };
904 // if collected after the universe, keepers are already destroyed, and there is nothing to clear
905 if (myK)
906 {
907 // if collected from my own keeper, we can't acquire/release it
908 // because we are already inside a protected area, and trying to do so would deadlock!
909 bool const need_acquire_release{ myK->L != L };
910 // Clean associated structures in the keeper state.
911 Keeper* const K{ need_acquire_release ? linda->acquireKeeper() : myK };
912 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex...
913 [[maybe_unused]] KeeperCallResult const result{ keeper_call(linda->U, K->L, KEEPER_API(clear), L, linda, 0) };
914 LUA_ASSERT(L, result.has_value() && result.value() == 0);
915 if (need_acquire_release)
916 {
917 linda->releaseKeeper(K);
918 }
919 }
920
921 delete linda; // operator delete overload ensures things go as expected
922}
923
924// #################################################################################################
925
926static luaL_Reg const s_LindaMT[] =
927{
928 { "__concat", LG_linda_concat },
929 { "__tostring", LG_linda_tostring },
930 { "__towatch", LG_linda_towatch }, // Decoda __towatch support
931 { "cancel", LG_linda_cancel },
932 { "count", LG_linda_count },
933 { "deep", LG_linda_deep },
934 { "dump", LG_linda_dump },
935 { "get", LG_linda_get },
936 { "limit", LG_linda_limit },
937 { "receive", LG_linda_receive },
938 { "send", LG_linda_send },
939 { "set", LG_linda_set },
940 { nullptr, nullptr }
941};
942
943void LindaFactory::createMetatable(lua_State* L) const
944{
945 STACK_CHECK_START_REL(L, 0);
946 lua_newtable(L);
947 // metatable is its own index
948 lua_pushvalue(L, -1);
949 lua_setfield(L, -2, "__index");
950
951 // protect metatable from external access
952 lua_pushliteral(L, "Linda");
953 lua_setfield(L, -2, "__metatable");
954
955 // the linda functions
956 luaL_setfuncs(L, s_LindaMT, 0);
957
958 // some constants
959 kLindaBatched.pushKey(L);
960 lua_setfield(L, -2, "batched");
961
962 kNilSentinel.pushKey(L);
963 lua_setfield(L, -2, "null");
964
965 STACK_CHECK(L, 1);
966}
967
968// #################################################################################################
969
970char const* LindaFactory::moduleName() const
971{
972 // linda is a special case because we know lanes must be loaded from the main lua state
973 // to be able to ever get here, so we know it will remain loaded as long a the main state is around
974 // in other words, forever.
975 return nullptr;
976}
977 863
978// ################################################################################################# 864// #################################################################################################
979 865
@@ -996,5 +882,5 @@ LUAG_FUNC(linda)
996 luaL_checktype(L, 1, LUA_TSTRING); 882 luaL_checktype(L, 1, LUA_TSTRING);
997 luaL_checktype(L, 2, LUA_TNUMBER); 883 luaL_checktype(L, 2, LUA_TNUMBER);
998 } 884 }
999 return g_LindaFactory.pushDeepUserdata(DestState{ L }, 0); 885 return LindaFactory::Instance.pushDeepUserdata(DestState{ L }, 0);
1000} 886}