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
- In particular, lane handles cannot be passed between lanes.
+ - Lanes can either throw an error or attempt a light userdata demotion.
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