From fb0c67b1c95b6a595c0cd34a66136af6193b4d1b Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Sat, 26 Jan 2013 20:21:39 +0100 Subject: version 3.4.4 * bugfix: take into account the fact that "coroutine" is no longer part of base library in Lua 5.2 * bugfix: if "bit32" was listed in the libraries, it wouldn't open (library list parsing failing on digits) * bugfix: Use luaL_requiref() to open standard libraries in Lua 5.2 as we should * bugfix: any Lua state created by Lanes reuses the allocator function of the originating state * bugfix: don't call on_state_create() while GC is suspended during lua state initialization --- CHANGES | 12 +++- docs/index.html | 2 +- src/keeper.c | 4 +- src/lanes.c | 8 +-- src/tools.c | 172 +++++++++++++++++++++++++++++++------------------------- src/tools.h | 2 +- tests/basic.lua | 89 +++++++++++++++++++++++------ 7 files changed, 180 insertions(+), 109 deletions(-) diff --git a/CHANGES b/CHANGES index 52ec52d..fc29440 100644 --- a/CHANGES +++ b/CHANGES @@ -1,15 +1,23 @@ CHANGES: +CHANGE 56: BGe 25-Jan-13 + * version 3.4.4 + * bugfix: take into account the fact that "coroutine" is no longer part of base library in Lua 5.2 + * bugfix: if "bit32" was listed in the libraries, it wouldn't open (library list parsing failing on digits) + * bugfix: Use luaL_requiref() to open standard libraries in Lua 5.2 as we should + * bugfix: any Lua state created by Lanes reuses the allocator function of the originating state + * bugfix: don't call on_state_create() while GC is suspended during lua state initialization + CHANGE 55: BGe 24-Jan-13 * version 3.4.3 * raise an error if lane generator libs specification contains a lib more than once * bit32 is a valid lib name in the libs specification (silently ignored by the Lua 5.1 build) * improved lanes.nameof to search inside table- and userdata- metatables for an object's name - * fixed an unwarranted error when trying to discover a function name upon a failed transfer + * bugfix: fixed an unwarranted error when trying to discover a function name upon a failed transfer * contents of package.[path,cpath,preload,loaders|searchers] are pulled *only once* inside keeper states at initialisation * Lua function upvalues equal to the global environment aren't copied by value, but bound to the destination's global environment especially useful for Lua 5.2 _ENV - * fixed loading of base libraries that didn't create the global tables when built for Lua 5.2 + * bugfix: fixed loading of base libraries that didn't create the global tables when built for Lua 5.2 CHANGE 54: BGe 10-Jan-13 * version 3.4.2 diff --git a/docs/index.html b/docs/index.html index 8188fe9..4f31923 100644 --- a/docs/index.html +++ b/docs/index.html @@ -69,7 +69,7 @@

- 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