diff options
Diffstat (limited to 'src/linda.cpp')
-rw-r--r-- | src/linda.cpp | 164 |
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 | ||
10 | Copyright (C) 2018 benoit Germain <bnt.germain@gmail.com> | 10 | Copyright (C) 2018-2024 benoit Germain <bnt.germain@gmail.com> |
11 | 11 | ||
12 | Permission is hereby granted, free of charge, to any person obtaining a copy | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy |
13 | of this software and associated documentation files (the "Software"), to deal | 13 | of 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 | ||
45 | static constexpr UniqueKey kLindaBatched{ 0xB8234DF772646567ull, "linda.batched" }; | ||
46 | |||
47 | // ################################################################################################# | ||
48 | |||
49 | class 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. | ||
59 | static LindaFactory g_LindaFactory; | ||
60 | |||
61 | // ################################################################################################# | 45 | // ################################################################################################# |
62 | // ################################################################################################# | 46 | // ################################################################################################# |
63 | 47 | ||
@@ -67,7 +51,7 @@ static LindaFactory g_LindaFactory; | |||
67 | static constexpr uintptr_t kPointerMagicShift{ 3 }; | 51 | static constexpr uintptr_t kPointerMagicShift{ 3 }; |
68 | 52 | ||
69 | Linda::Linda(Universe* U_, LindaGroup group_, char const* name_, size_t len_) | 53 | Linda::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 | |||
132 | template <bool OPT> | 116 | template <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 | ||
859 | DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L) const | 843 | namespace 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 | |||
899 | void 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 | |||
926 | static 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 | |||
943 | void 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 | |||
970 | char 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 | } |