From d1ef9b97e356805c622e4832ec76289bae391a6e Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Wed, 23 Jun 2021 12:38:01 +0200 Subject: __lanesclone now receives the original as light userdata the first time it is called --- CHANGES | 5 ++++- deep_test/deep_test.c | 12 ++++++++---- docs/index.html | 25 +++++++++++++++++-------- src/tools.c | 10 ++++++---- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/CHANGES b/CHANGES index c3893d0..792a52b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,10 @@ CHANGES: +CHANGE 148: BGe 23-Jun-21 + * __lanesclone now receives the original as light userdata the first time it is called -> BREAKS CUSTOM DEEP USERDATA API + CHANGE 147: BGe 16-Jun-21 - * changed lanes.threads() output so that several lanes with the same name don't clobber each other in the result table + * changed lanes.threads() output so that several lanes with the same name don't clobber each other in the result table -> BREAKS API * bumped version to 3.15 because of the API change CHANGE 146: BGe 26-Apr-19 diff --git a/deep_test/deep_test.c b/deep_test/deep_test.c index 9585a3c..61c81c5 100644 --- a/deep_test/deep_test.c +++ b/deep_test/deep_test.c @@ -166,8 +166,12 @@ static int clonable_lanesclone( lua_State* L) { switch( lua_gettop( L)) { - case 0: - lua_pushinteger( L, sizeof( struct s_MyClonableUserdata)); + case 1: + { + // in case we need it to compute the amount of memory we need + struct s_MyClonableUserdata* self = lua_touserdata( L, 1); + lua_pushinteger( L, sizeof( struct s_MyClonableUserdata)); + } return 1; case 2: @@ -175,8 +179,8 @@ static int clonable_lanesclone( lua_State* L) struct s_MyClonableUserdata* self = lua_touserdata( L, 1); struct s_MyClonableUserdata* from = lua_touserdata( L, 2); *self = *from; - return 0; } + return 0; default: (void) luaL_error( L, "Lanes called clonable_lanesclone with unexpected parameters"); @@ -223,7 +227,7 @@ extern int __declspec(dllexport) luaopen_deep_test(lua_State* L) { luaL_newlib( L, deep_module); // M - // preregister the metatables for the types we can instanciate so that Lanes can know about them + // preregister the metatables for the types we can instantiate so that Lanes can know about them if( luaL_newmetatable( L, "clonable")) // M mt { luaL_setfuncs( L, clonable_mt, 0); diff --git a/docs/index.html b/docs/index.html index 49b862f..e9a313e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -64,13 +64,13 @@


- Copyright © 2007-19 Asko Kauppi, Benoit Germain. All rights reserved. + Copyright © 2007-21 Asko Kauppi, Benoit Germain. All rights reserved.
Lua Lanes is published under the same MIT license as Lua 5.1, 5.2, 5.3 and 5.4.

- This document was revised on 26-Apr-19, and applies to version 3.14.0. + This document was revised on 23-Jun-21, and applies to version 3.15.0.

@@ -1548,23 +1548,31 @@ events to a common Linda, but... :).

Clonable full userdata in your own apps

- Starting with version 3.13.0, a new way of passing full userdata across lanes uses a new __lanesclone metamethod. A typical implementation would look like: + Starting with version 3.13.0, a new way of passing full userdata across lanes uses a new __lanesclone metamethod. + When a deep userdata is cloned, Lanes calls __lanesclone twice, in the context of the source lane.
+ The first call receives the original as light userdata, as in ud:__lanesclone(), and should return the amount of memory used to create the cloned full userdata.
+ The second call receives the clone and original as light userdata, as in clone:__lanesclone(original), and should perform the actual cloning.
+ A typical implementation would look like:
 static int clonable_lanesclone( lua_State* L)
 {
 	switch( lua_gettop( L))
 	{
-		case 0:
-		lua_pushinteger( L, sizeof( struct s_MyClonableUserdata));
+		case 1: // original:__lanesclone()
+		{
+			// the original (as light userdata), in case you need it to compute the size of the clone
+			struct s_MyClonableUserdata* self = lua_touserdata( L, 1);
+			lua_pushinteger( L, sizeof( struct s_MyClonableUserdata));
+		}
 		return 1;
 
-		case 2:
+		case 2: // clone:__lanesclone(original)
 		{
 			struct s_MyClonableUserdata* self = lua_touserdata( L, 1);
 			struct s_MyClonableUserdata* from = lua_touserdata( L, 2);
 			*self = *from;
-			return 0;
 		}
+		return 0;
 
 		default:
 		(void) luaL_error( L, "Lanes called clonable_lanesclone with unexpected parameters");
@@ -1605,7 +1613,7 @@ int luaopen_deep_test(lua_State* L)
 

- Then a new clonable userdata instance can just do like any non-Lanes aware userdata, as long as its metatable contains the aforementionned __lanesclone method. Note that the current implementation doesn't support uservalues on such userdata. + Then a new clonable userdata instance can just do like any non-Lanes aware userdata, as long as its metatable contains the aforementionned __lanesclone method.
 int luaD_new_clonable( lua_State* L)
 {
@@ -1746,3 +1754,4 @@ int luaD_new_clonable( lua_State* L)
 
 
 
+
\ No newline at end of file diff --git a/src/tools.c b/src/tools.c index 02d51ae..f3ac236 100644 --- a/src/tools.c +++ b/src/tools.c @@ -1760,8 +1760,9 @@ static bool_t copyclone( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_Stat void* const source = lua_touserdata( L, i); void* clone = NULL; lua_pushvalue( L, -1); // ... mt __lanesclone __lanesclone - // call the cloning function with 0 arguments, should return the number of bytes to allocate for the clone - lua_call( L, 0, 1); // ... mt __lanesclone size + // call the cloning function with 1 argument, should return the number of bytes to allocate for the clone + lua_pushlightuserdata( L, source); // ... mt __lanesclone __lanesclone source + lua_call( L, 1, 1); // ... mt __lanesclone size STACK_MID( L, 3); userdata_size = (size_t) lua_tointeger( L, -1); // ... mt __lanesclone size lua_pop( L, 1); // ... mt __lanesclone @@ -1899,8 +1900,9 @@ static bool_t inter_copy_function( Universe* U, lua_State* L2, uint_t L2_cache_i // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with lua_getfield( L2, -1, "__lanesclone"); // ... mt __lanesclone lua_pushvalue( L2, -1); // ... mt __lanesclone __lanesclone - // call the cloning function with 0 arguments, should return the number of bytes to allocate for the clone - lua_call( L2, 0, 1); // ... mt __lanesclone size + // call the cloning function with 1 argument, should return the number of bytes to allocate for the clone + lua_pushlightuserdata( L2, source); // ... mt __lanesclone __lanesclone source + lua_call( L2, 1, 1); // ... mt __lanesclone size userdata_size = (size_t) lua_tointeger( L2, -1); // ... mt __lanesclone size lua_pop( L2, 1); // ... mt __lanesclone lua_pushnil( L2); // ... mt __lanesclone nil -- cgit v1.2.3-55-g6feb