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/ |
