From 623a8f48a624510a0461b0893da647e22e08cdd7 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Fri, 27 Sep 2013 20:34:51 +0200 Subject: version 3.6.6 no longer call core.configure with dummy params when requiring lanes more than once (fixes potential multithreading issues with LuaJIT allocator) activated EnableCrashingOnCrashes() Win32 debug builds fixed some comments in code --- src/keeper.c | 2 - src/lanes.c | 120 ++++++++++++++++++++++++++-------------------------------- src/lanes.lua | 19 ++++------ src/tools.c | 8 ++-- 4 files changed, 64 insertions(+), 85 deletions(-) (limited to 'src') diff --git a/src/keeper.c b/src/keeper.c index 8d9f7ec..bd232cd 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -572,8 +572,6 @@ char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepe lua_State* K; DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d BEGIN\n" INDENT_END, i)); DEBUGSPEW_CODE( ++ debugspew_indent_depth); - // We need to load all base libraries in the keeper states so that the transfer databases are populated properly - // // we don't need any libs in the keeper states K = luaG_newstate( L, _on_state_create, NULL); diff --git a/src/lanes.c b/src/lanes.c index dc1eeed..f4427a4 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -52,7 +52,7 @@ * ... */ -char const* VERSION = "3.6.5"; +char const* VERSION = "3.6.6"; /* =============================================================================== @@ -414,8 +414,8 @@ LUAG_FUNC( linda_send) STACK_GROW(L, 1); { - struct s_Keeper *K = keeper_acquire( linda); - lua_State *KL = K->L; // need to do this for 'STACK_CHECK' + struct s_Keeper* K = keeper_acquire( linda); + lua_State* KL = K->L; // need to do this for 'STACK_CHECK' STACK_CHECK( KL); for( ;;) { @@ -2734,7 +2734,6 @@ LUAG_FUNC( configure) char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); // all parameter checks are done lua-side int const nbKeepers = (int)lua_tointeger( L, 1); - // all these can be nil when lanes.core is required internally! (but are only processed at first init anyway) int const on_state_create = lua_isfunction( L, 2) ? 2 : 0; lua_Number shutdown_timeout = lua_tonumber( L, 3); bool_t track_lanes = lua_toboolean( L, 4); @@ -2759,6 +2758,45 @@ LUAG_FUNC( configure) lua_setallocf( L, protected_lua_Alloc, s); } } + STACK_MID( L, 0); + + /* + ** Making one-time initializations. + ** + ** When the host application is single-threaded (and all threading happens via Lanes) + ** there is no problem. But if the host is multithreaded, we need to lock around the + ** initializations. + */ +#if THREADAPI == THREADAPI_WINDOWS + { + static volatile int /*bool*/ go_ahead; // = 0 + if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) + { + init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); + go_ahead = 1; // let others pass + } + else + { + while( !go_ahead) { Sleep(1); } // changes threads + } + } +#else // THREADAPI == THREADAPI_PTHREAD + if( s_initCount == 0) + { + static pthread_mutex_t my_lock = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock( &my_lock); + { + // Recheck now that we're within the lock + // + if( s_initCount == 0) + { + init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); + s_initCount = 1; + } + } + pthread_mutex_unlock( &my_lock); + } +#endif // THREADAPI == THREADAPI_PTHREAD // Create main module interface table lua_pushvalue( L, lua_upvalueindex( 2)); // ... M @@ -2818,49 +2856,7 @@ LUAG_FUNC( configure) populate_func_lookup_table( L, -1, NULL); lua_pop( L, 1); // ... M - STACK_MID( L, 1); - /* - ** Making one-time initializations. - ** - ** When the host application is single-threaded (and all threading happens via Lanes) - ** there is no problem. But if the host is multithreaded, we need to lock around the - ** initializations. - ** we must do this after the populate_func_lookup_table is called, else populating the keepers will fail - ** because this makes a copy of packages.loaders, which requires the lookup tables to exist! - */ -#if THREADAPI == THREADAPI_WINDOWS - { - static volatile int /*bool*/ go_ahead; // = 0 - if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) - { - init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); - go_ahead = 1; // let others pass - } - else - { - while( !go_ahead ) { Sleep(1); } // changes threads - } - } -#else // THREADAPI == THREADAPI_PTHREAD - if( s_initCount == 0) - { - static pthread_mutex_t my_lock = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock( &my_lock); - { - // Recheck now that we're within the lock - // - if( s_initCount == 0) - { - init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); - s_initCount = 1; - } - } - pthread_mutex_unlock( &my_lock); - } -#endif // THREADAPI == THREADAPI_PTHREAD - STACK_MID( L, 1); - - assert( timer_deep != NULL); + ASSERT_L( timer_deep != NULL); // init_once_LOCKED initializes timer_deep, so we must do this after, of course luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // ... M timer_deep lua_setfield( L, -2, "timer_gateway"); // ... M @@ -2875,9 +2871,9 @@ LUAG_FUNC( configure) // helper to have correct callstacks when crashing a Win32 running on 64 bits Windows // don't forget to toggle Debug/Exceptions/Win32 in visual Studio too! -void EnableCrashingOnCrashes() +static void EnableCrashingOnCrashes( void) { -#if 0 && defined PLATFORM_WIN32 +#if defined PLATFORM_WIN32 && !defined NDEBUG typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); const DWORD EXCEPTION_SWALLOWING = 0x1; @@ -2885,13 +2881,13 @@ void EnableCrashingOnCrashes() HMODULE kernel32 = LoadLibraryA("kernel32.dll"); tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy"); tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy"); - if (pGetPolicy && pSetPolicy) + if( pGetPolicy && pSetPolicy) { DWORD dwFlags; - if (pGetPolicy(&dwFlags)) + if( pGetPolicy( &dwFlags)) { // Turn off the filter - pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); + pSetPolicy( dwFlags & ~EXCEPTION_SWALLOWING); } } #endif // PLATFORM_WIN32 @@ -2906,21 +2902,11 @@ int LANES_API luaopen_lanes_core( lua_State* L) // Create main module interface table // we only have 1 closure, which must be called to configure Lanes - 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"); // M - } - else // already initialized: call it immediately and be done - { - // 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 - } + 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() + lua_setfield( L, -2, "configure"); // M STACK_END( L, 1); return 1; diff --git a/src/lanes.lua b/src/lanes.lua index 175002a..173db00 100644 --- a/src/lanes.lua +++ b/src/lanes.lua @@ -145,23 +145,18 @@ lanes.configure = function( _params) local core = require "lanes.core" assert( type( core)=="table") - - -- configure() is available only the first time lanes.core is required process-wide, and we *must* call it to have the other functions in the interface - if core.configure then core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator, _params.verbose_errors) end - + core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator, _params.verbose_errors) local thread_new = assert( core.thread_new) - local set_singlethreaded = assert( core.set_singlethreaded) - local max_prio = assert( core.max_prio) -lanes.ABOUT= +lanes.ABOUT = { - author= "Asko Kauppi , Benoit Germain ", - description= "Running multiple Lua states in parallel", - license= "MIT/X11", - copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-12, Benoit Germain", - version = assert( core.version) + author= "Asko Kauppi , Benoit Germain ", + description= "Running multiple Lua states in parallel", + license= "MIT/X11", + copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-13, Benoit Germain", + version = assert( core.version) } diff --git a/src/tools.c b/src/tools.c index a957f41..49194d0 100644 --- a/src/tools.c +++ b/src/tools.c @@ -1461,12 +1461,12 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLoo { char const* fqn; // L // L2 size_t len; - _ASSERT_L( L, lua_isfunction( L, i)); // ... f ... + ASSERT_L( lua_isfunction( L, i)); // ... f ... STACK_CHECK( L); if( mode_ == eLM_FromKeeper) { lua_CFunction f = lua_tocfunction( L, i); // should *always* be sentinelfunc! - _ASSERT_L( L, f == sentinelfunc); + ASSERT_L( f == sentinelfunc); lua_getupvalue( L, i, 1); // ... f ... "f.q.n" fqn = lua_tolstring( L, -1, &len); } @@ -1474,7 +1474,7 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLoo { // fetch the name from the source state's lookup table lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {} - _ASSERT_L( L, lua_istable( L, -1)); + ASSERT_L( lua_istable( L, -1)); lua_pushvalue( L, i); // ... f ... {} f lua_rawget( L, -2); // ... f ... {} "f.q.n" fqn = lua_tolstring( L, -1, &len); @@ -1521,7 +1521,7 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLoo else { lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} - _ASSERT_L( L2, lua_istable( L2, -1)); + ASSERT_L( lua_istable( L2, -1)); lua_pushlstring( L2, fqn, len); // {} "f.q.n" lua_rawget( L2, -2); // {} f if( !lua_isfunction( L2, -1)) -- cgit v1.2.3-55-g6feb