diff options
-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 | /* |