From 577bca074df12c520f49e9361381f0cad78200c1 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Wed, 13 Feb 2013 20:30:04 +0100 Subject: version 3.5.1 * new lanes.h header and API call luaopen_lanes_embedded() for embedders * "lanes.core" is an acceptable library in the generator libs argument * library "*" wildcard also opens lanes.core * tweaked code for Xbox 360 build --- CHANGES | 7 +++++ docs/index.html | 68 ++++++++++++++++++++++++++++++++++++++--- lanes-3.4.2-1.rockspec | 66 ---------------------------------------- lanes-3.5.1-1.rockspec | 66 ++++++++++++++++++++++++++++++++++++++++ src/keeper.c | 2 +- src/lanes.c | 82 +++++++++++++++++++++++++++++++++++--------------- src/lanes.h | 17 +++++++++++ src/lanes.lua | 30 +++++++++--------- src/threading.c | 21 ++++++++----- src/threading.h | 18 +++++++---- src/tools.c | 80 +++++++++++++++++++++++++++++++++++++++++++----- src/tools.h | 1 + 12 files changed, 327 insertions(+), 131 deletions(-) delete mode 100644 lanes-3.4.2-1.rockspec create mode 100644 lanes-3.5.1-1.rockspec create mode 100644 src/lanes.h diff --git a/CHANGES b/CHANGES index 3957956..b6a3d53 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,12 @@ CHANGES: +CHANGE 59: BGe 12-Feb-13 + * version 3.5.1 + * new lanes.h header and API call luaopen_lanes_embedded() for embedders + * "lanes.core" is an acceptable library in the generator libs argument + * library "*" wildcard also opens lanes.core + * tweaked code for Xbox 360 build + CHANGE 58: BGe 30-Jan-13 * version 3.5.0 * new: API lanes.require(), use it instead of regular require() for modules that export C functions you need to send over. diff --git a/docs/index.html b/docs/index.html index 8b21a97..89710ab 100644 --- a/docs/index.html +++ b/docs/index.html @@ -37,7 +37,8 @@

Description · Supported systems · - Building and Installing + Building and Installing · + Embedding

@@ -69,7 +70,7 @@

- This document was revised on 30-Jan-13, and applies to version 3.5.0. + This document was revised on 12-Feb-13, and applies to version 3.5.1.

@@ -164,6 +165,65 @@ + +
+

Embedding

+

+ When Lanes is embedded, it is possible to statically initialize with +

+ + + + +
+
	extern void LANES_API luaopen_lanes_embedded( lua_State* L, lua_CFunction _luaopen_lanes);
+
+

+ luaopen_lanes_embedded leaves the module table on the stack. lanes.configure() must still be called in order to use Lanes. +
+ If _luaopen_lanes is NULL, a default loader will simply attempt the equivalent of luaL_dofile( L, "lanes.lua"). +

+ +

+ To embed Lanes, compile source files in you application. In any Lua state were you want to use Lanes, initialize it as follows: +

+ +

+ + + + +
+
	#include "lanes.h"
+
+
	int load_lanes_lua( lua_State* L)
+
	{
+
		// retrieve lanes.lua from wherever it is stored and return the result of its execution
+
		// trivial example 1:
+
		luaL_dofile( L, "lanes.lua");
+
+
		// trivial example 2:
+
		luaL_dostring( L, bin2c_lanes_lua);
+
	}
+
+
	void embed_lanes( lua_State* L)
+
	{
+
		// we need base libraries for Lanes for work
+
		luaL_openlibs( L);
+
		...
+
		// will attempt luaL_dofile( L, "lanes.lua");
+
		luaopen_lanes_embedded( L, NULL);
+
		lua_pop( L, 1);
+
		// another example with a custom loader
+
		luaopen_lanes_embedded( L, load_lanes_lua);
+
		lua_pop( L, 1);
+
+
		// a little test to make sure things work as expected
+
		luaL_dostring( L, "local lanes = require 'lanes'.configure{with_timers = false}; local l = lanes.linda()");
+
	}
+
+

+
@@ -438,7 +498,7 @@ - All standard libraries (including those specific to LuaJIT and not listed above). This must be used alone. + All standard libraries (including those specific to LuaJIT and not listed above), as well as lanes.core. This must be used alone. @@ -765,7 +825,7 @@

- If the lane is still running after the timeout expired and force_kill is true, the OS thread running the lane is forcefully killed. This means no GC, and should generally be the last resort. + If the lane is still running after the timeout expired and force_kill is true, the OS thread running the lane is forcefully killed. This means no GC, probable OS resource leaks (thread stack, locks, DLL notifications), and should generally be the last resort.

diff --git a/lanes-3.4.2-1.rockspec b/lanes-3.4.2-1.rockspec deleted file mode 100644 index 23699ea..0000000 --- a/lanes-3.4.2-1.rockspec +++ /dev/null @@ -1,66 +0,0 @@ --- --- Lanes rockspec --- --- Ref: --- --- - -package = "Lanes" - -version = "3.4.2-1" - -source= { - url= "git://github.com/LuaLanes/lanes.git", - branch= "v3.4.2" -} - -description = { - summary= "Multithreading support for Lua", - detailed= [[ - Lua Lanes is a portable, message passing multithreading library - providing the possibility to run multiple Lua states in parallel. - ]], - license= "MIT/X11", - homepage="https://github.com/LuaLanes/lanes", - maintainer="Benoit Germain " -} - --- Q: What is the difference of "windows" and "win32"? Seems there is none; --- so should we list either one or both? --- -supported_platforms= { "win32", - "macosx", - "linux", - "freebsd", -- TBD: not tested - "msys", -- TBD: not supported by LuaRocks 1.0 (or is it?) -} - -dependencies= { - "lua >= 5.1", -- builds with either 5.1 and 5.2 -} - -build = { - type = "builtin", - platforms = - { - linux = - { - modules = - { - ["lanes.core"] = - { - libraries = "pthread" - }, - } - } - }, - modules = - { - ["lanes.core"] = - { - sources = { "src/lanes.c", "src/keeper.c", "src/tools.c", "src/threading.c"}, - incdirs = { "src"}, - }, - lanes = "src/lanes.lua" - } -} diff --git a/lanes-3.5.1-1.rockspec b/lanes-3.5.1-1.rockspec new file mode 100644 index 0000000..39191f2 --- /dev/null +++ b/lanes-3.5.1-1.rockspec @@ -0,0 +1,66 @@ +-- +-- Lanes rockspec +-- +-- Ref: +-- +-- + +package = "Lanes" + +version = "3.5.1-1" + +source= { + url= "git://github.com/LuaLanes/lanes.git", + branch= "v3.5.1" +} + +description = { + summary= "Multithreading support for Lua", + detailed= [[ + Lua Lanes is a portable, message passing multithreading library + providing the possibility to run multiple Lua states in parallel. + ]], + license= "MIT/X11", + homepage="https://github.com/LuaLanes/lanes", + maintainer="Benoit Germain " +} + +-- Q: What is the difference of "windows" and "win32"? Seems there is none; +-- so should we list either one or both? +-- +supported_platforms= { "win32", + "macosx", + "linux", + "freebsd", -- TBD: not tested + "msys", -- TBD: not supported by LuaRocks 1.0 (or is it?) +} + +dependencies= { + "lua >= 5.1", -- builds with either 5.1 and 5.2 +} + +build = { + type = "builtin", + platforms = + { + linux = + { + modules = + { + ["lanes.core"] = + { + libraries = "pthread" + }, + } + } + }, + modules = + { + ["lanes.core"] = + { + sources = { "src/lanes.c", "src/keeper.c", "src/tools.c", "src/threading.c"}, + incdirs = { "src"}, + }, + lanes = "src/lanes.lua" + } +} diff --git a/src/keeper.c b/src/keeper.c index 3511b56..848fe2a 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -572,7 +572,7 @@ char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepe // // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs // the others because they export functions that we may store in a keeper for transfer between lanes - K = luaG_newstate( L, _on_state_create, "*"); + K = luaG_newstate( L, _on_state_create, "K"); STACK_CHECK( K); diff --git a/src/lanes.c b/src/lanes.c index 2b3d8ac..7bd29ee 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -52,7 +52,7 @@ * ... */ -char const* VERSION = "3.5.0"; +char const* VERSION = "3.5.1"; /* =============================================================================== @@ -92,8 +92,9 @@ THE SOFTWARE. #include "threading.h" #include "tools.h" #include "keeper.h" +#include "lanes.h" -#if !((defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)) +#if !(defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) # include #endif @@ -2580,6 +2581,26 @@ static const struct luaL_Reg lanes_functions [] = { {NULL, NULL} }; + +/* + * minimal function registration for keepers, just so that we can populate the transfer databases with them + * without recursively deadlocking ourselves during one-time inits + */ +void register_core_libfuncs_for_keeper( lua_State* L) +{ + DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register_core_libfuncs_for_keeper()\n" INDENT_END)); + DEBUGSPEW_CODE( ++ debugspew_indent_depth); + STACK_GROW( L, 1); + STACK_CHECK( L); + lua_newtable( L); + luaG_registerlibfuncs( L, lanes_functions); + STACK_MID( L, 1); + populate_func_lookup_table( L, -1, "lanes.core"); + lua_pop( L, 1); + STACK_END( L, 0); + DEBUGSPEW_CODE( -- debugspew_indent_depth); +} + /* * One-time initializations */ @@ -2645,7 +2666,7 @@ static void init_once_LOCKED( lua_State* L, int const _on_state_create, int cons { (void) luaL_error( L, "Unable to initialize: %s", err ); } - + // Initialize 'timer_deep'; a common Linda object shared by all states // ASSERT_L( timer_deep == NULL); @@ -2842,43 +2863,54 @@ void EnableCrashingOnCrashes() #endif // PLATFORM_WIN32 } -int -#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) -__declspec(dllexport) -#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) -luaopen_lanes_core( lua_State* L) +int LANES_API luaopen_lanes_core( lua_State* L) { EnableCrashingOnCrashes(); STACK_GROW( L, 3); STACK_CHECK( L); - // sanity check: let's see if _"VERSION" matches what we we built against - lua_getglobal( L, "_VERSION"); - lua_pushstring( L, LUA_VERSION_NUM == 501 ? "Lua 5.1" : "Lua 5.2"); - if( !lua_rawequal( L, -1, -2)) - { - return luaL_error( L, "Lanes is built against %s, but you are running %s", lua_tostring( L, -1), lua_tostring( L, -2)); - } - lua_pop( L, 2); - // Create main module interface table // we only have 1 closure, which must be called to configure Lanes - lua_newtable(L); - lua_pushvalue(L, 1); // module name - lua_pushvalue(L, -2); // module table - lua_pushcclosure( L, LG_configure, 2); + lua_newtable(L); // M + lua_pushvalue(L, 1); // M "lanes.core" + lua_pushvalue(L, -2); // M "lanes.core" M + lua_pushcclosure( L, LG_configure, 2); // M LG_configure() if( s_initCount == 0) { - lua_setfield( L, -2, "configure"); + lua_setfield( L, -2, "configure"); // M } else // already initialized: call it immediately and be done { - lua_pushinteger( L, 666); // any value will do, it will be ignored - lua_pushnil( L); // almost idem - lua_call( L, 2, 0); + // any parameter value will do, they will be ignored + lua_pushinteger( L, 666); // M LG_configure() 666 + lua_pushnil( L); // M LG_configure() 666 nil + lua_call( L, 2, 0); // M } STACK_END( L, 1); return 1; } + +static int default_luaopen_lanes( lua_State* L) +{ + int rc = luaL_loadfile( L, "lanes.lua") || lua_pcall( L, 0, 1, 0); + if( rc != LUA_OK) + { + return luaL_error( L, "failed to initialize embedded Lanes"); + } + return 1; +} + +// call this instead of luaopen_lanes_core() when embedding Lua and Lanes in a custom application +void LANES_API luaopen_lanes_embedded( lua_State* L, lua_CFunction _luaopen_lanes) +{ + STACK_CHECK( L); + // pre-require lanes.core so that when lanes.lua calls require "lanes.core" it finds it is already loaded + luaL_requiref( L, "lanes.core", luaopen_lanes_core, 0); // ... lanes.core + lua_pop( L, 1); // ... + STACK_MID( L, 0); + // call user-provided function that runs the chunk "lanes.lua" from wherever they stored it + luaL_requiref( L, "lanes", _luaopen_lanes ? _luaopen_lanes : default_luaopen_lanes, 0); // ... lanes + STACK_END( L, 1); +} diff --git a/src/lanes.h b/src/lanes.h new file mode 100644 index 0000000..d07750a --- /dev/null +++ b/src/lanes.h @@ -0,0 +1,17 @@ +#if !defined( __lanes_h__) +#define __lanes_h__ 1 + +#include "lua.h" + +#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) +#define LANES_API __declspec(dllexport) +#else +#define LANES_API +#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) + +extern int LANES_API luaopen_lanes_core( lua_State* L); + +// Call this to work with embedded Lanes instead of calling luaopen_lanes_core() +extern void LANES_API luaopen_lanes_embedded( lua_State* L, lua_CFunction _luaopen_lanes); + +#endif // __lanes_h__ \ No newline at end of file diff --git a/src/lanes.lua b/src/lanes.lua index f4eef81..729116e 100644 --- a/src/lanes.lua +++ b/src/lanes.lua @@ -52,7 +52,7 @@ lanes.configure = function( _params) end -- - -- Cache globals for code that might run under sandboxing + -- Cache globals for code that might run under sandboxing -- local assert = assert local string_gmatch = assert( string.gmatch) @@ -199,18 +199,20 @@ end -- and call the generator later (maybe multiple times, with different parameters) -- or add on actual thread arguments to also ignite the thread on the same call. -local valid_libs= { - ["package"]= true, - ["table"]= true, - ["io"]= true, - ["os"]= true, - ["string"]= true, - ["math"]= true, - ["debug"]= true, - ["bit32"]= true, -- Lua 5.2 only, ignored silently under 5.1 - -- - ["base"]= true, - ["coroutine"]= true +local valid_libs= +{ + ["package"] = true, + ["table"] = true, + ["io"] = true, + ["os"] = true, + ["string"] = true, + ["math"] = true, + ["debug"] = true, + ["bit32"] = true, -- Lua 5.2 only, ignored silently under 5.1 + -- + ["base"] = true, + ["coroutine"] = true, -- part of "base" in Lua 5.1 + ["lanes.core"] = true } -- PUBLIC LANES API @@ -253,7 +255,7 @@ local function gen( ... ) if libs and libs ~= "*" then local found = {} -- check that the caller only provides reserved library names - for s in string_gmatch(libs, "[%a%d]+") do + for s in string_gmatch(libs, "[%a%d.]+") do if not valid_libs[s] then error( "Bad library name: " .. s) else diff --git a/src/threading.c b/src/threading.c index d19fe1a..754b6d1 100644 --- a/src/threading.c +++ b/src/threading.c @@ -42,7 +42,7 @@ THE SOFTWARE. #include "threading.h" #include "lua.h" -#if !defined( PLATFORM_WIN32) && !defined( PLATFORM_POCKETPC) +#if !defined( PLATFORM_XBOX) && !defined( PLATFORM_WIN32) && !defined( PLATFORM_POCKETPC) # include #endif // non-WIN32 timing @@ -83,7 +83,7 @@ THE SOFTWARE. * FAIL is for unexpected API return values - essentially programming * error in _this_ code. */ -#if defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) +#if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) static void FAIL( const char *funcname, int rc ) { fprintf( stderr, "%s() failed! (%d)\n", funcname, rc ); #ifdef _MSC_VER @@ -102,7 +102,7 @@ static void FAIL( const char *funcname, int rc ) { */ time_d now_secs(void) { -#if defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) +#if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) /* * Windows FILETIME values are "100-nanosecond intervals since * January 1, 1601 (UTC)" (MSDN). Well, we'd want Unix Epoch as @@ -226,7 +226,7 @@ static void prepare_timeout( struct timespec *ts, time_d abs_secs ) { // valid values N * 4KB // #ifndef _THREAD_STACK_SIZE -# if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PLATFORM_CYGWIN) +# if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) || defined( PLATFORM_CYGWIN) # define _THREAD_STACK_SIZE 0 // Win32: does it work with less? # elif (defined PLATFORM_OSX) @@ -311,10 +311,15 @@ bool_t THREAD_WAIT_IMPL( THREAD_T *ref, double secs) return TRUE; } // - void THREAD_KILL( THREAD_T *ref ) { - if (!TerminateThread( *ref, 0 )) FAIL("TerminateThread", GetLastError()); - *ref= NULL; - } + void THREAD_KILL( THREAD_T *ref ) + { + // nonexistent on Xbox360, simply disable until a better solution is found + #if !defined( PLATFORM_XBOX) + // in theory no-one should call this as it is very dangerous (memory and mutex leaks, no notification of DLLs, etc.) + if (!TerminateThread( *ref, 0 )) FAIL("TerminateThread", GetLastError()); + #endif // PLATFORM_XBOX + *ref= NULL; + } #if !defined __GNUC__ //see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx diff --git a/src/threading.h b/src/threading.h index 1d304fa..1b218b9 100644 --- a/src/threading.h +++ b/src/threading.h @@ -11,6 +11,8 @@ */ #ifdef _WIN32_WCE #define PLATFORM_POCKETPC +#elif defined(_XBOX) + #define PLATFORM_XBOX #elif (defined _WIN32) #define PLATFORM_WIN32 #elif (defined __linux__) @@ -47,7 +49,7 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED }; #define THREADAPI_WINDOWS 1 #define THREADAPI_PTHREAD 2 -#if( defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) && !defined( HAVE_WIN32_PTHREAD) +#if( defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) && !defined( HAVE_WIN32_PTHREAD) #define THREADAPI THREADAPI_WINDOWS #else // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) #define THREADAPI THREADAPI_PTHREAD @@ -57,10 +59,14 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED }; */ #if THREADAPI == THREADAPI_WINDOWS - #define WIN32_LEAN_AND_MEAN - // 'SignalObjectAndWait' needs this (targets Windows 2000 and above) - #define _WIN32_WINNT 0x0400 - #include + #if defined ( PLATFORM_XBOX) + #include + #else // !PLATFORM_XBOX + #define WIN32_LEAN_AND_MEAN + // 'SignalObjectAndWait' needs this (targets Windows 2000 and above) + #define _WIN32_WINNT 0x0400 + #include + #endif // !PLATFORM_XBOX #include // MSDN: http://msdn2.microsoft.com/en-us/library/ms684254.aspx @@ -119,7 +125,7 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED }; // #if defined( PLATFORM_OSX) #define YIELD() pthread_yield_np() - #elif defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) + #elif defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) // no PTHREAD for PLATFORM_XBOX // for some reason win32-pthread doesn't have pthread_yield(), but sched_yield() #define YIELD() sched_yield() #else diff --git a/src/tools.c b/src/tools.c index 13a3ebd..f72663f 100644 --- a/src/tools.c +++ b/src/tools.c @@ -33,6 +33,7 @@ THE SOFTWARE. #include "tools.h" #include "keeper.h" +#include "lanes.h" #include "lualib.h" #include "lauxlib.h" @@ -42,6 +43,43 @@ THE SOFTWARE. #include #include +/* +** Copied from Lua 5.2 loadlib.c +*/ +#if LUA_VERSION_NUM == 501 +static int luaL_getsubtable (lua_State *L, int idx, const char *fname) +{ + lua_getfield(L, idx, fname); + if (lua_istable(L, -1)) + return 1; /* table already there */ + else + { + lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); + lua_newtable(L); + lua_pushvalue(L, -1); /* copy to be left at top */ + lua_setfield(L, idx, fname); /* assign new table to field */ + return 0; /* false, because did not find table there */ + } +} + +void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb) +{ + lua_pushcfunction(L, openf); + lua_pushstring(L, modname); /* argument to open function */ + lua_call(L, 1, 1); /* open module */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_pushvalue(L, -2); /* make copy of module (call result) */ + lua_setfield(L, -2, modname); /* _LOADED[modname] = module */ + lua_pop(L, 1); /* remove _LOADED table */ + if (glb) + { + lua_pushvalue(L, -1); /* copy of 'mod' */ + lua_setglobal(L, modname); /* _G[modname] = module */ + } +} +#endif // LUA_VERSION_NUM + DEBUGSPEW_CODE( char const* debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); DEBUGSPEW_CODE( int debugspew_indent_depth = 0); @@ -98,14 +136,24 @@ void luaG_dump( lua_State* L ) { /*---=== luaG_newstate ===---*/ +static int require_lanes_core( lua_State* L) +{ + // leaves a copy of 'lanes.core' module table on the stack + luaL_requiref( L, "lanes.core", luaopen_lanes_core, 0); + return 1; +} + + static const luaL_Reg libs[] = { { LUA_LOADLIBNAME, luaopen_package}, { LUA_TABLIBNAME, luaopen_table}, { LUA_STRLIBNAME, luaopen_string}, { LUA_MATHLIBNAME, luaopen_math}, +#ifndef PLATFORM_XBOX // no os/io libs on xbox { LUA_OSLIBNAME, luaopen_os}, { LUA_IOLIBNAME, luaopen_io}, +#endif // PLATFORM_XBOX #if LUA_VERSION_NUM >= 502 { LUA_BITLIBNAME, luaopen_bit32}, { LUA_COLIBNAME, luaopen_coroutine}, // Lua 5.2: coroutine is no longer a part of base! @@ -113,6 +161,7 @@ static const luaL_Reg libs[] = { LUA_COLIBNAME, NULL}, // Lua 5.1: part of base package #endif // LUA_VERSION_NUM { LUA_DBLIBNAME, luaopen_debug}, + { "lanes.core", require_lanes_core}, // So that we can open it like any base library (possible since we have access to the init function) // { "base", NULL}, // ignore "base" (already acquired it) { NULL, NULL } @@ -135,9 +184,11 @@ static void open1lib( lua_State* L, char const* name, size_t len) lua_pop( L, 1); #else // LUA_VERSION_NUM STACK_GROW( L, 1); + // push function and 1 argument on the stack lua_pushcfunction( L, libs[i].func); - // pushes the module table on the stack - lua_call( L, 0, 0); + lua_pushstring( L, libs[i].name); + // call function, pushes the module table on the stack + lua_call( L, 1, 0); #endif // LUA_VERSION_NUM STACK_END( L, 0); } @@ -443,6 +494,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* _name) * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. * */ +extern void register_core_libfuncs_for_keeper( lua_State* L); lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) { @@ -475,10 +527,24 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con // if( libs) { - if( libs[0] == '*' && libs[1] == 0) // special "*" case (mainly to help with LuaJIT compatibility) + // special "*" case (mainly to help with LuaJIT compatibility) + // "K" is used when opening keeper states: almost the same as "*", but for the fact we don't open lanes.core + // as we are called from luaopen_lanes_core() already, and that would deadlock + if( (libs[0] == '*' || libs[0] == 'K') && libs[1] == 0) { DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); luaL_openlibs( L); + if( libs[0] == '*') + { + // don't forget lanes.core for regular lane states + open1lib( L, "lanes.core", 10); + } + else + { + // In keeper states however, we only want to register the lanes.core functions to be able to transfer them through lindas + // (we don't care about a full lanes.core init in the keeper states as we won't call anything in there) + register_core_libfuncs_for_keeper( L); + } libs = NULL; // done with libs } else @@ -504,12 +570,12 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con unsigned int len = 0; for( p = libs; *p; p += len) { - len = 0; - // skip delimiters - while( *p && !isalnum( *p)) + // skip delimiters ('.' can be part of name for "lanes.core") + while( *p && !isalnum( *p) && *p != '.') ++ p; // skip name - while( isalnum( p[len])) + len = 0; + while( isalnum( p[len]) || p[len] == '.') ++ len; // open library open1lib( L, p, len); diff --git a/src/tools.h b/src/tools.h index a06e23f..10711d4 100644 --- a/src/tools.h +++ b/src/tools.h @@ -27,6 +27,7 @@ #define luaG_registerlibfuncs( L, _funcs) luaL_register( L, NULL, _funcs) #define LUA_OK 0 #define LUA_ERRGCMM 666 // doesn't exist in Lua 5.1, we don't care about the actual value +void luaL_requiref (lua_State* L, const char* modname, lua_CFunction openf, int glb); // implementation copied from Lua 5.2 sources #endif // LUA_VERSION_NUM == 501 // wrap Lua 5.2 calls under Lua 5.1 API when it is simpler that way -- cgit v1.2.3-55-g6feb