From 974aa4343cf900938b5d357d10798d91faf60f5a Mon Sep 17 00:00:00 2001
From: Benoit Germain
Date: Mon, 21 Feb 2011 20:33:39 +0100
Subject: Make the number of internal keeper states selectable by an optional
parameter passed to require.
---
CHANGES | 11 +++++++----
docs/index.html | 41 ++++++++++++++++++++++++++++++++---------
src/keeper.c | 39 +++++++++++++++++++--------------------
src/keeper.h | 2 +-
src/lanes.c | 33 +++++++++++----------------------
src/lanes.lua | 2 +-
6 files changed, 71 insertions(+), 57 deletions(-)
diff --git a/CHANGES b/CHANGES
index 1850415..bc0368a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,9 +3,12 @@ CHANGES:
CHANGE X:
+CHANGE 29 BGe 21-Feb-2011
+ Make the number of internal keeper states selectable by an optional parameter passed to require.
+
CHANGE 28 BGe 18-Feb-2011
- - moved keeper-related code in a separate source file
- - keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility
+ Moved keeper-related code in a separate source file
+ keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility
CHANGE 27 BGe 17-Feb-2011
- we know Lanes is loaded in the master state, so we don't force it
@@ -26,7 +29,7 @@ CHANGE 26 BGe 14-Feb-2011:
inter-state data copy for unsupported types
CHANGE 25 BGe 12-Feb-2011:
- Changed idfunc signature and contract to clarify that fact it is not lua-callable
+ Changed idfunc signature and contract to clarify the fact it is not lua-callable
and to be able to require the module it was exported from in the target lanes
CHANGE 24 DPtr 25-Jan-2011:
@@ -56,7 +59,7 @@ CHANGE 19 BGe 2-Dec-2010:
CHANGE 18 BGe 6-Oct-2010:
Fixed 'memory leak' in some situations where a free running lane is collected before application shutdown
- A bit of code cleanup
+ A bit of code cleanup
CHANGE 17 BGe 21-Sept-2010:
Fixed stupid compilation errors.
diff --git a/docs/index.html b/docs/index.html
index a28dd41..3d2ecf2 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -56,7 +56,7 @@
Copyright © 2007-11 Asko Kauppi. All rights reserved.
Lua Lanes is published under the same MIT license as Lua 5.1.
-
This document was revised on 12-Feb-11, and applies to version 2.0.11.
+
This document was revised on 21-Feb-11, and applies to version 2.1.0.
@@ -817,12 +817,12 @@ can be used for custom userdata as well. Here's what to do.
"delete": receives this same pointer on the stack, and should cleanup the object.
"metatable": should build a metatable for the object. Don't cache the metatable
-yourself, Lanes takes care of it ("metatable" should only be invoked once).
+ yourself, Lanes takes care of it ("metatable" should only be invoked once).
"module": is the name of the module that exports the idfunc,
-to be pushed on the stack as a string. It is necessary so that Lanes can require it in
-any Lane and keeper state that receives a userdata. This is to prevent crashes in situations
-where the module could be unloaded while the idfunc pointer is still held.
+ to be pushed on the stack as a string. It is necessary so that Lanes can require it in
+ any Lane and keeper state that receives a userdata. This is to prevent crashes in situations
+ where the module could be unloaded while the idfunc pointer is still held.
Take a look at linda_id in lanes.c.
@@ -917,10 +917,10 @@ Here are some things one should consider, if best performance is vital:
merged into one main timer state (see timer.lua); no OS side
timers are utilized.
- Lindas are hashed to a fixed number of "keeper states", which are a locking entity.
- If you are using a lot of Linda objects,
- it may be useful to try having more of these keeper states. By default,
- only one is used (see KEEPER_STATES_N), but this is an implementation detail.
+ Lindas are hashed to a number of "keeper states", which are a locking entity.
+ If you are using a lot of Linda objects, it may be useful to try having more of
+ these keeper states. By default, only one is used but this is an implementation detail.
+ It is possible to require( "lanes", N) to use more keeper states.
@@ -952,6 +952,29 @@ its actual value.
Change log
+Feb-2011 (2.1.0)
+
+ - Added an auto-require mechanism to ensure any deep userdata transiting in a lane causes its parent module to be required in that lane
+
+ - Changed idfunc signature and contract to clarify the fact it is not lua-callable and to be able to require the module it was exported from in the target lanes
+ - When a deep userdata idfunc requests a module to be required, manually check that it is not loaded before requiring it instead of relying on the require function's loop detection feature
+ - When a module must be required, raise an error if the 'require' function is not found in the target state
+ - We know Lanes is loaded in the master state, so we don't force it to be required in every lane too when a linda deep userdata is copied
+
+
+ - Fixed application hang-up because keeper state was not released in case of errors thrown by inter-state data copy for unsupported types
+ - Refactor lane proxy implementation: it is now a full userdata instead of a table, and its methods are implemented in C instead of Lua
+
+ - its metatable is no longer accessible
+ - writing to the proxy raises an error
+ - it is no longer possible to overwrite its join() and cancel() methods
+
+
+ - Moved keeper-related code in a separate source file
+ - keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility
+ - Make the number of internal keeper states selctable by an optional parameter passed to require.
+
+
Feb-2011 (2.0.11):
- Fixed bug where reference to Linda object was dropped for a short time (crashing if GC was run during that time).
diff --git a/src/keeper.c b/src/keeper.c
index f19beed..f89c638 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -53,12 +53,6 @@
/*---=== Keeper states ===---
*/
-/* The selected number is not optimal; needs to be tested. Even using just
-* one keeper state may be good enough (depends on the number of Lindas used
-* in the applications).
-*/
-#define KEEPER_STATES_N 1 // 6
-
/*
* Pool of keeper states
*
@@ -66,12 +60,8 @@
* bigger the pool, the less chances of unnecessary waits. Lindas map to the
* keepers randomly, by a hash.
*/
-static struct s_Keeper GKeepers[KEEPER_STATES_N];
-
-/* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
-* checking for a lightuserdata is faster.
-*/
-static bool_t nil_sentinel = 0;
+static struct s_Keeper *GKeepers = NULL;
+static int GNbKeepers = 0;
/*
* Lua code for the keeper states (baked in)
@@ -88,10 +78,13 @@ static char const keeper_chunk[]=
* unclosed, because it does not really matter. In production code, this
* function never fails.
*/
-const char *init_keepers(void)
+char const *init_keepers( int const _nbKeepers)
{
- unsigned int i;
- for( i=0; i= 1);
+ GNbKeepers = _nbKeepers;
+ GKeepers = malloc( _nbKeepers * sizeof( struct s_Keeper));
+ for( i = 0; i < _nbKeepers; ++ i)
{
// Initialize Keeper states with bare minimum of libs (those required
@@ -104,8 +97,11 @@ const char *init_keepers(void)
luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs
serialize_require( L);
- lua_pushlightuserdata( L, &nil_sentinel );
- lua_setglobal( L, "nil_sentinel" );
+ /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
+ * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global of ours)
+ */
+ lua_pushlightuserdata( L, &GNbKeepers);
+ lua_setglobal( L, "nil_sentinel");
// Read in the preloaded chunk (and run it)
//
@@ -131,12 +127,12 @@ const char *init_keepers(void)
struct s_Keeper *keeper_acquire( const void *ptr)
{
/*
- * Any hashing will do that maps pointers to 0..KEEPER_STATES_N-1
+ * Any hashing will do that maps pointers to 0..GNbKeepers-1
* consistently.
*
* Pointers are often aligned by 8 or so - ignore the low order bits
*/
- unsigned int i= ((unsigned long)(ptr) >> 3) % KEEPER_STATES_N;
+ unsigned int i= ((unsigned long)(ptr) >> 3) % GNbKeepers;
struct s_Keeper *K= &GKeepers[i];
MUTEX_LOCK( &K->lock_);
@@ -190,10 +186,13 @@ int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda,
void close_keepers(void)
{
int i;
- for(i=0;i 0, 2, "Number of keeper states must be > 0");
/*
* Making one-time initializations.
*
@@ -2010,7 +2000,6 @@ __declspec(dllexport)
* there is no problem. But if the host is multithreaded, we need to lock around the
* initializations.
*/
- static volatile int /*bool*/ go_ahead; // = 0
#ifdef PLATFORM_WIN32
{
// TBD: Someone please replace this with reliable Win32 API code. Problem is,
@@ -2022,7 +2011,7 @@ __declspec(dllexport)
static volatile unsigned my_number; // = 0
if (my_number++ == 0) { // almost atomic
- init_once_LOCKED(L, &timer_deep);
+ init_once_LOCKED(L, &timer_deep, nbKeepers);
go_ahead= 1; // let others pass
} else {
while( !go_ahead ) { Sleep(1); } // changes threads
@@ -2036,7 +2025,7 @@ __declspec(dllexport)
// Recheck now that we're within the lock
//
if (!go_ahead) {
- init_once_LOCKED(L, &timer_deep);
+ init_once_LOCKED(L, &timer_deep, nbKeepers);
go_ahead= 1;
}
}
diff --git a/src/lanes.lua b/src/lanes.lua
index 95bdeeb..78582f9 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -52,7 +52,6 @@ local _version= assert(mm._version)
local now_secs= assert( mm.now_secs )
local wakeup_conv= assert( mm.wakeup_conv )
-local timer_gateway= assert( mm.timer_gateway )
local max_prio= assert( mm.max_prio )
@@ -239,6 +238,7 @@ linda = mm.linda
---=== Timers ===---
+local timer_gateway= assert( mm.timer_gateway )
--
-- On first 'require "lanes"', a timer lane is spawned that will maintain
-- timer tables and sleep in between the timer events. All interaction with
--
cgit v1.2.3-55-g6feb