diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2021-06-24 17:47:20 +0200 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2021-06-24 17:47:20 +0200 |
commit | 050e14dd7fa04e2262ae6b1cc984d76c4149b664 (patch) | |
tree | 8b7cead727e2b9e545dbbd458ef4009eb099db92 | |
parent | 4e8242de0c5d8c853201ec49dacf5aa9a5b0f7d3 (diff) | |
download | lanes-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.c | 5 | ||||
-rw-r--r-- | deep_test/deep_test.vcxproj | 3 | ||||
-rw-r--r-- | deep_test/deep_test.vcxproj.filters | 6 | ||||
-rw-r--r-- | deep_test/deep_test.vcxproj.user | 2 | ||||
-rw-r--r-- | deep_test/deeptest.lua | 10 | ||||
-rw-r--r-- | docs/index.html | 2 | ||||
-rw-r--r-- | lanes-3.15.0-0.rockspec | 66 | ||||
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/deep.c | 43 | ||||
-rw-r--r-- | src/deep.h | 8 | ||||
-rw-r--r-- | src/keeper.c | 1 | ||||
-rw-r--r-- | src/lanes.c | 3 | ||||
-rw-r--r-- | src/linda.c | 2 | ||||
-rw-r--r-- | src/state.c | 439 | ||||
-rw-r--r-- | src/state.h | 22 | ||||
-rw-r--r-- | src/tools.c | 398 | ||||
-rw-r--r-- | src/tools.h | 8 |
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 | ||
127 | int luaD_new_deep( lua_State* L) | 127 | int 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 | |||
23 | local performTest = function( obj_) | 23 | local 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)) |
51 | end | 59 | end |
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 | |||
8 | package = "Lanes" | ||
9 | |||
10 | version = "3.13.0-0" | ||
11 | |||
12 | source= { | ||
13 | url= "git://github.com/LuaLanes/lanes.git", | ||
14 | branch= "v3.13.0" | ||
15 | } | ||
16 | |||
17 | description = { | ||
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 | -- | ||
31 | supported_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 | |||
38 | dependencies= { | ||
39 | "lua >= 5.1", -- builds with either 5.1, 5.2, 5.3 and 5.4 | ||
40 | } | ||
41 | |||
42 | build = { | ||
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 | ||
8 | MODULE=lanes | 8 | MODULE=lanes |
9 | 9 | ||
10 | SRC=lanes.c cancel.c compat.c threading.c tools.c linda.c deep.c keeper.c universe.c | 10 | SRC=lanes.c cancel.c compat.c threading.c tools.c state.c linda.c deep.c keeper.c universe.c |
11 | 11 | ||
12 | OBJ=$(SRC:.c=.o) | 12 | OBJ=$(SRC:.c=.o) |
13 | 13 | ||
@@ -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 | */ |
259 | char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, LookupMode mode_) | 259 | char 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 | */ |
433 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) | 434 | int 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) |
@@ -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 |
47 | static DECLARE_CONST_UNIQUE_KEY( DEEP_VERSION, 0x4f4eadf0accf6c73); | 47 | static 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 |
50 | struct s_DeepPrelude | 50 | struct s_DeepPrelude |
@@ -57,10 +57,10 @@ struct s_DeepPrelude | |||
57 | }; | 57 | }; |
58 | typedef struct s_DeepPrelude DeepPrelude; | 58 | typedef struct s_DeepPrelude DeepPrelude; |
59 | 59 | ||
60 | char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, LookupMode mode_); | 60 | char const* push_deep_proxy( Universe* U, lua_State* L, DeepPrelude* prelude, int nuv_, LookupMode mode_); |
61 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); | 61 | void free_deep_prelude( lua_State* L, DeepPrelude* prelude_); |
62 | 62 | ||
63 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); | 63 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc, int nuv_); |
64 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); | 64 | extern 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 | |||
10 | Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com> | ||
11 | 2011-21 benoit Germain <bnt.germain@gmail.com> | ||
12 | |||
13 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
14 | of this software and associated documentation files (the "Software"), to deal | ||
15 | in the Software without restriction, including without limitation the rights | ||
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
17 | copies of the Software, and to permit persons to whom the Software is | ||
18 | furnished to do so, subject to the following conditions: | ||
19 | |||
20 | The above copyright notice and this permission notice shall be included in | ||
21 | all copies or substantial portions of the Software. | ||
22 | |||
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
29 | THE 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 | // | ||
60 | static 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 | */ | ||
97 | void 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 | |||
125 | static 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 | |||
133 | static 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 | |||
169 | static 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) | ||
200 | static 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 | |||
222 | void 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 | |||
253 | lua_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 | |||
278 | void 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 | */ | ||
325 | lua_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 | |||
10 | void serialize_require( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State *L); | ||
11 | |||
12 | // ################################################################################################ | ||
13 | |||
14 | lua_State* create_state( Universe* U, lua_State* from_); | ||
15 | lua_State* luaG_newstate( Universe* U, lua_State* _from, char const* libs); | ||
16 | |||
17 | // ################################################################################################ | ||
18 | |||
19 | void initialize_on_state_create( Universe* U, lua_State* L); | ||
20 | void 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 | ||
181 | void 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) | ||
215 | static 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 | |||
240 | static 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 | |||
248 | static 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 | |||
284 | static 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 | |||
314 | static int dummy_writer( lua_State* L, void const* p, size_t sz, void* ud) | 181 | static 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 | ||
671 | void 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 | |||
705 | lua_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 | */ | ||
743 | lua_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 | // | ||
2280 | int 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 | */ | ||
2317 | void 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; | |||
20 | void luaG_dump( lua_State* L); | 20 | void luaG_dump( lua_State* L); |
21 | #endif // _DEBUG | 21 | #endif // _DEBUG |
22 | 22 | ||
23 | lua_State* create_state( Universe* U, lua_State* from_); | ||
24 | lua_State* luaG_newstate( Universe* U, lua_State* _from, char const* libs); | ||
25 | |||
26 | // ################################################################################################ | 23 | // ################################################################################################ |
27 | 24 | ||
28 | int luaG_inter_copy_package( Universe* U, lua_State* L, lua_State* L2, int package_idx_, LookupMode mode_); | 25 | int 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 | |||
31 | int luaG_inter_move( Universe* U, lua_State* L, lua_State* L2, uint_t n, LookupMode mode_); | 28 | int luaG_inter_move( Universe* U, lua_State* L, lua_State* L2, uint_t n, LookupMode mode_); |
32 | 29 | ||
33 | int luaG_nameof( lua_State* L); | 30 | int luaG_nameof( lua_State* L); |
34 | int luaG_new_require( lua_State* L); | ||
35 | 31 | ||
36 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); | 32 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); |
37 | void serialize_require( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State *L); | ||
38 | void initialize_allocator_function( Universe* U, lua_State* L); | 33 | void initialize_allocator_function( Universe* U, lua_State* L); |
39 | void cleanup_allocator_function( Universe* U, lua_State* L); | 34 | void cleanup_allocator_function( Universe* U, lua_State* L); |
40 | 35 | ||
41 | void initialize_on_state_create( Universe* U, lua_State* L); | ||
42 | void 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/ |