From 076344633e7b2525cf48005f84f3935f324b60bf Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Sat, 18 Feb 2012 14:08:52 +0100 Subject: * changed lanes.configure signature to receive a table instead of individual parameters * added support for an on_state_create callback called to load custom functions in a state in addition to the base libraries --- src/keeper.c | 18 ++++++------- src/keeper.h | 2 +- src/lanes.c | 66 ++++++++++++++++++++++-------------------------- src/lanes.lua | 32 +++++++++++++++-------- src/tools.c | 81 ++++++++++++++++++++++++++++++++++------------------------- src/tools.h | 4 +-- 6 files changed, 108 insertions(+), 95 deletions(-) (limited to 'src') diff --git a/src/keeper.c b/src/keeper.c index 1f69d40..6f5bd95 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -78,7 +78,7 @@ static char const keeper_chunk[]= * unclosed, because it does not really matter. In production code, this * function never fails. */ -char const *init_keepers( int const _nbKeepers) +char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create) { int i; assert( _nbKeepers >= 1); @@ -87,10 +87,11 @@ char const *init_keepers( int const _nbKeepers) for( i = 0; i < _nbKeepers; ++ i) { - // Initialize Keeper states with bare minimum of libs (those required - // by 'keeper.lua') - // - lua_State *K = luaL_newstate(); + // Initialize Keeper states with bare minimum of libs (those required by 'keeper.lua') + // + // '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"; @@ -100,11 +101,6 @@ char const *init_keepers( int const _nbKeepers) lua_concat( K, 2); lua_setglobal( K, "decoda_name"); - // '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 - luaG_openlibs( K, "*"); - serialize_require( K); - // Read in the preloaded chunk (and run it) // if( luaL_loadbuffer( K, keeper_chunk, sizeof(keeper_chunk), "@keeper.lua")) @@ -114,7 +110,7 @@ char const *init_keepers( int const _nbKeepers) { // LUA_ERRRUN / LUA_ERRMEM / LUA_ERRERR // - const char *err = lua_tostring(K, -1); + char const* err = lua_tostring( K, -1); assert( err); return err; } diff --git a/src/keeper.h b/src/keeper.h index 1bcb36b..0990846 100644 --- a/src/keeper.h +++ b/src/keeper.h @@ -8,7 +8,7 @@ struct s_Keeper //int count; }; -const char *init_keepers( int const _nbKeepers); +char const* init_keepers( int const _nbKeepers, lua_CFunction _on_state_create); void populate_keepers( lua_State *L); struct s_Keeper *keeper_acquire( const void *ptr); void keeper_release( struct s_Keeper *K); diff --git a/src/lanes.c b/src/lanes.c index 676032a..513a006 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -51,7 +51,7 @@ * ... */ -const char *VERSION= "3.0-beta"; +char const* VERSION = "3.1.0"; /* =============================================================================== @@ -1540,7 +1540,7 @@ static void require_one_module( lua_State *L, lua_State *L2, bool_t _fatal) { lua_pop( L2, 1); if( _fatal) - luaL_error( L, "cannot pre-require modules without loading package library first"); + luaL_error( L, "cannot pre-require modules without loading 'package' library first"); } else { @@ -1557,14 +1557,15 @@ LUAG_FUNC( thread_new ) struct s_lane *s; struct s_lane **ud; - const char *libs= lua_tostring( L, 2 ); - uint_t cs= luaG_optunsigned( L, 3,0); - int prio= (int)luaL_optinteger( L, 4,0); - uint_t glob= luaG_isany(L,5) ? 5:0; - uint_t package = luaG_isany(L,6) ? 6:0; - uint_t required = luaG_isany(L,7) ? 7:0; + char const* libs = lua_tostring( L, 2); + lua_CFunction on_state_create = lua_iscfunction( L, 3) ? lua_tocfunction( L, 3) : NULL; + uint_t cs = luaG_optunsigned( L, 4, 0); + int prio = (int) luaL_optinteger( L, 5, 0); + uint_t glob = luaG_isany( L, 6) ? 6 : 0; + uint_t package = luaG_isany( L,7) ? 7 : 0; + uint_t required = luaG_isany( L, 8) ? 8 : 0; -#define FIXED_ARGS (7) +#define FIXED_ARGS 8 uint_t args= lua_gettop(L) - FIXED_ARGS; if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) @@ -1575,23 +1576,13 @@ LUAG_FUNC( thread_new ) /* --- Create and prepare the sub state --- */ - L2 = luaL_newstate(); // uses standard 'realloc()'-based allocator, - // sets the panic callback - + // populate with selected libraries at the same time + // + L2 = luaG_newstate( libs, on_state_create); if (!L2) luaL_error( L, "'luaL_newstate()' failed; out of memory" ); STACK_GROW( L, 2); - // Selected libraries - // - if (libs) - { - const char *err= luaG_openlibs( L2, libs); - ASSERT_L( !err ); // bad libs should have been noticed by 'lanes.lua' - - serialize_require( L2); - } - ASSERT_L( lua_gettop(L2) == 0); // package.path @@ -1600,7 +1591,7 @@ LUAG_FUNC( thread_new ) if( package) { if (lua_type(L,package) != LUA_TTABLE) - luaL_error( L, "expected package as table, got %s", luaG_typename(L,package)); + luaL_error( L, "expected package as table, got %s", luaL_typename(L,package)); lua_getglobal( L2, "package"); if( !lua_isnil( L2, -1)) // package library not loaded: do nothing { @@ -1628,7 +1619,7 @@ LUAG_FUNC( thread_new ) // modules to require in the target lane *before* the function is transfered! //start by requiring lua51-lanes, since it is a bit special - // it not fatal if 'require' isn't loaded, just ignore (may cause function transfer errors later on if the lane pulls the lanes module itself) + // it is not fatal if 'require' isn't loaded, just ignore (may cause function transfer errors later on if the lane pulls the lanes module itself) STACK_CHECK(L) STACK_CHECK(L2) lua_pushliteral( L, "lua51-lanes"); @@ -1644,7 +1635,7 @@ LUAG_FUNC( thread_new ) int nbRequired = 1; // should not happen, was checked in lanes.lua before calling thread_new() if (lua_type(L, required) != LUA_TTABLE) - luaL_error( L, "expected required module list as a table, got %s", luaG_typename( L, required)); + luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required)); lua_pushnil( L); while( lua_next( L, required) != 0) { @@ -1671,7 +1662,7 @@ LUAG_FUNC( thread_new ) STACK_CHECK(L) STACK_CHECK(L2) if (!lua_istable(L,glob)) - luaL_error( L, "Expected table, got %s", luaG_typename(L,glob)); + luaL_error( L, "Expected table, got %s", luaL_typename(L,glob)); lua_pushnil( L); while( lua_next( L, glob)) @@ -2240,7 +2231,7 @@ static const struct luaL_reg lanes_functions [] = { /* * One-time initializations */ -static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ref, int const nbKeepers) +static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_ref, int const nbKeepers, lua_CFunction _on_state_create) { const char *err; @@ -2291,7 +2282,7 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ } #endif #endif - err= init_keepers( nbKeepers); + err = init_keepers( nbKeepers, _on_state_create); if (err) { luaL_error( L, "Unable to initialize: %s", err ); @@ -2338,9 +2329,11 @@ static volatile long s_initCount = 0; LUAG_FUNC( configure ) { - char const *name = luaL_checkstring( L, lua_upvalueindex( 1)); + char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); int const nbKeepers = luaL_optint( L, 1, 1); - luaL_argcheck( L, nbKeepers > 0, 2, "Number of keeper states must be > 0"); + lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL; + luaL_argcheck( L, nbKeepers > 0, 1, "Number of keeper states must be > 0"); + luaL_argcheck( L, lua_iscfunction( L, 2) || lua_isnil( L, 2), 2, "on_state_create should be a C function"); /* * Making one-time initializations. * @@ -2353,7 +2346,7 @@ LUAG_FUNC( configure ) static volatile int /*bool*/ go_ahead; // = 0 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) { - init_once_LOCKED(L, &timer_deep, nbKeepers); + init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create); go_ahead= 1; // let others pass } else @@ -2365,13 +2358,13 @@ LUAG_FUNC( configure ) if( s_initCount == 0) { static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&my_lock); + pthread_mutex_lock( &my_lock); { // Recheck now that we're within the lock // - if (s_initCount == 0) + if( s_initCount == 0) { - init_once_LOCKED(L, &timer_deep, nbKeepers); + init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create); s_initCount = 1; } } @@ -2451,10 +2444,11 @@ luaopen_lanes( lua_State *L ) { lua_setfield( L, -2, "configure"); } - else // already initialized: call it mmediately and be done + else // already initialized: call it immediately and be done { lua_pushinteger( L, 666); // any value will do, it will be ignored - lua_call( L, 1, 0); + lua_pushnil( L); // almost idem + lua_call( L, 2, 0); } STACK_END( L, 1) return 1; diff --git a/src/lanes.lua b/src/lanes.lua index d56e05f..ec5a4e4 100644 --- a/src/lanes.lua +++ b/src/lanes.lua @@ -45,13 +45,21 @@ THE SOFTWARE. -- -> simply create a table, populate it, return it, and be done local lanes = {} -lanes.configure = function( _nb_keepers, _timers) +lanes.configure = function( _params) +_params = _params or { nb_keepers = 1, with_timers = true, on_state_create = nil} +if type( _params) ~= "table" then + error( "Bad parameter #1 to lanes.configure(), should be a table") +end +-- on_state_create may be nil or a function +if _params.on_state_create and (type( _params.on_state_create) ~= "function") then + error( "Bad on_state_create: " .. tostring( _params.on_state_create), 2) +end local mm = require "lua51-lanes" assert( type(mm)=="table" ) -- configure() is available only the first time lua51-lanes is required process-wide, and we *must* call it to have the other functions in the interface -if mm.configure then mm.configure( _nb_keepers) end +if mm.configure then mm.configure( _params.nb_keepers, _params.on_state_create) end local thread_new = assert(mm.thread_new) @@ -238,7 +246,7 @@ local function gen( ... ) -- Lane generator -- return function(...) - return thread_new( func, libs, cs, prio, g_tbl, package_tbl, required, ...) -- args + return thread_new( func, libs, _params.on_state_create, cs, prio, g_tbl, package_tbl, required, ...) -- args end end @@ -258,7 +266,7 @@ local linda = mm.linda -- PUBLIC LANES API local timer = function() error "timers are not active" end -if _timers ~= "NO_TIMERS" then +if _params.with_timers ~= false then local timer_gateway= assert( mm.timer_gateway ) -- @@ -477,7 +485,7 @@ timer = function( linda, key, a, period ) timer_gateway:send( TGW_KEY, linda, key, wakeup_at, period ) end -end -- _timers +end -- _params.with_timers ---=== Lock & atomic generators ===--- @@ -552,12 +560,16 @@ end lanes.genlock = genlock lanes.genatomic = genatomic -- from now on, calling configure does nothing but checking that we don't call it with parameters that changed compared to the first invocation - lanes.configure = function( _nk, _t) - if _nk ~= _nb_keepers then - error( "mismatched configuration: " .. tostring( _nk) .. " keepers instead of " .. tostring( _nb_keepers)) + lanes.configure = function( _params2) + _params2 = _params2 or _params + if _params2.nb_keepers ~= _params.nb_keepers then + error( "mismatched configuration: " .. tostring( _params2.nb_keepers) .. " keepers instead of " .. tostring( _params.nb_keepers)) + end + if _params2.with_timers ~= _params.with_timers then + error( "mismatched configuration: " .. tostring( _params2.with_timers) .. " timer activity instead of " .. tostring( _params.with_timers)) end - if _t ~= _timers then - error( "mismatched configuration: " .. tostring( _t) .. " timer activity instead of " .. tostring( _timers)) + if _params2.on_create_state and _params2.on_create_state ~= _params.on_create_state then + error( "mismatched configuration: " .. tostring( _params2.on_create_state) .. " timer activity instead of " .. tostring( _params.on_create_state)) end return lanes end diff --git a/src/tools.c b/src/tools.c index 85672e2..212cf52 100644 --- a/src/tools.c +++ b/src/tools.c @@ -91,7 +91,7 @@ void luaG_dump( lua_State* L ) { } -/*---=== luaG_openlibs ===---*/ +/*---=== luaG_newstate ===---*/ static const luaL_Reg libs[] = { { LUA_LOADLIBNAME, luaopen_package }, @@ -371,7 +371,7 @@ static void populate_func_lookup_table_recur( lua_State *L, int _ctx_base, int _ } /* - * create a "fully.qualified.name" <-> function equivalence dabase + * create a "fully.qualified.name" <-> function equivalence database */ void populate_func_lookup_table( lua_State *L, int _i, char const *_name) { @@ -422,39 +422,52 @@ void populate_func_lookup_table( lua_State *L, int _i, char const *_name) */ #define is_name_char(c) (isalpha(c) || (c)=='*') -const char *luaG_openlibs( lua_State *L, const char *libs) +lua_State* luaG_newstate( char const* libs, lua_CFunction _on_state_create) { - const char *p; - unsigned len; + char const* p; + unsigned int len; + lua_State* const L = luaL_newstate(); - if (!libs) return NULL; // no libs, not even 'base' - - // 'lua.c' stops GC during initialization so perhaps its a good idea. :) - // - lua_gc( L, LUA_GCSTOP, 0); - - // Anything causes 'base' to be taken in - // - STACK_GROW(L,2); - STACK_CHECK(L) - lua_pushcfunction( L, luaopen_base); - lua_call( L, 0, 1); - // after opening base, register the functions they exported in our name<->function database - populate_func_lookup_table( L, LUA_GLOBALSINDEX, NULL); - lua_pop( L, 1); - STACK_MID( L, 0); - for( p= libs; *p; p+=len ) + // no libs, or special init func (not even 'base') + if (libs || _on_state_create) { - len=0; - while (*p && !is_name_char(*p)) p++; // bypass delimiters - while (is_name_char(p[len])) len++; // bypass name - if (len && (!openlib( L, p, len ))) - break; - } - STACK_END(L,0) - lua_gc(L, LUA_GCRESTART, 0); + // 'lua.c' stops GC during initialization so perhaps its a good idea. :) + // + lua_gc( L, LUA_GCSTOP, 0); - return *p ? p : NULL; + // Anything causes 'base' to be taken in + // + STACK_GROW( L, 2); + STACK_CHECK( L) + if( _on_state_create) + { + lua_pushcfunction( L, _on_state_create); + lua_call( L, 0, 0); + } + if( libs) + { + lua_pushcfunction( L, luaopen_base); + lua_call( L, 0, 0); + } + // after opening base, register the functions it exported in our name<->function database + populate_func_lookup_table( L, LUA_GLOBALSINDEX, NULL); + STACK_MID( L, 0); + if( libs) + { + for( p = libs; *p; p += len) + { + len=0; + while (*p && !is_name_char(*p)) p++; // bypass delimiters + while (is_name_char(p[len])) len++; // bypass name + if (len && (!openlib( L, p, len ))) + break; + } + serialize_require( L); + } + STACK_END(L,0) + lua_gc( L, LUA_GCRESTART, 0); + } + return L; } @@ -1317,7 +1330,7 @@ static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uin else { if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop(L), VT_NORMAL)) - luaL_error( L, "Cannot copy upvalue type '%s'", luaG_typename( L, -1)); + luaL_error( L, "Cannot copy upvalue type '%s'", luaL_typename( L, -1)); } lua_pop( L, 1); } @@ -1475,7 +1488,7 @@ static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, u lua_rawset( L2, -3 ); // add to table (pops key & val) } else { luaL_error( L, "Unable to copy over type '%s' (in %s)", - luaG_typename(L,val_i), + luaL_typename(L,val_i), vt==VT_NORMAL ? "table":"metatable" ); } } @@ -1647,7 +1660,7 @@ static int new_require( lua_State *L) { int rc, i; int args = lua_gettop( L); - //char const *modname = luaL_checkstring( L, 1); + //char const* modname = luaL_checkstring( L, 1); STACK_GROW( L, args + 1); STACK_CHECK( L) diff --git a/src/tools.h b/src/tools.h index 1c9b00a..67f9874 100644 --- a/src/tools.h +++ b/src/tools.h @@ -46,13 +46,11 @@ #define luaG_isany(L,i) (!lua_isnil(L,i)) -#define luaG_typename( L, index ) lua_typename( L, lua_type(L,index) ) - typedef void (*luaG_IdFunction)( lua_State *L, char const * const which); void luaG_dump( lua_State* L ); -const char *luaG_openlibs( lua_State *L, const char *libs ); +lua_State* luaG_newstate( char const* libs, lua_CFunction _on_state_create); int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc); void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index ); -- cgit v1.2.3-55-g6feb