From 44540b9335f3bbd2f6fda3e13329b28ec76b6d7a Mon Sep 17 00:00:00 2001
From: Benoit Germain
Date: Fri, 11 Oct 2013 20:08:32 +0200
Subject: version 3.7.0
* fix lanes.threads() not being available in a lane where
lanes.configure() settings didn't contain track_lanes although the
initial configure() call did.
* require "lanes".configure() sequence is only necessary at the first
require "lanes".
* fix a crash at application shutdown where in some situations we could
deinitialize the protected allocator mutex while a lane was still using
it.
* fix timers broken by change 69
---
CHANGES | 15 ++-
docs/index.html | 14 +--
src/keeper.c | 46 ++++++---
src/keeper.h | 2 +-
src/lanes.c | 251 ++++++++++++++++++++++++++--------------------
src/lanes.lua | 72 ++++++-------
src/threading.c | 5 +-
src/threading.h | 2 +-
src/tools.c | 96 ++++++++++++------
src/tools.h | 12 ++-
tests/fibonacci.lua | 5 +-
tests/irayo_recursive.lua | 6 +-
tests/recursive.lua | 6 +-
13 files changed, 319 insertions(+), 213 deletions(-)
diff --git a/CHANGES b/CHANGES
index 5a42777..8a4e9e2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,19 @@
CHANGES:
-CHANGE 72: BGe 3-Ost-13
+CHANGE 76: BGe 10-Oct-13
+ * version 3.7.0
+ * fix lanes.threads() not being available in a lane where lanes.configure() settings didn't contain track_lanes although the initial configure() call did.
+
+CHANGE 75: BGe 7-Oct-13
+ * require "lanes".configure() sequence is only necessary at the first require "lanes".
+
+CHANGE 74: BGe 7-Oct-13
+ * fix a crash at application shutdown where in some situations we could deinitialize the protected allocator mutex while a lane was still using it.
+
+CHANGE 73: BGe 4-Oct-13
+ * fix timers broken by change 69
+
+CHANGE 72: BGe 3-Oct-13
* bugfix: no longer create a global named "lanes.core" inside lanes having "*" as library list
CHANGE 71: BGe 30-Sept-13
diff --git a/docs/index.html b/docs/index.html
index eda1758..20a5c3f 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -70,7 +70,7 @@
- This document was revised on 27-Sept-13, and applies to version 3.6.6.
+ This document was revised on 11-Oct-13, and applies to version 3.7.0.
@@ -248,7 +248,10 @@
After lanes is required, it is necessary to call lanes.configure(), which is the only function exposed by the module at this point. Calling configure() will perform one-time initializations and make the rest of the API available.
- At the same time, configure() itself will be replaced by another function that raises an error if called again with differing arguments.
+ At the same time, configure() itself will be replaced by another function that raises an error if called again with differing arguments, if any.
+
+
+ IMPORTANT NOTE: Starting with version 3.7.0, only the first occurence of require "lanes" must be followed by a call to .configure(). From this point, a simple require "lanes" will do wherever you need to require lanes again.
@@ -326,7 +329,8 @@
nil/false/anything
- Any non-nil|false value instructs Lanes keeps track of all lanes, so that lanes.threads() can list them.
+ Any non-nil|false value instructs Lanes keeps track of all lanes, so that lanes.threads() can list them. If false, lanes.threads() will raise an error when called.
+ Default is false.
|
@@ -364,9 +368,7 @@
- NEW (version 3.5.0)
-
- Once Lanes is configured, one should register with Lanes the modules exporting functions that will be transferred either during lane generation or through lindas.
+ (Since v3.5.0) Once Lanes is configured, one should register with Lanes the modules exporting functions that will be transferred either during lane generation or through lindas.
Use lanes.require() for this purpose. This will call the original require(), then add the result to the lookup databases.
diff --git a/src/keeper.c b/src/keeper.c
index bd232cd..c9b2039 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -70,7 +70,7 @@ typedef struct
static keeper_fifo* prepare_fifo_access( lua_State* L, int idx)
{
keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx);
- if( fifo)
+ if( fifo != NULL)
{
idx = lua_absindex( L, idx);
STACK_GROW( L, 1);
@@ -286,15 +286,15 @@ int keepercall_receive( lua_State* L)
{
int top = lua_gettop( L);
int i;
- keeper_fifo* fifo;
push_table( L, 1); // ud keys fifos
lua_replace( L, 1); // fifos keys
for( i = 2; i <= top; ++ i)
{
+ keeper_fifo* fifo;
lua_pushvalue( L, i); // fifos keys key[i]
lua_rawget( L, 1); // fifos keys fifo
fifo = prepare_fifo_access( L, -1); // fifos keys fifo
- if( fifo && fifo->count > 0)
+ if( fifo != NULL && fifo->count > 0)
{
fifo_pop( L, fifo, 1); // fifos keys val
if( !lua_isnil( L, -1))
@@ -332,7 +332,7 @@ int keepercall_receive_batched( lua_State* L)
lua_rawget( L, 2); // key fifos fifo
lua_remove( L, 2); // key fifo
fifo = prepare_fifo_access( L, 2); // key fifo
- if( fifo && fifo->count >= min_count)
+ if( fifo != NULL && fifo->count >= min_count)
{
fifo_pop( L, fifo, __min( max_count, fifo->count)); // key ...
}
@@ -360,7 +360,7 @@ int keepercall_limit( lua_State* L)
lua_pushvalue( L, -1); // fifos key key
lua_rawget( L, -3); // fifos key fifo
fifo = (keeper_fifo*) lua_touserdata( L, -1);
- if( !fifo)
+ if( fifo == NULL)
{
lua_pop( L, 1); // fifos key
fifo_new( L); // fifos key fifo
@@ -437,7 +437,7 @@ int keepercall_get( lua_State* L)
lua_replace( L, 1); // fifos key
lua_rawget( L, 1); // fifos fifo
fifo = prepare_fifo_access( L, -1); // fifos fifo
- if( fifo && fifo->count > 0)
+ if( fifo != NULL && fifo->count > 0)
{
lua_remove( L, 1); // fifo
// read one value off the fifo
@@ -497,7 +497,7 @@ int keepercall_count( lua_State* L)
lua_rawget( L, 2); // out fifos keys fifo
fifo = prepare_fifo_access( L, -1); // out fifos keys fifo
lua_pop( L, 1); // out fifos keys
- if( fifo)
+ if( fifo != NULL)
{
lua_pushinteger( L, fifo->count); // out fifos keys count
lua_rawset( L, 1); // out fifos keys
@@ -540,14 +540,17 @@ void close_keepers( void)
for( i = 0; i < GNbKeepers; ++ i)
{
lua_State* L = GKeepers[i].L;
- GKeepers[i].L = 0;
+ GKeepers[i].L = NULL;
lua_close( L);
}
for( i = 0; i < GNbKeepers; ++ i)
{
MUTEX_FREE( &GKeepers[i].lock_);
}
- if( GKeepers) free( GKeepers);
+ if( GKeepers != NULL)
+ {
+ free( GKeepers);
+ }
GKeepers = NULL;
GNbKeepers = 0;
}
@@ -560,20 +563,29 @@ void close_keepers( void)
* Note: Any problems would be design flaws; the created Lua state is left
* unclosed, because it does not really matter. In production code, this
* function never fails.
+* settings table is at position 1 on the stack
*/
-char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers)
+char const* init_keepers( lua_State* L)
{
- int i;
- assert( _nbKeepers >= 1);
- GNbKeepers = _nbKeepers;
- GKeepers = malloc( _nbKeepers * sizeof( struct s_Keeper));
- for( i = 0; i < _nbKeepers; ++ i)
+ int i, on_state_create;
+ STACK_CHECK( L);
+ lua_getfield( L, 1, "nb_keepers");
+ GNbKeepers = lua_tointeger( L, -1);
+ lua_pop( L, 1);
+ STACK_MID( L, 0);
+ assert( GNbKeepers >= 1);
+
+ lua_getfield( L, 1, "on_state_create");
+ on_state_create = lua_isnil( L, -1) ? -1 : lua_absindex( L, -1);
+
+ GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper));
+ for( i = 0; i < GNbKeepers; ++ i)
{
lua_State* K;
DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d BEGIN\n" INDENT_END, i));
DEBUGSPEW_CODE( ++ debugspew_indent_depth);
// we don't need any libs in the keeper states
- K = luaG_newstate( L, _on_state_create, NULL);
+ K = luaG_newstate( L, on_state_create, NULL);
STACK_CHECK( K);
@@ -596,6 +608,8 @@ char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepe
GKeepers[i].L = K;
//GKeepers[i].count = 0;
}
+ lua_pop( L, 1);
+ STACK_END( L, 0);
#if HAVE_KEEPER_ATEXIT_DESINIT
atexit( atexit_close_keepers);
#endif // HAVE_KEEPER_ATEXIT_DESINIT
diff --git a/src/keeper.h b/src/keeper.h
index 420eca1..2ef443d 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -13,7 +13,7 @@ struct s_Keeper
// problem: maybe on some platforms (linux) atexit() is called after DLL/so are unloaded...
#define HAVE_KEEPER_ATEXIT_DESINIT 0
-char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers);
+char const* init_keepers( lua_State* L);
#if !HAVE_KEEPER_ATEXIT_DESINIT
void close_keepers( void);
#endif // HAVE_KEEPER_ATEXIT_DESINIT
diff --git a/src/lanes.c b/src/lanes.c
index 5ccc05a..3a3cdf0 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
* ...
*/
-char const* VERSION = "3.6.6";
+char const* VERSION = "3.7.0";
/*
===============================================================================
@@ -1932,7 +1932,7 @@ LUAG_FUNC( thread_new)
uint_t required = lua_isnoneornil( L, 8) ? 0 : 8;
#define FIXED_ARGS 8
- uint_t args= lua_gettop(L) - FIXED_ARGS;
+ uint_t args = lua_gettop(L) - FIXED_ARGS;
if( prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX)
{
@@ -2002,8 +2002,19 @@ LUAG_FUNC( thread_new)
}
else
{
+ // if is it "lanes" or "lanes.core", make sure we have copied the initial settings over
+ // which might not be the case if the libs list didn't include lanes.core or "*"
+ if( strncmp( name, "lanes.core", len) == 0) // this works both both "lanes" and "lanes.core" because of len
+ {
+ luaG_copy_one_time_settings( L, L2, name);
+ }
lua_pushlstring( L2, name, len); // require() name
- lua_pcall( L2, 1, 1, 0); // ret
+ if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode
+ {
+ // propagate error to main state if any
+ luaG_inter_move( L2, L, 1, eLM_LaneBody); //
+ return lua_error( L);
+ }
STACK_MID( L2, 1);
// after requiring the module, register the functions it exported in our name<->function database
populate_func_lookup_table( L2, -1, name);
@@ -2110,7 +2121,7 @@ LUAG_FUNC( thread_new)
ASSERT_L( s);
//memset( s, 0, sizeof(struct s_lane) );
- s->L= L2;
+ s->L = L2;
s->status= PENDING;
s->waiting_on = NULL;
s->debug_name = NULL;
@@ -2128,8 +2139,8 @@ LUAG_FUNC( thread_new)
// Set metatable for the userdata
//
- lua_pushvalue( L, lua_upvalueindex(1) );
- lua_setmetatable( L, -2 );
+ lua_pushvalue( L, lua_upvalueindex( 1));
+ lua_setmetatable( L, -2);
STACK_MID( L, 1);
// Clear environment for the userdata
@@ -2140,11 +2151,11 @@ LUAG_FUNC( thread_new)
// Place 's' in registry, for 'cancel_test()' (even if 'cs'==0 we still
// do cancel tests at pending send/receive).
//
- lua_pushlightuserdata( L2, CANCEL_TEST_KEY );
- lua_pushlightuserdata( L2, s );
- lua_rawset( L2, LUA_REGISTRYINDEX );
+ lua_pushlightuserdata( L2, CANCEL_TEST_KEY);
+ lua_pushlightuserdata( L2, s);
+ lua_rawset( L2, LUA_REGISTRYINDEX);
- if (cs)
+ if( cs)
{
lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cs );
}
@@ -2632,9 +2643,6 @@ LUAG_FUNC( wakeup_conv )
static const struct luaL_Reg lanes_functions [] = {
{"linda", LG_linda},
{"now_secs", LG_now_secs},
-#if HAVE_LANE_TRACKING
- {"threads", LG_threads},
-#endif // HAVE_LANE_TRACKING
{"wakeup_conv", LG_wakeup_conv},
{"nameof", luaG_nameof},
{"set_singlethreaded", LG_set_singlethreaded},
@@ -2644,10 +2652,18 @@ static const struct luaL_Reg lanes_functions [] = {
/*
** One-time initializations
+ * settings table it at position 1 on the stack
*/
-static void init_once_LOCKED( lua_State* L, int const _on_state_create, int const nbKeepers, lua_Number _shutdown_timeout, bool_t _track_lanes, bool_t verbose_errors)
+static void init_once_LOCKED( lua_State* L)
{
- GVerboseErrors = verbose_errors;
+ STACK_CHECK( L);
+
+ lua_getfield( L, 1, "verbose_errors");
+ GVerboseErrors = lua_toboolean( L, -1);
+ lua_pop( L, 1);
+
+ STACK_MID( L, 0);
+
#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
now_secs(); // initialize 'now_secs()' internal offset
#endif
@@ -2657,26 +2673,27 @@ static void init_once_LOCKED( lua_State* L, int const _on_state_create, int cons
#endif
#if HAVE_LANE_TRACKING
- tracking_first = _track_lanes ? TRACKING_END : NULL;
+ MUTEX_INIT( &tracking_cs);
+ lua_getfield( L, 1, "track_lanes");
+ tracking_first = lua_toboolean( L, -1) ? TRACKING_END : NULL;
+ lua_pop( L, 1);
+ STACK_MID( L, 0);
#endif // HAVE_LANE_TRACKING
// Locks for 'tools.c' inc/dec counters
//
- MUTEX_INIT( &deep_lock );
- MUTEX_INIT( &mtid_lock );
+ MUTEX_INIT( &deep_lock);
+ MUTEX_INIT( &mtid_lock);
// Serialize calls to 'require' from now on, also in the primary state
//
- MUTEX_RECURSIVE_INIT( &require_cs );
+ MUTEX_RECURSIVE_INIT( &require_cs);
serialize_require( L);
// Linked chains handling
//
- MUTEX_INIT( &selfdestruct_cs );
-#if HAVE_LANE_TRACKING
- MUTEX_INIT( &tracking_cs);
-#endif // HAVE_LANE_TRACKING
+ MUTEX_INIT( &selfdestruct_cs);
//---
// Linux needs SCHED_RR to change thread priorities, and that is only
@@ -2702,7 +2719,7 @@ static void init_once_LOCKED( lua_State* L, int const _on_state_create, int cons
#endif // LINUX_SCHED_RR
#endif // PLATFORM_LINUX
{
- char const* err = init_keepers( L, _on_state_create, nbKeepers);
+ char const* err = init_keepers( L);
if (err)
{
(void) luaL_error( L, "Unable to initialize: %s", err );
@@ -2713,40 +2730,41 @@ static void init_once_LOCKED( lua_State* L, int const _on_state_create, int cons
//
ASSERT_L( timer_deep == NULL);
- STACK_CHECK( L);
- {
- // proxy_ud= deep_userdata( idfunc )
- //
- lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes
- luaG_deep_userdata( L, linda_id);
- STACK_MID( L, 2);
- lua_remove( L, -2); // remove the name as we no longer need it
-
- ASSERT_L( lua_isuserdata(L,-1) );
+ // proxy_ud= deep_userdata( idfunc )
+ //
+ lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes
+ luaG_deep_userdata( L, linda_id);
+ STACK_MID( L, 2);
+ lua_remove( L, -2); // remove the name as we no longer need it
- // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer
- //
- timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1);
- ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep);
+ ASSERT_L( lua_isuserdata(L,-1));
- // The host Lua state must always have a reference to this Linda object in order for the timer_deep pointer to be valid.
- // So store a reference that we will never actually use.
- // at the same time, use this object as a 'desinit' marker:
- // when the main lua State is closed, this object will be GC'ed
- {
- lua_newuserdata( L, 1);
- lua_newtable( L);
- lua_pushnumber( L, _shutdown_timeout);
- lua_pushcclosure( L, selfdestruct_gc, 1);
- lua_setfield( L, -2, "__gc");
- lua_pushliteral( L, "AtExit");
- lua_setfield( L, -2, "__metatable");
- lua_setmetatable( L, -2);
- }
- lua_insert( L, -2); // Swap key with the Linda object
- lua_rawset( L, LUA_REGISTRYINDEX);
+ // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer
+ //
+ timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1);
+ ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep);
+ // The host Lua state must always have a reference to this Linda object in order for the timer_deep pointer to be valid.
+ // So store a reference that we will never actually use.
+ // at the same time, use this object as a 'desinit' marker:
+ // when the main lua State is closed, this object will be GC'ed
+ {
+ lua_newuserdata( L, 1);
+ lua_newtable( L);
+ lua_getfield( L, 1, "shutdown_timeout");
+ lua_pushcclosure( L, selfdestruct_gc, 1);
+ lua_setfield( L, -2, "__gc");
+ lua_pushliteral( L, "AtExit");
+ lua_setfield( L, -2, "__metatable");
+ lua_setmetatable( L, -2);
}
+ lua_insert( L, -2); // Swap key with the Linda object
+ lua_rawset( L, LUA_REGISTRYINDEX);
+
+ // we'll need this everytime we transfer some C function from/to this state
+ lua_newtable( L);
+ lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY);
+
STACK_END( L, 0);
}
@@ -2754,23 +2772,19 @@ static volatile long s_initCount = 0;
// upvalue 1: module name
// upvalue 2: module table
+// param 1: settings table
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);
- 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);
- bool_t protect_allocator = lua_toboolean( L, 5);
- bool_t verbose_errors = lua_toboolean( L, 6);
+ _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE);
+ STACK_CHECK( L);
DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L));
DEBUGSPEW_CODE( ++ debugspew_indent_depth);
- STACK_CHECK( L);
// not in init_once_LOCKED because we can have several hosted "master" Lua states where Lanes is require()d.
- if( protect_allocator)
+ lua_getfield( L, 1, "protect_allocator"); // settings protect_allocator
+ if( lua_toboolean( L, -1))
{
void* ud;
lua_Alloc allocf = lua_getallocf( L, &ud);
@@ -2783,6 +2797,7 @@ LUAG_FUNC( configure)
lua_setallocf( L, protected_lua_Alloc, s);
}
}
+ lua_pop( L, 1); // settings
STACK_MID( L, 0);
/*
@@ -2797,7 +2812,7 @@ LUAG_FUNC( configure)
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);
+ init_once_LOCKED( L);
go_ahead = 1; // let others pass
}
else
@@ -2815,7 +2830,7 @@ LUAG_FUNC( configure)
//
if( s_initCount == 0)
{
- init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors);
+ init_once_LOCKED( L);
s_initCount = 1;
}
}
@@ -2824,56 +2839,64 @@ LUAG_FUNC( configure)
#endif // THREADAPI == THREADAPI_PTHREAD
// Retrieve main module interface table
- lua_pushvalue( L, lua_upvalueindex( 2)); // ... M
+ lua_pushvalue( L, lua_upvalueindex( 2)); // settings M
// remove configure() (this function) from the module interface
- lua_pushnil( L); // ... M nil
- lua_setfield( L, -2, "configure"); // ... M
+ lua_pushnil( L); // settings M nil
+ lua_setfield( L, -2, "configure"); // settings M
// add functions to the module's table
luaG_registerlibfuncs( L, lanes_functions);
+#if HAVE_LANE_TRACKING
+ // register core.threads() only if settings say it should be available
+ if( tracking_first != NULL)
+ {
+ lua_pushcfunction( L, LG_threads); // settings M LG_threads()
+ lua_setfield( L, -2, "threads");
+ }
+#endif // HAVE_LANE_TRACKING
STACK_MID( L, 1);
ASSERT_L( timer_deep != NULL); // initialized by init_once_LOCKED
- luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // ... M timer_deep
- lua_setfield( L, -2, "timer_gateway"); // ... M
+ luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // settings M timer_deep
+ lua_setfield( L, -2, "timer_gateway"); // settings M
STACK_MID( L, 1);
// prepare the metatable for threads
// contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join }
//
- lua_newtable( L); // ... M mt
- lua_pushcfunction( L, LG_thread_gc); // ... M mt LG_thread_gc
- lua_setfield( L, -2, "__gc"); // ... M mt
- lua_pushcfunction( L, LG_thread_index); // ... M mt LG_thread_index
- lua_setfield( L, -2, "__index"); // ... M mt
- lua_getglobal( L, "error"); // ... M mt error
+ lua_newtable( L); // settings M mt
+ lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc
+ lua_setfield( L, -2, "__gc"); // settings M mt
+ lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index
+ lua_setfield( L, -2, "__index"); // settings M mt
+ lua_getglobal( L, "error"); // settings M mt error
ASSERT_L( lua_isfunction( L, -1));
- lua_setfield( L, -2, "cached_error"); // ... M mt
- lua_getglobal( L, "tostring"); // ... M mt tostring
+ lua_setfield( L, -2, "cached_error"); // settings M mt
+ lua_getglobal( L, "tostring"); // settings M mt tostring
ASSERT_L( lua_isfunction( L, -1));
- lua_setfield( L, -2, "cached_tostring"); // ... M mt
- lua_pushcfunction( L, LG_thread_join); // ... M mt LG_thread_join
- lua_setfield( L, -2, "join"); // ... M mt
- lua_pushcfunction( L, LG_thread_cancel); // ... M mt LG_thread_cancel
- lua_setfield( L, -2, "cancel"); // ... M mt
- lua_pushliteral( L, "Lane"); // ... M mt "Lane"
- lua_setfield( L, -2, "__metatable"); // ... M mt
+ lua_setfield( L, -2, "cached_tostring"); // settings M mt
+ lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join
+ lua_setfield( L, -2, "join"); // settings M mt
+ lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel
+ lua_setfield( L, -2, "cancel"); // settings M mt
+ lua_pushliteral( L, "Lane"); // settings M mt "Lane"
+ lua_setfield( L, -2, "__metatable"); // settings M mt
- lua_pushcclosure( L, LG_thread_new, 1); // ... M LG_thread_new
- lua_setfield(L, -2, "thread_new"); // ... M
+ lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new
+ lua_setfield(L, -2, "thread_new"); // settings M
// we can't register 'lanes.require' normally because we want to create an upvalued closure
- lua_getglobal( L, "require"); // ... M require
- lua_pushcclosure( L, LG_require, 1); // ... M lanes.require
- lua_setfield( L, -2, "require"); // ... M
+ lua_getglobal( L, "require"); // settings M require
+ lua_pushcclosure( L, LG_require, 1); // settings M lanes.require
+ lua_setfield( L, -2, "require"); // settings M
- lua_pushstring(L, VERSION); // ... M VERSION
- lua_setfield(L, -2, "version"); // ... M
+ lua_pushstring(L, VERSION); // settings M VERSION
+ lua_setfield(L, -2, "version"); // settings M
- lua_pushinteger(L, THREAD_PRIO_MAX); // ... M THREAD_PRIO_MAX
- lua_setfield(L, -2, "max_prio"); // ... M
+ lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX
+ lua_setfield(L, -2, "max_prio"); // settings M
- lua_pushlightuserdata( L, CANCEL_ERROR); // ... M CANCEL_ERROR
- lua_setfield(L, -2, "cancel_error"); // ... M
+ lua_pushlightuserdata( L, CANCEL_ERROR); // settings M CANCEL_ERROR
+ lua_setfield(L, -2, "cancel_error"); // settings M
// register all native functions found in that module in the transferable functions database
// we process it before _G because we don't want to find the module when scanning _G (this would generate longer names)
@@ -2882,14 +2905,18 @@ LUAG_FUNC( configure)
// record all existing C/JIT-fast functions
// Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
- lua_pushglobaltable( L); // ... M _G
+ lua_pushglobaltable( L); // settings M _G
populate_func_lookup_table( L, -1, NULL);
- lua_pop( L, 2); // ...
+ lua_pop( L, 1); // settings M
+ // set _R[CONFIG_REGKEY] = settings
+ lua_pushvalue( L, -2); // settings M settings
+ lua_setfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // settings M
+ lua_pop( L, 1); // settings
STACK_END( L, 0);
DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L));
DEBUGSPEW_CODE( -- debugspew_indent_depth);
- // Return nothing
- return 0;
+ // Return the settings table
+ return 1;
}
// helper to have correct callstacks when crashing a Win32 running on 64 bits Windows
@@ -2920,16 +2947,28 @@ int LANES_API luaopen_lanes_core( lua_State* L)
{
EnableCrashingOnCrashes();
- STACK_GROW( L, 3);
+ STACK_GROW( L, 4);
STACK_CHECK( 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()
- lua_setfield( L, -2, "configure"); // 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_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // M LG_configure() settings
+ if( !lua_isnil( L, -1)) // this is not the first require "lanes.core": call configure() immediately
+ {
+ lua_pushvalue( L, -1); // M LG_configure() settings settings
+ lua_setfield( L, -4, "settings"); // M LG_configure() settings
+ lua_call( L, 1, 0); // M
+ }
+ else
+ {
+ // will do nothing on first invocation, as we haven't stored settings in the registry yet
+ lua_setfield( L, -3, "settings"); // 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 01ca181..0e27ea6 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -35,13 +35,15 @@ THE SOFTWARE.
===============================================================================
]]--
+local core = require "lanes.core"
-- Lua 5.1: module() creates a global variable
-- Lua 5.2: module() is gone
-- almost everything module() does is done by require() anyway
-- -> simply create a table, populate it, return it, and be done
local lanes = {}
-lanes.configure = function( _params)
+-- this function is available in the public interface until it is called, after which it disappears
+lanes.configure = function( settings_)
-- This check is for sublanes requiring Lanes
--
@@ -68,7 +70,7 @@ lanes.configure = function( _params)
on_state_create = nil,
shutdown_timeout = 0.25,
with_timers = true,
- track_lanes = nil,
+ track_lanes = false,
verbose_errors = false,
-- LuaJIT provides a thread-unsafe allocator by default, so we need to protect it when used in parallel lanes
protect_allocator = (jit and jit.version) and true or false
@@ -117,35 +119,32 @@ lanes.configure = function( _params)
end
}
- local params_checker = function( _params)
- if not _params then
+ local params_checker = function( settings_)
+ if not settings_ then
return default_params
end
- if type( _params) ~= "table" then
- error( "Bad parameter #1 to lanes.configure(), should be a table")
+ -- make a copy of the table to leave the provided one unchanged, *and* to help ensure it won't change behind our back
+ local settings = {}
+ if type( settings_) ~= "table" then
+ error "Bad parameter #1 to lanes.configure(), should be a table"
end
-- any setting not present in the provided parameters takes the default value
- for key, value in pairs( default_params) do
- local my_param = _params[key]
+ for key, checker in pairs( param_checkers) do
+ local my_param = settings_[key]
local param
if my_param ~= nil then
param = my_param
else
param = default_params[key]
end
- if not param_checkers[key]( param) then
+ if not checker( param) then
error( "Bad " .. key .. ": " .. tostring( param), 2)
end
- _params[key] = param
+ settings[key] = param
end
- return _params
+ return settings
end
-
- _params = params_checker( _params)
-
- local core = require "lanes.core"
- assert( type( core)=="table")
- core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator, _params.verbose_errors)
+ local settings = core.configure and core.configure( params_checker( settings_)) or core.settings
local thread_new = assert( core.thread_new)
local set_singlethreaded = assert( core.set_singlethreaded)
local max_prio = assert( core.max_prio)
@@ -316,8 +315,8 @@ local function gen( ... )
-- Lane generator
--
return function(...)
- return thread_new( func, libs, _params.on_state_create, cs, prio, g_tbl, package_tbl, required, ...) -- args
- end
+ return thread_new( func, libs, settings.on_state_create, cs, prio, g_tbl, package_tbl, required, ...) -- args
+ end
end
---=== Lindas ===---
@@ -338,7 +337,7 @@ local timer = function() error "timers are not active" end
local timer_lane = nil
local timers = timer
-if _params.with_timers ~= false then
+if settings.with_timers ~= false then
local timer_gateway = assert( core.timer_gateway)
--
@@ -364,6 +363,8 @@ timer_gateway:set(first_time_key,true)
--
if first_time then
+ local now_secs = core.now_secs
+ assert( type( now_secs) == "function")
-----
-- Snore loop (run as a lane on the background)
--
@@ -373,10 +374,7 @@ if first_time then
-- remains.
--
local timer_body = function()
- -- require lanes.core inside the timer body to prevent pulling now_secs() through an uvpvalue
- local core = require "lanes.core"
- core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator, _params.verbose_errors)
-
+ set_debug_threadname( "LanesTimer")
--
-- { [deep_linda_lightuserdata]= { [deep_linda_lightuserdata]=linda_h,
-- [key]= { wakeup_secs [,period_secs] } [, ...] },
@@ -463,8 +461,6 @@ if first_time then
end
end -- set_timer()
- local now_secs = core.now_secs
- assert( type( now_secs) == "function")
-----
-- [next_wakeup_at]= check_timers()
-- Check timers, and wake up the ones expired (if any)
@@ -520,7 +516,6 @@ if first_time then
end -- check_timers()
local timer_gateway_batched = timer_gateway.batched
- set_debug_threadname( "LanesTimer")
set_finalizer( function( err, stk)
if err and type( err) ~= "userdata" then
WR( "LanesTimer error: "..tostring(err))
@@ -601,7 +596,7 @@ timers = function()
return r
end
-end -- _params.with_timers
+end -- settings.with_timers
---=== Lock & atomic generators ===---
@@ -673,26 +668,23 @@ end
lanes.linda = core.linda
lanes.cancel_error = core.cancel_error
lanes.nameof = core.nameof
- lanes.threads = (_params.track_lanes and core.threads) and core.threads or function() error "lane tracking is not available" end
+ lanes.threads = core.threads or function() error "lane tracking is not available" end -- core.threads isn't registered if settings.track_lanes is false
lanes.timer = timer
lanes.timer_lane = timer_lane
lanes.timers = timers
lanes.genlock = genlock
lanes.now_secs = core.now_secs
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( _params2)
- _params2 = params_checker( _params2 or _params)
- for key, value2 in pairs( _params2) do
- local value = _params[key]
- if value2 ~= value then
- error( "mismatched configuration: " .. key .. " is " .. tostring( value2) .. " instead of " .. tostring( value))
- end
- end
- return lanes
- end
+ lanes.configure = nil -- no need to call configure() ever again
return lanes
end -- lanes.configure
+-- no need to force calling configure() excepted the first time
+if core.settings then
+ return lanes.configure()
+else
+ return lanes
+end
+
--the end
return lanes
diff --git a/src/threading.c b/src/threading.c
index 1e4fc92..42c0cde 100644
--- a/src/threading.c
+++ b/src/threading.c
@@ -84,8 +84,9 @@ THE SOFTWARE.
* error in _this_ code.
*/
#if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)
-static void FAIL( const char *funcname, int rc ) {
- fprintf( stderr, "%s() failed! (%d)\n", funcname, rc );
+static void FAIL( char const* funcname, int rc)
+{
+ fprintf( stderr, "%s() failed! (%d)\n", funcname, rc );
#ifdef _MSC_VER
__debugbreak(); // give a chance to the debugger!
#endif // _MSC_VER
diff --git a/src/threading.h b/src/threading.h
index 7d94f26..d2320aa 100644
--- a/src/threading.h
+++ b/src/threading.h
@@ -97,7 +97,7 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
#define SIGNAL_T CONDITION_VARIABLE
#define MUTEX_T CRITICAL_SECTION
#define MUTEX_INIT( ref) InitializeCriticalSection( ref)
- #define MUTEX_FREE( ref) DeleteCriticalSection( ref)
+ #define MUTEX_FREE( ref) do{ DeleteCriticalSection( ref); *ref = INVALID_HANDLE_VALUE;} while(0)
#define MUTEX_LOCK( ref) EnterCriticalSection( ref)
#define MUTEX_UNLOCK( ref) LeaveCriticalSection( ref)
diff --git a/src/tools.c b/src/tools.c
index b02177b..95104d6 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -44,9 +44,31 @@ THE SOFTWARE.
#include
#include
+/*
+ * ###############################################################################################
+ * ########################################### ASSERT ############################################
+ * ###############################################################################################
+ */
+void ASSERT_IMPL( lua_State* L, bool_t cond_, char const* file_, int const line_, char const* text_)
+{
+ if ( !cond_)
+ {
+ (void) luaL_error( L, "ASSERT failed: %s:%d '%s'", file_, line_, text_);
+ }
+}
+
// for verbose errors
bool_t GVerboseErrors = FALSE;
+char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4";
+char const* const LOOKUP_REGKEY = "ddea37aa-50c7-4d3f-8e0b-fb7a9d62bac5";
+
+/*
+ * ###############################################################################################
+ * ######################################### Lua 5.1/5.2 #########################################
+ * ###############################################################################################
+ */
+
/*
** Copied from Lua 5.2 loadlib.c
*/
@@ -137,6 +159,19 @@ void luaG_dump( lua_State* L ) {
fprintf( stderr, "\n" );
}
+// just like lua_xmove, args are (from, to)
+void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_)
+{
+ STACK_GROW( L, 1);
+ // copy settings from from source to destination registry
+ lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY);
+ if( luaG_inter_move( L, L2, 1, eLM_LaneBody) < 0) // error?
+ {
+ (void) luaL_error( L, "failed to copy settings when loading %s", name_);
+ }
+ lua_setfield( L2, LUA_REGISTRYINDEX, CONFIG_REGKEY);
+}
+
/*---=== luaG_newstate ===---*/
@@ -171,24 +206,31 @@ static const luaL_Reg libs[] =
{ NULL, NULL }
};
-static void open1lib( lua_State* L, char const* name, size_t len)
+static void open1lib( lua_State* L, char const* name_, size_t len_, lua_State* from_)
{
int i;
for( i = 0; libs[i].name; ++ i)
{
- if( strncmp( name, libs[i].name, len) == 0)
+ if( strncmp( name_, libs[i].name, len_) == 0)
{
lua_CFunction libfunc = libs[i].func;
- if( libfunc)
+ name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_
+ if( libfunc != NULL)
{
- bool_t createGlobal = (libfunc != require_lanes_core) ? TRUE : FALSE; // don't want to create a global for "lanes.core"
- DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, len, name));
+ bool_t const isLanesCore = (libfunc == require_lanes_core) ? TRUE : FALSE; // don't want to create a global for "lanes.core"
+ DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, len_, name_));
STACK_CHECK( L);
+ if( isLanesCore == TRUE)
+ {
+ // copy settings from from source to destination registry
+ luaG_copy_one_time_settings( from_, L, name_);
+ }
// open the library as if through require(), and create a global as well if necessary (the library table is left on the stack)
- luaL_requiref( L, libs[i].name, libfunc, createGlobal);
- if( createGlobal == FALSE)
+ luaL_requiref( L, name_, libfunc, !isLanesCore);
+ // lanes.core doesn't declare a global, so scan it here and now
+ if( isLanesCore == TRUE)
{
- populate_func_lookup_table( L, -1, name);
+ populate_func_lookup_table( L, -1, name_);
}
lua_pop( L, 1);
STACK_END( L, 0);
@@ -473,14 +515,8 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_)
DEBUGSPEW_CODE( ++ debugspew_indent_depth);
STACK_GROW( L, 3);
STACK_CHECK( L);
- lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}?
- if( lua_isnil( L, -1)) // nil
- {
- lua_pop( L, 1); //
- lua_newtable( L); // {}
- lua_pushvalue( L, -1); // {} {}
- lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}
- }
+ lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {}
+ ASSERT_L( lua_istable( L, -1));
if( lua_type( L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function
{
name_ = name_ ? name_ : "NULL";
@@ -538,17 +574,18 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
lua_Alloc allocF = lua_getallocf( _from, &allocUD);
lua_State* L = lua_newstate( allocF, allocUD);
- if( !L)
+ if( L == NULL)
{
- luaL_error( _from, "'lua_newstate()' failed; out of memory");
+ (void) luaL_error( _from, "'lua_newstate()' failed; out of memory");
}
// neither libs (not even 'base') nor special init func: we are done
if( libs == NULL && _on_state_create <= 0)
{
+ DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END));
return L;
}
- // if we are here, no keeper state is involved (because libs == NULL when we init keepers)
+ // from this point, we are not creating a keeper state (because libs == NULL when we init keepers)
DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END));
DEBUGSPEW_CODE( ++ debugspew_indent_depth);
@@ -556,12 +593,15 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
STACK_GROW( L, 2);
STACK_CHECK( L);
// 'lua.c' stops GC during initialization so perhaps its a good idea. :)
- // but do it after _on_state_create in case it does a lot of stuff...
lua_gc( L, LUA_GCSTOP, 0);
+ // we'll need this everytime we transfer some C function from/to this state
+ lua_newtable( L);
+ lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY);
+
// Anything causes 'base' to be taken in
//
- if( libs)
+ if( libs != NULL)
{
// special "*" case (mainly to help with LuaJIT compatibility)
// as we are called from luaopen_lanes_core() already, and that would deadlock
@@ -570,7 +610,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END));
luaL_openlibs( L);
// don't forget lanes.core for regular lane states
- open1lib( L, "lanes.core", 10);
+ open1lib( L, "lanes.core", 10, _from);
libs = NULL; // done with libs
}
else
@@ -604,7 +644,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
while( isalnum( p[len]) || p[len] == '.')
++ len;
// open library
- open1lib( L, p, len);
+ open1lib( L, p, len, _from);
}
serialize_require( L);
}
@@ -612,7 +652,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
lua_gc( L, LUA_GCRESTART, 0);
STACK_CHECK( L);
- // call this after the base libraries are loaded!
+ // call this after the base libraries are loaded and GC is restarted
if( _on_state_create > 0)
{
DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END));
@@ -633,7 +673,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
// capture error and forward it to main state
if( lua_pcall( L, 0, 0, 0) != LUA_OK)
{
- luaL_error( _from, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1)));
+ (void) luaL_error( _from, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1)));
}
STACK_MID( L, 0);
}
@@ -1486,7 +1526,7 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLoo
else
{
// fetch the name from the source state's lookup table
- lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {}
+ lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // ... f ... {}
ASSERT_L( lua_istable( L, -1));
lua_pushvalue( L, i); // ... f ... {} f
lua_rawget( L, -2); // ... f ... {} "f.q.n"
@@ -1533,7 +1573,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); // {}
+ lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {}
ASSERT_L( lua_istable( L2, -1));
lua_pushlstring( L2, fqn, len); // {} "f.q.n"
lua_rawget( L2, -2); // {} f
@@ -1923,7 +1963,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u
*/
if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL, mode_, valPath))
{
- ASSERT_L( lua_istable(L2,-3));
+ ASSERT_L( lua_istable( L2, -3));
lua_rawset( L2, -3); // add to table (pops key & val)
}
else
diff --git a/src/tools.h b/src/tools.h
index 1113131..6d3b3c7 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -56,7 +56,8 @@ extern int debugspew_indent_depth;
#define STACK_END(L,c) /*nothing*/
#define STACK_DUMP(L) /*nothing*/
#else
- #define _ASSERT_L(lua,c) do { if (!(c)) luaL_error( lua, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #c ); } while( 0)
+ void ASSERT_IMPL( lua_State* L, bool_t cond_, char const* file_, int const line_, char const* text_);
+ #define _ASSERT_L(lua,c) ASSERT_IMPL( lua, (c) != 0, __FILE__, __LINE__, #c)
//
#define STACK_CHECK(L) { int const _oldtop_##L = lua_gettop( L)
#define STACK_MID(L,change) \
@@ -75,7 +76,7 @@ extern int debugspew_indent_depth;
#define STACK_GROW(L,n) do { if (!lua_checkstack(L,n)) luaL_error( L, "Cannot grow stack!" ); } while( 0)
-#define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State *L )
+#define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State* L)
#define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d))
#define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i))
@@ -83,6 +84,7 @@ extern int debugspew_indent_depth;
void luaG_dump( lua_State* L );
lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs);
+void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_);
typedef struct {
volatile int refcount;
@@ -117,5 +119,7 @@ extern MUTEX_T require_cs;
// for verbose errors
extern bool_t GVerboseErrors;
-#endif
- // TOOLS_H
+char const* const CONFIG_REGKEY;
+char const* const LOOKUP_REGKEY;
+
+#endif // TOOLS_H
diff --git a/tests/fibonacci.lua b/tests/fibonacci.lua
index 5cdb4be..6dba1dd 100644
--- a/tests/fibonacci.lua
+++ b/tests/fibonacci.lua
@@ -12,8 +12,7 @@
-- Need to say it's 'local' so it can be an upvalue
--
-local lanes = require "lanes"
-lanes.configure{ nb_keepers =1, with_timers = false}
+local lanes = require "lanes".configure{ nb_keepers =1, with_timers = false}
local function WR(str)
io.stderr:write( str.."\n" )
@@ -33,7 +32,7 @@ end
--
local function fib( n )
set_debug_threadname( "fib(" .. n .. ")")
- local lanes = require"lanes".configure()
+ local lanes = require"lanes"
--
local sum
local floor= assert(math.floor)
diff --git a/tests/irayo_recursive.lua b/tests/irayo_recursive.lua
index f6fe87e..2f8b8a8 100644
--- a/tests/irayo_recursive.lua
+++ b/tests/irayo_recursive.lua
@@ -1,3 +1,4 @@
+local lanes = require "lanes".configure{ nb_keepers = 1, with_timers = false}
--
-- Bugs filed by irayo Jul-2008
--
@@ -8,10 +9,9 @@ local function recurse()
print("level "..i);
if i > 10 then return "finished" end
- local lanes = require "lanes"
- lanes.configure{ nb_keepers = 1, with_timers = false}
+ --local lanes = require "lanes"
- local lane = lanes.gen( "*", { globals = { ["i"]= i + 1 } }, recurse ) ()
+ local lane = lanes.gen( "base,string,lanes.core", { globals = { ["i"]= i + 1 } }, recurse ) ()
return lane[1]
end
diff --git a/tests/recursive.lua b/tests/recursive.lua
index 571fc1e..82a43b9 100644
--- a/tests/recursive.lua
+++ b/tests/recursive.lua
@@ -12,8 +12,10 @@ local function func( depth )
end
local lanes = require "lanes"
- -- lanes.configure() is gone after we call it...
- lanes.configure()
+ -- lanes.configure() is available only at the first require()
+ if lanes.configure then
+ lanes = lanes.configure()
+ end
local lane= lanes.gen("*", func)( depth+1 )
return lane[1]
end
--
cgit v1.2.3-55-g6feb