aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/keeper.cpp2
-rw-r--r--src/state.cpp71
-rw-r--r--src/state.h4
-rw-r--r--src/universe.cpp79
-rw-r--r--src/universe.h4
5 files changed, 84 insertions, 76 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp
index 11f1797..cdbfac9 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -876,7 +876,7 @@ void Keepers::initialize(Universe& U_, lua_State* L_, int const nbKeepers_, int
876 // attempt to call on_state_create(), if we have one and it is a C function 876 // attempt to call on_state_create(), if we have one and it is a C function
877 // (only support a C function because we can't transfer executable Lua code in keepers) 877 // (only support a C function because we can't transfer executable Lua code in keepers)
878 // will raise an error in L_ in case of problem 878 // will raise an error in L_ in case of problem
879 state::CallOnStateCreate(U, _K, L, LookupMode::ToKeeper); 879 U->callOnStateCreate(_K, L, LookupMode::ToKeeper);
880 880
881 // _R[kLindasRegKey] = {} 881 // _R[kLindasRegKey] = {}
882 kLindasRegKey.setValue(_K, [](lua_State* L_) { lua_newtable(L_); }); 882 kLindasRegKey.setValue(_K, [](lua_State* L_) { lua_newtable(L_); });
diff --git a/src/state.cpp b/src/state.cpp
index 1975148..0757203 100644
--- a/src/state.cpp
+++ b/src/state.cpp
@@ -41,10 +41,6 @@ THE SOFTWARE.
41#include "universe.h" 41#include "universe.h"
42 42
43// ################################################################################################# 43// #################################################################################################
44
45static constexpr std::string_view kOnStateCreate{ "on_state_create" }; // update lanes.lua if the name changes!
46
47// #################################################################################################
48// ################################################################################################# 44// #################################################################################################
49namespace { 45namespace {
50 // ############################################################################################# 46 // #############################################################################################
@@ -157,42 +153,6 @@ namespace state {
157 // ############################################################################################# 153 // #############################################################################################
158 // ############################################################################################# 154 // #############################################################################################
159 155
160 void CallOnStateCreate(Universe* const U_, lua_State* const L_, lua_State* const from_, LookupMode const mode_)
161 {
162 if (U_->onStateCreateFunc == nullptr) {
163 return;
164 }
165
166 STACK_CHECK_START_REL(L_, 0);
167 DEBUGSPEW_CODE(DebugSpew(U_) << "calling on_state_create()" << std::endl);
168 if (U_->onStateCreateFunc != reinterpret_cast<lua_CFunction>(InitializeOnStateCreate)) {
169 // C function: recreate a closure in the new state, bypassing the lookup scheme
170 lua_pushcfunction(L_, U_->onStateCreateFunc); // on_state_create()
171 } else { // Lua function located in the config table, copied when we opened "lanes.core"
172 if (mode_ != LookupMode::LaneBody) {
173 // if attempting to call in a keeper state, do nothing because the function doesn't exist there
174 // this doesn't count as an error though
175 STACK_CHECK(L_, 0);
176 return;
177 }
178 kConfigRegKey.pushValue(L_); // L_: {}
179 STACK_CHECK(L_, 1);
180 LuaType const _funcType{ luaG_getfield(L_, -1, kOnStateCreate) }; // L_: {} on_state_create()
181 if (_funcType != LuaType::FUNCTION) {
182 raise_luaL_error(L_, "INTERNAL ERROR: %s is a %s, not a function", kOnStateCreate.data(), luaG_typename(L_, _funcType).data());
183 }
184 lua_remove(L_, -2); // L_: on_state_create()
185 }
186 STACK_CHECK(L_, 1);
187 // capture error and raise it in caller state
188 std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" };
189 luaG_pushstring(L_, _stateType); // L_: on_state_create() "<type>"
190 if (lua_pcall(L_, 1, 0, 0) != LUA_OK) {
191 raise_luaL_error(from_, "%s failed: \"%s\"", kOnStateCreate.data(), lua_isstring(L_, -1) ? luaG_tostring(L_, -1).data() : luaG_typename(L_, -1).data());
192 }
193 STACK_CHECK(L_, 0);
194 }
195
196 // ############################################################################################# 156 // #############################################################################################
197 157
198 lua_State* CreateState([[maybe_unused]] Universe* const U_, lua_State* const from_, std::string_view const& hint_) 158 lua_State* CreateState([[maybe_unused]] Universe* const U_, lua_State* const from_, std::string_view const& hint_)
@@ -219,33 +179,6 @@ namespace state {
219 179
220 // ############################################################################################# 180 // #############################################################################################
221 181
222 void InitializeOnStateCreate(Universe* const U_, lua_State* const L_)
223 {
224 STACK_CHECK_START_REL(L_, 1); // L_: settings
225 if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil
226 // store C function pointer in an internal variable
227 U_->onStateCreateFunc = lua_tocfunction(L_, -1); // L_: settings on_state_create
228 if (U_->onStateCreateFunc != nullptr) {
229 // make sure the function doesn't have upvalues
230 char const* _upname{ lua_getupvalue(L_, -1, 1) }; // L_: settings on_state_create upval?
231 if (_upname != nullptr) { // should be "" for C functions with upvalues if any
232 raise_luaL_error(L_, "%s shouldn't have upvalues", kOnStateCreate.data());
233 }
234 // remove this C function from the config table so that it doesn't cause problems
235 // when we transfer the config table in newly created Lua states
236 lua_pushnil(L_); // L_: settings on_state_create nil
237 luaG_setfield(L_, -3, kOnStateCreate); // L_: settings on_state_create
238 } else {
239 // optim: store marker saying we have such a function in the config table
240 U_->onStateCreateFunc = reinterpret_cast<lua_CFunction>(InitializeOnStateCreate);
241 }
242 }
243 lua_pop(L_, 1); // L_: settings
244 STACK_CHECK(L_, 1);
245 }
246
247 // #############################################################################################
248
249 /* 182 /*
250 * Like 'luaL_openlibs()' but allows the set of libraries be selected 183 * Like 'luaL_openlibs()' but allows the set of libraries be selected
251 * 184 *
@@ -274,7 +207,7 @@ namespace state {
274 STACK_CHECK(_L, 0); 207 STACK_CHECK(_L, 0);
275 208
276 // neither libs (not even 'base') nor special init func: we are done 209 // neither libs (not even 'base') nor special init func: we are done
277 if (!libs_.has_value() && U_->onStateCreateFunc == nullptr) { 210 if (!libs_.has_value() && std::holds_alternative<std::nullptr_t>(U_->onStateCreateFunc)) {
278 DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate(nullptr)" << std::endl); 211 DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate(nullptr)" << std::endl);
279 return _L; 212 return _L;
280 } 213 }
@@ -342,7 +275,7 @@ namespace state {
342 275
343 // call this after the base libraries are loaded and GC is restarted 276 // call this after the base libraries are loaded and GC is restarted
344 // will raise an error in from_ in case of problem 277 // will raise an error in from_ in case of problem
345 CallOnStateCreate(U_, _L, from_, LookupMode::LaneBody); 278 U_->callOnStateCreate(_L, from_, LookupMode::LaneBody);
346 279
347 STACK_CHECK(_L, 0); 280 STACK_CHECK(_L, 0);
348 // after all this, register everything we find in our name<->function database 281 // after all this, register everything we find in our name<->function database
diff --git a/src/state.h b/src/state.h
index 98bb47b..f809d50 100644
--- a/src/state.h
+++ b/src/state.h
@@ -8,10 +8,6 @@ enum class LookupMode;
8class Universe; 8class Universe;
9 9
10namespace state { 10namespace state {
11
12 void CallOnStateCreate(Universe* U_, lua_State* L_, lua_State* from_, LookupMode mode_);
13 [[nodiscard]] lua_State* CreateState(Universe* U_, lua_State* from_, std::string_view const& hint_); 11 [[nodiscard]] lua_State* CreateState(Universe* U_, lua_State* from_, std::string_view const& hint_);
14 void InitializeOnStateCreate(Universe* U_, lua_State* L_);
15 [[nodiscard]] lua_State* NewLaneState(Universe* U_, SourceState from_, std::optional<std::string_view> const& libs_); 12 [[nodiscard]] lua_State* NewLaneState(Universe* U_, SourceState from_, std::optional<std::string_view> const& libs_);
16
17} // namespace state 13} // namespace state
diff --git a/src/universe.cpp b/src/universe.cpp
index 097c642..b63008a 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -41,6 +41,10 @@ extern LUAG_FUNC(linda);
41 41
42// ################################################################################################# 42// #################################################################################################
43 43
44static constexpr std::string_view kOnStateCreate{ "on_state_create" }; // update lanes.lua if the name changes!
45
46// #################################################################################################
47
44// xxh64 of string "kUniverseFullRegKey" generated at https://www.pelock.com/products/hash-calculator 48// xxh64 of string "kUniverseFullRegKey" generated at https://www.pelock.com/products/hash-calculator
45static constexpr RegistryUniqueKey kUniverseFullRegKey{ 0x1C2D76870DD9DD9Full }; 49static constexpr RegistryUniqueKey kUniverseFullRegKey{ 0x1C2D76870DD9DD9Full };
46 50
@@ -74,6 +78,48 @@ Universe::Universe()
74 78
75// ################################################################################################# 79// #################################################################################################
76 80
81void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, LookupMode const mode_)
82{
83 if (std::holds_alternative<std::nullptr_t>(onStateCreateFunc)) {
84 return;
85 }
86
87 STACK_CHECK_START_REL(L_, 0);
88 DEBUGSPEW_CODE(DebugSpew(U_) << "calling on_state_create()" << std::endl);
89 if (std::holds_alternative<lua_CFunction>(onStateCreateFunc)) {
90
91 // C function: recreate a closure in the new state, bypassing the lookup scheme
92 lua_pushcfunction(L_, std::get<lua_CFunction>(onStateCreateFunc)); // on_state_create()
93 } else { // Lua function located in the config table, copied when we opened "lanes.core"
94 LUA_ASSERT(from_, std::holds_alternative<uintptr_t>(onStateCreateFunc));
95 if (mode_ != LookupMode::LaneBody) {
96 // if attempting to call in a keeper state, do nothing because the function doesn't exist there
97 // this doesn't count as an error though
98 STACK_CHECK(L_, 0);
99 return;
100 }
101 kConfigRegKey.pushValue(L_); // L_: config
102 STACK_CHECK(L_, 1);
103 LuaType const _funcType{ luaG_getfield(L_, -1, kOnStateCreate) }; // L_: config on_state_create()
104 if (_funcType != LuaType::FUNCTION) {
105 raise_luaL_error(L_, "INTERNAL ERROR: %s is a %s, not a function", kOnStateCreate.data(), luaG_typename(L_, _funcType).data());
106 }
107 lua_remove(L_, -2); // L_: on_state_create()
108 }
109 STACK_CHECK(L_, 1);
110 // capture error and raise it in caller state
111 std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" };
112 luaG_pushstring(L_, _stateType); // L_: on_state_create() "<type>"
113 if (lua_pcall(L_, 1, 0, 0) != LUA_OK) {
114 raise_luaL_error(from_, "%s failed: \"%s\"", kOnStateCreate.data(), lua_isstring(L_, -1) ? luaG_tostring(L_, -1).data() : luaG_typename(L_, -1).data());
115 }
116 STACK_CHECK(L_, 0);
117}
118
119
120
121// #################################################################################################
122
77// only called from the master state 123// only called from the master state
78[[nodiscard]] Universe* Universe::Create(lua_State* const L_) 124[[nodiscard]] Universe* Universe::Create(lua_State* const L_)
79{ 125{
@@ -125,7 +171,7 @@ Universe::Universe()
125 // Linked chains handling 171 // Linked chains handling
126 _U->selfdestructFirst = SELFDESTRUCT_END; 172 _U->selfdestructFirst = SELFDESTRUCT_END;
127 _U->initializeAllocatorFunction(L_); 173 _U->initializeAllocatorFunction(L_);
128 state::InitializeOnStateCreate(_U, L_); 174 _U->initializeOnStateCreate(L_);
129 _U->keepers.initialize(*_U, L_, _nbUserKeepers, _keepers_gc_threshold); 175 _U->keepers.initialize(*_U, L_, _nbUserKeepers, _keepers_gc_threshold);
130 STACK_CHECK(L_, 0); 176 STACK_CHECK(L_, 0);
131 177
@@ -252,6 +298,37 @@ int Universe::InitializeFinalizer(lua_State* const L_)
252 298
253// ################################################################################################# 299// #################################################################################################
254 300
301void Universe::initializeOnStateCreate(lua_State* const L_)
302{
303 STACK_CHECK_START_REL(L_, 1); // L_: settings
304 if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil
305 LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation
306 // make sure the function doesn't have upvalues
307 char const* _upname{ lua_getupvalue(L_, -1, 1) }; // L_: settings on_state_create upval?
308 if (_upname != nullptr) { // should be "" for C functions with upvalues if any
309 raise_luaL_error(L_, "%s with upvalues are forbidden", kOnStateCreate.data());
310 }
311 // store C function pointer in an internal variable
312 lua_CFunction const _func{ lua_tocfunction(L_, -1) }; // L_: settings on_state_create
313 if (_func) {
314 onStateCreateFunc.emplace<lua_CFunction>(_func);
315 // remove this C function from the config table so that it doesn't cause problems
316 // when we transfer the config table in newly created Lua states
317 lua_pushnil(L_); // L_: settings on_state_create nil
318 luaG_setfield(L_, -3, kOnStateCreate); // L_: settings on_state_create
319 } else {
320 // the function is still in the config table
321 onStateCreateFunc.emplace<uintptr_t>(std::bit_cast<uintptr_t>(kOnStateCreate.data()));
322 }
323 } else {
324 LUA_ASSERT(L_, std::holds_alternative<std::nullptr_t>(onStateCreateFunc));
325 };
326 lua_pop(L_, 1); // L_: settings
327 STACK_CHECK(L_, 1);
328}
329
330// #################################################################################################
331
255lanes::AllocatorDefinition Universe::resolveAllocator(lua_State* const L_, std::string_view const& hint_) const 332lanes::AllocatorDefinition Universe::resolveAllocator(lua_State* const L_, std::string_view const& hint_) const
256{ 333{
257 lanes::AllocatorDefinition _ret{ protectedAllocator }; 334 lanes::AllocatorDefinition _ret{ protectedAllocator };
diff --git a/src/universe.h b/src/universe.h
index 6ccdaca..6374648 100644
--- a/src/universe.h
+++ b/src/universe.h
@@ -84,7 +84,7 @@ class Universe
84 lua_CFunction provideAllocator{ nullptr }; 84 lua_CFunction provideAllocator{ nullptr };
85 85
86 // after a state is created, this function will be called right after the bases libraries are loaded 86 // after a state is created, this function will be called right after the bases libraries are loaded
87 lua_CFunction onStateCreateFunc{ nullptr }; 87 std::variant<std::nullptr_t, uintptr_t, lua_CFunction> onStateCreateFunc;
88 88
89 // if allocator="protected" is found in the configuration settings, a wrapper allocator will protect all allocator calls with a mutex 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 90 // contains a mutex and the original allocator definition
@@ -131,10 +131,12 @@ class Universe
131 Universe& operator=(Universe const&) = delete; 131 Universe& operator=(Universe const&) = delete;
132 Universe& operator=(Universe&&) = delete; 132 Universe& operator=(Universe&&) = delete;
133 133
134 void callOnStateCreate(lua_State* const L_, lua_State* const from_, LookupMode const mode_);
134 [[nodiscard]] static Universe* Create(lua_State* L_); 135 [[nodiscard]] static Universe* Create(lua_State* L_);
135 [[nodiscard]] static inline Universe* Get(lua_State* L_); 136 [[nodiscard]] static inline Universe* Get(lua_State* L_);
136 void initializeAllocatorFunction(lua_State* L_); 137 void initializeAllocatorFunction(lua_State* L_);
137 static int InitializeFinalizer(lua_State* L_); 138 static int InitializeFinalizer(lua_State* L_);
139 void initializeOnStateCreate(lua_State* const L_);
138 lanes::AllocatorDefinition resolveAllocator(lua_State* const L_, std::string_view const& hint_) const; 140 lanes::AllocatorDefinition resolveAllocator(lua_State* const L_, std::string_view const& hint_) const;
139 static inline void Store(lua_State* L_, Universe* U_); 141 static inline void Store(lua_State* L_, Universe* U_);
140 void terminateFreeRunningLanes(lua_State* L_, lua_Duration shutdownTimeout_, CancelOp op_); 142 void terminateFreeRunningLanes(lua_State* L_, lua_Duration shutdownTimeout_, CancelOp op_);