aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES4
-rw-r--r--deep_test/deep_test.c54
-rw-r--r--deep_test/deep_test.lua6
-rw-r--r--src/deep.c46
-rw-r--r--src/tools.c2
5 files changed, 78 insertions, 34 deletions
diff --git a/CHANGES b/CHANGES
index 338c48f..92fb7f9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 123: BGe 2-Aug-17
4 * added support for user-provided __gc in deep userdata
5 * more complete deep userdata sample
6
3CHANGE 122: BGe 1-Aug-17 7CHANGE 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
15struct s_MyDeepUserdata
16{
17 lua_Integer val;
18};
19static void* deep_test_id( lua_State* L, enum eDeepOp op_);
20
21// ################################################################################################
22
23static 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
15static int deep_tostring(lua_State* L) 33static 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
42static 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
23static luaL_Reg const deep_mt[] = 50static 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
72int luaD_new_deep(lua_State* L) 100int 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
2local dt = require "deep_test" 2local dt = require "deep_test"
3local deep = dt.new_deep() 3local deep = dt.new_deep()
4deep:set(666)
4print( deep) 5print( 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--[[
8local lanes = require("lanes").configure() 9local lanes = require("lanes").configure()
9 10
10local l = lanes.linda "my linda" 11local l = lanes.linda "my linda"
11l.put( "key", deep) 12l.put( "key", deep)
12local out = l.get( "key") 13local out = l.get( "key")
13print( out) \ No newline at end of file 14print( out)
15]] \ No newline at end of file
diff --git a/src/deep.c b/src/deep.c
index 71a798c..737ebe9 100644
--- a/src/deep.c
+++ b/src/deep.c
@@ -104,7 +104,7 @@ void push_registry_subtable( lua_State* L, void* key_)
104 104
105/*---=== Deep userdata ===---*/ 105/*---=== Deep userdata ===---*/
106 106
107void luaG_pushdeepversion( lua_State* L) { (void) lua_pushliteral( L, "f248e77a-a84d-44b5-9ad0-96c05679b885");} 107void 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 */
227static int deep_userdata_gc( lua_State* L) 227static 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
823static int table_lookup_sentinel( lua_State* L) 823static 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/*