aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2021-06-24 17:47:20 +0200
committerBenoit Germain <bnt.germain@gmail.com>2021-06-24 17:47:20 +0200
commit050e14dd7fa04e2262ae6b1cc984d76c4149b664 (patch)
tree8b7cead727e2b9e545dbbd458ef4009eb099db92
parent4e8242de0c5d8c853201ec49dacf5aa9a5b0f7d3 (diff)
downloadlanes-050e14dd7fa04e2262ae6b1cc984d76c4149b664.tar.gz
lanes-050e14dd7fa04e2262ae6b1cc984d76c4149b664.tar.bz2
lanes-050e14dd7fa04e2262ae6b1cc984d76c4149b664.zip
correctly transfer the uservalue of a deep userdata
-rw-r--r--deep_test/deep_test.c5
-rw-r--r--deep_test/deep_test.vcxproj3
-rw-r--r--deep_test/deep_test.vcxproj.filters6
-rw-r--r--deep_test/deep_test.vcxproj.user2
-rw-r--r--deep_test/deeptest.lua10
-rw-r--r--docs/index.html2
-rw-r--r--lanes-3.15.0-0.rockspec66
-rw-r--r--src/Makefile2
-rw-r--r--src/deep.c43
-rw-r--r--src/deep.h8
-rw-r--r--src/keeper.c1
-rw-r--r--src/lanes.c3
-rw-r--r--src/linda.c2
-rw-r--r--src/state.c439
-rw-r--r--src/state.h22
-rw-r--r--src/tools.c398
-rw-r--r--src/tools.h8
17 files changed, 598 insertions, 422 deletions
diff --git a/deep_test/deep_test.c b/deep_test/deep_test.c
index c400cac..dabc84d 100644
--- a/deep_test/deep_test.c
+++ b/deep_test/deep_test.c
@@ -126,7 +126,10 @@ static void* deep_test_id( lua_State* L, enum eDeepOp op_)
126 126
127int luaD_new_deep( lua_State* L) 127int luaD_new_deep( lua_State* L)
128{ 128{
129 return luaG_newdeepuserdata( L, deep_test_id); 129 int nuv = (int) luaL_optinteger( L, 1, 0);
130 // no additional parameter to luaG_newdeepuserdata!
131 lua_settop( L, 0);
132 return luaG_newdeepuserdata( L, deep_test_id, nuv);
130} 133}
131 134
132// ################################################################################################ 135// ################################################################################################
diff --git a/deep_test/deep_test.vcxproj b/deep_test/deep_test.vcxproj
index d94b855..67d3afd 100644
--- a/deep_test/deep_test.vcxproj
+++ b/deep_test/deep_test.vcxproj
@@ -181,6 +181,7 @@
181 <ConformanceMode>true</ConformanceMode> 181 <ConformanceMode>true</ConformanceMode>
182 <AdditionalIncludeDirectories>$(SolutionDir)Lanes\lanes\src;$(SolutionDir)..\lualib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 182 <AdditionalIncludeDirectories>$(SolutionDir)Lanes\lanes\src;$(SolutionDir)..\lualib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
183 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 183 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
184 <PreprocessorDefinitions>_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
184 </ClCompile> 185 </ClCompile>
185 <PostBuildEvent> 186 <PostBuildEvent>
186 <Command>xcopy /R /F /Y /I "$(TargetPath)" $(SolutionDir)..\framework\</Command> 187 <Command>xcopy /R /F /Y /I "$(TargetPath)" $(SolutionDir)..\framework\</Command>
@@ -230,12 +231,14 @@
230 <ItemGroup> 231 <ItemGroup>
231 <ClCompile Include="..\src\compat.c" /> 232 <ClCompile Include="..\src\compat.c" />
232 <ClCompile Include="..\src\deep.c" /> 233 <ClCompile Include="..\src\deep.c" />
234 <ClCompile Include="..\src\tools.c" />
233 <ClCompile Include="..\src\universe.c" /> 235 <ClCompile Include="..\src\universe.c" />
234 <ClCompile Include="deep_test.c" /> 236 <ClCompile Include="deep_test.c" />
235 </ItemGroup> 237 </ItemGroup>
236 <ItemGroup> 238 <ItemGroup>
237 <ClInclude Include="..\src\compat.h" /> 239 <ClInclude Include="..\src\compat.h" />
238 <ClInclude Include="..\src\deep.h" /> 240 <ClInclude Include="..\src\deep.h" />
241 <ClInclude Include="..\src\tools.h" />
239 <ClInclude Include="..\src\universe.h" /> 242 <ClInclude Include="..\src\universe.h" />
240 </ItemGroup> 243 </ItemGroup>
241 <ItemGroup> 244 <ItemGroup>
diff --git a/deep_test/deep_test.vcxproj.filters b/deep_test/deep_test.vcxproj.filters
index 93f6148..be47da9 100644
--- a/deep_test/deep_test.vcxproj.filters
+++ b/deep_test/deep_test.vcxproj.filters
@@ -27,6 +27,9 @@
27 <ClCompile Include="..\src\compat.c"> 27 <ClCompile Include="..\src\compat.c">
28 <Filter>Lanes</Filter> 28 <Filter>Lanes</Filter>
29 </ClCompile> 29 </ClCompile>
30 <ClCompile Include="..\src\tools.c">
31 <Filter>Lanes</Filter>
32 </ClCompile>
30 </ItemGroup> 33 </ItemGroup>
31 <ItemGroup> 34 <ItemGroup>
32 <ClInclude Include="..\src\deep.h"> 35 <ClInclude Include="..\src\deep.h">
@@ -38,6 +41,9 @@
38 <ClInclude Include="..\src\compat.h"> 41 <ClInclude Include="..\src\compat.h">
39 <Filter>Lanes</Filter> 42 <Filter>Lanes</Filter>
40 </ClInclude> 43 </ClInclude>
44 <ClInclude Include="..\src\tools.h">
45 <Filter>Lanes</Filter>
46 </ClInclude>
41 </ItemGroup> 47 </ItemGroup>
42 <ItemGroup> 48 <ItemGroup>
43 <None Include="deeptest.lua"> 49 <None Include="deeptest.lua">
diff --git a/deep_test/deep_test.vcxproj.user b/deep_test/deep_test.vcxproj.user
index f6a2db8..70871df 100644
--- a/deep_test/deep_test.vcxproj.user
+++ b/deep_test/deep_test.vcxproj.user
@@ -3,7 +3,7 @@
3 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'"> 3 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">
4 <LocalDebuggerCommand>D:\Boulot\anubis\Lua\framework\lua53.exe</LocalDebuggerCommand> 4 <LocalDebuggerCommand>D:\Boulot\anubis\Lua\framework\lua53.exe</LocalDebuggerCommand>
5 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> 5 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
6 <LocalDebuggerCommandArguments>-i -- deeptest.lua</LocalDebuggerCommandArguments> 6 <LocalDebuggerCommandArguments>-i</LocalDebuggerCommandArguments>
7 <LocalDebuggerWorkingDirectory>D:\Boulot\anubis\Lua\bindings\Lanes\lanes\deep_test\</LocalDebuggerWorkingDirectory> 7 <LocalDebuggerWorkingDirectory>D:\Boulot\anubis\Lua\bindings\Lanes\lanes\deep_test\</LocalDebuggerWorkingDirectory>
8 </PropertyGroup> 8 </PropertyGroup>
9 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> 9 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua
index b3e523f..92cd372 100644
--- a/deep_test/deeptest.lua
+++ b/deep_test/deeptest.lua
@@ -23,13 +23,19 @@ end
23local performTest = function( obj_) 23local performTest = function( obj_)
24 -- setup the userdata with some value and a uservalue 24 -- setup the userdata with some value and a uservalue
25 obj_:set( 666) 25 obj_:set( 666)
26 obj_:setuv( 1, makeUserValue( obj_)) 26 -- lua 5.1->5.2 support a single table uservalue
27 -- lua 5.3 supports an arbitrary type uservalue
28 obj_:setuv( 1, makeUserValue( obj_))
29 -- lua 5.4 supports multiple uservalues of arbitrary types
30 -- obj_:setuv( 2, "ENDUV")
27 31
28 -- read back the contents of the object 32 -- read back the contents of the object
29 print( "immediate:", obj_, obj_:getuv( 1)) 33 print( "immediate:", obj_, obj_:getuv( 1))
30 34
31 -- send the object in a linda, get it back out, read the contents 35 -- send the object in a linda, get it back out, read the contents
32 l:set( "key", obj_) 36 l:set( "key", obj_)
37 -- when obj_ is a deep userdata, out is the same userdata as obj_ (not another one pointing on the same deep memory block) because of an internal cache table [deep*] -> proxy)
38 -- when obj_ is a clonable userdata, we get a different clone everytime we cross a linda or lane barrier
33 local out = l:get( "key") 39 local out = l:get( "key")
34 print( "out of linda:", out, out:getuv( 1)) 40 print( "out of linda:", out, out:getuv( 1))
35 41
@@ -46,6 +52,8 @@ local performTest = function( obj_)
46 end 52 end
47 ) 53 )
48 h = g( obj_) 54 h = g( obj_)
55 -- when obj_ is a deep userdata, from_lane is the same userdata as obj_ (not another one pointing on the same deep memory block) because of an internal cache table [deep*] -> proxy)
56 -- when obj_ is a clonable userdata, we get a different clone everytime we cross a linda or lane barrier
49 local from_lane = h[1] 57 local from_lane = h[1]
50 print( "from lane:", from_lane, from_lane:getuv( 1)) 58 print( "from lane:", from_lane, from_lane:getuv( 1))
51end 59end
diff --git a/docs/index.html b/docs/index.html
index e9a313e..76752f5 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1643,7 +1643,7 @@ int luaD_new_clonable( lua_State* L)
1643 </ul> 1643 </ul>
1644 Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt> or <tt>deep_test_id</tt> in <tt>deep_test.c</tt>. 1644 Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt> or <tt>deep_test_id</tt> in <tt>deep_test.c</tt>.
1645 </li> 1645 </li>
1646 <li>Include <tt>"deep.h"</tt> and either link against Lanes or statically compile <tt>deep.c</tt> and <tt>universe.c</tt> into your module if you want to avoid a runtime dependency for users that will use your module without Lanes. 1646 <li>Include <tt>"deep.h"</tt> and either link against Lanes or statically compile <tt>compat.c deep.c tools.c universe.c</tt> into your module if you want to avoid a runtime dependency for users that will use your module without Lanes.
1647 <li>Instanciate your userdata using <tt>luaG_newdeepuserdata()</tt>, instead of the regular <tt>lua_newuserdata()</tt>. Given an <tt>idfunc</tt>, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.</li> 1647 <li>Instanciate your userdata using <tt>luaG_newdeepuserdata()</tt>, instead of the regular <tt>lua_newuserdata()</tt>. Given an <tt>idfunc</tt>, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.</li>
1648 <li>Accessing the deep userdata from your C code, use <tt>luaG_todeep()</tt> instead of the regular <tt>lua_touserdata()</tt>.</li> 1648 <li>Accessing the deep userdata from your C code, use <tt>luaG_todeep()</tt> instead of the regular <tt>lua_touserdata()</tt>.</li>
1649</ol> 1649</ol>
diff --git a/lanes-3.15.0-0.rockspec b/lanes-3.15.0-0.rockspec
new file mode 100644
index 0000000..47fcaa5
--- /dev/null
+++ b/lanes-3.15.0-0.rockspec
@@ -0,0 +1,66 @@
1--
2-- Lanes rockspec
3--
4-- Ref:
5-- <http://luarocks.org/en/Rockspec_format>
6--
7
8package = "Lanes"
9
10version = "3.13.0-0"
11
12source= {
13 url= "git://github.com/LuaLanes/lanes.git",
14 branch= "v3.13.0"
15}
16
17description = {
18 summary= "Multithreading support for Lua",
19 detailed= [[
20 Lua Lanes is a portable, message passing multithreading library
21 providing the possibility to run multiple Lua states in parallel.
22 ]],
23 license= "MIT/X11",
24 homepage="https://github.com/LuaLanes/lanes",
25 maintainer="Benoit Germain <bnt.germain@gmail.com>"
26}
27
28-- Q: What is the difference of "windows" and "win32"? Seems there is none;
29-- so should we list either one or both?
30--
31supported_platforms= { "win32",
32 "macosx",
33 "linux",
34 "freebsd", -- TBD: not tested
35 "msys", -- TBD: not supported by LuaRocks 1.0 (or is it?)
36}
37
38dependencies= {
39 "lua >= 5.1", -- builds with either 5.1, 5.2, 5.3 and 5.4
40}
41
42build = {
43 type = "builtin",
44 platforms =
45 {
46 linux =
47 {
48 modules =
49 {
50 ["lanes.core"] =
51 {
52 libraries = "pthread"
53 },
54 }
55 }
56 },
57 modules =
58 {
59 ["lanes.core"] =
60 {
61 sources = { "src/compat.c", "src/deep.c", "src/lanes.c", "src/linda.c", "src/keeper.c", "src/tools.c", "src/state.c", "src/threading.c", "src/universe.c"},
62 incdirs = { "src"},
63 },
64 lanes = "src/lanes.lua"
65 }
66}
diff --git a/src/Makefile b/src/Makefile
index 8729c29..c4d4c30 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -7,7 +7,7 @@
7 7
8MODULE=lanes 8MODULE=lanes
9 9
10SRC=lanes.c cancel.c compat.c threading.c tools.c linda.c deep.c keeper.c universe.c 10SRC=lanes.c cancel.c compat.c threading.c tools.c state.c linda.c deep.c keeper.c universe.c
11 11
12OBJ=$(SRC:.c=.o) 12OBJ=$(SRC:.c=.o)
13 13
diff --git a/src/deep.c b/src/deep.c
index fadb895..fd2ae73 100644
--- a/src/deep.c
+++ b/src/deep.c
@@ -256,7 +256,7 @@ static int deep_userdata_gc( lua_State* L)
256 * used in this Lua state (metatable, registring it). Otherwise, increments the 256 * used in this Lua state (metatable, registring it). Otherwise, increments the
257 * reference count. 257 * reference count.
258 */ 258 */
259char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, LookupMode mode_) 259char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_)
260{ 260{
261 DeepPrelude** proxy; 261 DeepPrelude** proxy;
262 262
@@ -283,7 +283,8 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo
283 STACK_GROW( L, 7); 283 STACK_GROW( L, 7);
284 STACK_CHECK( L, 0); 284 STACK_CHECK( L, 0);
285 285
286 proxy = lua_newuserdatauv( L, sizeof(DeepPrelude*), 0); // DPC proxy 286 // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4)
287 proxy = lua_newuserdatauv( L, sizeof(DeepPrelude*), nuv_); // DPC proxy
287 ASSERT_L( proxy); 288 ASSERT_L( proxy);
288 *proxy = prelude; 289 *proxy = prelude;
289 290
@@ -414,7 +415,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo
414* proxy_ud= deep_userdata( idfunc [, ...] ) 415* proxy_ud= deep_userdata( idfunc [, ...] )
415* 416*
416* Creates a deep userdata entry of the type defined by 'idfunc'. 417* Creates a deep userdata entry of the type defined by 'idfunc'.
417* Other parameters are passed on to the 'idfunc' "new" invocation. 418* Parameters found on the stack are left as is passed on to the 'idfunc' "new" invocation.
418* 419*
419* 'idfunc' must fulfill the following features: 420* 'idfunc' must fulfill the following features:
420* 421*
@@ -430,7 +431,7 @@ char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, Lo
430* 431*
431* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' 432* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()'
432*/ 433*/
433int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) 434int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_)
434{ 435{
435 char const* errmsg; 436 char const* errmsg;
436 437
@@ -460,7 +461,7 @@ int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc)
460 idfunc( L, eDO_delete); 461 idfunc( L, eDO_delete);
461 return luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); 462 return luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack");
462 } 463 }
463 errmsg = push_deep_proxy( universe_get( L), L, prelude, eLM_LaneBody); // proxy 464 errmsg = push_deep_proxy( universe_get( L), L, prelude, nuv_, eLM_LaneBody); // proxy
464 if( errmsg != NULL) 465 if( errmsg != NULL)
465 { 466 {
466 return luaL_error( L, errmsg); 467 return luaL_error( L, errmsg);
@@ -506,12 +507,42 @@ bool_t copydeep( Universe* U, lua_State* L, lua_State* L2, int index, LookupMode
506{ 507{
507 char const* errmsg; 508 char const* errmsg;
508 luaG_IdFunction idfunc = get_idfunc( L, index, mode_); 509 luaG_IdFunction idfunc = get_idfunc( L, index, mode_);
510 int nuv = 0;
511
509 if( idfunc == NULL) 512 if( idfunc == NULL)
510 { 513 {
511 return FALSE; // not a deep userdata 514 return FALSE; // not a deep userdata
512 } 515 }
513 516
514 errmsg = push_deep_proxy( U, L2, *(DeepPrelude**) lua_touserdata( L, index), mode_); 517 STACK_CHECK( L, 0);
518 STACK_CHECK( L2, 0);
519
520 // extract all uservalues of the source
521 while( lua_getiuservalue( L, index, nuv + 1) != LUA_TNONE) // ... u [uv]+ nil
522 {
523 ++ nuv;
524 }
525 // last call returned TNONE and pushed nil, that we don't need
526 lua_pop( L, 1); // ... u [uv]+
527 STACK_MID( L, nuv);
528
529 errmsg = push_deep_proxy( U, L2, *(DeepPrelude**) lua_touserdata( L, index), nuv, mode_); // u
530
531 // transfer all uservalues of the source in the destination
532 {
533 int const clone_i = lua_gettop( L2);
534 luaG_inter_move( U, L, L2, nuv, mode_); // ... u // u [uv]+
535 while( nuv > 0)
536 {
537 // this pops the value from the stack
538 lua_setiuservalue( L2, clone_i, nuv); // ... u // u
539 -- nuv;
540 }
541 }
542
543 STACK_END( L2, 1);
544 STACK_END( L, 0);
545
515 if( errmsg != NULL) 546 if( errmsg != NULL)
516 { 547 {
517 // raise the error in the proper state (not the keeper) 548 // raise the error in the proper state (not the keeper)
diff --git a/src/deep.h b/src/deep.h
index 8d06395..35c8bd4 100644
--- a/src/deep.h
+++ b/src/deep.h
@@ -43,8 +43,8 @@ typedef void* (*luaG_IdFunction)( lua_State* L, DeepOp op_);
43 43
44// ################################################################################################ 44// ################################################################################################
45 45
46// crc64/we of string "DEEP_VERSION_1" generated at http://www.nitrxgen.net/hashgen/ 46// fnv164 of string "DEEP_VERSION_2" generated at https://www.pelock.com/products/hash-calculator
47static DECLARE_CONST_UNIQUE_KEY( DEEP_VERSION, 0x4f4eadf0accf6c73); 47static DECLARE_CONST_UNIQUE_KEY( DEEP_VERSION, 0xB4B0119C10642B29);
48 48
49// should be used as header for full userdata 49// should be used as header for full userdata
50struct s_DeepPrelude 50struct s_DeepPrelude
@@ -57,10 +57,10 @@ struct s_DeepPrelude
57}; 57};
58typedef struct s_DeepPrelude DeepPrelude; 58typedef struct s_DeepPrelude DeepPrelude;
59 59
60char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, LookupMode mode_); 60char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_);
61void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); 61void free_deep_prelude( lua_State* L, DeepPrelude* prelude_);
62 62
63extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); 63extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_);
64extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); 64extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index);
65 65
66#endif // __LANES_DEEP_H__ 66#endif // __LANES_DEEP_H__
diff --git a/src/keeper.c b/src/keeper.c
index 05e9a02..c777866 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -47,6 +47,7 @@
47#include "keeper.h" 47#include "keeper.h"
48#include "compat.h" 48#include "compat.h"
49#include "tools.h" 49#include "tools.h"
50#include "state.h"
50#include "universe.h" 51#include "universe.h"
51#include "uniquekey.h" 52#include "uniquekey.h"
52 53
diff --git a/src/lanes.c b/src/lanes.c
index f3fdc76..e697bf5 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -89,6 +89,7 @@ THE SOFTWARE.
89#include "threading.h" 89#include "threading.h"
90#include "compat.h" 90#include "compat.h"
91#include "tools.h" 91#include "tools.h"
92#include "state.h"
92#include "universe.h" 93#include "universe.h"
93#include "keeper.h" 94#include "keeper.h"
94#include "lanes_private.h" 95#include "lanes_private.h"
@@ -1930,7 +1931,7 @@ LUAG_FUNC( configure)
1930 1931
1931 { 1932 {
1932 char const* errmsg; 1933 char const* errmsg;
1933 errmsg = push_deep_proxy( U, L, (DeepPrelude*) U->timer_deep, eLM_LaneBody); // settings M timer_deep 1934 errmsg = push_deep_proxy( U, L, (DeepPrelude*) U->timer_deep, 0, eLM_LaneBody); // settings M timer_deep
1934 if( errmsg != NULL) 1935 if( errmsg != NULL)
1935 { 1936 {
1936 return luaL_error( L, errmsg); 1937 return luaL_error( L, errmsg);
diff --git a/src/linda.c b/src/linda.c
index 150649d..d3ed8a0 100644
--- a/src/linda.c
+++ b/src/linda.c
@@ -933,5 +933,5 @@ LUAG_FUNC( linda)
933 luaL_checktype( L, 1, LUA_TSTRING); 933 luaL_checktype( L, 1, LUA_TSTRING);
934 luaL_checktype( L, 2, LUA_TNUMBER); 934 luaL_checktype( L, 2, LUA_TNUMBER);
935 } 935 }
936 return luaG_newdeepuserdata( L, linda_id); 936 return luaG_newdeepuserdata( L, linda_id, 0);
937} 937}
diff --git a/src/state.c b/src/state.c
new file mode 100644
index 0000000..cbbc0d8
--- /dev/null
+++ b/src/state.c
@@ -0,0 +1,439 @@
1/*
2* STATE.C
3*
4* Lua tools to support Lanes.
5*/
6
7/*
8===============================================================================
9
10Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com>
112011-21 benoit Germain <bnt.germain@gmail.com>
12
13Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal
15in the Software without restriction, including without limitation the rights
16to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the Software is
18furnished to do so, subject to the following conditions:
19
20The above copyright notice and this permission notice shall be included in
21all copies or substantial portions of the Software.
22
23THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29THE SOFTWARE.
30
31===============================================================================
32*/
33
34#include <stdio.h>
35#include <assert.h>
36#include <string.h>
37#include <ctype.h>
38#include <stdlib.h>
39#if !defined(__APPLE__)
40#include <malloc.h>
41#endif // __APPLE__
42
43#include "compat.h"
44#include "universe.h"
45#include "tools.h"
46#include "lanes.h"
47
48// ################################################################################################
49
50/*---=== Serialize require ===---
51*/
52
53//---
54// [val]= new_require( ... )
55//
56// Call 'old_require' but only one lane at a time.
57//
58// Upvalues: [1]: original 'require' function
59//
60static int luaG_new_require( lua_State* L)
61{
62 int rc, i;
63 int args = lua_gettop( L);
64 Universe* U = universe_get( L);
65 //char const* modname = luaL_checkstring( L, 1);
66
67 STACK_GROW( L, args + 1);
68 STACK_CHECK( L, 0);
69
70 lua_pushvalue( L, lua_upvalueindex( 1));
71 for( i = 1; i <= args; ++ i)
72 {
73 lua_pushvalue( L, i);
74 }
75
76 // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would
77 // leave us locked, blocking any future 'require' calls from other lanes.
78 //
79 MUTEX_LOCK( &U->require_cs);
80 rc = lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ );
81 MUTEX_UNLOCK( &U->require_cs);
82
83 // the required module (or an error message) is left on the stack as returned value by original require function
84 STACK_END( L, 1);
85
86 if( rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ?
87 {
88 return lua_error( L); // error message already at [-1]
89 }
90
91 return 1;
92}
93
94/*
95* Serialize calls to 'require', if it exists
96*/
97void serialize_require( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L)
98{
99 STACK_GROW( L, 1);
100 STACK_CHECK( L, 0);
101 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "serializing require()\n" INDENT_END));
102
103 // Check 'require' is there and not already wrapped; if not, do nothing
104 //
105 lua_getglobal( L, "require");
106 if( lua_isfunction( L, -1) && lua_tocfunction( L, -1) != luaG_new_require)
107 {
108 // [-1]: original 'require' function
109 lua_pushcclosure( L, luaG_new_require, 1 /*upvalues*/);
110 lua_setglobal( L, "require");
111 }
112 else
113 {
114 // [-1]: nil
115 lua_pop( L, 1);
116 }
117
118 STACK_END( L, 0);
119}
120
121// ################################################################################################
122
123/*---=== luaG_newstate ===---*/
124
125static int require_lanes_core( lua_State* L)
126{
127 // leaves a copy of 'lanes.core' module table on the stack
128 luaL_requiref( L, "lanes.core", luaopen_lanes_core, 0);
129 return 1;
130}
131
132
133static const luaL_Reg libs[] =
134{
135 { LUA_LOADLIBNAME, luaopen_package},
136{ LUA_TABLIBNAME, luaopen_table},
137{ LUA_STRLIBNAME, luaopen_string},
138{ LUA_MATHLIBNAME, luaopen_math},
139#ifndef PLATFORM_XBOX // no os/io libs on xbox
140{ LUA_OSLIBNAME, luaopen_os},
141{ LUA_IOLIBNAME, luaopen_io},
142#endif // PLATFORM_XBOX
143#if LUA_VERSION_NUM >= 503
144{ LUA_UTF8LIBNAME, luaopen_utf8},
145#endif
146#if LUA_VERSION_NUM >= 502
147#ifdef luaopen_bit32
148{ LUA_BITLIBNAME, luaopen_bit32},
149#endif
150{ LUA_COLIBNAME, luaopen_coroutine}, // Lua 5.2: coroutine is no longer a part of base!
151#else // LUA_VERSION_NUM
152{ LUA_COLIBNAME, NULL}, // Lua 5.1: part of base package
153#endif // LUA_VERSION_NUM
154{ LUA_DBLIBNAME, luaopen_debug},
155#if defined LUA_JITLIBNAME // building against LuaJIT headers, add some LuaJIT-specific libs
156//#pragma message( "supporting JIT base libs")
157{ LUA_BITLIBNAME, luaopen_bit},
158{ LUA_JITLIBNAME, luaopen_jit},
159{ LUA_FFILIBNAME, luaopen_ffi},
160#endif // LUA_JITLIBNAME
161
162{ LUA_DBLIBNAME, luaopen_debug},
163{ "lanes.core", require_lanes_core}, // So that we can open it like any base library (possible since we have access to the init function)
164 //
165{ "base", NULL}, // ignore "base" (already acquired it)
166{ NULL, NULL }
167};
168
169static void open1lib( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L, char const* name_, size_t len_)
170{
171 int i;
172 for( i = 0; libs[i].name; ++ i)
173 {
174 if( strncmp( name_, libs[i].name, len_) == 0)
175 {
176 lua_CFunction libfunc = libs[i].func;
177 name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_
178 if( libfunc != NULL)
179 {
180 bool_t const isLanesCore = (libfunc == require_lanes_core) ? TRUE : FALSE; // don't want to create a global for "lanes.core"
181 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, (int) len_, name_));
182 STACK_CHECK( L, 0);
183 // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack)
184 luaL_requiref( L, name_, libfunc, !isLanesCore);
185 // lanes.core doesn't declare a global, so scan it here and now
186 if( isLanesCore == TRUE)
187 {
188 populate_func_lookup_table( L, -1, name_);
189 }
190 lua_pop( L, 1);
191 STACK_END( L, 0);
192 }
193 break;
194 }
195 }
196}
197
198
199// just like lua_xmove, args are (from, to)
200static void copy_one_time_settings( Universe* U, lua_State* L, lua_State* L2)
201{
202 STACK_GROW( L, 2);
203 STACK_CHECK( L, 0);
204 STACK_CHECK( L2, 0);
205
206 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "copy_one_time_settings()\n" INDENT_END));
207 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
208
209 REGISTRY_GET( L, CONFIG_REGKEY); // config
210 // copy settings from from source to destination registry
211 if( luaG_inter_move( U, L, L2, 1, eLM_LaneBody) < 0) // // config
212 {
213 (void) luaL_error( L, "failed to copy settings when loading lanes.core");
214 }
215 // set L2:_R[CONFIG_REGKEY] = settings
216 REGISTRY_SET( L2, CONFIG_REGKEY, lua_insert( L2, -2)); //
217 STACK_END( L2, 0);
218 STACK_END( L, 0);
219 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
220}
221
222void initialize_on_state_create( Universe* U, lua_State* L)
223{
224 STACK_CHECK( L, 0);
225 lua_getfield( L, -1, "on_state_create"); // settings on_state_create|nil
226 if( !lua_isnil( L, -1))
227 {
228 // store C function pointer in an internal variable
229 U->on_state_create_func = lua_tocfunction( L, -1); // settings on_state_create
230 if( U->on_state_create_func != NULL)
231 {
232 // make sure the function doesn't have upvalues
233 char const* upname = lua_getupvalue( L, -1, 1); // settings on_state_create upval?
234 if( upname != NULL) // should be "" for C functions with upvalues if any
235 {
236 (void) luaL_error( L, "on_state_create shouldn't have upvalues");
237 }
238 // remove this C function from the config table so that it doesn't cause problems
239 // when we transfer the config table in newly created Lua states
240 lua_pushnil( L); // settings on_state_create nil
241 lua_setfield( L, -3, "on_state_create"); // settings on_state_create
242 }
243 else
244 {
245 // optim: store marker saying we have such a function in the config table
246 U->on_state_create_func = (lua_CFunction) initialize_on_state_create;
247 }
248 }
249 lua_pop( L, 1); // settings
250 STACK_END( L, 0);
251}
252
253lua_State* create_state( Universe* U, lua_State* from_)
254{
255 lua_State* L;
256 if( U->provide_allocator != NULL)
257 {
258 lua_pushcclosure( from_, U->provide_allocator, 0);
259 lua_call( from_, 0, 1);
260 {
261 AllocatorDefinition* def = lua_touserdata( from_, -1);
262 L = lua_newstate( def->allocF, def->allocUD);
263 }
264 lua_pop( from_, 1);
265 }
266 else
267 {
268 L = luaL_newstate();
269 }
270
271 if( L == NULL)
272 {
273 (void) luaL_error( from_, "luaG_newstate() failed while creating state; out of memory");
274 }
275 return L;
276}
277
278void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMode mode_)
279{
280 if( U->on_state_create_func != NULL)
281 {
282 STACK_CHECK( L, 0);
283 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END));
284 if( U->on_state_create_func != (lua_CFunction) initialize_on_state_create)
285 {
286 // C function: recreate a closure in the new state, bypassing the lookup scheme
287 lua_pushcfunction( L, U->on_state_create_func); // on_state_create()
288 }
289 else // Lua function located in the config table, copied when we opened "lanes.core"
290 {
291 if( mode_ != eLM_LaneBody)
292 {
293 // if attempting to call in a keeper state, do nothing because the function doesn't exist there
294 // this doesn't count as an error though
295 return;
296 }
297 REGISTRY_GET( L, CONFIG_REGKEY); // {}
298 STACK_MID( L, 1);
299 lua_getfield( L, -1, "on_state_create"); // {} on_state_create()
300 lua_remove( L, -2); // on_state_create()
301 }
302 STACK_MID( L, 1);
303 // capture error and raise it in caller state
304 if( lua_pcall( L, 0, 0, 0) != LUA_OK)
305 {
306 luaL_error( from_, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1)));
307 }
308 STACK_END( L, 0);
309 }
310}
311
312/*
313* Like 'luaL_openlibs()' but allows the set of libraries be selected
314*
315* NULL no libraries, not even base
316* "" base library only
317* "io,string" named libraries
318* "*" all libraries
319*
320* Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL.
321*
322* *NOT* called for keeper states!
323*
324*/
325lua_State* luaG_newstate( Universe* U, lua_State* from_, char const* libs_)
326{
327 lua_State* L = create_state( U, from_);
328
329 STACK_GROW( L, 2);
330 STACK_CHECK_ABS( L, 0);
331
332 // copy the universe as a light userdata (only the master state holds the full userdata)
333 // that way, if Lanes is required in this new state, we'll know we are part of this universe
334 universe_store( L, U);
335 STACK_MID( L, 0);
336
337 // we'll need this every time we transfer some C function from/to this state
338 REGISTRY_SET( L, LOOKUP_REGKEY, lua_newtable( L));
339 STACK_MID( L, 0);
340
341 // neither libs (not even 'base') nor special init func: we are done
342 if( libs_ == NULL && U->on_state_create_func == NULL)
343 {
344 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END));
345 return L;
346 }
347
348 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END));
349 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
350
351 // copy settings (for example because it may contain a Lua on_state_create function)
352 copy_one_time_settings( U, from_, L);
353
354 // 'lua.c' stops GC during initialization so perhaps its a good idea. :)
355 lua_gc( L, LUA_GCSTOP, 0);
356
357
358 // Anything causes 'base' to be taken in
359 //
360 if( libs_ != NULL)
361 {
362 // special "*" case (mainly to help with LuaJIT compatibility)
363 // as we are called from luaopen_lanes_core() already, and that would deadlock
364 if( libs_[0] == '*' && libs_[1] == 0)
365 {
366 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END));
367 luaL_openlibs( L);
368 // don't forget lanes.core for regular lane states
369 open1lib( DEBUGSPEW_PARAM_COMMA( U) L, "lanes.core", 10);
370 libs_ = NULL; // done with libs
371 }
372 else
373 {
374 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening base library\n" INDENT_END));
375#if LUA_VERSION_NUM >= 502
376 // open base library the same way as in luaL_openlibs()
377 luaL_requiref( L, "_G", luaopen_base, 1);
378 lua_pop( L, 1);
379#else // LUA_VERSION_NUM
380 lua_pushcfunction( L, luaopen_base);
381 lua_pushstring( L, "");
382 lua_call( L, 1, 0);
383#endif // LUA_VERSION_NUM
384 }
385 }
386 STACK_END( L, 0);
387
388 // scan all libraries, open them one by one
389 if( libs_)
390 {
391 char const* p;
392 unsigned int len = 0;
393 for( p = libs_; *p; p += len)
394 {
395 // skip delimiters ('.' can be part of name for "lanes.core")
396 while( *p && !isalnum( *p) && *p != '.')
397 ++ p;
398 // skip name
399 len = 0;
400 while( isalnum( p[len]) || p[len] == '.')
401 ++ len;
402 // open library
403 open1lib( DEBUGSPEW_PARAM_COMMA( U) L, p, len);
404 }
405 }
406 lua_gc( L, LUA_GCRESTART, 0);
407
408 serialize_require( DEBUGSPEW_PARAM_COMMA( U) L);
409
410 // call this after the base libraries are loaded and GC is restarted
411 // will raise an error in from_ in case of problem
412 call_on_state_create( U, L, from_, eLM_LaneBody);
413
414 STACK_CHECK( L, 0);
415 // after all this, register everything we find in our name<->function database
416 lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
417 populate_func_lookup_table( L, -1, NULL);
418
419#if 0 && USE_DEBUG_SPEW
420 // dump the lookup database contents
421 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {}
422 lua_pushnil( L); // {} nil
423 while( lua_next( L, -2)) // {} k v
424 {
425 lua_getglobal( L, "print"); // {} k v print
426 lua_pushlstring( L, debugspew_indent, U->debugspew_indent_depth); // {} k v print " "
427 lua_pushvalue( L, -4); // {} k v print " " k
428 lua_pushvalue( L, -4); // {} k v print " " k v
429 lua_call( L, 3, 0); // {} k v
430 lua_pop( L, 1); // {} k
431 }
432 lua_pop( L, 1); // {}
433#endif // USE_DEBUG_SPEW
434
435 lua_pop( L, 1);
436 STACK_END( L, 0);
437 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
438 return L;
439}
diff --git a/src/state.h b/src/state.h
new file mode 100644
index 0000000..e844405
--- /dev/null
+++ b/src/state.h
@@ -0,0 +1,22 @@
1#ifndef __LANES_STATE_H__
2#define __LANES_STATE_H__
3
4//#include "lauxlib.h"
5#include "threading.h"
6#include "deep.h"
7
8#include "macros_and_utils.h"
9
10void serialize_require( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State *L);
11
12// ################################################################################################
13
14lua_State* create_state( Universe* U, lua_State* from_);
15lua_State* luaG_newstate( Universe* U, lua_State* _from, char const* libs);
16
17// ################################################################################################
18
19void initialize_on_state_create( Universe* U, lua_State* L);
20void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMode mode_);
21
22#endif // __LANES_STATE_H__
diff --git a/src/tools.c b/src/tools.c
index f3ac236..a0ba20e 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * TOOLS.C Copyright (c) 2002-10, Asko Kauppi 2 * TOOLS.C Copyright (c) 2002-10, Asko Kauppi
3 * 3 *
4 * Lua tools to support Lanes. 4 * Lua tools to support Lanes.
5*/ 5*/
@@ -178,139 +178,6 @@ void cleanup_allocator_function( Universe* U, lua_State* L)
178 178
179// ################################################################################################ 179// ################################################################################################
180 180
181void initialize_on_state_create( Universe* U, lua_State* L)
182{
183 STACK_CHECK( L, 0);
184 lua_getfield( L, -1, "on_state_create"); // settings on_state_create|nil
185 if( !lua_isnil( L, -1))
186 {
187 // store C function pointer in an internal variable
188 U->on_state_create_func = lua_tocfunction( L, -1); // settings on_state_create
189 if( U->on_state_create_func != NULL)
190 {
191 // make sure the function doesn't have upvalues
192 char const* upname = lua_getupvalue( L, -1, 1); // settings on_state_create upval?
193 if( upname != NULL) // should be "" for C functions with upvalues if any
194 {
195 (void) luaL_error( L, "on_state_create shouldn't have upvalues");
196 }
197 // remove this C function from the config table so that it doesn't cause problems
198 // when we transfer the config table in newly created Lua states
199 lua_pushnil( L); // settings on_state_create nil
200 lua_setfield( L, -3, "on_state_create"); // settings on_state_create
201 }
202 else
203 {
204 // optim: store marker saying we have such a function in the config table
205 U->on_state_create_func = (lua_CFunction) initialize_on_state_create;
206 }
207 }
208 lua_pop( L, 1); // settings
209 STACK_END( L, 0);
210}
211
212// ################################################################################################
213
214// just like lua_xmove, args are (from, to)
215static void copy_one_time_settings( Universe* U, lua_State* L, lua_State* L2)
216{
217 STACK_GROW( L, 2);
218 STACK_CHECK( L, 0);
219 STACK_CHECK( L2, 0);
220
221 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "copy_one_time_settings()\n" INDENT_END));
222 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
223
224 REGISTRY_GET( L, CONFIG_REGKEY); // config
225 // copy settings from from source to destination registry
226 if( luaG_inter_move( U, L, L2, 1, eLM_LaneBody) < 0) // // config
227 {
228 (void) luaL_error( L, "failed to copy settings when loading lanes.core");
229 }
230 // set L2:_R[CONFIG_REGKEY] = settings
231 REGISTRY_SET( L2, CONFIG_REGKEY, lua_insert( L2, -2)); //
232 STACK_END( L2, 0);
233 STACK_END( L, 0);
234 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
235}
236
237
238/*---=== luaG_newstate ===---*/
239
240static int require_lanes_core( lua_State* L)
241{
242 // leaves a copy of 'lanes.core' module table on the stack
243 luaL_requiref( L, "lanes.core", luaopen_lanes_core, 0);
244 return 1;
245}
246
247
248static const luaL_Reg libs[] =
249{
250 { LUA_LOADLIBNAME, luaopen_package},
251 { LUA_TABLIBNAME, luaopen_table},
252 { LUA_STRLIBNAME, luaopen_string},
253 { LUA_MATHLIBNAME, luaopen_math},
254#ifndef PLATFORM_XBOX // no os/io libs on xbox
255 { LUA_OSLIBNAME, luaopen_os},
256 { LUA_IOLIBNAME, luaopen_io},
257#endif // PLATFORM_XBOX
258#if LUA_VERSION_NUM >= 503
259 { LUA_UTF8LIBNAME, luaopen_utf8},
260#endif
261#if LUA_VERSION_NUM >= 502
262#ifdef luaopen_bit32
263 { LUA_BITLIBNAME, luaopen_bit32},
264#endif
265 { LUA_COLIBNAME, luaopen_coroutine}, // Lua 5.2: coroutine is no longer a part of base!
266#else // LUA_VERSION_NUM
267 { LUA_COLIBNAME, NULL}, // Lua 5.1: part of base package
268#endif // LUA_VERSION_NUM
269 { LUA_DBLIBNAME, luaopen_debug},
270#if defined LUA_JITLIBNAME // building against LuaJIT headers, add some LuaJIT-specific libs
271//#pragma message( "supporting JIT base libs")
272 { LUA_BITLIBNAME, luaopen_bit},
273 { LUA_JITLIBNAME, luaopen_jit},
274 { LUA_FFILIBNAME, luaopen_ffi},
275#endif // LUA_JITLIBNAME
276
277 { LUA_DBLIBNAME, luaopen_debug},
278 { "lanes.core", require_lanes_core}, // So that we can open it like any base library (possible since we have access to the init function)
279 //
280 { "base", NULL}, // ignore "base" (already acquired it)
281 { NULL, NULL }
282};
283
284static void open1lib( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L, char const* name_, size_t len_)
285{
286 int i;
287 for( i = 0; libs[i].name; ++ i)
288 {
289 if( strncmp( name_, libs[i].name, len_) == 0)
290 {
291 lua_CFunction libfunc = libs[i].func;
292 name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_
293 if( libfunc != NULL)
294 {
295 bool_t const isLanesCore = (libfunc == require_lanes_core) ? TRUE : FALSE; // don't want to create a global for "lanes.core"
296 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, (int) len_, name_));
297 STACK_CHECK( L, 0);
298 // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack)
299 luaL_requiref( L, name_, libfunc, !isLanesCore);
300 // lanes.core doesn't declare a global, so scan it here and now
301 if( isLanesCore == TRUE)
302 {
303 populate_func_lookup_table( L, -1, name_);
304 }
305 lua_pop( L, 1);
306 STACK_END( L, 0);
307 }
308 break;
309 }
310 }
311}
312
313
314static int dummy_writer( lua_State* L, void const* p, size_t sz, void* ud) 181static int dummy_writer( lua_State* L, void const* p, size_t sz, void* ud)
315{ 182{
316 (void)L; (void)p; (void)sz; (void) ud; // unused 183 (void)L; (void)p; (void)sz; (void) ud; // unused
@@ -668,197 +535,6 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_)
668 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 535 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
669} 536}
670 537
671void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMode mode_)
672{
673 if( U->on_state_create_func != NULL)
674 {
675 STACK_CHECK( L, 0);
676 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END));
677 if( U->on_state_create_func != (lua_CFunction) initialize_on_state_create)
678 {
679 // C function: recreate a closure in the new state, bypassing the lookup scheme
680 lua_pushcfunction( L, U->on_state_create_func); // on_state_create()
681 }
682 else // Lua function located in the config table, copied when we opened "lanes.core"
683 {
684 if( mode_ != eLM_LaneBody)
685 {
686 // if attempting to call in a keeper state, do nothing because the function doesn't exist there
687 // this doesn't count as an error though
688 return;
689 }
690 REGISTRY_GET( L, CONFIG_REGKEY); // {}
691 STACK_MID( L, 1);
692 lua_getfield( L, -1, "on_state_create"); // {} on_state_create()
693 lua_remove( L, -2); // on_state_create()
694 }
695 STACK_MID( L, 1);
696 // capture error and raise it in caller state
697 if( lua_pcall( L, 0, 0, 0) != LUA_OK)
698 {
699 luaL_error( from_, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1)));
700 }
701 STACK_END( L, 0);
702 }
703}
704
705lua_State* create_state( Universe* U, lua_State* from_)
706{
707 lua_State* L;
708 if( U->provide_allocator != NULL)
709 {
710 lua_pushcclosure( from_, U->provide_allocator, 0);
711 lua_call( from_, 0, 1);
712 {
713 AllocatorDefinition* def = lua_touserdata( from_, -1);
714 L = lua_newstate( def->allocF, def->allocUD);
715 }
716 lua_pop( from_, 1);
717 }
718 else
719 {
720 L = luaL_newstate();
721 }
722
723 if( L == NULL)
724 {
725 (void) luaL_error( from_, "luaG_newstate() failed while creating state; out of memory");
726 }
727 return L;
728}
729
730/*
731 * Like 'luaL_openlibs()' but allows the set of libraries be selected
732 *
733 * NULL no libraries, not even base
734 * "" base library only
735 * "io,string" named libraries
736 * "*" all libraries
737 *
738 * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL.
739 *
740 * *NOT* called for keeper states!
741 *
742 */
743lua_State* luaG_newstate( Universe* U, lua_State* from_, char const* libs_)
744{
745 lua_State* L = create_state( U, from_);
746
747 STACK_GROW( L, 2);
748 STACK_CHECK_ABS( L, 0);
749
750 // copy the universe as a light userdata (only the master state holds the full userdata)
751 // that way, if Lanes is required in this new state, we'll know we are part of this universe
752 universe_store( L, U);
753 STACK_MID( L, 0);
754
755 // we'll need this every time we transfer some C function from/to this state
756 REGISTRY_SET( L, LOOKUP_REGKEY, lua_newtable( L));
757 STACK_MID( L, 0);
758
759 // neither libs (not even 'base') nor special init func: we are done
760 if( libs_ == NULL && U->on_state_create_func == NULL)
761 {
762 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END));
763 return L;
764 }
765
766 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END));
767 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
768
769 // copy settings (for example because it may contain a Lua on_state_create function)
770 copy_one_time_settings( U, from_, L);
771
772 // 'lua.c' stops GC during initialization so perhaps its a good idea. :)
773 lua_gc( L, LUA_GCSTOP, 0);
774
775
776 // Anything causes 'base' to be taken in
777 //
778 if( libs_ != NULL)
779 {
780 // special "*" case (mainly to help with LuaJIT compatibility)
781 // as we are called from luaopen_lanes_core() already, and that would deadlock
782 if( libs_[0] == '*' && libs_[1] == 0)
783 {
784 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END));
785 luaL_openlibs( L);
786 // don't forget lanes.core for regular lane states
787 open1lib( DEBUGSPEW_PARAM_COMMA( U) L, "lanes.core", 10);
788 libs_ = NULL; // done with libs
789 }
790 else
791 {
792 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening base library\n" INDENT_END));
793#if LUA_VERSION_NUM >= 502
794 // open base library the same way as in luaL_openlibs()
795 luaL_requiref( L, "_G", luaopen_base, 1);
796 lua_pop( L, 1);
797#else // LUA_VERSION_NUM
798 lua_pushcfunction( L, luaopen_base);
799 lua_pushstring( L, "");
800 lua_call( L, 1, 0);
801#endif // LUA_VERSION_NUM
802 }
803 }
804 STACK_END( L, 0);
805
806 // scan all libraries, open them one by one
807 if( libs_)
808 {
809 char const* p;
810 unsigned int len = 0;
811 for( p = libs_; *p; p += len)
812 {
813 // skip delimiters ('.' can be part of name for "lanes.core")
814 while( *p && !isalnum( *p) && *p != '.')
815 ++ p;
816 // skip name
817 len = 0;
818 while( isalnum( p[len]) || p[len] == '.')
819 ++ len;
820 // open library
821 open1lib( DEBUGSPEW_PARAM_COMMA( U) L, p, len);
822 }
823 }
824 lua_gc( L, LUA_GCRESTART, 0);
825
826 serialize_require( DEBUGSPEW_PARAM_COMMA( U) L);
827
828 // call this after the base libraries are loaded and GC is restarted
829 // will raise an error in from_ in case of problem
830 call_on_state_create( U, L, from_, eLM_LaneBody);
831
832 STACK_CHECK( L, 0);
833 // after all this, register everything we find in our name<->function database
834 lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
835 populate_func_lookup_table( L, -1, NULL);
836
837#if 0 && USE_DEBUG_SPEW
838 // dump the lookup database contents
839 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {}
840 lua_pushnil( L); // {} nil
841 while( lua_next( L, -2)) // {} k v
842 {
843 lua_getglobal( L, "print"); // {} k v print
844 lua_pushlstring( L, debugspew_indent, U->debugspew_indent_depth); // {} k v print " "
845 lua_pushvalue( L, -4); // {} k v print " " k
846 lua_pushvalue( L, -4); // {} k v print " " k v
847 lua_call( L, 3, 0); // {} k v
848 lua_pop( L, 1); // {} k
849 }
850 lua_pop( L, 1); // {}
851#endif // USE_DEBUG_SPEW
852
853 lua_pop( L, 1);
854 STACK_END( L, 0);
855 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
856 return L;
857}
858
859
860
861
862/*---=== Inter-state copying ===---*/ 538/*---=== Inter-state copying ===---*/
863 539
864// crc64/we of string "REG_MTID" generated at http://www.nitrxgen.net/hashgen/ 540// crc64/we of string "REG_MTID" generated at http://www.nitrxgen.net/hashgen/
@@ -2265,75 +1941,3 @@ int luaG_inter_copy_package( Universe* U, lua_State* L, lua_State* L2, int packa
2265 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1941 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2266 return 0; 1942 return 0;
2267} 1943}
2268
2269
2270/*---=== Serialize require ===---
2271*/
2272
2273//---
2274// [val]= new_require( ... )
2275//
2276// Call 'old_require' but only one lane at a time.
2277//
2278// Upvalues: [1]: original 'require' function
2279//
2280int luaG_new_require( lua_State* L)
2281{
2282 int rc, i;
2283 int args = lua_gettop( L);
2284 Universe* U = universe_get( L);
2285 //char const* modname = luaL_checkstring( L, 1);
2286
2287 STACK_GROW( L, args + 1);
2288 STACK_CHECK( L, 0);
2289
2290 lua_pushvalue( L, lua_upvalueindex( 1));
2291 for( i = 1; i <= args; ++ i)
2292 {
2293 lua_pushvalue( L, i);
2294 }
2295
2296 // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would
2297 // leave us locked, blocking any future 'require' calls from other lanes.
2298 //
2299 MUTEX_LOCK( &U->require_cs);
2300 rc = lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ );
2301 MUTEX_UNLOCK( &U->require_cs);
2302
2303 // the required module (or an error message) is left on the stack as returned value by original require function
2304 STACK_END( L, 1);
2305
2306 if( rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ?
2307 {
2308 return lua_error( L); // error message already at [-1]
2309 }
2310
2311 return 1;
2312}
2313
2314/*
2315* Serialize calls to 'require', if it exists
2316*/
2317void serialize_require( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L)
2318{
2319 STACK_GROW( L, 1);
2320 STACK_CHECK( L, 0);
2321 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "serializing require()\n" INDENT_END));
2322
2323 // Check 'require' is there and not already wrapped; if not, do nothing
2324 //
2325 lua_getglobal( L, "require");
2326 if( lua_isfunction( L, -1) && lua_tocfunction( L, -1) != luaG_new_require)
2327 {
2328 // [-1]: original 'require' function
2329 lua_pushcclosure( L, luaG_new_require, 1 /*upvalues*/);
2330 lua_setglobal( L, "require");
2331 }
2332 else
2333 {
2334 // [-1]: nil
2335 lua_pop( L, 1);
2336 }
2337
2338 STACK_END( L, 0);
2339}
diff --git a/src/tools.h b/src/tools.h
index 8a8ad7b..0df88e9 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -20,9 +20,6 @@ typedef struct s_Universe Universe;
20void luaG_dump( lua_State* L); 20void luaG_dump( lua_State* L);
21#endif // _DEBUG 21#endif // _DEBUG
22 22
23lua_State* create_state( Universe* U, lua_State* from_);
24lua_State* luaG_newstate( Universe* U, lua_State* _from, char const* libs);
25
26// ################################################################################################ 23// ################################################################################################
27 24
28int luaG_inter_copy_package( Universe* U, lua_State* L, lua_State* L2, int package_idx_, LookupMode mode_); 25int luaG_inter_copy_package( Universe* U, lua_State* L, lua_State* L2, int package_idx_, LookupMode mode_);
@@ -31,16 +28,11 @@ int luaG_inter_copy( Universe* U, lua_State* L, lua_State* L2, uint_t n, LookupM
31int luaG_inter_move( Universe* U, lua_State* L, lua_State* L2, uint_t n, LookupMode mode_); 28int luaG_inter_move( Universe* U, lua_State* L, lua_State* L2, uint_t n, LookupMode mode_);
32 29
33int luaG_nameof( lua_State* L); 30int luaG_nameof( lua_State* L);
34int luaG_new_require( lua_State* L);
35 31
36void populate_func_lookup_table( lua_State* L, int _i, char const* _name); 32void populate_func_lookup_table( lua_State* L, int _i, char const* _name);
37void serialize_require( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State *L);
38void initialize_allocator_function( Universe* U, lua_State* L); 33void initialize_allocator_function( Universe* U, lua_State* L);
39void cleanup_allocator_function( Universe* U, lua_State* L); 34void cleanup_allocator_function( Universe* U, lua_State* L);
40 35
41void initialize_on_state_create( Universe* U, lua_State* L);
42void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMode mode_);
43
44// ################################################################################################ 36// ################################################################################################
45 37
46// crc64/we of string "CONFIG_REGKEY" generated at http://www.nitrxgen.net/hashgen/ 38// crc64/we of string "CONFIG_REGKEY" generated at http://www.nitrxgen.net/hashgen/