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 | ||