aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/deep.cpp149
-rw-r--r--src/deep.h62
-rw-r--r--src/keeper.cpp2
-rw-r--r--src/keeper.h2
-rw-r--r--src/lanes.cpp6
-rw-r--r--src/linda.cpp292
6 files changed, 249 insertions, 264 deletions
diff --git a/src/deep.cpp b/src/deep.cpp
index d0b8123..780c86e 100644
--- a/src/deep.cpp
+++ b/src/deep.cpp
@@ -47,11 +47,11 @@ THE SOFTWARE.
47/*---=== Deep userdata ===---*/ 47/*---=== Deep userdata ===---*/
48 48
49/* 49/*
50* 'registry[REGKEY]' is a two-way lookup table for 'idfunc's and those type's 50* 'registry[REGKEY]' is a two-way lookup table for 'factory's and those type's
51* metatables: 51* metatables:
52* 52*
53* metatable -> idfunc 53* metatable -> factory
54* idfunc -> metatable 54* factory -> metatable
55*/ 55*/
56// crc64/we of string "DEEP_LOOKUP_KEY" generated at http://www.nitrxgen.net/hashgen/ 56// crc64/we of string "DEEP_LOOKUP_KEY" generated at http://www.nitrxgen.net/hashgen/
57static constexpr UniqueKey DEEP_LOOKUP_KEY{ 0x9fb9b4f3f633d83dull }; 57static constexpr UniqueKey DEEP_LOOKUP_KEY{ 0x9fb9b4f3f633d83dull };
@@ -84,8 +84,8 @@ static void set_deep_lookup(lua_State* L)
84// ################################################################################################ 84// ################################################################################################
85 85
86/* 86/*
87* Pops the key (metatable or idfunc) off the stack, and replaces with the 87* Pops the key (metatable or factory) off the stack, and replaces with the
88* deep lookup value (idfunc/metatable/nil). 88* deep lookup value (factory/metatable/nil).
89*/ 89*/
90static void get_deep_lookup(lua_State* L) 90static void get_deep_lookup(lua_State* L)
91{ 91{
@@ -104,21 +104,21 @@ static void get_deep_lookup(lua_State* L)
104// ################################################################################################ 104// ################################################################################################
105 105
106/* 106/*
107* Return the registered ID function for 'index' (deep userdata proxy), 107* Return the registered factory for 'index' (deep userdata proxy),
108* or nullptr if 'index' is not a deep userdata proxy. 108* or nullptr if 'index' is not a deep userdata proxy.
109*/ 109*/
110[[nodiscard]] static inline luaG_IdFunction get_idfunc(lua_State* L, int index, LookupMode mode_) 110[[nodiscard]] static inline DeepFactory* get_factory(lua_State* L, int index, LookupMode mode_)
111{ 111{
112 // when looking inside a keeper, we are 100% sure the object is a deep userdata 112 // when looking inside a keeper, we are 100% sure the object is a deep userdata
113 if (mode_ == LookupMode::FromKeeper) 113 if (mode_ == LookupMode::FromKeeper)
114 { 114 {
115 DeepPrelude** const proxy{ lua_tofulluserdata<DeepPrelude*>(L, index) }; 115 DeepPrelude* const proxy{ *lua_tofulluserdata<DeepPrelude*>(L, index) };
116 // we can (and must) cast and fetch the internally stored idfunc 116 // we can (and must) cast and fetch the internally stored factory
117 return (*proxy)->idfunc; 117 return &proxy->m_factory;
118 } 118 }
119 else 119 else
120 { 120 {
121 // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/idfunc database 121 // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/factory database
122 // it is the only way to ensure that the userdata is indeed a deep userdata! 122 // it is the only way to ensure that the userdata is indeed a deep userdata!
123 // of course, we could just trust the caller, but we won't 123 // of course, we could just trust the caller, but we won't
124 STACK_GROW( L, 1); 124 STACK_GROW( L, 1);
@@ -129,10 +129,10 @@ static void get_deep_lookup(lua_State* L)
129 return nullptr; // no metatable: can't be a deep userdata object! 129 return nullptr; // no metatable: can't be a deep userdata object!
130 } 130 }
131 131
132 // replace metatable with the idfunc pointer, if it is actually a deep userdata 132 // replace metatable with the factory pointer, if it is actually a deep userdata
133 get_deep_lookup( L); // deep ... idfunc|nil 133 get_deep_lookup( L); // deep ... factory|nil
134 134
135 luaG_IdFunction const ret{ *lua_tolightuserdata<luaG_IdFunction>(L, -1) }; // nullptr if not a userdata 135 DeepFactory* const ret{ lua_tolightuserdata<DeepFactory>(L, -1) }; // nullptr if not a userdata
136 lua_pop( L, 1); 136 lua_pop( L, 1);
137 STACK_CHECK( L, 0); 137 STACK_CHECK( L, 0);
138 return ret; 138 return ret;
@@ -141,14 +141,10 @@ static void get_deep_lookup(lua_State* L)
141 141
142// ################################################################################################ 142// ################################################################################################
143 143
144void free_deep_prelude(lua_State* L, DeepPrelude* prelude_) 144void DeepFactory::DeleteDeepObject(lua_State* L, DeepPrelude* o_)
145{ 145{
146 ASSERT_L(prelude_->idfunc);
147 STACK_CHECK_START_REL(L, 0); 146 STACK_CHECK_START_REL(L, 0);
148 // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup 147 o_->m_factory.deleteDeepObjectInternal(L, o_);
149 lua_pushlightuserdata( L, prelude_);
150 prelude_->idfunc( L, DeepOp::Delete);
151 lua_pop(L, 1);
152 STACK_CHECK(L, 0); 148 STACK_CHECK(L, 0);
153} 149}
154 150
@@ -162,8 +158,8 @@ void free_deep_prelude(lua_State* L, DeepPrelude* prelude_)
162 */ 158 */
163[[nodiscard]] static int deep_userdata_gc(lua_State* L) 159[[nodiscard]] static int deep_userdata_gc(lua_State* L)
164{ 160{
165 DeepPrelude** const proxy{ lua_tofulluserdata<DeepPrelude*>(L, 1) }; 161 DeepPrelude* const* const proxy{ lua_tofulluserdata<DeepPrelude*>(L, 1) };
166 DeepPrelude* p = *proxy; 162 DeepPrelude* const p{ *proxy };
167 163
168 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded 164 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded
169 // in that case, we are not multithreaded and locking isn't necessary anyway 165 // in that case, we are not multithreaded and locking isn't necessary anyway
@@ -178,17 +174,9 @@ void free_deep_prelude(lua_State* L, DeepPrelude* prelude_)
178 lua_insert( L, -2); // __gc self 174 lua_insert( L, -2); // __gc self
179 lua_call( L, 1, 0); // 175 lua_call( L, 1, 0); //
180 } 176 }
181 // 'idfunc' expects a clean stack to work on 177 // we don't really know what remains on the stack at that point (depending on us finding a __gc or not), but we don't care
182 lua_settop( L, 0); 178 DeepFactory::DeleteDeepObject(L, p);
183 free_deep_prelude( L, p);
184
185 // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything!
186 if ( lua_gettop( L) > 1)
187 {
188 return luaL_error( L, "Bad idfunc(DeepOp::Delete): should not push anything");
189 }
190 } 179 }
191 *proxy = nullptr; // make sure we don't use it any more, just in case
192 return 0; 180 return 0;
193} 181}
194 182
@@ -196,14 +184,14 @@ void free_deep_prelude(lua_State* L, DeepPrelude* prelude_)
196 184
197/* 185/*
198 * Push a proxy userdata on the stack. 186 * Push a proxy userdata on the stack.
199 * returns nullptr if ok, else some error string related to bad idfunc behavior or module require problem 187 * returns nullptr if ok, else some error string related to bad factory behavior or module require problem
200 * (error cannot happen with mode_ == LookupMode::ToKeeper) 188 * (error cannot happen with mode_ == LookupMode::ToKeeper)
201 * 189 *
202 * Initializes necessary structures if it's the first time 'idfunc' is being 190 * Initializes necessary structures if it's the first time 'factory' is being
203 * used in this Lua state (metatable, registring it). Otherwise, increments the 191 * used in this Lua state (metatable, registring it). Otherwise, increments the
204 * reference count. 192 * reference count.
205 */ 193 */
206char const* push_deep_proxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode mode_) 194char const* DeepFactory::PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode mode_)
207{ 195{
208 // Check if a proxy already exists 196 // Check if a proxy already exists
209 push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC 197 push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC
@@ -228,24 +216,25 @@ char const* push_deep_proxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode m
228 *proxy = prelude; 216 *proxy = prelude;
229 prelude->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data 217 prelude->m_refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data
230 218
231 // Get/create metatable for 'idfunc' (in this state) 219 // Get/create metatable for 'factory' (in this state)
232 lua_pushlightuserdata( L, std::bit_cast<void*>(prelude->idfunc)); // DPC proxy idfunc 220 DeepFactory& factory = prelude->m_factory;
221 lua_pushlightuserdata( L, std::bit_cast<void*>(&factory)); // DPC proxy factory
233 get_deep_lookup( L); // DPC proxy metatable? 222 get_deep_lookup( L); // DPC proxy metatable?
234 223
235 if( lua_isnil( L, -1)) // // No metatable yet. 224 if( lua_isnil( L, -1)) // // No metatable yet.
236 { 225 {
237 char const* modname;
238 int oldtop = lua_gettop( L); // DPC proxy nil 226 int oldtop = lua_gettop( L); // DPC proxy nil
239 lua_pop( L, 1); // DPC proxy 227 lua_pop( L, 1); // DPC proxy
240 // 1 - make one and register it 228 // 1 - make one and register it
241 if (mode_ != LookupMode::ToKeeper) 229 if (mode_ != LookupMode::ToKeeper)
242 { 230 {
243 (void) prelude->idfunc( L, DeepOp::Metatable); // DPC proxy metatable 231 factory.createMetatable(L); // DPC proxy metatable
244 if( lua_gettop( L) - oldtop != 0 || !lua_istable( L, -1)) 232 if (lua_gettop(L) - oldtop != 0 || !lua_istable(L, -1))
245 { 233 {
234 // factory didn't push exactly 1 value, or the value it pushed is not a table: ERROR!
246 lua_settop( L, oldtop); // DPC proxy X 235 lua_settop( L, oldtop); // DPC proxy X
247 lua_pop( L, 3); // 236 lua_pop( L, 3); //
248 return "Bad idfunc(eOP_metatable): unexpected pushed value"; 237 return "Bad DeepFactory::createMetatable overload: unexpected pushed value";
249 } 238 }
250 // if the metatable contains a __gc, we will call it from our own 239 // if the metatable contains a __gc, we will call it from our own
251 lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc 240 lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc
@@ -271,22 +260,11 @@ char const* push_deep_proxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode m
271 260
272 // Memorize for later rounds 261 // Memorize for later rounds
273 lua_pushvalue( L, -1); // DPC proxy metatable metatable 262 lua_pushvalue( L, -1); // DPC proxy metatable metatable
274 lua_pushlightuserdata( L, std::bit_cast<void*>(prelude->idfunc)); // DPC proxy metatable metatable idfunc 263 lua_pushlightuserdata(L, std::bit_cast<void*>(&factory)); // DPC proxy metatable metatable factory
275 set_deep_lookup( L); // DPC proxy metatable 264 set_deep_lookup( L); // DPC proxy metatable
276 265
277 // 2 - cause the target state to require the module that exported the idfunc 266 // 2 - cause the target state to require the module that exported the factory
278 // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc 267 if (char const* const modname{ factory.moduleName() }; modname) // we actually got a module name
279 {
280 int oldtop_module = lua_gettop( L);
281 modname = (char const*) prelude->idfunc( L, DeepOp::Module); // DPC proxy metatable
282 // make sure the function pushed nothing on the stack!
283 if( lua_gettop( L) - oldtop_module != 0)
284 {
285 lua_pop( L, 3); //
286 return "Bad idfunc(eOP_module): should not push anything";
287 }
288 }
289 if (nullptr != modname) // we actually got a module name
290 { 268 {
291 // L.registry._LOADED exists without having registered the 'package' library. 269 // L.registry._LOADED exists without having registered the 'package' library.
292 lua_getglobal( L, "require"); // DPC proxy metatable require() 270 lua_getglobal( L, "require"); // DPC proxy metatable require()
@@ -309,7 +287,7 @@ char const* push_deep_proxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode m
309 if( require_result != LUA_OK) 287 if( require_result != LUA_OK)
310 { 288 {
311 // failed, return the error message 289 // failed, return the error message
312 lua_pushfstring( L, "error while requiring '%s' identified by idfunc(eOP_module): ", modname); 290 lua_pushfstring( L, "error while requiring '%s' identified by DeepFactory::moduleName: ", modname);
313 lua_insert( L, -2); // DPC proxy metatable prefix error 291 lua_insert( L, -2); // DPC proxy metatable prefix error
314 lua_concat( L, 2); // DPC proxy metatable error 292 lua_concat( L, 2); // DPC proxy metatable error
315 return lua_tostring( L, -1); 293 return lua_tostring( L, -1);
@@ -323,7 +301,7 @@ char const* push_deep_proxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode m
323 else // no L.registry._LOADED; can this ever happen? 301 else // no L.registry._LOADED; can this ever happen?
324 { 302 {
325 lua_pop( L, 6); // 303 lua_pop( L, 6); //
326 return "unexpected error while requiring a module identified by idfunc(eOP_module)"; 304 return "unexpected error while requiring a module identified by DeepFactory::moduleName";
327 } 305 }
328 } 306 }
329 else // a module name, but no require() function :-( 307 else // a module name, but no require() function :-(
@@ -334,7 +312,7 @@ char const* push_deep_proxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode m
334 } 312 }
335 } 313 }
336 STACK_CHECK(L, 2); // DPC proxy metatable 314 STACK_CHECK(L, 2); // DPC proxy metatable
337 ASSERT_L(lua_type(L, -2) == LUA_TUSERDATA); 315 ASSERT_L(lua_type_as_enum(L, -2) == LuaType::USERDATA);
338 ASSERT_L(lua_istable( L, -1)); 316 ASSERT_L(lua_istable( L, -1));
339 lua_setmetatable( L, -2); // DPC proxy 317 lua_setmetatable( L, -2); // DPC proxy
340 318
@@ -343,7 +321,7 @@ char const* push_deep_proxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode m
343 lua_pushvalue( L, -2); // DPC proxy deep proxy 321 lua_pushvalue( L, -2); // DPC proxy deep proxy
344 lua_rawset( L, -4); // DPC proxy 322 lua_rawset( L, -4); // DPC proxy
345 lua_remove( L, -2); // proxy 323 lua_remove( L, -2); // proxy
346 ASSERT_L(lua_type(L, -1) == LUA_TUSERDATA); 324 ASSERT_L(lua_type_as_enum(L, -1) == LuaType::USERDATA);
347 STACK_CHECK(L, 0); 325 STACK_CHECK(L, 0);
348 return nullptr; 326 return nullptr;
349} 327}
@@ -353,56 +331,47 @@ char const* push_deep_proxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode m
353/* 331/*
354* Create a deep userdata 332* Create a deep userdata
355* 333*
356* proxy_ud= deep_userdata( idfunc [, ...] ) 334* proxy_ud= deep_userdata( [...] )
357*
358* Creates a deep userdata entry of the type defined by 'idfunc'.
359* Parameters found on the stack are left as is passed on to the 'idfunc' "new" invocation.
360*
361* 'idfunc' must fulfill the following features:
362* 335*
363* lightuserdata = idfunc( DeepOp::New [, ...] ) -- creates a new deep data instance 336* Creates a deep userdata entry of the type defined by the factory.
364* void = idfunc( DeepOp::Delete, lightuserdata ) -- releases a deep data instance 337* Parameters found on the stack are left as is and passed on to DeepFactory::newDeepObjectInternal.
365* tbl = idfunc( DeepOp::Metatable ) -- gives metatable for userdata proxies
366* 338*
367* Reference counting and true userdata proxying are taken care of for the 339* Reference counting and true userdata proxying are taken care of for the actual data type.
368* actual data type.
369* 340*
370* Types using the deep userdata system (and only those!) can be passed between 341* Types using the deep userdata system (and only those!) can be passed between
371* separate Lua states via 'luaG_inter_move()'. 342* separate Lua states via 'luaG_inter_move()'.
372* 343*
373* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' 344* Returns: 'proxy' userdata for accessing the deep data via 'DeepFactory::toDeep()'
374*/ 345*/
375int luaG_newdeepuserdata(Dest L, luaG_IdFunction idfunc, int nuv_) 346int DeepFactory::pushDeepUserdata(Dest L, int nuv_) const
376{ 347{
377 STACK_GROW( L, 1); 348 STACK_GROW( L, 1);
378 STACK_CHECK_START_REL(L, 0); 349 STACK_CHECK_START_REL(L, 0);
379 int const oldtop{ lua_gettop(L) }; 350 int const oldtop{ lua_gettop(L) };
380 DeepPrelude* const prelude{ static_cast<DeepPrelude*>(idfunc(L, DeepOp::New)) }; 351 DeepPrelude* const prelude{ newDeepObjectInternal(L) };
381 if (prelude == nullptr) 352 if (prelude == nullptr)
382 { 353 {
383 return luaL_error( L, "idfunc(DeepOp::New) failed to create deep userdata (out of memory)"); 354 return luaL_error( L, "DeepFactory::newDeepObjectInternal failed to create deep userdata (out of memory)");
384 } 355 }
385 356
386 if( prelude->magic != DEEP_VERSION) 357 if( prelude->m_magic != DEEP_VERSION)
387 { 358 {
388 // just in case, don't leak the newly allocated deep userdata object 359 // just in case, don't leak the newly allocated deep userdata object
389 lua_pushlightuserdata( L, prelude); 360 deleteDeepObjectInternal(L, prelude);
390 idfunc( L, DeepOp::Delete); 361 return luaL_error( L, "Bad Deep Factory: DEEP_VERSION is incorrect, rebuild your implementation with the latest deep implementation");
391 return luaL_error( L, "Bad idfunc(DeepOp::New): DEEP_VERSION is incorrect, rebuild your implementation with the latest deep implementation");
392 } 362 }
393 363
394 ASSERT_L(prelude->m_refcount.load(std::memory_order_relaxed) == 0); // 'push_deep_proxy' will lift it to 1 364 ASSERT_L(prelude->m_refcount.load(std::memory_order_relaxed) == 0); // 'DeepFactory::PushDeepProxy' will lift it to 1
395 prelude->idfunc = idfunc; 365 ASSERT_L(&prelude->m_factory == this);
396 366
397 if( lua_gettop( L) - oldtop != 0) 367 if( lua_gettop( L) - oldtop != 0)
398 { 368 {
399 // just in case, don't leak the newly allocated deep userdata object 369 // just in case, don't leak the newly allocated deep userdata object
400 lua_pushlightuserdata( L, prelude); 370 deleteDeepObjectInternal(L, prelude);
401 idfunc( L, DeepOp::Delete); 371 return luaL_error(L, "Bad DeepFactory::newDeepObjectInternal overload: should not push anything on the stack");
402 return luaL_error( L, "Bad idfunc(DeepOp::New): should not push anything on the stack");
403 } 372 }
404 373
405 char const* const errmsg{ push_deep_proxy(L, prelude, nuv_, LookupMode::LaneBody) }; // proxy 374 char const* const errmsg{ DeepFactory::PushDeepProxy(L, prelude, nuv_, LookupMode::LaneBody) }; // proxy
406 if (errmsg != nullptr) 375 if (errmsg != nullptr)
407 { 376 {
408 return luaL_error( L, errmsg); 377 return luaL_error( L, errmsg);
@@ -419,11 +388,11 @@ int luaG_newdeepuserdata(Dest L, luaG_IdFunction idfunc, int nuv_)
419* Reference count is not changed, and access to the deep userdata is not 388* Reference count is not changed, and access to the deep userdata is not
420* serialized. It is the module's responsibility to prevent conflicting usage. 389* serialized. It is the module's responsibility to prevent conflicting usage.
421*/ 390*/
422DeepPrelude* luaG_todeep(lua_State* L, luaG_IdFunction idfunc, int index) 391DeepPrelude* DeepFactory::toDeep(lua_State* L, int index) const
423{ 392{
424 STACK_CHECK_START_REL(L, 0); 393 STACK_CHECK_START_REL(L, 0);
425 // ensure it is actually a deep userdata 394 // ensure it is actually a deep userdata we created
426 if (get_idfunc(L, index, LookupMode::LaneBody) != idfunc) 395 if (get_factory(L, index, LookupMode::LaneBody) != this)
427 { 396 {
428 return nullptr; // no metatable, or wrong kind 397 return nullptr; // no metatable, or wrong kind
429 } 398 }
@@ -444,8 +413,8 @@ DeepPrelude* luaG_todeep(lua_State* L, luaG_IdFunction idfunc, int index)
444 */ 413 */
445bool copydeep(Universe* U, Dest L2, int L2_cache_i, Source L, int i, LookupMode mode_, char const* upName_) 414bool copydeep(Universe* U, Dest L2, int L2_cache_i, Source L, int i, LookupMode mode_, char const* upName_)
446{ 415{
447 luaG_IdFunction const idfunc { get_idfunc(L, i, mode_) }; 416 DeepFactory* const factory { get_factory(L, i, mode_) };
448 if (idfunc == nullptr) 417 if (factory == nullptr)
449 { 418 {
450 return false; // not a deep userdata 419 return false; // not a deep userdata
451 } 420 }
@@ -463,7 +432,7 @@ bool copydeep(Universe* U, Dest L2, int L2_cache_i, Source L, int i, LookupMode
463 lua_pop( L, 1); // ... u [uv]* 432 lua_pop( L, 1); // ... u [uv]*
464 STACK_CHECK( L, nuv); 433 STACK_CHECK( L, nuv);
465 434
466 char const* errmsg{ push_deep_proxy(L2, *lua_tofulluserdata<DeepPrelude*>(L, i), nuv, mode_) }; // u 435 char const* errmsg{ DeepFactory::PushDeepProxy(L2, *lua_tofulluserdata<DeepPrelude*>(L, i), nuv, mode_) }; // u
467 436
468 // transfer all uservalues of the source in the destination 437 // transfer all uservalues of the source in the destination
469 { 438 {
diff --git a/src/deep.h b/src/deep.h
index 7be5c5d..7c0aa6d 100644
--- a/src/deep.h
+++ b/src/deep.h
@@ -28,34 +28,60 @@ enum class LookupMode
28 FromKeeper // send a function from a keeper state to a lane 28 FromKeeper // send a function from a keeper state to a lane
29}; 29};
30 30
31enum class DeepOp
32{
33 New,
34 Delete,
35 Metatable,
36 Module,
37};
38
39using luaG_IdFunction = void*(*)(lua_State* L, DeepOp op_);
40
41// ################################################################################################ 31// ################################################################################################
42 32
43// xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator 33// xxh64 of string "DEEP_VERSION_3" generated at https://www.pelock.com/products/hash-calculator
44static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull }; 34static constexpr UniqueKey DEEP_VERSION{ 0xB2CC0FD9C0AE9674ull, "DEEP_VERSION_3" };
45 35
46// should be used as header for deep userdata 36// should be used as header for deep userdata
47// a deep userdata is a full userdata that stores a single pointer to the actual DeepPrelude-derived object 37// a deep userdata is a full userdata that stores a single pointer to the actual DeepPrelude-derived object
48struct DeepPrelude 38struct DeepPrelude
49{ 39{
50 UniqueKey const magic{ DEEP_VERSION }; 40 UniqueKey const m_magic{ DEEP_VERSION };
51 // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc 41 // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the factory
52 luaG_IdFunction idfunc { nullptr }; 42 class DeepFactory& m_factory;
53 // data is destroyed when refcount is 0 43 // data is destroyed when refcount is 0
54 std::atomic<int> m_refcount{ 0 }; 44 std::atomic<int> m_refcount{ 0 };
45
46 DeepPrelude(DeepFactory& factory_)
47 : m_factory{ factory_ }
48 {
49 }
55}; 50};
56 51
57[[nodiscard]] char const* push_deep_proxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode mode_); 52// external C modules should create a single object implementing that interface for each Deep userdata class they want to expose
58void free_deep_prelude(lua_State* L, DeepPrelude* prelude_); 53class DeepFactory
54{
55 protected:
56
57 // protected non-virtual destructor: Lanes won't manage the Factory's lifetime
58 DeepFactory() = default;
59 ~DeepFactory() = default;
60
61 public:
62
63 // non-copyable, non-movable
64 DeepFactory(DeepFactory const&) = delete;
65 DeepFactory(DeepFactory const&&) = delete;
66 DeepFactory& operator=(DeepFactory const&) = delete;
67 DeepFactory& operator=(DeepFactory const&&) = delete;
68
69 private:
70
71 // NVI: private overrides
72 virtual DeepPrelude* newDeepObjectInternal(lua_State* L) const = 0;
73 virtual void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const = 0;
74 virtual void createMetatable(lua_State* L) const = 0;
75 virtual char const* moduleName() const = 0;
76
77 public:
78
79 // NVI: public interface
80 int pushDeepUserdata(Dest L, int nuv_) const;
81 DeepPrelude* toDeep(lua_State* L, int index) const;
82 static void DeleteDeepObject(lua_State* L, DeepPrelude* o_);
83 static char const* PushDeepProxy(Dest L, DeepPrelude* prelude, int nuv_, LookupMode mode_);
84};
59 85
60LANES_API [[nodiscard]] int luaG_newdeepuserdata(Dest L, luaG_IdFunction idfunc, int nuv_); 86//LANES_API [[nodiscard]] int luaG_newdeepuserdata(Dest L, DeepFactory& factory_, int nuv_);
61LANES_API [[nodiscard]] DeepPrelude* luaG_todeep(lua_State* L, luaG_IdFunction idfunc, int index); 87//LANES_API [[nodiscard]] DeepPrelude* luaG_todeep(lua_State* L, DeepFactory &factory_, int index);
diff --git a/src/keeper.cpp b/src/keeper.cpp
index 61321e1..36733e3 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -833,6 +833,8 @@ KeeperCallResult keeper_call(Universe* U, lua_State* K, keeper_api_t func_, lua_
833 KeeperCallResult result; 833 KeeperCallResult result;
834 int const args{ starting_index ? (lua_gettop(L) - starting_index + 1) : 0 }; 834 int const args{ starting_index ? (lua_gettop(L) - starting_index + 1) : 0 };
835 int const top_K{ lua_gettop(K) }; 835 int const top_K{ lua_gettop(K) };
836 // if we didn't do anything wrong, the keeper stack should be clean
837 ASSERT_L(lua_gettop(K) == 0);
836 838
837 STACK_GROW(K, 2); 839 STACK_GROW(K, 2);
838 840
diff --git a/src/keeper.h b/src/keeper.h
index 7ec8b15..c1ee244 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -34,7 +34,7 @@ struct Keepers
34 34
35static constexpr uintptr_t KEEPER_MAGIC_SHIFT{ 3 }; 35static constexpr uintptr_t KEEPER_MAGIC_SHIFT{ 3 };
36// crc64/we of string "NIL_SENTINEL" generated at http://www.nitrxgen.net/hashgen/ 36// crc64/we of string "NIL_SENTINEL" generated at http://www.nitrxgen.net/hashgen/
37static constexpr UniqueKey NIL_SENTINEL{ 0x7eaafa003a1d11a1ull, "internal nil sentinel" }; 37static constexpr UniqueKey NIL_SENTINEL{ 0x7eaafa003a1d11a1ull, "linda.null" };
38 38
39void init_keepers(Universe* U, lua_State* L); 39void init_keepers(Universe* U, lua_State* L);
40void close_keepers(Universe* U); 40void close_keepers(Universe* U);
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 1f795cc..d9262cf 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -544,14 +544,12 @@ static void selfdestruct_add(Lane* lane_)
544 } 544 }
545 } 545 }
546 546
547 // necessary so that calling free_deep_prelude doesn't crash because linda_id expects a linda lightuserdata at absolute slot 1
548 lua_settop(L, 0);
549 // no need to mutex-protect this as all threads in the universe are gone at that point 547 // no need to mutex-protect this as all threads in the universe are gone at that point
550 if (U->timer_deep != nullptr) // test ins case some early internal error prevented Lanes from creating the deep timer 548 if (U->timer_deep != nullptr) // test ins case some early internal error prevented Lanes from creating the deep timer
551 { 549 {
552 [[maybe_unused]] int const prev_ref_count{ U->timer_deep->m_refcount.fetch_sub(1, std::memory_order_relaxed) }; 550 [[maybe_unused]] int const prev_ref_count{ U->timer_deep->m_refcount.fetch_sub(1, std::memory_order_relaxed) };
553 ASSERT_L(prev_ref_count == 1); // this should be the last reference 551 ASSERT_L(prev_ref_count == 1); // this should be the last reference
554 free_deep_prelude(L, U->timer_deep); 552 DeepFactory::DeleteDeepObject(L, U->timer_deep);
555 U->timer_deep = nullptr; 553 U->timer_deep = nullptr;
556 } 554 }
557 555
@@ -1840,7 +1838,7 @@ LUAG_FUNC(configure)
1840 STACK_CHECK(L, 2); 1838 STACK_CHECK(L, 2);
1841 1839
1842 { 1840 {
1843 char const* errmsg{ push_deep_proxy(Dest{ L }, U->timer_deep, 0, LookupMode::LaneBody) }; // settings M timer_deep 1841 char const* errmsg{ DeepFactory::PushDeepProxy(Dest{ L }, U->timer_deep, 0, LookupMode::LaneBody) }; // settings M timer_deep
1844 if (errmsg != nullptr) 1842 if (errmsg != nullptr)
1845 { 1843 {
1846 return luaL_error(L, errmsg); 1844 return luaL_error(L, errmsg);
diff --git a/src/linda.cpp b/src/linda.cpp
index dbd6b21..103f4ed 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -45,6 +45,18 @@ THE SOFTWARE.
45// xxh64 of string "CANCEL_ERROR" generated at https://www.pelock.com/products/hash-calculator 45// xxh64 of string "CANCEL_ERROR" generated at https://www.pelock.com/products/hash-calculator
46static constexpr UniqueKey BATCH_SENTINEL{ 0x2DDFEE0968C62AA7ull, "linda.batched" }; 46static constexpr UniqueKey BATCH_SENTINEL{ 0x2DDFEE0968C62AA7ull, "linda.batched" };
47 47
48class LindaFactory : public DeepFactory
49{
50 private:
51
52 DeepPrelude* newDeepObjectInternal(lua_State* L) const override;
53 void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const override;
54 void createMetatable(lua_State* L) const override;
55 char const* moduleName() const override;
56};
57// I'm not totally happy with having a global variable. But since it's stateless, it will do for the time being.
58static LindaFactory g_LindaFactory;
59
48/* 60/*
49* Actual data is kept within a keeper state, which is hashed by the 'Linda' 61* Actual data is kept within a keeper state, which is hashed by the 'Linda'
50* pointer (which is same to all userdatas pointing to it). 62* pointer (which is same to all userdatas pointing to it).
@@ -82,7 +94,8 @@ class Linda : public DeepPrelude // Deep userdata MUST start with this header
82 static void operator delete(void* p_) { static_cast<Linda*>(p_)->U->internal_allocator.free(p_, sizeof(Linda)); } 94 static void operator delete(void* p_) { static_cast<Linda*>(p_)->U->internal_allocator.free(p_, sizeof(Linda)); }
83 95
84 Linda(Universe* U_, uintptr_t group_, char const* name_, size_t len_) 96 Linda(Universe* U_, uintptr_t group_, char const* name_, size_t len_)
85 : U{ U_ } 97 : DeepPrelude{ g_LindaFactory }
98 , U{ U_ }
86 , group{ group_ << KEEPER_MAGIC_SHIFT } 99 , group{ group_ << KEEPER_MAGIC_SHIFT }
87 { 100 {
88 setName(name_, len_); 101 setName(name_, len_);
@@ -141,12 +154,13 @@ class Linda : public DeepPrelude // Deep userdata MUST start with this header
141 return nullptr; 154 return nullptr;
142 } 155 }
143}; 156};
144[[nodiscard]] static void* linda_id(lua_State*, DeepOp);
145 157
146template<bool OPT> 158// #################################################################################################
159
160template <bool OPT>
147[[nodiscard]] static inline Linda* ToLinda(lua_State* L, int idx_) 161[[nodiscard]] static inline Linda* ToLinda(lua_State* L, int idx_)
148{ 162{
149 Linda* const linda{ static_cast<Linda*>(luaG_todeep(L, linda_id, idx_)) }; 163 Linda* const linda{ static_cast<Linda*>(g_LindaFactory.toDeep(L, idx_)) };
150 if constexpr (!OPT) 164 if constexpr (!OPT)
151 { 165 {
152 luaL_argcheck(L, linda != nullptr, idx_, "expecting a linda object"); 166 luaL_argcheck(L, linda != nullptr, idx_, "expecting a linda object");
@@ -171,7 +185,6 @@ static void check_key_types(lua_State* L, int start_, int end_)
171 185
172 case LuaType::LIGHTUSERDATA: 186 case LuaType::LIGHTUSERDATA:
173 { 187 {
174 // NIL_SENTINEL isn't publicly exposed, but it doesn't hurt to check
175 static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> to_check{ BATCH_SENTINEL, CANCEL_ERROR, NIL_SENTINEL }; 188 static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> to_check{ BATCH_SENTINEL, CANCEL_ERROR, NIL_SENTINEL };
176 for (UniqueKey const& key : to_check) 189 for (UniqueKey const& key : to_check)
177 { 190 {
@@ -199,12 +212,16 @@ LUAG_FUNC(linda_protected_call)
199 lua_State* const KL{ K ? K->L : nullptr }; 212 lua_State* const KL{ K ? K->L : nullptr };
200 if (KL == nullptr) 213 if (KL == nullptr)
201 return 0; 214 return 0;
215 // if we didn't do anything wrong, the keeper stack should be clean
216 ASSERT_L(lua_gettop(KL) == 0);
202 217
203 // retrieve the actual function to be called and move it before the arguments 218 // retrieve the actual function to be called and move it before the arguments
204 lua_pushvalue(L, lua_upvalueindex(1)); 219 lua_pushvalue(L, lua_upvalueindex(1));
205 lua_insert(L, 1); 220 lua_insert(L, 1);
206 // do a protected call 221 // do a protected call
207 int const rc{ lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) }; 222 int const rc{ lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) };
223 // whatever happens, the keeper state stack must be empty when we are done
224 lua_settop(KL, 0);
208 225
209 // release the keeper 226 // release the keeper
210 keeper_release(K); 227 keeper_release(K);
@@ -838,179 +855,152 @@ LUAG_FUNC(linda_towatch)
838 855
839// ################################################################################################# 856// #################################################################################################
840 857
841/* 858DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* L) const
842* Identity function of a shared userdata object.
843*
844* lightuserdata= linda_id( "new" [, ...] )
845* = linda_id( "delete", lightuserdata )
846*
847* Creation and cleanup of actual 'deep' objects. 'luaG_...' will wrap them into
848* regular userdata proxies, per each state using the deep data.
849*
850* tbl= linda_id( "metatable" )
851*
852* Returns a metatable for the proxy objects ('__gc' method not needed; will
853* be added by 'luaG_...')
854*
855* string= linda_id( "module")
856*
857* Returns the name of the module that a state should require
858* in order to keep a handle on the shared library that exported the idfunc
859*
860* = linda_id( str, ... )
861*
862* For any other strings, the ID function must not react at all. This allows
863* future extensions of the system.
864*/
865[[nodiscard]] static void* linda_id(lua_State* L, DeepOp op_)
866{ 859{
867 switch( op_) 860 size_t name_len = 0;
861 char const* linda_name = nullptr;
862 unsigned long linda_group = 0;
863 // should have a string and/or a number of the stack as parameters (name and group)
864 switch (lua_gettop(L))
868 { 865 {
869 case DeepOp::New: 866 default: // 0
867 break;
868
869 case 1: // 1 parameter, either a name or a group
870 if (lua_type(L, -1) == LUA_TSTRING)
870 { 871 {
871 size_t name_len = 0; 872 linda_name = lua_tolstring(L, -1, &name_len);
872 char const* linda_name = nullptr; 873 }
873 unsigned long linda_group = 0; 874 else
874 // should have a string and/or a number of the stack as parameters (name and group) 875 {
875 switch (lua_gettop(L)) 876 linda_group = (unsigned long) lua_tointeger(L, -1);
876 { 877 }
877 default: // 0 878 break;
878 break;
879 879
880 case 1: // 1 parameter, either a name or a group 880 case 2: // 2 parameters, a name and group, in that order
881 if (lua_type(L, -1) == LUA_TSTRING) 881 linda_name = lua_tolstring(L, -2, &name_len);
882 { 882 linda_group = (unsigned long) lua_tointeger(L, -1);
883 linda_name = lua_tolstring(L, -1, &name_len); 883 break;
884 } 884 }
885 else
886 {
887 linda_group = (unsigned long) lua_tointeger(L, -1);
888 }
889 break;
890 885
891 case 2: // 2 parameters, a name and group, in that order 886 /* The deep data is allocated separately of Lua stack; we might no
892 linda_name = lua_tolstring(L, -2, &name_len); 887 * longer be around when last reference to it is being released.
893 linda_group = (unsigned long) lua_tointeger(L, -1); 888 * One can use any memory allocation scheme.
894 break; 889 * just don't use L's allocF because we don't know which state will get the honor of GCing the linda
895 } 890 */
891 Universe* const U{ universe_get(L) };
892 Linda* linda{ new (U) Linda{ U, linda_group, linda_name, name_len } };
893 return linda;
894}
896 895
897 /* The deep data is allocated separately of Lua stack; we might no 896// #################################################################################################
898 * longer be around when last reference to it is being released.
899 * One can use any memory allocation scheme.
900 * just don't use L's allocF because we don't know which state will get the honor of GCing the linda
901 */
902 Universe* const U{ universe_get(L) };
903 Linda* linda{ new (U) Linda{ U, linda_group, linda_name, name_len } };
904 return linda;
905 }
906 897
907 case DeepOp::Delete: 898void LindaFactory::deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const
899{
900 Linda* const linda{ static_cast<Linda*>(o_) };
901 ASSERT_L(linda);
902 Keeper* const myK{ which_keeper(linda->U->keepers, linda->hashSeed()) };
903 // if collected after the universe, keepers are already destroyed, and there is nothing to clear
904 if (myK)
905 {
906 // if collected from my own keeper, we can't acquire/release it
907 // because we are already inside a protected area, and trying to do so would deadlock!
908 bool const need_acquire_release{ myK->L != L };
909 // Clean associated structures in the keeper state.
910 Keeper* const K{ need_acquire_release ? keeper_acquire(linda->U->keepers, linda->hashSeed()) : myK };
911 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex...
912 [[maybe_unused]] KeeperCallResult const result{ keeper_call(linda->U, K->L, KEEPER_API(clear), L, linda, 0) };
913 ASSERT_L(result.has_value() && result.value() == 0);
914 if (need_acquire_release)
908 { 915 {
909 Linda* const linda{ lua_tolightuserdata<Linda>(L, 1) }; 916 keeper_release(K);
910 ASSERT_L(linda);
911 Keeper* const myK{ which_keeper(linda->U->keepers, linda->hashSeed()) };
912 // if collected after the universe, keepers are already destroyed, and there is nothing to clear
913 if (myK)
914 {
915 // if collected from my own keeper, we can't acquire/release it
916 // because we are already inside a protected area, and trying to do so would deadlock!
917 bool const need_acquire_release{ myK->L != L };
918 // Clean associated structures in the keeper state.
919 Keeper* const K{ need_acquire_release ? keeper_acquire(linda->U->keepers, linda->hashSeed()) : myK };
920 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex...
921 [[maybe_unused]] KeeperCallResult const result{ keeper_call(linda->U, K->L, KEEPER_API(clear), L, linda, 0) };
922 ASSERT_L(result.has_value() && result.value() == 0);
923 if (need_acquire_release)
924 {
925 keeper_release(K);
926 }
927 }
928
929 delete linda; // operator delete overload ensures things go as expected
930 return nullptr;
931 } 917 }
918 }
932 919
933 case DeepOp::Metatable: 920 delete linda; // operator delete overload ensures things go as expected
934 { 921}
935 STACK_CHECK_START_REL(L, 0);
936 lua_newtable(L);
937 // metatable is its own index
938 lua_pushvalue(L, -1);
939 lua_setfield(L, -2, "__index");
940 922
941 // protect metatable from external access 923// #################################################################################################
942 lua_pushliteral(L, "Linda");
943 lua_setfield(L, -2, "__metatable");
944 924
945 lua_pushcfunction(L, LG_linda_tostring); 925void LindaFactory::createMetatable(lua_State* L) const
946 lua_setfield(L, -2, "__tostring"); 926{
927 STACK_CHECK_START_REL(L, 0);
928 lua_newtable(L);
929 // metatable is its own index
930 lua_pushvalue(L, -1);
931 lua_setfield(L, -2, "__index");
947 932
948 // Decoda __towatch support 933 // protect metatable from external access
949 lua_pushcfunction(L, LG_linda_towatch); 934 lua_pushliteral(L, "Linda");
950 lua_setfield(L, -2, "__towatch"); 935 lua_setfield(L, -2, "__metatable");
951 936
952 lua_pushcfunction(L, LG_linda_concat); 937 lua_pushcfunction(L, LG_linda_tostring);
953 lua_setfield(L, -2, "__concat"); 938 lua_setfield(L, -2, "__tostring");
954 939
955 // protected calls, to ensure associated keeper is always released even in case of error 940 // Decoda __towatch support
956 // all function are the protected call wrapper, where the actual operation is provided as upvalue 941 lua_pushcfunction(L, LG_linda_towatch);
957 // note that this kind of thing can break function lookup as we use the function pointer here and there 942 lua_setfield(L, -2, "__towatch");
958 // TODO: change that and use different functions!
959 943
960 lua_pushcfunction(L, LG_linda_send); 944 lua_pushcfunction(L, LG_linda_concat);
961 lua_pushcclosure(L, LG_linda_protected_call, 1); 945 lua_setfield(L, -2, "__concat");
962 lua_setfield(L, -2, "send");
963 946
964 lua_pushcfunction(L, LG_linda_receive); 947 // protected calls, to ensure associated keeper is always released even in case of error
965 lua_pushcclosure(L, LG_linda_protected_call, 1); 948 // all function are the protected call wrapper, where the actual operation is provided as upvalue
966 lua_setfield(L, -2, "receive"); 949 // note that this kind of thing can break function lookup as we use the function pointer here and there
950 // TODO: change that and use different functions!
967 951
968 lua_pushcfunction(L, LG_linda_limit); 952 lua_pushcfunction(L, LG_linda_send);
969 lua_pushcclosure(L, LG_linda_protected_call, 1); 953 lua_pushcclosure(L, LG_linda_protected_call, 1);
970 lua_setfield(L, -2, "limit"); 954 lua_setfield(L, -2, "send");
971 955
972 lua_pushcfunction(L, LG_linda_set); 956 lua_pushcfunction(L, LG_linda_receive);
973 lua_pushcclosure(L, LG_linda_protected_call, 1); 957 lua_pushcclosure(L, LG_linda_protected_call, 1);
974 lua_setfield(L, -2, "set"); 958 lua_setfield(L, -2, "receive");
975 959
976 lua_pushcfunction(L, LG_linda_count); 960 lua_pushcfunction(L, LG_linda_limit);
977 lua_pushcclosure(L, LG_linda_protected_call, 1); 961 lua_pushcclosure(L, LG_linda_protected_call, 1);
978 lua_setfield(L, -2, "count"); 962 lua_setfield(L, -2, "limit");
979 963
980 lua_pushcfunction(L, LG_linda_get); 964 lua_pushcfunction(L, LG_linda_set);
981 lua_pushcclosure(L, LG_linda_protected_call, 1); 965 lua_pushcclosure(L, LG_linda_protected_call, 1);
982 lua_setfield(L, -2, "get"); 966 lua_setfield(L, -2, "set");
983 967
984 lua_pushcfunction(L, LG_linda_cancel); 968 lua_pushcfunction(L, LG_linda_count);
985 lua_setfield(L, -2, "cancel"); 969 lua_pushcclosure(L, LG_linda_protected_call, 1);
970 lua_setfield(L, -2, "count");
986 971
987 lua_pushcfunction(L, LG_linda_deep); 972 lua_pushcfunction(L, LG_linda_get);
988 lua_setfield(L, -2, "deep"); 973 lua_pushcclosure(L, LG_linda_protected_call, 1);
974 lua_setfield(L, -2, "get");
989 975
990 lua_pushcfunction(L, LG_linda_dump); 976 lua_pushcfunction(L, LG_linda_cancel);
991 lua_pushcclosure(L, LG_linda_protected_call, 1); 977 lua_setfield(L, -2, "cancel");
992 lua_setfield(L, -2, "dump");
993 978
994 // some constants 979 lua_pushcfunction(L, LG_linda_deep);
995 BATCH_SENTINEL.pushKey(L); 980 lua_setfield(L, -2, "deep");
996 lua_setfield(L, -2, "batched");
997 981
998 NIL_SENTINEL.pushKey(L); 982 lua_pushcfunction(L, LG_linda_dump);
999 lua_setfield(L, -2, "null"); 983 lua_pushcclosure(L, LG_linda_protected_call, 1);
984 lua_setfield(L, -2, "dump");
1000 985
1001 STACK_CHECK(L, 1); 986 // some constants
1002 return nullptr; 987 BATCH_SENTINEL.pushKey(L);
1003 } 988 lua_setfield(L, -2, "batched");
1004 989
1005 case DeepOp::Module: 990 NIL_SENTINEL.pushKey(L);
1006 // linda is a special case because we know lanes must be loaded from the main lua state 991 lua_setfield(L, -2, "null");
1007 // to be able to ever get here, so we know it will remain loaded as long a the main state is around 992
1008 // in other words, forever. 993 STACK_CHECK(L, 1);
1009 default: 994}
1010 { 995
1011 return nullptr; 996// #################################################################################################
1012 } 997
1013 } 998char const* LindaFactory::moduleName() const
999{
1000 // linda is a special case because we know lanes must be loaded from the main lua state
1001 // to be able to ever get here, so we know it will remain loaded as long a the main state is around
1002 // in other words, forever.
1003 return nullptr;
1014} 1004}
1015 1005
1016// ################################################################################################# 1006// #################################################################################################
@@ -1034,5 +1024,5 @@ LUAG_FUNC(linda)
1034 luaL_checktype(L, 1, LUA_TSTRING); 1024 luaL_checktype(L, 1, LUA_TSTRING);
1035 luaL_checktype(L, 2, LUA_TNUMBER); 1025 luaL_checktype(L, 2, LUA_TNUMBER);
1036 } 1026 }
1037 return luaG_newdeepuserdata(Dest{ L }, linda_id, 0); 1027 return g_LindaFactory.pushDeepUserdata(Dest{ L }, 0);
1038} 1028}