aboutsummaryrefslogtreecommitdiff
path: root/src/universe.hpp
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-10-28 18:03:24 +0100
committerBenoit Germain <benoit.germain@ubisoft.com>2024-10-28 18:03:24 +0100
commitdf60f71fe943686deed8ca0f85c6d597570ab030 (patch)
treef62aebc4829f7d3a3734df9a19bb2033fbc870c3 /src/universe.hpp
parent8ac314c806a0ed0d78a000474a779743d6ae5943 (diff)
downloadlanes-df60f71fe943686deed8ca0f85c6d597570ab030.tar.gz
lanes-df60f71fe943686deed8ca0f85c6d597570ab030.tar.bz2
lanes-df60f71fe943686deed8ca0f85c6d597570ab030.zip
Renamed universe.h → universe.hpp
Diffstat (limited to 'src/universe.hpp')
-rw-r--r--src/universe.hpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/universe.hpp b/src/universe.hpp
new file mode 100644
index 0000000..18e125f
--- /dev/null
+++ b/src/universe.hpp
@@ -0,0 +1,168 @@
1#pragma once
2
3#include "allocator.hpp"
4#include "keeper.hpp"
5#include "lanesconf.h"
6#include "tracker.hpp"
7#include "uniquekey.hpp"
8
9// #################################################################################################
10
11// forwards
12enum class CancelOp;
13struct DeepPrelude;
14class Lane;
15
16// #################################################################################################
17
18// mutex-protected allocator for use with Lua states that share a non-threadsafe allocator
19class ProtectedAllocator
20: public lanes::AllocatorDefinition
21{
22 private:
23 std::mutex mutex;
24
25 [[nodiscard]] static void* protected_lua_Alloc(void* ud_, void* ptr_, size_t osize_, size_t nsize_)
26 {
27 ProtectedAllocator* const allocator{ static_cast<ProtectedAllocator*>(ud_) };
28 std::lock_guard<std::mutex> guard{ allocator->mutex };
29 return allocator->allocF(allocator->allocUD, ptr_, osize_, nsize_);
30 }
31
32 public:
33 // we are not like our base class: we can't be created inside a full userdata (or we would have to install a metatable and __gc handler to destroy ourselves properly)
34 [[nodiscard]] static void* operator new(size_t size_, lua_State* L_) noexcept = delete;
35 static void operator delete(void* p_, lua_State* L_) = delete;
36
37 AllocatorDefinition makeDefinition()
38 {
39 return AllocatorDefinition{ version, protected_lua_Alloc, this };
40 }
41
42 void installIn(lua_State* L_)
43 {
44 lua_setallocf(L_, protected_lua_Alloc, this);
45 }
46
47 void removeFrom(lua_State* L_)
48 {
49 // remove the protected allocator, if any
50 if (allocF != nullptr) {
51 // install the non-protected allocator
52 lua_setallocf(L_, allocF, allocUD);
53 }
54 }
55};
56
57// #################################################################################################
58
59// xxh64 of string "kUniverseLightRegKey" generated at https://www.pelock.com/products/hash-calculator
60static constexpr RegistryUniqueKey kUniverseLightRegKey{ 0x48BBE9CEAB0BA04Full };
61
62// #################################################################################################
63
64// everything regarding the Lanes universe is stored in that global structure
65// held as a full userdata in the master Lua state that required it for the first time
66class Universe
67{
68 public:
69 static constexpr char const* kFinally{ "finally" }; // update lanes.lua if the name changes!
70
71#ifdef PLATFORM_LINUX
72 // Linux needs to check, whether it's been run as root
73 bool const sudo{ geteuid() == 0 };
74#else
75 bool const sudo{ false };
76#endif // PLATFORM_LINUX
77
78 // for verbose errors
79 bool verboseErrors{ false };
80
81 bool stripFunctions{ true };
82
83 // before a state is created, this function will be called to obtain the allocator
84 lua_CFunction provideAllocator{ nullptr };
85
86 // after a state is created, this function will be called right after the bases libraries are loaded
87 std::variant<std::nullptr_t, uintptr_t, lua_CFunction> onStateCreateFunc;
88
89 // if allocator="protected" is found in the configuration settings, a wrapper allocator will protect all allocator calls with a mutex
90 // contains a mutex and the original allocator definition
91 ProtectedAllocator protectedAllocator;
92
93 lanes::AllocatorDefinition internalAllocator;
94
95 Keepers keepers;
96
97 // Initialized by 'init_once_LOCKED()': the deep userdata Linda object
98 // used for timers (each lane will get a proxy to this)
99 DeepPrelude* timerLinda{ nullptr };
100
101 LaneTracker tracker;
102
103 // Protects modifying the selfdestruct chain
104 std::mutex selfdestructMutex;
105
106 // require() serialization
107 std::recursive_mutex requireMutex;
108
109 // metatable unique identifiers
110 std::atomic<lua_Integer> nextMetatableId{ 1 };
111
112#if USE_DEBUG_SPEW()
113 std::atomic<int> debugspewIndentDepth{ 0 };
114#endif // USE_DEBUG_SPEW()
115
116 Lane* volatile selfdestructFirst{ nullptr };
117 // After a lane has removed itself from the chain, it still performs some processing.
118 // The terminal desinit sequence should wait for all such processing to terminate before force-killing threads
119 std::atomic<int> selfdestructingCount{ 0 };
120
121 public:
122 [[nodiscard]] static void* operator new([[maybe_unused]] size_t size_, lua_State* L_) noexcept { return luaG_newuserdatauv<Universe>(L_, UserValueCount{ 0 }); };
123 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
124 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] lua_State* L_) {} // nothing to do, as nothing is allocated independently
125
126 Universe();
127 ~Universe() = default;
128 // non-copyable, non-movable
129 Universe(Universe const&) = delete;
130 Universe(Universe&&) = delete;
131 Universe& operator=(Universe const&) = delete;
132 Universe& operator=(Universe&&) = delete;
133
134 void callOnStateCreate(lua_State* const L_, lua_State* const from_, LookupMode const mode_);
135 [[nodiscard]] static Universe* Create(lua_State* L_);
136 [[nodiscard]] static inline Universe* Get(lua_State* L_);
137 void initializeAllocatorFunction(lua_State* L_);
138 static int InitializeFinalizer(lua_State* L_);
139 void initializeOnStateCreate(lua_State* const L_);
140 lanes::AllocatorDefinition resolveAllocator(lua_State* const L_, std::string_view const& hint_) const;
141 static inline void Store(lua_State* L_, Universe* U_);
142 [[nodiscard]] bool terminateFreeRunningLanes(lua_Duration shutdownTimeout_, CancelOp op_);
143};
144
145// #################################################################################################
146
147inline Universe* Universe::Get(lua_State* L_)
148{
149 STACK_CHECK_START_REL(L_, 0);
150 Universe* const _universe{ kUniverseLightRegKey.readLightUserDataValue<Universe>(L_) };
151 STACK_CHECK(L_, 0);
152 return _universe;
153}
154
155// #################################################################################################
156
157inline void Universe::Store(lua_State* L_, Universe* U_)
158{
159 // TODO: check if we actually ever call Store with a null universe
160 LUA_ASSERT(L_, !U_ || Universe::Get(L_) == nullptr);
161 STACK_CHECK_START_REL(L_, 0);
162 kUniverseLightRegKey.setValue(L_, [U = U_](lua_State* L_) { U ? lua_pushlightuserdata(L_, U) : lua_pushnil(L_); });
163 STACK_CHECK(L_, 0);
164}
165
166// #################################################################################################
167
168LUAG_FUNC(universe_gc);