aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2018-11-15 11:20:14 +0100
committerBenoit Germain <bnt.germain@gmail.com>2018-11-15 11:20:14 +0100
commit01f83215a2ad235fbf306f591c6c0547b1bb7047 (patch)
tree51d1edff1c3f684bac388c64d91ee30d8f6fbbf2 /src
parent55acf8e19728ac39581c35f1324debf9449bd185 (diff)
downloadlanes-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.c66
-rw-r--r--src/deep.h12
-rw-r--r--src/keeper.c2
-rw-r--r--src/lanes.c6
-rw-r--r--src/lanes_private.h2
-rw-r--r--src/linda.c5
6 files changed, 42 insertions, 51 deletions
diff --git a/src/deep.c b/src/deep.c
index af7f580..c351bf7 100644
--- a/src/deep.c
+++ b/src/deep.c
@@ -105,16 +105,6 @@ void push_registry_subtable( lua_State* L, UniqueKey key_)
105 105
106/*---=== Deep userdata ===---*/ 106/*---=== Deep userdata ===---*/
107 107
108void 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
211void free_deep_prelude( lua_State* L, DeepPrelude* prelude_) 201void 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
454int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) 436int 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
diff --git a/src/deep.h b/src/deep.h
index 918de6a..8d06395 100644
--- a/src/deep.h
+++ b/src/deep.h
@@ -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
13struct s_Universe; 14struct 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/
47static DECLARE_CONST_UNIQUE_KEY( DEEP_VERSION, 0x4f4eadf0accf6c73);
48
49// should be used as header for full userdata
46struct s_DeepPrelude 50struct 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};
53typedef struct s_DeepPrelude DeepPrelude; 58typedef struct s_DeepPrelude DeepPrelude;
54 59
@@ -57,6 +62,5 @@ void free_deep_prelude( lua_State* L, DeepPrelude* prelude_);
57 62
58extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); 63extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc);
59extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); 64extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index);
60extern 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
757void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode mode_) 757void 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*/
47struct s_Linda 47struct 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