diff options
| author | Benoit Germain <bnt.germain@gmail.com> | 2018-11-15 11:20:14 +0100 |
|---|---|---|
| committer | Benoit Germain <bnt.germain@gmail.com> | 2018-11-15 11:20:14 +0100 |
| commit | 01f83215a2ad235fbf306f591c6c0547b1bb7047 (patch) | |
| tree | 51d1edff1c3f684bac388c64d91ee30d8f6fbbf2 /src | |
| parent | 55acf8e19728ac39581c35f1324debf9449bd185 (diff) | |
| download | lanes-01f83215a2ad235fbf306f591c6c0547b1bb7047.tar.gz lanes-01f83215a2ad235fbf306f591c6c0547b1bb7047.tar.bz2 lanes-01f83215a2ad235fbf306f591c6c0547b1bb7047.zip | |
Deep userdata must embed DeepPrelude to save an allocation (also changes Deep protocol)
Diffstat (limited to 'src')
| -rw-r--r-- | src/deep.c | 66 | ||||
| -rw-r--r-- | src/deep.h | 12 | ||||
| -rw-r--r-- | src/keeper.c | 2 | ||||
| -rw-r--r-- | src/lanes.c | 6 | ||||
| -rw-r--r-- | src/lanes_private.h | 2 | ||||
| -rw-r--r-- | src/linda.c | 5 |
6 files changed, 42 insertions, 51 deletions
| @@ -105,16 +105,6 @@ void push_registry_subtable( lua_State* L, UniqueKey key_) | |||
| 105 | 105 | ||
| 106 | /*---=== Deep userdata ===---*/ | 106 | /*---=== Deep userdata ===---*/ |
| 107 | 107 | ||
| 108 | void luaG_pushdeepversion( lua_State* L) { (void) lua_pushliteral( L, "ab8743e5-84f8-485d-9c39-008e84656188");} | ||
| 109 | |||
| 110 | |||
| 111 | |||
| 112 | /* The deep portion must be allocated separately of any Lua state's; it's | ||
| 113 | * lifespan may be longer than that of the creating state. | ||
| 114 | */ | ||
| 115 | #define DEEP_MALLOC malloc | ||
| 116 | #define DEEP_FREE free | ||
| 117 | |||
| 118 | /* | 108 | /* |
| 119 | * 'registry[REGKEY]' is a two-way lookup table for 'idfunc's and those type's | 109 | * 'registry[REGKEY]' is a two-way lookup table for 'idfunc's and those type's |
| 120 | * metatables: | 110 | * metatables: |
| @@ -211,10 +201,9 @@ static inline luaG_IdFunction get_idfunc( lua_State* L, int index, LookupMode mo | |||
| 211 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) | 201 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) |
| 212 | { | 202 | { |
| 213 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | 203 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup |
| 214 | lua_pushlightuserdata( L, prelude_->deep); | 204 | lua_pushlightuserdata( L, prelude_); |
| 215 | ASSERT_L( prelude_->idfunc); | 205 | ASSERT_L( prelude_->idfunc); |
| 216 | prelude_->idfunc( L, eDO_delete); | 206 | prelude_->idfunc( L, eDO_delete); |
| 217 | DEEP_FREE( (void*) prelude_); | ||
| 218 | } | 207 | } |
| 219 | 208 | ||
| 220 | 209 | ||
| @@ -276,7 +265,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo | |||
| 276 | 265 | ||
| 277 | // Check if a proxy already exists | 266 | // Check if a proxy already exists |
| 278 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC | 267 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
| 279 | lua_pushlightuserdata( L, prelude->deep); // DPC deep | 268 | lua_pushlightuserdata( L, prelude); // DPC deep |
| 280 | lua_rawget( L, -2); // DPC proxy | 269 | lua_rawget( L, -2); // DPC proxy |
| 281 | if ( !lua_isnil( L, -1)) | 270 | if ( !lua_isnil( L, -1)) |
| 282 | { | 271 | { |
| @@ -313,20 +302,13 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo | |||
| 313 | // 1 - make one and register it | 302 | // 1 - make one and register it |
| 314 | if( mode_ != eLM_ToKeeper) | 303 | if( mode_ != eLM_ToKeeper) |
| 315 | { | 304 | { |
| 316 | (void) prelude->idfunc( L, eDO_metatable); // DPC proxy metatable deepversion | 305 | (void) prelude->idfunc( L, eDO_metatable); // DPC proxy metatable |
| 317 | if( lua_gettop( L) - oldtop != 1 || !lua_istable( L, -2) || !lua_isstring( L, -1)) | 306 | if( lua_gettop( L) - oldtop != 0 || !lua_istable( L, -1)) |
| 318 | { | 307 | { |
| 319 | lua_settop( L, oldtop); // DPC proxy X | 308 | lua_settop( L, oldtop); // DPC proxy X |
| 320 | lua_pop( L, 3); // | 309 | lua_pop( L, 3); // |
| 321 | return "Bad idfunc(eOP_metatable): unexpected pushed value"; | 310 | return "Bad idfunc(eOP_metatable): unexpected pushed value"; |
| 322 | } | 311 | } |
| 323 | luaG_pushdeepversion( L); // DPC proxy metatable deepversion deepversion | ||
| 324 | if( !lua501_equal( L, -1, -2)) | ||
| 325 | { | ||
| 326 | lua_pop( L, 5); // | ||
| 327 | return "Bad idfunc(eOP_metatable): mismatched deep version"; | ||
| 328 | } | ||
| 329 | lua_pop( L, 2); // DPC proxy metatable | ||
| 330 | // if the metatable contains a __gc, we will call it from our own | 312 | // if the metatable contains a __gc, we will call it from our own |
| 331 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc | 313 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc |
| 332 | } | 314 | } |
| @@ -420,7 +402,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo | |||
| 420 | lua_setmetatable( L, -2); // DPC proxy | 402 | lua_setmetatable( L, -2); // DPC proxy |
| 421 | 403 | ||
| 422 | // If we're here, we obviously had to create a new proxy, so cache it. | 404 | // If we're here, we obviously had to create a new proxy, so cache it. |
| 423 | lua_pushlightuserdata( L, (*proxy)->deep); // DPC proxy deep | 405 | lua_pushlightuserdata( L, prelude); // DPC proxy deep |
| 424 | lua_pushvalue( L, -2); // DPC proxy deep proxy | 406 | lua_pushvalue( L, -2); // DPC proxy deep proxy |
| 425 | lua_rawset( L, -4); // DPC proxy | 407 | lua_rawset( L, -4); // DPC proxy |
| 426 | lua_remove( L, -2); // proxy | 408 | lua_remove( L, -2); // proxy |
| @@ -454,34 +436,38 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo | |||
| 454 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | 436 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) |
| 455 | { | 437 | { |
| 456 | char const* errmsg; | 438 | char const* errmsg; |
| 457 | DeepPrelude* prelude = DEEP_MALLOC( sizeof( DeepPrelude)); | ||
| 458 | if( prelude == NULL) | ||
| 459 | { | ||
| 460 | return luaL_error( L, "couldn't not allocate deep prelude: out of memory"); | ||
| 461 | } | ||
| 462 | |||
| 463 | prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 | ||
| 464 | prelude->idfunc = idfunc; | ||
| 465 | 439 | ||
| 466 | STACK_GROW( L, 1); | 440 | STACK_GROW( L, 1); |
| 467 | STACK_CHECK( L); | 441 | STACK_CHECK( L); |
| 468 | { | 442 | { |
| 469 | int oldtop = lua_gettop( L); | 443 | int oldtop = lua_gettop( L); |
| 470 | prelude->deep = idfunc( L, eDO_new); | 444 | DeepPrelude* prelude = idfunc( L, eDO_new); |
| 471 | if( prelude->deep == NULL) | 445 | if( prelude == NULL) |
| 472 | { | 446 | { |
| 473 | luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); | 447 | luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)"); |
| 474 | } | 448 | } |
| 449 | if( prelude->magic.value != DEEP_VERSION.value) | ||
| 450 | { | ||
| 451 | // just in case, don't leak the newly allocated deep userdata object | ||
| 452 | lua_pushlightuserdata( L, prelude); | ||
| 453 | idfunc( L, eDO_delete); | ||
| 454 | return luaL_error( L, "Bad idfunc(eDO_new): DEEP_VERSION is incorrect, rebuild your implementation with the latest deep implementation"); | ||
| 455 | } | ||
| 456 | prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 | ||
| 457 | prelude->idfunc = idfunc; | ||
| 475 | 458 | ||
| 476 | if( lua_gettop( L) - oldtop != 0) | 459 | if( lua_gettop( L) - oldtop != 0) |
| 477 | { | 460 | { |
| 478 | luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | 461 | // just in case, don't leak the newly allocated deep userdata object |
| 462 | lua_pushlightuserdata( L, prelude); | ||
| 463 | idfunc( L, eDO_delete); | ||
| 464 | return luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | ||
| 465 | } | ||
| 466 | errmsg = push_deep_proxy( universe_get( L), L, prelude, eLM_LaneBody); // proxy | ||
| 467 | if( errmsg != NULL) | ||
| 468 | { | ||
| 469 | return luaL_error( L, errmsg); | ||
| 479 | } | 470 | } |
| 480 | } | ||
| 481 | errmsg = push_deep_proxy( universe_get( L), L, prelude, eLM_LaneBody); // proxy | ||
| 482 | if( errmsg != NULL) | ||
| 483 | { | ||
| 484 | luaL_error( L, errmsg); | ||
| 485 | } | 471 | } |
| 486 | STACK_END( L, 1); | 472 | STACK_END( L, 1); |
| 487 | return 1; | 473 | return 1; |
| @@ -508,7 +494,7 @@ void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) | |||
| 508 | proxy = (DeepPrelude**) lua_touserdata( L, index); | 494 | proxy = (DeepPrelude**) lua_touserdata( L, index); |
| 509 | STACK_END( L, 0); | 495 | STACK_END( L, 0); |
| 510 | 496 | ||
| 511 | return (*proxy)->deep; | 497 | return *proxy; |
| 512 | } | 498 | } |
| 513 | 499 | ||
| 514 | 500 | ||
| @@ -8,6 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | #include "lua.h" | 9 | #include "lua.h" |
| 10 | #include "platform.h" | 10 | #include "platform.h" |
| 11 | #include "uniquekey.h" | ||
| 11 | 12 | ||
| 12 | // forwards | 13 | // forwards |
| 13 | struct s_Universe; | 14 | struct s_Universe; |
| @@ -42,13 +43,17 @@ typedef void* (*luaG_IdFunction)( lua_State* L, DeepOp op_); | |||
| 42 | 43 | ||
| 43 | // ################################################################################################ | 44 | // ################################################################################################ |
| 44 | 45 | ||
| 45 | // this is pointed to by full userdata proxies, and allocated with malloc() to survive any lua_State lifetime | 46 | // crc64/we of string "DEEP_VERSION_1" generated at http://www.nitrxgen.net/hashgen/ |
| 47 | static DECLARE_CONST_UNIQUE_KEY( DEEP_VERSION, 0x4f4eadf0accf6c73); | ||
| 48 | |||
| 49 | // should be used as header for full userdata | ||
| 46 | struct s_DeepPrelude | 50 | struct s_DeepPrelude |
| 47 | { | 51 | { |
| 48 | volatile int refcount; | 52 | DECLARE_UNIQUE_KEY( magic); // must be filled by the Deep userdata idfunc that allocates it on eDO_new operation |
| 49 | void* deep; | ||
| 50 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc | 53 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc |
| 51 | luaG_IdFunction idfunc; | 54 | luaG_IdFunction idfunc; |
| 55 | // data is destroyed when refcount is 0 | ||
| 56 | volatile int refcount; | ||
| 52 | }; | 57 | }; |
| 53 | typedef struct s_DeepPrelude DeepPrelude; | 58 | typedef struct s_DeepPrelude DeepPrelude; |
| 54 | 59 | ||
| @@ -57,6 +62,5 @@ void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); | |||
| 57 | 62 | ||
| 58 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); | 63 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); |
| 59 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); | 64 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); |
| 60 | extern LANES_API void luaG_pushdeepversion( lua_State* L); | ||
| 61 | 65 | ||
| 62 | #endif // __LANES_DEEP_H__ | 66 | #endif // __LANES_DEEP_H__ |
diff --git a/src/keeper.c b/src/keeper.c index 091463e..0471cb7 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
| @@ -754,7 +754,7 @@ void keeper_release( Keeper* K) | |||
| 754 | if( K) MUTEX_UNLOCK( &K->keeper_cs); | 754 | if( K) MUTEX_UNLOCK( &K->keeper_cs); |
| 755 | } | 755 | } |
| 756 | 756 | ||
| 757 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode mode_) | 757 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mode_) |
| 758 | { | 758 | { |
| 759 | int i, n = lua_gettop( L); | 759 | int i, n = lua_gettop( L); |
| 760 | for( i = val_i_; i <= n; ++ i) | 760 | for( i = val_i_; i <= n; ++ i) |
diff --git a/src/lanes.c b/src/lanes.c index f2e3065..037e44f 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
| @@ -733,7 +733,10 @@ static int selfdestruct_gc( lua_State* L) | |||
| 733 | // necessary so that calling free_deep_prelude doesn't crash because linda_id expects a linda lightuserdata at absolute slot 1 | 733 | // necessary so that calling free_deep_prelude doesn't crash because linda_id expects a linda lightuserdata at absolute slot 1 |
| 734 | lua_settop( L, 0); | 734 | lua_settop( L, 0); |
| 735 | // no need to mutex-protect this as all threads in the universe are gone at that point | 735 | // no need to mutex-protect this as all threads in the universe are gone at that point |
| 736 | -- U->timer_deep->refcount; // should be 0 now | 736 | if( U->timer_deep != NULL) // test ins case some early internal error prevented Lanes from creating the deep timer |
| 737 | { | ||
| 738 | -- U->timer_deep->refcount; // should be 0 now | ||
| 739 | } | ||
| 737 | free_deep_prelude( L, (DeepPrelude*) U->timer_deep); | 740 | free_deep_prelude( L, (DeepPrelude*) U->timer_deep); |
| 738 | U->timer_deep = NULL; | 741 | U->timer_deep = NULL; |
| 739 | 742 | ||
| @@ -2162,7 +2165,6 @@ LUAG_FUNC( configure) | |||
| 2162 | 2165 | ||
| 2163 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer | 2166 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer |
| 2164 | U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); | 2167 | U->timer_deep = *(DeepPrelude**) lua_touserdata( L, -1); |
| 2165 | ASSERT_L( U->timer_deep && (U->timer_deep->refcount == 1) && U->timer_deep->deep && U->timer_deep->idfunc == linda_id); | ||
| 2166 | // increment refcount that this linda remains alive as long as the universe is. | 2168 | // increment refcount that this linda remains alive as long as the universe is. |
| 2167 | ++ U->timer_deep->refcount; | 2169 | ++ U->timer_deep->refcount; |
| 2168 | lua_pop( L, 1); // settings | 2170 | lua_pop( L, 1); // settings |
diff --git a/src/lanes_private.h b/src/lanes_private.h index a7e21d7..1adfa31 100644 --- a/src/lanes_private.h +++ b/src/lanes_private.h | |||
| @@ -112,6 +112,4 @@ static inline int cancel_error( lua_State* L) | |||
| 112 | return lua_error( L); // doesn't return | 112 | return lua_error( L); // doesn't return |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | |||
| 116 | |||
| 117 | #endif // __lanes_private_h__ \ No newline at end of file | 115 | #endif // __lanes_private_h__ \ No newline at end of file |
diff --git a/src/linda.c b/src/linda.c index 98d2a8e..ee60ebc 100644 --- a/src/linda.c +++ b/src/linda.c | |||
| @@ -46,6 +46,7 @@ THE SOFTWARE. | |||
| 46 | */ | 46 | */ |
| 47 | struct s_Linda | 47 | struct s_Linda |
| 48 | { | 48 | { |
| 49 | DeepPrelude prelude; // Deep userdata MUST start with this header | ||
| 49 | SIGNAL_T read_happened; | 50 | SIGNAL_T read_happened; |
| 50 | SIGNAL_T write_happened; | 51 | SIGNAL_T write_happened; |
| 51 | Universe* U; // the universe this linda belongs to | 52 | Universe* U; // the universe this linda belongs to |
| @@ -794,6 +795,7 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
| 794 | s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included | 795 | s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included |
| 795 | if( s) | 796 | if( s) |
| 796 | { | 797 | { |
| 798 | s->prelude.magic.value = DEEP_VERSION.value; | ||
| 797 | SIGNAL_INIT( &s->read_happened); | 799 | SIGNAL_INIT( &s->read_happened); |
| 798 | SIGNAL_INIT( &s->write_happened); | 800 | SIGNAL_INIT( &s->write_happened); |
| 799 | s->U = universe_get( L); | 801 | s->U = universe_get( L); |
| @@ -895,8 +897,7 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
| 895 | push_unique_key( L, NIL_SENTINEL); | 897 | push_unique_key( L, NIL_SENTINEL); |
| 896 | lua_setfield(L, -2, "null"); | 898 | lua_setfield(L, -2, "null"); |
| 897 | 899 | ||
| 898 | luaG_pushdeepversion( L); | 900 | STACK_END( L, 1); |
| 899 | STACK_END( L, 2); | ||
| 900 | return NULL; | 901 | return NULL; |
| 901 | } | 902 | } |
| 902 | 903 | ||
