From 95c696cffe7bf16e27d6d766750c96a38dd23b32 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Fri, 20 Dec 2013 11:47:38 +0100 Subject: fixed a shutdown crash * fixed a crash that can occur at shutdown when an object stored inside a keeper state performs a linda operation on a linda making use of another keeper * bumped version to 3.7.5 --- CHANGES | 5 +++++ docs/index.html | 32 +++++++++++++++++++++++--------- src/keeper.c | 16 ++++++++++------ src/lanes.c | 25 ++++++++++++++++--------- 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/CHANGES b/CHANGES index 2e6838e..c196455 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,10 @@ CHANGES: +CHANGE 87: BGe 20-Dec-13 + * version 3.7.5 + * fixed a crash that can occur at shutdown when an object stored inside a keeper state performs a linda operation on a linda making use of another keeper + * new setting demote_full_userdata to select between light userdata demotion or raising an error when attempting to transfer a non-deep full userdata + CHANGE 86: BGe 3-Dec-13 * version 3.7.4 * internal refactoring of pthread priority management code diff --git a/docs/index.html b/docs/index.html index af08397..f25463d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -70,7 +70,7 @@

- This document was revised on 3-Dec-13, and applies to version 3.7.4. + This document was revised on 20-Dec-13, and applies to version 3.7.5.

@@ -273,7 +273,7 @@ definition - + .nb_keepers integer >= 1 @@ -283,7 +283,7 @@ - + .with_timers @@ -296,7 +296,7 @@ - + .verbose_errors @@ -309,7 +309,7 @@ - + .protect_allocator @@ -321,6 +321,19 @@ + + + .demote_full_userdata + + + nil/false/true + + + (Since v3.7.5) If equal to false or nil, Lanes raises an error when attempting to transfer a non-deep full userdata, else it will be demoted to a light userdata in the destination. + Default is false (set to true to get the legacy behaviour). + + + .track_lanes @@ -335,7 +348,7 @@ - + .on_state_create @@ -354,8 +367,8 @@ - - .shutdown_timeout
+ + .shutdown_timeout number >= 0 @@ -1133,7 +1146,7 @@ events to a common Linda, but... :).

- Timers are implemented as a lane. They can be disabled by setting "with_timers" to nil or false to lanes.configure(). + Timers are implemented as a lane. They can be disabled by setting "with_timers" to nil or false to lanes.configure().

@@ -1289,6 +1302,7 @@ events to a common Linda, but... :). Full userdata can be passed only if it's prepared using the deep userdata system, which handles its lifespan management

  • Coroutines cannot be passed. A coroutine's Lua state is tied to the Lua state that created it, and there is no way the mixed C/Lua stack of a coroutine can be transfered from one Lua state to another.
  • diff --git a/src/keeper.c b/src/keeper.c index 99f510b..4c90069 100644 --- a/src/keeper.c +++ b/src/keeper.c @@ -184,7 +184,8 @@ static void push_table( lua_State* L, int idx) int keeper_push_linda_storage( lua_State* L, void* ptr) { struct s_Keeper* K = keeper_acquire( ptr); - lua_State* KL = K->L; + lua_State* KL = K ? K->L : NULL; + if( KL == NULL) return 0; STACK_CHECK( KL); lua_pushlightuserdata( KL, fifos_key); // fifos_key lua_rawget( KL, LUA_REGISTRYINDEX); // fifos @@ -535,14 +536,18 @@ void close_keepers( void) #endif // HAVE_KEEPER_ATEXIT_DESINIT { int i; - // 2-pass close, in case a keeper holds a reference to a linda bound to another keeoer - for( i = 0; i < GNbKeepers; ++ i) + int const nbKeepers = GNbKeepers; + // NOTE: imagine some keeper state N+1 currently holds a linda that uses another keeper N, and a _gc that will make use of it + // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists + // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success + GNbKeepers = 0; + for( i = 0; i < nbKeepers; ++ i) { lua_State* L = GKeepers[i].L; GKeepers[i].L = NULL; lua_close( L); } - for( i = 0; i < GNbKeepers; ++ i) + for( i = 0; i < nbKeepers; ++ i) { MUTEX_FREE( &GKeepers[i].lock_); } @@ -551,7 +556,6 @@ void close_keepers( void) free( GKeepers); } GKeepers = NULL; - GNbKeepers = 0; } /* @@ -626,7 +630,7 @@ struct s_Keeper* keeper_acquire( void const* ptr) * have to cast to unsigned long to avoid compilation warnings about loss of data when converting pointer-to-integer */ unsigned int i = (unsigned int)(((unsigned long)(ptr) >> 3) % GNbKeepers); - struct s_Keeper *K= &GKeepers[i]; + struct s_Keeper* K= &GKeepers[i]; MUTEX_LOCK( &K->lock_); //++ K->count; diff --git a/src/lanes.c b/src/lanes.c index 6621735..e66342d 100644 --- a/src/lanes.c +++ b/src/lanes.c @@ -52,7 +52,7 @@ * ... */ -char const* VERSION = "3.7.4"; +char const* VERSION = "3.7.5"; /* =============================================================================== @@ -420,7 +420,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' + lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' + if( KL == NULL) return 0; STACK_CHECK( KL); for( ;;) { @@ -584,6 +585,7 @@ LUAG_FUNC( linda_receive) { struct s_Keeper *K = keeper_acquire( linda); + if( K == NULL) return 0; for( ;;) { // all arguments of receive() but the first are passed to the keeper's receive function @@ -690,6 +692,7 @@ LUAG_FUNC( linda_set) { int pushed; struct s_Keeper *K = keeper_acquire( linda); + if( K == NULL) return 0; // no nil->sentinel toggling, we really clear the linda contents for the given key with a set() pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); if( pushed >= 0) // no error? @@ -722,7 +725,7 @@ LUAG_FUNC( linda_set) */ LUAG_FUNC( linda_count) { - struct s_Linda *linda= lua_toLinda( L, 1); + struct s_Linda* linda = lua_toLinda( L, 1); int pushed; luaL_argcheck( L, linda, 1, "expected a linda object!"); @@ -730,7 +733,8 @@ LUAG_FUNC( linda_count) check_key_types( L, 2, lua_gettop( L)); { - struct s_Keeper *K = keeper_acquire( linda); + struct s_Keeper* K = keeper_acquire( linda); + if( K == NULL) return 0; pushed = keeper_call( K->L, KEEPER_API( count), L, linda, 2); keeper_release( K); if( pushed < 0) @@ -758,14 +762,15 @@ LUAG_FUNC( linda_get) check_key_types( L, 2, 2); { - struct s_Keeper *K = keeper_acquire( linda); + struct s_Keeper* K = keeper_acquire( linda); + if( K == NULL) return 0; pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); - ASSERT_L( pushed==0 || pushed==1 ); + ASSERT_L( pushed == 0 || pushed == 1); if( pushed > 0) { keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0); } - keeper_release(K); + keeper_release( K); // must trigger error after keeper state has been released if( pushed < 0) { @@ -784,7 +789,8 @@ LUAG_FUNC( linda_get) */ LUAG_FUNC( linda_limit) { - struct s_Linda* linda= lua_toLinda( L, 1 ); + struct s_Linda* linda= lua_toLinda( L, 1); + int pushed; luaL_argcheck( L, linda, 1, "expected a linda object!"); // make sure we got a key and a limit @@ -796,7 +802,8 @@ LUAG_FUNC( linda_limit) { struct s_Keeper* K = keeper_acquire( linda); - int pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); + if( K == NULL) return 0; + pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); ASSERT_L( pushed <= 0); // either error or no return values keeper_release( K); // must trigger error after keeper state has been released -- cgit v1.2.3-55-g6feb