diff options
| author | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2017-08-02 14:39:44 +0200 |
|---|---|---|
| committer | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2017-08-02 14:39:44 +0200 |
| commit | c5d772fd0dd9120885be96255d5dd4a3ed6b8aac (patch) | |
| tree | 4f92866eddac0788ad3c060af041c6945ffe7797 | |
| parent | 00fa87f8460f32259737d0285d7855e68b55ab31 (diff) | |
| download | lanes-c5d772fd0dd9120885be96255d5dd4a3ed6b8aac.tar.gz lanes-c5d772fd0dd9120885be96255d5dd4a3ed6b8aac.tar.bz2 lanes-c5d772fd0dd9120885be96255d5dd4a3ed6b8aac.zip | |
Deep userdata improvements
Support for user-provided __gc
Improved example
| -rw-r--r-- | CHANGES | 4 | ||||
| -rw-r--r-- | deep_test/deep_test.c | 54 | ||||
| -rw-r--r-- | deep_test/deep_test.lua | 6 | ||||
| -rw-r--r-- | src/deep.c | 46 | ||||
| -rw-r--r-- | src/tools.c | 2 |
5 files changed, 78 insertions, 34 deletions
| @@ -1,5 +1,9 @@ | |||
| 1 | CHANGES: | 1 | CHANGES: |
| 2 | 2 | ||
| 3 | CHANGE 123: BGe 2-Aug-17 | ||
| 4 | * added support for user-provided __gc in deep userdata | ||
| 5 | * more complete deep userdata sample | ||
| 6 | |||
| 3 | CHANGE 122: BGe 1-Aug-17 | 7 | CHANGE 122: BGe 1-Aug-17 |
| 4 | * fix crash trying to use a deep-aware module while not requiring Lanes | 8 | * fix crash trying to use a deep-aware module while not requiring Lanes |
| 5 | * bumped version to 3.12 | 9 | * bumped version to 3.12 |
diff --git a/deep_test/deep_test.c b/deep_test/deep_test.c index a48ecb2..abe9fdc 100644 --- a/deep_test/deep_test.c +++ b/deep_test/deep_test.c | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | #include <malloc.h> | ||
| 2 | |||
| 1 | #include "lua.h" | 3 | #include "lua.h" |
| 2 | #include "lualib.h" | 4 | #include "lualib.h" |
| 3 | #include "lauxlib.h" | 5 | #include "lauxlib.h" |
| @@ -10,19 +12,46 @@ | |||
| 10 | #define LANES_API | 12 | #define LANES_API |
| 11 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 13 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
| 12 | 14 | ||
| 15 | struct s_MyDeepUserdata | ||
| 16 | { | ||
| 17 | lua_Integer val; | ||
| 18 | }; | ||
| 19 | static void* deep_test_id( lua_State* L, enum eDeepOp op_); | ||
| 20 | |||
| 21 | // ################################################################################################ | ||
| 22 | |||
| 23 | static int deep_set( lua_State* L) | ||
| 24 | { | ||
| 25 | struct s_MyDeepUserdata* self = luaG_todeep( L, deep_test_id, 1); | ||
| 26 | lua_Integer i = lua_tointeger( L, 2); | ||
| 27 | self->val = i; | ||
| 28 | return 0; | ||
| 29 | } | ||
| 30 | |||
| 13 | // ################################################################################################ | 31 | // ################################################################################################ |
| 14 | 32 | ||
| 15 | static int deep_tostring(lua_State* L) | 33 | static int deep_tostring( lua_State* L) |
| 16 | { | 34 | { |
| 17 | lua_pushliteral( L, "I am a deep_test"); | 35 | struct s_MyDeepUserdata* self = luaG_todeep( L, deep_test_id, 1); |
| 36 | lua_pushfstring( L, "deep_test(%d)", self->val); | ||
| 18 | return 1; | 37 | return 1; |
| 19 | } | 38 | } |
| 20 | 39 | ||
| 21 | // ################################################################################################ | 40 | // ################################################################################################ |
| 22 | 41 | ||
| 42 | static int deep_gc( lua_State* L) | ||
| 43 | { | ||
| 44 | struct s_MyDeepUserdata* self = luaG_todeep( L, deep_test_id, 1); | ||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | // ################################################################################################ | ||
| 49 | |||
| 23 | static luaL_Reg const deep_mt[] = | 50 | static luaL_Reg const deep_mt[] = |
| 24 | { | 51 | { |
| 25 | { "__tostring", deep_tostring}, | 52 | { "__tostring", deep_tostring}, |
| 53 | { "__gc", deep_gc}, | ||
| 54 | { "set", deep_set}, | ||
| 26 | { NULL, NULL } | 55 | { NULL, NULL } |
| 27 | }; | 56 | }; |
| 28 | 57 | ||
| @@ -34,26 +63,25 @@ static void* deep_test_id( lua_State* L, enum eDeepOp op_) | |||
| 34 | { | 63 | { |
| 35 | case eDO_new: | 64 | case eDO_new: |
| 36 | { | 65 | { |
| 37 | void* allocUD; | 66 | struct s_MyDeepUserdata* deep_test = (struct s_MyDeepUserdata*) malloc( sizeof(struct s_MyDeepUserdata)); |
| 38 | lua_Alloc allocF = lua_getallocf( L, &allocUD); | 67 | deep_test->val = 0; |
| 39 | void* deep_test = allocF( allocUD, NULL, 0, sizeof(void*)); | ||
| 40 | return deep_test; | 68 | return deep_test; |
| 41 | } | 69 | } |
| 42 | 70 | ||
| 43 | case eDO_delete: | 71 | case eDO_delete: |
| 44 | { | 72 | { |
| 45 | void* allocUD; | 73 | struct s_MyDeepUserdata* deep_test = (struct s_MyDeepUserdata*) lua_touserdata( L, 1); |
| 46 | lua_Alloc allocF = lua_getallocf( L, &allocUD); | 74 | free( deep_test); |
| 47 | void* deep_test = lua_touserdata( L, 1); | ||
| 48 | allocF( allocUD, deep_test, sizeof(void*), 0); | ||
| 49 | return NULL; | 75 | return NULL; |
| 50 | } | 76 | } |
| 51 | 77 | ||
| 52 | case eDO_metatable: | 78 | case eDO_metatable: |
| 53 | { | 79 | { |
| 54 | lua_newtable( L); | 80 | lua_newtable( L); // mt |
| 55 | luaL_setfuncs( L, deep_mt, 0); | 81 | luaL_setfuncs( L, deep_mt, 0); // mt |
| 56 | luaG_pushdeepversion( L); | 82 | lua_pushvalue( L, -1); // mt mt |
| 83 | lua_setfield( L, -2, "__index"); // mt | ||
| 84 | luaG_pushdeepversion( L); // mt version | ||
| 57 | return NULL; | 85 | return NULL; |
| 58 | } | 86 | } |
| 59 | 87 | ||
| @@ -69,7 +97,7 @@ static void* deep_test_id( lua_State* L, enum eDeepOp op_) | |||
| 69 | 97 | ||
| 70 | // ################################################################################################ | 98 | // ################################################################################################ |
| 71 | 99 | ||
| 72 | int luaD_new_deep(lua_State* L) | 100 | int luaD_new_deep( lua_State* L) |
| 73 | { | 101 | { |
| 74 | return luaG_newdeepuserdata( L, deep_test_id); | 102 | return luaG_newdeepuserdata( L, deep_test_id); |
| 75 | } | 103 | } |
diff --git a/deep_test/deep_test.lua b/deep_test/deep_test.lua index 034c07d..fd78115 100644 --- a/deep_test/deep_test.lua +++ b/deep_test/deep_test.lua | |||
| @@ -1,13 +1,15 @@ | |||
| 1 | -- create a deep-aware full userdata while Lanes isn't loaded | 1 | -- create a deep-aware full userdata while Lanes isn't loaded |
| 2 | local dt = require "deep_test" | 2 | local dt = require "deep_test" |
| 3 | local deep = dt.new_deep() | 3 | local deep = dt.new_deep() |
| 4 | deep:set(666) | ||
| 4 | print( deep) | 5 | print( deep) |
| 5 | 6 | ||
| 6 | -- now load Lanes and see if that userdata is transferable | 7 | -- now load Lanes and see if that userdata is transferable |
| 7 | 8 | --[[ | |
| 8 | local lanes = require("lanes").configure() | 9 | local lanes = require("lanes").configure() |
| 9 | 10 | ||
| 10 | local l = lanes.linda "my linda" | 11 | local l = lanes.linda "my linda" |
| 11 | l.put( "key", deep) | 12 | l.put( "key", deep) |
| 12 | local out = l.get( "key") | 13 | local out = l.get( "key") |
| 13 | print( out) \ No newline at end of file | 14 | print( out) |
| 15 | ]] \ No newline at end of file | ||
| @@ -104,7 +104,7 @@ void push_registry_subtable( lua_State* L, void* key_) | |||
| 104 | 104 | ||
| 105 | /*---=== Deep userdata ===---*/ | 105 | /*---=== Deep userdata ===---*/ |
| 106 | 106 | ||
| 107 | void luaG_pushdeepversion( lua_State* L) { (void) lua_pushliteral( L, "f248e77a-a84d-44b5-9ad0-96c05679b885");} | 107 | void luaG_pushdeepversion( lua_State* L) { (void) lua_pushliteral( L, "ab8743e5-84f8-485d-9c39-008e84656188");} |
| 108 | 108 | ||
| 109 | 109 | ||
| 110 | 110 | ||
| @@ -219,11 +219,11 @@ void free_deep_prelude( lua_State* L, struct DEEP_PRELUDE* prelude_) | |||
| 219 | 219 | ||
| 220 | 220 | ||
| 221 | /* | 221 | /* |
| 222 | * void= mt.__gc( proxy_ud ) | 222 | * void= mt.__gc( proxy_ud ) |
| 223 | * | 223 | * |
| 224 | * End of life for a proxy object; reduce the deep reference count and clean | 224 | * End of life for a proxy object; reduce the deep reference count and clean it up if reaches 0. |
| 225 | * it up if reaches 0. | 225 | * |
| 226 | */ | 226 | */ |
| 227 | static int deep_userdata_gc( lua_State* L) | 227 | static int deep_userdata_gc( lua_State* L) |
| 228 | { | 228 | { |
| 229 | struct DEEP_PRELUDE** proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, 1); | 229 | struct DEEP_PRELUDE** proxy = (struct DEEP_PRELUDE**) lua_touserdata( L, 1); |
| @@ -231,8 +231,6 @@ static int deep_userdata_gc( lua_State* L) | |||
| 231 | struct s_Universe* U = universe_get( L); | 231 | struct s_Universe* U = universe_get( L); |
| 232 | int v; | 232 | int v; |
| 233 | 233 | ||
| 234 | *proxy = 0; // make sure we don't use it any more | ||
| 235 | |||
| 236 | // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded | 234 | // 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 | 235 | // in that case, we are not multithreaded and locking isn't necessary anyway |
| 238 | if( U) MUTEX_LOCK( &U->deep_lock); | 236 | if( U) MUTEX_LOCK( &U->deep_lock); |
| @@ -241,6 +239,13 @@ static int deep_userdata_gc( lua_State* L) | |||
| 241 | 239 | ||
| 242 | if( v == 0) | 240 | if( v == 0) |
| 243 | { | 241 | { |
| 242 | // retrieve wrapped __gc | ||
| 243 | lua_pushvalue( L, lua_upvalueindex( 1)); // self __gc? | ||
| 244 | if( !lua_isnil( L, -1)) | ||
| 245 | { | ||
| 246 | lua_insert( L, -2); // __gc self | ||
| 247 | lua_call( L, 1, 0); // | ||
| 248 | } | ||
| 244 | // 'idfunc' expects a clean stack to work on | 249 | // 'idfunc' expects a clean stack to work on |
| 245 | lua_settop( L, 0); | 250 | lua_settop( L, 0); |
| 246 | free_deep_prelude( L, p); | 251 | free_deep_prelude( L, p); |
| @@ -251,6 +256,7 @@ static int deep_userdata_gc( lua_State* L) | |||
| 251 | luaL_error( L, "Bad idfunc(eDO_delete): should not push anything"); | 256 | luaL_error( L, "Bad idfunc(eDO_delete): should not push anything"); |
| 252 | } | 257 | } |
| 253 | } | 258 | } |
| 259 | *proxy = NULL; // make sure we don't use it any more, just in case | ||
| 254 | return 0; | 260 | return 0; |
| 255 | } | 261 | } |
| 256 | 262 | ||
| @@ -321,22 +327,26 @@ char const* push_deep_proxy( struct s_Universe* U, lua_State* L, struct DEEP_PRE | |||
| 321 | return "Bad idfunc(eOP_metatable): mismatched deep version"; | 327 | return "Bad idfunc(eOP_metatable): mismatched deep version"; |
| 322 | } | 328 | } |
| 323 | lua_pop( L, 2); // DPC proxy metatable | 329 | lua_pop( L, 2); // DPC proxy metatable |
| 324 | // make sure the idfunc didn't export __gc, as we will store our own | 330 | // if the metatable contains a __gc, we will call it from our own |
| 325 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc | 331 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc |
| 326 | if( !lua_isnil( L, -1)) | ||
| 327 | { | ||
| 328 | lua_pop( L, 4); // | ||
| 329 | return "idfunc-created metatable shouldn't contain __gc"; | ||
| 330 | } | ||
| 331 | lua_pop( L, 1); // DPC proxy metatable | ||
| 332 | } | 332 | } |
| 333 | else | 333 | else |
| 334 | { | 334 | { |
| 335 | // keepers need a minimal metatable that only contains __gc | 335 | // keepers need a minimal metatable that only contains our own __gc |
| 336 | lua_newtable( L); // DPC proxy metatable | 336 | lua_newtable( L); // DPC proxy metatable |
| 337 | lua_pushnil( L); // DPC proxy metatable nil | ||
| 338 | } | ||
| 339 | if (lua_isnil(L, -1)) | ||
| 340 | { | ||
| 341 | // Add our own '__gc' method | ||
| 342 | lua_pop( L, 1); // DPC proxy metatable | ||
| 343 | lua_pushcfunction( L, deep_userdata_gc); // DPC proxy metatable deep_userdata_gc | ||
| 344 | } | ||
| 345 | else | ||
| 346 | { | ||
| 347 | // Add our own '__gc' method wrapping the original | ||
| 348 | lua_pushcclosure( L, deep_userdata_gc, 1); // DPC proxy metatable deep_userdata_gc | ||
| 337 | } | 349 | } |
| 338 | // Add our own '__gc' method | ||
| 339 | lua_pushcfunction( L, deep_userdata_gc); // DPC proxy metatable __gc | ||
| 340 | lua_setfield( L, -2, "__gc"); // DPC proxy metatable | 350 | lua_setfield( L, -2, "__gc"); // DPC proxy metatable |
| 341 | 351 | ||
| 342 | // Memorize for later rounds | 352 | // Memorize for later rounds |
diff --git a/src/tools.c b/src/tools.c index f935c26..9403fd6 100644 --- a/src/tools.c +++ b/src/tools.c | |||
| @@ -822,7 +822,7 @@ static int func_lookup_sentinel( lua_State* L) | |||
| 822 | // function sentinel used to transfer native table from/to keeper states | 822 | // function sentinel used to transfer native table from/to keeper states |
| 823 | static int table_lookup_sentinel( lua_State* L) | 823 | static int table_lookup_sentinel( lua_State* L) |
| 824 | { | 824 | { |
| 825 | return luaL_error( L, "table lookup sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex(1))); | 825 | return luaL_error( L, "table lookup sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1))); |
| 826 | } | 826 | } |
| 827 | 827 | ||
| 828 | /* | 828 | /* |
