diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-10 18:16:57 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-10 18:16:57 +0200 |
commit | 7d31e295dc782afc92f3215d1571e629a5407fbf (patch) | |
tree | 2be6f774be1b41f65dd4e8c015712dacee42c21b | |
parent | ae582acdb1bfb3fb4171682b884545d174e95aa9 (diff) | |
download | lanes-7d31e295dc782afc92f3215d1571e629a5407fbf.tar.gz lanes-7d31e295dc782afc92f3215d1571e629a5407fbf.tar.bz2 lanes-7d31e295dc782afc92f3215d1571e629a5407fbf.zip |
Removed .demote_full_userdata
Diffstat (limited to '')
-rw-r--r-- | deep_test/deep_test.cpp | 2 | ||||
-rw-r--r-- | deep_test/deeptest.lua | 13 | ||||
-rw-r--r-- | docs/index.html | 52 | ||||
-rw-r--r-- | src/intercopycontext.cpp | 19 | ||||
-rw-r--r-- | src/lanes.lua | 2 | ||||
-rw-r--r-- | src/universe.cpp | 4 | ||||
-rw-r--r-- | src/universe.h | 2 |
7 files changed, 29 insertions, 65 deletions
diff --git a/deep_test/deep_test.cpp b/deep_test/deep_test.cpp index 812019a..178075d 100644 --- a/deep_test/deep_test.cpp +++ b/deep_test/deep_test.cpp | |||
@@ -58,7 +58,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c | |||
58 | { | 58 | { |
59 | MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) }; | 59 | MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) }; |
60 | _self->inUse.fetch_add(1, std::memory_order_seq_cst); | 60 | _self->inUse.fetch_add(1, std::memory_order_seq_cst); |
61 | std::ignore = luaG_pushstring(L, "%p:deep(%d)", lua_topointer(L, 1), _self->val); | 61 | std::ignore = luaG_pushstring(L, "%p:deep(%d)", _self, _self->val); |
62 | _self->inUse.fetch_sub(1, std::memory_order_seq_cst); | 62 | _self->inUse.fetch_sub(1, std::memory_order_seq_cst); |
63 | return 1; | 63 | return 1; |
64 | } | 64 | } |
diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua index 250eb98..bab91d9 100644 --- a/deep_test/deeptest.lua +++ b/deep_test/deeptest.lua | |||
@@ -38,9 +38,13 @@ local printDeep = function( prefix_, obj_, t_) | |||
38 | print ("uv #" .. uvi, type( uservalue), uservalue, type(uservalue) == "function" and uservalue() or "") | 38 | print ("uv #" .. uvi, type( uservalue), uservalue, type(uservalue) == "function" and uservalue() or "") |
39 | end | 39 | end |
40 | if t_ then | 40 | if t_ then |
41 | for k, v in pairs( t_) do | 41 | local count = 0 |
42 | for k, v in ipairs( t_) do | ||
42 | print( "t["..tostring(k).."]", v) | 43 | print( "t["..tostring(k).."]", v) |
44 | count = count + 1 | ||
43 | end | 45 | end |
46 | -- we should have only 2 indexed entries with the same value | ||
47 | assert(count == 2 and t_[1] == t_[2]) | ||
44 | end | 48 | end |
45 | print() | 49 | print() |
46 | end | 50 | end |
@@ -56,8 +60,11 @@ local performTest = function( obj_) | |||
56 | 60 | ||
57 | local t = | 61 | local t = |
58 | { | 62 | { |
59 | ["key"] = obj_, | 63 | -- two indices with an identical value: we should also have identical values on the other side (even if not the same as the original ones when they are clonables) |
60 | [obj_] = "val" -- this one won't transfer because we don't support full uservalue as keys | 64 | obj_, |
65 | obj_, | ||
66 | -- this one won't transfer because we don't support full uservalue as keys | ||
67 | [obj_] = "val" | ||
61 | } | 68 | } |
62 | 69 | ||
63 | -- read back the contents of the object | 70 | -- read back the contents of the object |
diff --git a/docs/index.html b/docs/index.html index 5675f65..4e8cc25 100644 --- a/docs/index.html +++ b/docs/index.html | |||
@@ -368,19 +368,6 @@ | |||
368 | </tr> | 368 | </tr> |
369 | 369 | ||
370 | <tr valign=top> | 370 | <tr valign=top> |
371 | <td id="demote_full_userdata"> | ||
372 | <code>.demote_full_userdata</code> | ||
373 | </td> | ||
374 | <td> | ||
375 | <tt>nil</tt>/<tt>false</tt>/<tt>true</tt> | ||
376 | </td> | ||
377 | <td> | ||
378 | If equal to <tt>false</tt> or <tt>nil</tt>, Lanes raises an error when attempting to transfer a non-deep full userdata, else it will be demoted to a light userdata in the destination. | ||
379 | Default is <tt>false</tt> (set to <tt>true</tt> to get the legacy behaviour). | ||
380 | </td> | ||
381 | </tr> | ||
382 | |||
383 | <tr valign=top> | ||
384 | <td id="track_lanes"> | 371 | <td id="track_lanes"> |
385 | <code>.track_lanes</code> | 372 | <code>.track_lanes</code> |
386 | </td> | 373 | </td> |
@@ -1547,47 +1534,36 @@ On the other side, you need to use a common Linda for waiting for multiple keys. | |||
1547 | 1534 | ||
1548 | <p> | 1535 | <p> |
1549 | Data passed between lanes (either as starting parameters, return values, upvalues or via Lindas) must conform to the following: | 1536 | Data passed between lanes (either as starting parameters, return values, upvalues or via Lindas) must conform to the following: |
1550 | </p> | ||
1551 | |||
1552 | <p> | ||
1553 | <ul> | 1537 | <ul> |
1538 | <li>Coroutines cannot be passed. A coroutine's Lua state is tied to the Lua state that created it, and there is no way the mixed C/Lua stack of a coroutine can be transfered from one Lua state to another.</li> | ||
1539 | <li>Lane handles cannot be passed between lanes.</li> | ||
1554 | <li>Booleans, numbers, strings, light userdata, Lua functions and tables of such can always be passed.</li> | 1540 | <li>Booleans, numbers, strings, light userdata, Lua functions and tables of such can always be passed.</li> |
1555 | <li> | 1541 | <li> |
1556 | Cyclic tables and/or duplicate references are allowed and reproduced appropriately, but only <u>within the same transmission</u>. | 1542 | Cyclic tables and/or duplicate references are allowed and reproduced appropriately, but only <u>within the same transmission</u>. |
1557 | <ul> | 1543 | Using the same source table in multiple <a href="#lindas">Linda</a> messages keeps no ties between the tables (this is the same reason why tables can't be used as keys). |
1558 | <li>Using the same source table in multiple <a href="#lindas">Linda</a> messages keeps no ties between the tables (this is the same reason why tables can't be used as keys).</li> | ||
1559 | </ul> | ||
1560 | </li> | 1544 | </li> |
1561 | <li> | 1545 | <li> |
1562 | Objects (tables with a metatable) are copyable between lanes. | 1546 | For tables and full userdata: before anything else, the metatable is searched for a <tt>__lanesconvert</tt> field. If found, the source object is converted as follows depending on <tt>__lanesconvert</tt>'s value: |
1563 | <ul> | 1547 | <ul> |
1564 | <li>Metatables are assumed to be immutable; they are internally indexed and only copied once per each type of objects per lane.</li> | 1548 | <li><tt>lanes.null</tt>: The value is converted to <tt>nil</tt>.</li> |
1549 | <li><tt>"decay"</tt>: The value is converted to a light userdata obtained from <tt>lua_topointer()</tt>.</li> | ||
1550 | <li>A function: The function is called as <tt>o:__lanesconvert(string)</tt>, where the argument is either <tt>"keeper"</tt> or <tt>"regular"</tt>, depending on the type of destination. Its (single) return value is the result of the conversion.</li> | ||
1551 | <li>Any other value raises an error.</li> | ||
1565 | </ul> | 1552 | </ul> |
1566 | </li> | 1553 | </li> |
1567 | <li> | 1554 | <li> |
1568 | C functions (<tt>lua_CFunction</tt>) referring to <tt>LUA_ENVIRONINDEX</tt> or <tt>LUA_REGISTRYINDEX</tt> might not do what you expect in the target, since they will actually use a different environment. | 1555 | Non-converted full userdata can be passed only if it is prepared using the <a href="#deep_userdata">deep userdata</a> system, which handles its lifespan management. |
1569 | </li> | 1556 | </li> |
1570 | <li> | 1557 | <li> |
1571 | Lua 5.2 functions may have a special <tt>_ENV</tt> upvalue if they perform 'global namespace' lookups. Unless special care is taken, this upvalue defaults to the table found at <tt>LUA_RIDX_GLOBALS</tt>. | 1558 | Objects (tables with a metatable) are copyable between lanes. Metatables are assumed to be immutable; they are internally indexed and only copied once per each type of objects per lane. |
1572 | Obviously, we don't want to transfer the whole global table along with each Lua function. Therefore, any upvalue equal to the global table is not transfered by value, but simply bound | ||
1573 | to the global table in the destination state. Note that this also applies when Lanes is built for Lua 5.1, as it doesn't hurt. | ||
1574 | </li> | 1559 | </li> |
1575 | <li> | 1560 | <li> |
1576 | Full userdata can be passed only if it is prepared using the <a href="#deep_userdata">deep userdata</a> system, which handles its lifespan management | 1561 | C functions (<tt>lua_CFunction</tt>) referring to <tt>LUA_ENVIRONINDEX</tt> or <tt>LUA_REGISTRYINDEX</tt> might not do what you expect in the target, since they will actually use a different environment. |
1577 | <ul> | ||
1578 | <li>In particular, lane handles cannot be passed between lanes.</li> | ||
1579 | <li>Lanes can either throw an error or attempt a <a href="#demote_full_userdata">light userdata demotion</a>.</li> | ||
1580 | </ul> | ||
1581 | </li> | 1562 | </li> |
1582 | <li>Coroutines cannot be passed. A coroutine's Lua state is tied to the Lua state that created it, and there is no way the mixed C/Lua stack of a coroutine can be transfered from one Lua state to another.</li> | ||
1583 | <li> | 1563 | <li> |
1584 | If the metatable contains <tt>__lanesconvert</tt>, the object is converted as follows depending on the value: | 1564 | Lua 5.2 functions may have a special <tt>_ENV</tt> upvalue if they perform 'global namespace' lookups. Unless special care is taken, this upvalue defaults to the table found at <tt>LUA_RIDX_GLOBALS</tt>. |
1585 | <ul> | 1565 | Obviously, we don't want to transfer the whole global table along with each Lua function. Therefore, any upvalue equal to the global table is not transfered by value, but simply bound |
1586 | <li><tt>lanes.null</tt>: The value is converted to <tt>nil</tt>.</li> | 1566 | to the global table in the destination state. Note that this also applies when Lanes is built for Lua 5.1, as it doesn't hurt. |
1587 | <li><tt>"decay"</tt>: The value is converted to a light userdata obtained from <tt>lua_topointer()</tt>.</li> | ||
1588 | <li>A function: The function is called as <tt>o:__lanesconvert(string)</tt>, where the argument is either <tt>"keeper"</tt> or <tt>"regular"</tt>, depending on the type of destination. Its (single) return value is the result of the conversion.</li> | ||
1589 | <li>Any other value raises an error.</li> | ||
1590 | </ul> | ||
1591 | </li> | 1567 | </li> |
1592 | </ul> | 1568 | </ul> |
1593 | </p> | 1569 | </p> |
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp index a5fd400..5be4304 100644 --- a/src/intercopycontext.cpp +++ b/src/intercopycontext.cpp | |||
@@ -718,6 +718,8 @@ LuaType InterCopyContext::processConversion() const | |||
718 | return false; | 718 | return false; |
719 | } | 719 | } |
720 | 720 | ||
721 | DEBUGSPEW_CODE(DebugSpew(U) << "CLONABLE USERDATA" << std::endl); | ||
722 | |||
721 | // we need to copy over the uservalues of the userdata as well | 723 | // we need to copy over the uservalues of the userdata as well |
722 | { | 724 | { |
723 | int const _mt{ luaG_absindex(L1, -2) }; // L1: ... mt __lanesclone | 725 | int const _mt{ luaG_absindex(L1, -2) }; // L1: ... mt __lanesclone |
@@ -795,6 +797,7 @@ LuaType InterCopyContext::processConversion() const | |||
795 | return false; // not a deep userdata | 797 | return false; // not a deep userdata |
796 | } | 798 | } |
797 | 799 | ||
800 | DEBUGSPEW_CODE(DebugSpew(U) << "DEEP USERDATA" << std::endl); | ||
798 | STACK_CHECK_START_REL(L1, 0); | 801 | STACK_CHECK_START_REL(L1, 0); |
799 | STACK_CHECK_START_REL(L2, 0); | 802 | STACK_CHECK_START_REL(L2, 0); |
800 | 803 | ||
@@ -1085,27 +1088,13 @@ LuaType InterCopyContext::processConversion() const | |||
1085 | STACK_CHECK(L2, 0); | 1088 | STACK_CHECK(L2, 0); |
1086 | 1089 | ||
1087 | // Allow only deep userdata entities to be copied across | 1090 | // Allow only deep userdata entities to be copied across |
1088 | DEBUGSPEW_CODE(DebugSpew(nullptr) << "USERDATA" << std::endl); | ||
1089 | if (tryCopyDeep()) { | 1091 | if (tryCopyDeep()) { |
1090 | STACK_CHECK(L1, 0); | 1092 | STACK_CHECK(L1, 0); |
1091 | STACK_CHECK(L2, 1); | 1093 | STACK_CHECK(L2, 1); |
1092 | return true; | 1094 | return true; |
1093 | } | 1095 | } |
1094 | 1096 | ||
1095 | STACK_CHECK(L1, 0); | 1097 | raise_luaL_error(getErrL(), "can't copy non-deep full userdata across lanes"); |
1096 | STACK_CHECK(L2, 0); | ||
1097 | |||
1098 | // Not a deep or clonable full userdata | ||
1099 | if (U->demoteFullUserdata) { // attempt demotion to light userdata | ||
1100 | void* const _lud{ lua_touserdata(L1, L1_i) }; | ||
1101 | lua_pushlightuserdata(L2, _lud); | ||
1102 | } else { // raise an error | ||
1103 | raise_luaL_error(getErrL(), "can't copy non-deep full userdata across lanes"); | ||
1104 | } | ||
1105 | |||
1106 | STACK_CHECK(L2, 1); | ||
1107 | STACK_CHECK(L1, 0); | ||
1108 | return true; | ||
1109 | } | 1098 | } |
1110 | 1099 | ||
1111 | // ################################################################################################# | 1100 | // ################################################################################################# |
diff --git a/src/lanes.lua b/src/lanes.lua index 92e773a..1378412 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
@@ -92,7 +92,6 @@ local default_params = | |||
92 | { | 92 | { |
93 | -- LuaJIT provides a thread-unsafe allocator by default, so we need to protect it when used in parallel lanes | 93 | -- LuaJIT provides a thread-unsafe allocator by default, so we need to protect it when used in parallel lanes |
94 | allocator = isLuaJIT and "protected" or nil, | 94 | allocator = isLuaJIT and "protected" or nil, |
95 | demote_full_userdata = nil, | ||
96 | -- it looks also like LuaJIT allocator may not appreciate direct use of its allocator for other purposes than the VM operation | 95 | -- it looks also like LuaJIT allocator may not appreciate direct use of its allocator for other purposes than the VM operation |
97 | internal_allocator = isLuaJIT and "libc" or "allocator", | 96 | internal_allocator = isLuaJIT and "libc" or "allocator", |
98 | keepers_gc_threshold = -1, | 97 | keepers_gc_threshold = -1, |
@@ -119,7 +118,6 @@ local param_checkers = | |||
119 | -- can be nil, "protected", or a function | 118 | -- can be nil, "protected", or a function |
120 | return val_ and (type(val_) == "function" or val_ == "protected") or true | 119 | return val_ and (type(val_) == "function" or val_ == "protected") or true |
121 | end, | 120 | end, |
122 | demote_full_userdata = boolean_param_checker, | ||
123 | internal_allocator = function(val_) | 121 | internal_allocator = function(val_) |
124 | -- can be "libc" or "allocator" | 122 | -- can be "libc" or "allocator" |
125 | return val_ == "libc" or val_ == "allocator" | 123 | return val_ == "libc" or val_ == "allocator" |
diff --git a/src/universe.cpp b/src/universe.cpp index 9ab6019..82522f1 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
@@ -107,7 +107,6 @@ Universe::Universe() | |||
107 | lua_setmetatable(L_, -2); // L_: settings universe | 107 | lua_setmetatable(L_, -2); // L_: settings universe |
108 | lua_pop(L_, 1); // L_: settings | 108 | lua_pop(L_, 1); // L_: settings |
109 | 109 | ||
110 | // TODO: write some tests to see what happens when we trigger errors in stripped mode | ||
111 | std::ignore = luaG_getfield(L_, 1, "strip_functions"); // L_: settings strip_functions | 110 | std::ignore = luaG_getfield(L_, 1, "strip_functions"); // L_: settings strip_functions |
112 | _U->stripFunctions = lua_toboolean(L_, -1) ? true : false; | 111 | _U->stripFunctions = lua_toboolean(L_, -1) ? true : false; |
113 | lua_pop(L_, 1); // L_: settings | 112 | lua_pop(L_, 1); // L_: settings |
@@ -115,9 +114,6 @@ Universe::Universe() | |||
115 | std::ignore = luaG_getfield(L_, 1, "verbose_errors"); // L_: settings verbose_errors | 114 | std::ignore = luaG_getfield(L_, 1, "verbose_errors"); // L_: settings verbose_errors |
116 | _U->verboseErrors = lua_toboolean(L_, -1) ? true : false; | 115 | _U->verboseErrors = lua_toboolean(L_, -1) ? true : false; |
117 | lua_pop(L_, 1); // L_: settings | 116 | lua_pop(L_, 1); // L_: settings |
118 | std::ignore = luaG_getfield(L_, 1, "demote_full_userdata"); // L_: settings demote_full_userdata | ||
119 | _U->demoteFullUserdata = lua_toboolean(L_, -1) ? true : false; | ||
120 | lua_pop(L_, 1); // L_: settings | ||
121 | 117 | ||
122 | // tracking | 118 | // tracking |
123 | std::ignore = luaG_getfield(L_, 1, "track_lanes"); // L_: settings track_lanes | 119 | std::ignore = luaG_getfield(L_, 1, "track_lanes"); // L_: settings track_lanes |
diff --git a/src/universe.h b/src/universe.h index 2b8cdf2..f0975d8 100644 --- a/src/universe.h +++ b/src/universe.h | |||
@@ -128,8 +128,6 @@ class Universe | |||
128 | // for verbose errors | 128 | // for verbose errors |
129 | bool verboseErrors{ false }; | 129 | bool verboseErrors{ false }; |
130 | 130 | ||
131 | bool demoteFullUserdata{ false }; | ||
132 | |||
133 | bool stripFunctions{ true }; | 131 | bool stripFunctions{ true }; |
134 | 132 | ||
135 | // before a state is created, this function will be called to obtain the allocator | 133 | // before a state is created, this function will be called to obtain the allocator |