From fb0c67b1c95b6a595c0cd34a66136af6193b4d1b Mon Sep 17 00:00:00 2001
From: Benoit Germain
- This document was revised on 24-Jan-13, and applies to version 3.4.3. + This document was revised on 26-Jan-13, and applies to version 3.4.4.
diff --git a/src/keeper.c b/src/keeper.c index a7c8647..516fe85 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -569,9 +569,7 @@ char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_ // // '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 - lua_State* K = luaG_newstate( "*", _on_state_create); - if( !K) - return "out of memory"; + lua_State* K = luaG_newstate( L, "*", _on_state_create); DEBUGSPEW_CODE( fprintf( stderr, "init_keepers %d\n", i)); diff --git a/src/lanes.c b/src/lanes.c index 6fec951..62d56c1 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -52,7 +52,7 @@ * ... */ -char const* VERSION = "3.4.3"; +char const* VERSION = "3.4.4"; /* =============================================================================== @@ -1894,11 +1894,7 @@ LUAG_FUNC( thread_new ) // populate with selected libraries at the same time // - L2 = luaG_newstate( libs, on_state_create); - if (!L2) - { - return luaL_error( L, "'luaL_newstate()' failed; out of memory"); - } + L2 = luaG_newstate( L, libs, on_state_create); STACK_GROW( L, 2); STACK_GROW( L2, 3); diff --git a/src/tools.c b/src/tools.c index fe1728d..ade8cb8 100644 --- a/src/tools.c +++ b/src/tools.c @@ -100,17 +100,19 @@ static const luaL_Reg libs[] = { { LUA_LOADLIBNAME, luaopen_package}, { LUA_TABLIBNAME, luaopen_table}, - { LUA_IOLIBNAME, luaopen_io}, - { LUA_OSLIBNAME, luaopen_os}, { LUA_STRLIBNAME, luaopen_string}, { LUA_MATHLIBNAME, luaopen_math}, + { LUA_OSLIBNAME, luaopen_os}, + { LUA_IOLIBNAME, luaopen_io}, #if LUA_VERSION_NUM >= 502 { LUA_BITLIBNAME, luaopen_bit32}, + { LUA_COLIBNAME, luaopen_coroutine}, // Lua 5.2: coroutine is no longer a part of base! +#else // LUA_VERSION_NUM + { LUA_COLIBNAME, NULL}, // Lua 5.1: part of base package #endif // LUA_VERSION_NUM { LUA_DBLIBNAME, luaopen_debug}, // - { "base", NULL }, // ignore "base" (already acquired it) - { LUA_COLIBNAME, NULL }, // part of Lua 5.[1|2] base package + { "base", NULL}, // ignore "base" (already acquired it) { NULL, NULL } }; @@ -124,18 +126,16 @@ static void open1lib( lua_State* L, char const* name, size_t len) if( libs[i].func) { DEBUGSPEW_CODE( fprintf( stderr, "opening %.*s library\n", len, name)); - STACK_GROW( L, 1); STACK_CHECK( L) - lua_pushcfunction( L, libs[i].func); - // pushes the module table on the stack - lua_call( L, 0, 1); - populate_func_lookup_table( L, -1, libs[i].name); #if LUA_VERSION_NUM >= 502 - // Lua 5.2: luaopen_x doesn't create the global, we have to do it ourselves! - lua_setglobal( L, libs[i].name); -#else // LUA_VERSION_NUM - // Lua 5.1: remove the module when we are done + // open the library as if through require(), and create a global as well (the library table is left on the stack) + luaL_requiref( L, libs[i].name, libs[i].func, 1); lua_pop( L, 1); +#else // LUA_VERSION_NUM + STACK_GROW( L, 1); + lua_pushcfunction( L, libs[i].func); + // pushes the module table on the stack + lua_call( L, 0, 0); #endif // LUA_VERSION_NUM STACK_END( L, 0) } @@ -427,75 +427,93 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* _name) * * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. * -* Returns NULL for ok, position of error within 'libs' on failure. */ -#define is_name_char(c) (isalpha(c) || (c)=='*') -lua_State* luaG_newstate( char const* libs, lua_CFunction _on_state_create) +lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_state_create) { - lua_State* const L = luaL_newstate(); + // reuse alloc function from the originating state + void* allocUD; + lua_Alloc allocF = lua_getallocf( _from, &allocUD); + lua_State* L = lua_newstate( allocF, allocUD); - // no libs, or special init func (not even 'base') - if (libs || _on_state_create) + if( !L) { - // 'lua.c' stops GC during initialization so perhaps its a good idea. :) - // - lua_gc( L, LUA_GCSTOP, 0); + luaL_error( _from, "'lua_newstate()' failed; out of memory"); + } - // Anything causes 'base' to be taken in - // - STACK_GROW( L, 2); - STACK_CHECK( L) - if( _on_state_create) + // neither libs (not even 'base') nor special init func: we are done + if( !libs && !_on_state_create) + { + return L; + } + + STACK_GROW( L, 2); + STACK_CHECK( L) + if( _on_state_create) + { + DEBUGSPEW_CODE( fprintf( stderr, "calling on_state_create()\n")); + lua_pushcfunction( L, _on_state_create); + lua_call( L, 0, 0); + } + + // 'lua.c' stops GC during initialization so perhaps its a good idea. :) + // but do it after _on_state_create in case it does a lot of stuff... + lua_gc( L, LUA_GCSTOP, 0); + + // Anything causes 'base' to be taken in + // + if( libs) + { + if( libs[0] == '*' && libs[1] == 0) // special "*" case (mainly to help with LuaJIT compatibility) { - lua_pushcfunction( L, _on_state_create); - lua_call( L, 0, 0); + DEBUGSPEW_CODE( fprintf( stderr, "opening ALL standard libraries\n")); + luaL_openlibs( L); + libs = NULL; // done with libs } - if( libs) + else { - if( libs[0] == '*' && libs[1] == 0) // special "*" case (mainly to help with LuaJIT compatibility) - { - DEBUGSPEW_CODE( fprintf( stderr, "opening ALL base libraries\n")); - luaL_openlibs( L); - libs = NULL; // done with libs - } - else - { - DEBUGSPEW_CODE( fprintf( stderr, "opening base library\n")); - lua_pushcfunction( L, luaopen_base); - lua_call( L, 0, 0); - } + DEBUGSPEW_CODE( fprintf( stderr, "opening base library\n")); +#if LUA_VERSION_NUM >= 502 + // open base library the same way as in luaL_openlibs() + luaL_requiref( L, "_G", luaopen_base, 1); + lua_pop( L, 1); +#else // LUA_VERSION_NUM + lua_pushcfunction( L, luaopen_base); + lua_pushstring( L, ""); + lua_call( L, 1, 0); +#endif // LUA_VERSION_NUM } + } + STACK_END( L, 0) - // after opening base, register the functions it exported in our name<->function database - lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack - populate_func_lookup_table( L, -1, NULL); - lua_pop( L, 1); - - STACK_MID( L, 0); + // scan all libraries, open them one by one + if( libs) + { + char const* p; + unsigned int len = 0; + for( p = libs; *p; p += len) { - char const* p; - unsigned int len = 0; - if( libs) - { - for( p = libs; *p; p += len) - { - len = 0; - // skip delimiters - while( *p && !is_name_char( *p)) - ++ p; - // skip name - while( is_name_char( p[len])) - ++ len; - // open library - open1lib( L, p, len); - } - serialize_require( L); - } + len = 0; + // skip delimiters + while( *p && !isalnum( *p)) + ++ p; + // skip name + while( isalnum( p[len])) + ++ len; + // open library + open1lib( L, p, len); } - STACK_END(L,0) - lua_gc( L, LUA_GCRESTART, 0); + serialize_require( L); } + + lua_gc( L, LUA_GCRESTART, 0); + + STACK_CHECK( L) + // after opening base, register the functions it exported in our name<->function database + lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack + populate_func_lookup_table( L, -1, NULL); + lua_pop( L, 1); + STACK_END( L, 0) return L; } @@ -1895,25 +1913,23 @@ static int new_require( lua_State *L) */ void serialize_require( lua_State *L ) { - STACK_GROW(L,1); - STACK_CHECK(L) + STACK_GROW( L, 1); + STACK_CHECK( L) // Check 'require' is there; if not, do nothing // - lua_getglobal( L, "require" ); - if (lua_isfunction( L, -1 )) + lua_getglobal( L, "require"); + if( lua_isfunction( L, -1)) { // [-1]: original 'require' function - - lua_pushcclosure( L, new_require, 1 /*upvalues*/ ); - lua_setglobal( L, "require" ); - + lua_pushcclosure( L, new_require, 1 /*upvalues*/); + lua_setglobal( L, "require"); } else { // [-1]: nil - lua_pop(L,1); + lua_pop( L, 1); } - STACK_END(L,0) + STACK_END( L, 0) } diff --git a/src/tools.h b/src/tools.h index d0169cf..e4fbd94 100644 --- a/src/tools.h +++ b/src/tools.h @@ -73,7 +73,7 @@ extern char const* debugspew_indent; void luaG_dump( lua_State* L ); -lua_State* luaG_newstate( char const* libs, lua_CFunction _on_state_create); +lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_state_create); typedef struct { volatile int refcount; diff --git a/tests/basic.lua b/tests/basic.lua index c35f16a..1f4eb1e 100644 --- a/tests/basic.lua +++ b/tests/basic.lua @@ -54,8 +54,11 @@ tables_match= function( a, b ) return subtable( a, b ) and subtable( b, a ) end +--############################################################## +--############################################################## +--############################################################## -PRINT( "---=== Tasking (basic) ===---") +PRINT( "\n\n", "---=== Tasking (basic) ===---", "\n\n") local function task( a, b, c ) set_debug_threadname( "task("..a..","..b..","..c..")") @@ -98,8 +101,11 @@ assert( v2_hey == true ) assert( lane1.status == "done" ) assert( lane1.status == "done" ) +--############################################################## +--############################################################## +--############################################################## -PRINT( "---=== Tasking (cancelling) ===---") +PRINT( "\n\n", "---=== Tasking (cancelling) ===---", "\n\n") local task_launch2= lanes_gen( "", { cancelstep=100, globals={hey=true} }, task ) @@ -181,7 +187,11 @@ repeat until wait_receive_batched_lane.status == "cancelled" print "wait_receive_batched_lane is cancelled" --################################################]] -PRINT( "---=== Communications ===---") +--############################################################## +--############################################################## +--############################################################## + +PRINT( "\n\n", "---=== Communications ===---", "\n\n") local function WR(...) io.stderr:write(...) end @@ -246,28 +256,64 @@ assert( tables_match( a, {'a','b','c',d=10} ) ) assert( PEEK() == nil ) SEND(4) +-- wait +linda: receive( 1, "wait") + +--############################################################## +--############################################################## +--############################################################## -PRINT( "---=== Stdlib naming ===---") +PRINT( "\n\n", "---=== Stdlib naming ===---", "\n\n") -local function io_os_f() - assert(io) - assert(os) - assert(print) - return true +local function dump_g( _x) + assert(print) + print( "### dumping _G for '" .. _x .. "'") + for k, v in pairs( _G) do + print( "\t" .. k .. ": " .. type( v)) + end + return true end -local f1= lanes_gen( "io,os", io_os_f ) -- any delimiter will do -local f2= lanes_gen( "io+os", io_os_f ) -local f3= lanes_gen( "io,os,base", io_os_f ) +local function io_os_f( _x) + assert(print) + print( "### checking io and os libs existence for '" .. _x .. "'") + assert(io) + assert(os) + return true +end + +local function coro_f( _x) + assert(print) + print( "### checking coroutine lib existence for '" .. _x .. "'") + assert(coroutine) + return true +end assert.fails( function() lanes_gen( "xxx", io_os_f ) end ) -assert( f1()[1] ) -assert( f2()[1] ) -assert( f3()[1] ) +local stdlib_naming_tests = +{ + -- { "", dump_g}, + -- { "coroutine", dump_g}, + -- { "io", dump_g}, + -- { "bit32", dump_g}, + { "coroutine", coro_f}, + { "*", io_os_f}, + { "io,os", io_os_f}, + { "io+os", io_os_f}, + { "io,os,base", io_os_f}, +} + +for _, t in ipairs( stdlib_naming_tests) do + local f= lanes_gen( t[1], t[2]) -- any delimiter will do + assert( f(t[1])[1] ) +end +--############################################################## +--############################################################## +--############################################################## -PRINT( "---=== Comms criss cross ===---") +PRINT( "\n\n", "---=== Comms criss cross ===---", "\n\n") -- We make two identical lanes, which are using the same Linda channel. -- @@ -293,7 +339,11 @@ local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twis local _= a[1],b[1] -- waits until they are both ready -PRINT( "---=== Receive & send of code ===---") +--############################################################## +--############################################################## +--############################################################## + +PRINT( "\n\n", "---=== Receive & send of code ===---", "\n\n") local upvalue="123" @@ -351,8 +401,11 @@ assert( s2==":)" ) local k,ok2= linda:receive( "up" ) assert( ok2 == "ok2" ) +--############################################################## +--############################################################## +--############################################################## -PRINT( "---=== :join test ===---") +PRINT( "\n\n", "---=== :join test ===---", "\n\n") -- NOTE: 'unpack()' cannot be used on the lane handle; it will always return nil -- (unless [1..n] has been read earlier, in which case it would seemingly -- cgit v1.2.3-55-g6feb