diff options
Diffstat (limited to 'src/deep.c')
-rw-r--r-- | src/deep.c | 61 |
1 files changed, 33 insertions, 28 deletions
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * DEEP.C Copyright (c) 2014, Benoit Germain | 2 | * DEEP.C Copyright (c) 2017, Benoit Germain |
3 | * | 3 | * |
4 | * Depp userdata support, separate in its own source file to help integration | 4 | * Deep userdata support, separate in its own source file to help integration |
5 | * without enforcing a Lanes dependency | 5 | * without enforcing a Lanes dependency |
6 | */ | 6 | */ |
7 | 7 | ||
@@ -9,7 +9,7 @@ | |||
9 | =============================================================================== | 9 | =============================================================================== |
10 | 10 | ||
11 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> | 11 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> |
12 | 2011-14 Benoit Germain <bnt.germain@gmail.com> | 12 | 2011-17 Benoit Germain <bnt.germain@gmail.com> |
13 | 13 | ||
14 | Permission is hereby granted, free of charge, to any person obtaining a copy | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy |
15 | of this software and associated documentation files (the "Software"), to deal | 15 | of this software and associated documentation files (the "Software"), to deal |
@@ -34,6 +34,7 @@ THE SOFTWARE. | |||
34 | 34 | ||
35 | #include "compat.h" | 35 | #include "compat.h" |
36 | #include "tools.h" | 36 | #include "tools.h" |
37 | #include "universe.h" | ||
37 | #include "deep.h" | 38 | #include "deep.h" |
38 | 39 | ||
39 | #include <stdio.h> | 40 | #include <stdio.h> |
@@ -120,14 +121,15 @@ void luaG_pushdeepversion( lua_State* L) { (void) lua_pushliteral( L, "f248e77a- | |||
120 | * metatable -> idfunc | 121 | * metatable -> idfunc |
121 | * idfunc -> metatable | 122 | * idfunc -> metatable |
122 | */ | 123 | */ |
123 | #define DEEP_LOOKUP_KEY ((void*)set_deep_lookup) | 124 | // crc64/we of string "DEEP_LOOKUP_KEY" generated at https://www.nitrxgen.net/hashgen/ |
124 | // any unique light userdata | 125 | #define DEEP_LOOKUP_KEY ((void*)0x9fb9b4f3f633d83d) |
125 | 126 | ||
126 | 127 | ||
127 | /* | 128 | /* |
128 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying | 129 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying |
130 | * crc64/we of string "DEEP_PROXY_CACHE_KEY" generated at https://www.nitrxgen.net/hashgen/ | ||
129 | */ | 131 | */ |
130 | #define DEEP_PROXY_CACHE_KEY ((void*)push_deep_proxy) | 132 | #define DEEP_PROXY_CACHE_KEY ((void*)0x05773d6fc26be106) |
131 | 133 | ||
132 | /* | 134 | /* |
133 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. | 135 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. |
@@ -163,7 +165,7 @@ static void get_deep_lookup( lua_State* L) | |||
163 | { | 165 | { |
164 | lua_insert( L, -2); // {} a | 166 | lua_insert( L, -2); // {} a |
165 | lua_rawget( L, -2); // {} b | 167 | lua_rawget( L, -2); // {} b |
166 | } | 168 | } |
167 | lua_remove( L, -2); // a|b | 169 | lua_remove( L, -2); // a|b |
168 | STACK_END( L, 0); | 170 | STACK_END( L, 0); |
169 | } | 171 | } |
@@ -177,7 +179,7 @@ static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupM | |||
177 | // when looking inside a keeper, we are 100% sure the object is a deep userdata | 179 | // when looking inside a keeper, we are 100% sure the object is a deep userdata |
178 | if( mode_ == eLM_FromKeeper) | 180 | if( mode_ == eLM_FromKeeper) |
179 | { | 181 | { |
180 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); | 182 | struct DEEP_PRELUDE** proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, index); |
181 | // we can (and must) cast and fetch the internally stored idfunc | 183 | // we can (and must) cast and fetch the internally stored idfunc |
182 | return (*proxy)->idfunc; | 184 | return (*proxy)->idfunc; |
183 | } | 185 | } |
@@ -206,7 +208,7 @@ static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupM | |||
206 | } | 208 | } |
207 | 209 | ||
208 | 210 | ||
209 | void free_deep_prelude( lua_State* L, DEEP_PRELUDE* prelude_) | 211 | void free_deep_prelude( lua_State* L, struct DEEP_PRELUDE* prelude_) |
210 | { | 212 | { |
211 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | 213 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup |
212 | lua_pushlightuserdata( L, prelude_->deep); | 214 | lua_pushlightuserdata( L, prelude_->deep); |
@@ -224,16 +226,18 @@ void free_deep_prelude( lua_State* L, DEEP_PRELUDE* prelude_) | |||
224 | */ | 226 | */ |
225 | static int deep_userdata_gc( lua_State* L) | 227 | static int deep_userdata_gc( lua_State* L) |
226 | { | 228 | { |
227 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, 1); | 229 | struct DEEP_PRELUDE** proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, 1); |
228 | DEEP_PRELUDE* p = *proxy; | 230 | struct DEEP_PRELUDE* p = *proxy; |
229 | struct s_Universe* U = get_universe( L); | 231 | struct s_Universe* U = universe_get( L); |
230 | int v; | 232 | int v; |
231 | 233 | ||
232 | *proxy = 0; // make sure we don't use it any more | 234 | *proxy = 0; // make sure we don't use it any more |
233 | 235 | ||
234 | MUTEX_LOCK( &U->deep_lock); | 236 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded |
237 | // in that case, we are not multithreaded and locking isn't necessary anyway | ||
238 | if( U) MUTEX_LOCK( &U->deep_lock); | ||
235 | v = -- (p->refcount); | 239 | v = -- (p->refcount); |
236 | MUTEX_UNLOCK( &U->deep_lock); | 240 | if (U) MUTEX_UNLOCK( &U->deep_lock); |
237 | 241 | ||
238 | if( v == 0) | 242 | if( v == 0) |
239 | { | 243 | { |
@@ -260,9 +264,9 @@ static int deep_userdata_gc( lua_State* L) | |||
260 | * used in this Lua state (metatable, registring it). Otherwise, increments the | 264 | * used in this Lua state (metatable, registring it). Otherwise, increments the |
261 | * reference count. | 265 | * reference count. |
262 | */ | 266 | */ |
263 | char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_) | 267 | char const* push_deep_proxy( struct s_Universe* U, lua_State* L, struct DEEP_PRELUDE* prelude, enum eLookupMode mode_) |
264 | { | 268 | { |
265 | DEEP_PRELUDE** proxy; | 269 | struct DEEP_PRELUDE** proxy; |
266 | 270 | ||
267 | // Check if a proxy already exists | 271 | // Check if a proxy already exists |
268 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC | 272 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
@@ -278,14 +282,16 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
278 | lua_pop( L, 1); // DPC | 282 | lua_pop( L, 1); // DPC |
279 | } | 283 | } |
280 | 284 | ||
281 | MUTEX_LOCK( &U->deep_lock); | 285 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded |
286 | // in that case, we are not multithreaded and locking isn't necessary anyway | ||
287 | if( U) MUTEX_LOCK( &U->deep_lock); | ||
282 | ++ (prelude->refcount); // one more proxy pointing to this deep data | 288 | ++ (prelude->refcount); // one more proxy pointing to this deep data |
283 | MUTEX_UNLOCK( &U->deep_lock); | 289 | if( U) MUTEX_UNLOCK( &U->deep_lock); |
284 | 290 | ||
285 | STACK_GROW( L, 7); | 291 | STACK_GROW( L, 7); |
286 | STACK_CHECK( L); | 292 | STACK_CHECK( L); |
287 | 293 | ||
288 | proxy = lua_newuserdata( L, sizeof( DEEP_PRELUDE*)); // DPC proxy | 294 | proxy = lua_newuserdata( L, sizeof(struct DEEP_PRELUDE*)); // DPC proxy |
289 | ASSERT_L( proxy); | 295 | ASSERT_L( proxy); |
290 | *proxy = prelude; | 296 | *proxy = prelude; |
291 | 297 | ||
@@ -301,7 +307,7 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
301 | // 1 - make one and register it | 307 | // 1 - make one and register it |
302 | if( mode_ != eLM_ToKeeper) | 308 | if( mode_ != eLM_ToKeeper) |
303 | { | 309 | { |
304 | prelude->idfunc( L, eDO_metatable); // DPC proxy metatable deepversion | 310 | (void) prelude->idfunc( L, eDO_metatable); // DPC proxy metatable deepversion |
305 | if( lua_gettop( L) - oldtop != 1 || !lua_istable( L, -2) || !lua_isstring( L, -1)) | 311 | if( lua_gettop( L) - oldtop != 1 || !lua_istable( L, -2) || !lua_isstring( L, -1)) |
306 | { | 312 | { |
307 | lua_settop( L, oldtop); // DPC proxy X | 313 | lua_settop( L, oldtop); // DPC proxy X |
@@ -350,7 +356,7 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
350 | return "Bad idfunc(eOP_module): should not push anything"; | 356 | return "Bad idfunc(eOP_module): should not push anything"; |
351 | } | 357 | } |
352 | } | 358 | } |
353 | if( modname) // we actually got a module name | 359 | if( NULL != modname) // we actually got a module name |
354 | { | 360 | { |
355 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. | 361 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. |
356 | lua_getglobal( L, "require"); // DPC proxy metatable require() | 362 | lua_getglobal( L, "require"); // DPC proxy metatable require() |
@@ -413,7 +419,6 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
413 | return NULL; | 419 | return NULL; |
414 | } | 420 | } |
415 | 421 | ||
416 | |||
417 | /* | 422 | /* |
418 | * Create a deep userdata | 423 | * Create a deep userdata |
419 | * | 424 | * |
@@ -439,7 +444,7 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* p | |||
439 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | 444 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) |
440 | { | 445 | { |
441 | char const* errmsg; | 446 | char const* errmsg; |
442 | DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(DEEP_PRELUDE)); | 447 | struct DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(struct DEEP_PRELUDE)); |
443 | if( prelude == NULL) | 448 | if( prelude == NULL) |
444 | { | 449 | { |
445 | return luaL_error( L, "couldn't not allocate deep prelude: out of memory"); | 450 | return luaL_error( L, "couldn't not allocate deep prelude: out of memory"); |
@@ -463,7 +468,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | |||
463 | luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | 468 | luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); |
464 | } | 469 | } |
465 | } | 470 | } |
466 | errmsg = push_deep_proxy( get_universe( L), L, prelude, eLM_LaneBody); // proxy | 471 | errmsg = push_deep_proxy( universe_get( L), L, prelude, eLM_LaneBody); // proxy |
467 | if( errmsg != NULL) | 472 | if( errmsg != NULL) |
468 | { | 473 | { |
469 | luaL_error( L, errmsg); | 474 | luaL_error( L, errmsg); |
@@ -481,7 +486,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | |||
481 | */ | 486 | */ |
482 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | 487 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) |
483 | { | 488 | { |
484 | DEEP_PRELUDE** proxy; | 489 | struct DEEP_PRELUDE** proxy; |
485 | 490 | ||
486 | STACK_CHECK( L); | 491 | STACK_CHECK( L); |
487 | // ensure it is actually a deep userdata | 492 | // ensure it is actually a deep userdata |
@@ -490,7 +495,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | |||
490 | return NULL; // no metatable, or wrong kind | 495 | return NULL; // no metatable, or wrong kind |
491 | } | 496 | } |
492 | 497 | ||
493 | proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); | 498 | proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, index); |
494 | STACK_END( L, 0); | 499 | STACK_END( L, 0); |
495 | 500 | ||
496 | return (*proxy)->deep; | 501 | return (*proxy)->deep; |
@@ -513,7 +518,7 @@ luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int | |||
513 | return NULL; // not a deep userdata | 518 | return NULL; // not a deep userdata |
514 | } | 519 | } |
515 | 520 | ||
516 | errmsg = push_deep_proxy( U, L2, *(DEEP_PRELUDE**) lua_touserdata( L, index), mode_); | 521 | errmsg = push_deep_proxy( U, L2, *(struct DEEP_PRELUDE**) lua_touserdata( L, index), mode_); |
517 | if( errmsg != NULL) | 522 | if( errmsg != NULL) |
518 | { | 523 | { |
519 | // raise the error in the proper state (not the keeper) | 524 | // raise the error in the proper state (not the keeper) |