aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES15
-rw-r--r--docs/index.html14
-rw-r--r--src/keeper.c46
-rw-r--r--src/keeper.h2
-rw-r--r--src/lanes.c251
-rw-r--r--src/lanes.lua72
-rw-r--r--src/threading.c5
-rw-r--r--src/threading.h2
-rw-r--r--src/tools.c96
-rw-r--r--src/tools.h12
-rw-r--r--tests/fibonacci.lua5
-rw-r--r--tests/irayo_recursive.lua6
-rw-r--r--tests/recursive.lua6
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 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 72: BGe 3-Ost-13 3CHANGE 76: BGe 10-Oct-13
4 * version 3.7.0
5 * fix lanes.threads() not being available in a lane where lanes.configure() settings didn't contain track_lanes although the initial configure() call did.
6
7CHANGE 75: BGe 7-Oct-13
8 * require "lanes".configure() sequence is only necessary at the first require "lanes".
9
10CHANGE 74: BGe 7-Oct-13
11 * fix a crash at application shutdown where in some situations we could deinitialize the protected allocator mutex while a lane was still using it.
12
13CHANGE 73: BGe 4-Oct-13
14 * fix timers broken by change 69
15
16CHANGE 72: BGe 3-Oct-13
4 * bugfix: no longer create a global named "lanes.core" inside lanes having "*" as library list 17 * bugfix: no longer create a global named "lanes.core" inside lanes having "*" as library list
5 18
6CHANGE 71: BGe 30-Sept-13 19CHANGE 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 @@
70 </p> 70 </p>
71 71
72 <p> 72 <p>
73 This document was revised on 27-Sept-13, and applies to version <tt>3.6.6</tt>. 73 This document was revised on 11-Oct-13, and applies to version <tt>3.7.0</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -248,7 +248,10 @@
248 After lanes is required, it is necessary to call <tt>lanes.configure()</tt>, which is the only function exposed by the module at this point. Calling <tt>configure()</tt> will perform one-time initializations and make the rest of the API available. 248 After lanes is required, it is necessary to call <tt>lanes.configure()</tt>, which is the only function exposed by the module at this point. Calling <tt>configure()</tt> will perform one-time initializations and make the rest of the API available.
249</p> 249</p>
250<p> 250<p>
251 At the same time, <tt>configure()</tt> itself will be replaced by another function that raises an error if called again with differing arguments. 251 At the same time, <tt>configure()</tt> itself will be replaced by another function that raises an error if called again with differing arguments, if any.
252</p>
253<p>
254 <b>IMPORTANT NOTE:</b> Starting with version 3.7.0, only the first occurence of <tt>require "lanes"</tt> must be followed by a call to <tt>.configure()</tt>. From this point, a simple <tt>require "lanes"</tt> will do wherever you need to require lanes again.
252</p> 255</p>
253 256
254<p> 257<p>
@@ -326,7 +329,8 @@
326 <tt>nil</tt>/<tt>false</tt>/anything 329 <tt>nil</tt>/<tt>false</tt>/anything
327 </td> 330 </td>
328 <td> 331 <td>
329 Any non-<tt>nil|false</tt> value instructs Lanes keeps track of all lanes, so that <a href="#tracking"><tt>lanes.threads()</tt></a> can list them. 332 Any non-<tt>nil|false</tt> value instructs Lanes keeps track of all lanes, so that <a href="#tracking"><tt>lanes.threads()</tt></a> can list them. If <tt>false</tt>, <tt>lanes.threads()</tt> will raise an error when called.
333 Default is <tt>false</tt>.
330 </td> 334 </td>
331 </tr> 335 </tr>
332 336
@@ -364,9 +368,7 @@
364</p> 368</p>
365 369
366<p> 370<p>
367 NEW (version 3.5.0) 371 (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 <a href="#lindas">lindas</a>.
368 <br>
369 Once Lanes is configured, one should register with Lanes the modules exporting functions that will be transferred either during lane generation or through <a href="#lindas">lindas</a>.
370 <br> 372 <br>
371 Use <tt>lanes.require()</tt> for this purpose. This will call the original <tt>require()</tt>, then add the result to the lookup databases. 373 Use <tt>lanes.require()</tt> for this purpose. This will call the original <tt>require()</tt>, then add the result to the lookup databases.
372</p> 374</p>
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
70static keeper_fifo* prepare_fifo_access( lua_State* L, int idx) 70static keeper_fifo* prepare_fifo_access( lua_State* L, int idx)
71{ 71{
72 keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx); 72 keeper_fifo* fifo = (keeper_fifo*) lua_touserdata( L, idx);
73 if( fifo) 73 if( fifo != NULL)
74 { 74 {
75 idx = lua_absindex( L, idx); 75 idx = lua_absindex( L, idx);
76 STACK_GROW( L, 1); 76 STACK_GROW( L, 1);
@@ -286,15 +286,15 @@ int keepercall_receive( lua_State* L)
286{ 286{
287 int top = lua_gettop( L); 287 int top = lua_gettop( L);
288 int i; 288 int i;
289 keeper_fifo* fifo;
290 push_table( L, 1); // ud keys fifos 289 push_table( L, 1); // ud keys fifos
291 lua_replace( L, 1); // fifos keys 290 lua_replace( L, 1); // fifos keys
292 for( i = 2; i <= top; ++ i) 291 for( i = 2; i <= top; ++ i)
293 { 292 {
293 keeper_fifo* fifo;
294 lua_pushvalue( L, i); // fifos keys key[i] 294 lua_pushvalue( L, i); // fifos keys key[i]
295 lua_rawget( L, 1); // fifos keys fifo 295 lua_rawget( L, 1); // fifos keys fifo
296 fifo = prepare_fifo_access( L, -1); // fifos keys fifo 296 fifo = prepare_fifo_access( L, -1); // fifos keys fifo
297 if( fifo && fifo->count > 0) 297 if( fifo != NULL && fifo->count > 0)
298 { 298 {
299 fifo_pop( L, fifo, 1); // fifos keys val 299 fifo_pop( L, fifo, 1); // fifos keys val
300 if( !lua_isnil( L, -1)) 300 if( !lua_isnil( L, -1))
@@ -332,7 +332,7 @@ int keepercall_receive_batched( lua_State* L)
332 lua_rawget( L, 2); // key fifos fifo 332 lua_rawget( L, 2); // key fifos fifo
333 lua_remove( L, 2); // key fifo 333 lua_remove( L, 2); // key fifo
334 fifo = prepare_fifo_access( L, 2); // key fifo 334 fifo = prepare_fifo_access( L, 2); // key fifo
335 if( fifo && fifo->count >= min_count) 335 if( fifo != NULL && fifo->count >= min_count)
336 { 336 {
337 fifo_pop( L, fifo, __min( max_count, fifo->count)); // key ... 337 fifo_pop( L, fifo, __min( max_count, fifo->count)); // key ...
338 } 338 }
@@ -360,7 +360,7 @@ int keepercall_limit( lua_State* L)
360 lua_pushvalue( L, -1); // fifos key key 360 lua_pushvalue( L, -1); // fifos key key
361 lua_rawget( L, -3); // fifos key fifo 361 lua_rawget( L, -3); // fifos key fifo
362 fifo = (keeper_fifo*) lua_touserdata( L, -1); 362 fifo = (keeper_fifo*) lua_touserdata( L, -1);
363 if( !fifo) 363 if( fifo == NULL)
364 { 364 {
365 lua_pop( L, 1); // fifos key 365 lua_pop( L, 1); // fifos key
366 fifo_new( L); // fifos key fifo 366 fifo_new( L); // fifos key fifo
@@ -437,7 +437,7 @@ int keepercall_get( lua_State* L)
437 lua_replace( L, 1); // fifos key 437 lua_replace( L, 1); // fifos key
438 lua_rawget( L, 1); // fifos fifo 438 lua_rawget( L, 1); // fifos fifo
439 fifo = prepare_fifo_access( L, -1); // fifos fifo 439 fifo = prepare_fifo_access( L, -1); // fifos fifo
440 if( fifo && fifo->count > 0) 440 if( fifo != NULL && fifo->count > 0)
441 { 441 {
442 lua_remove( L, 1); // fifo 442 lua_remove( L, 1); // fifo
443 // read one value off the fifo 443 // read one value off the fifo
@@ -497,7 +497,7 @@ int keepercall_count( lua_State* L)
497 lua_rawget( L, 2); // out fifos keys fifo 497 lua_rawget( L, 2); // out fifos keys fifo
498 fifo = prepare_fifo_access( L, -1); // out fifos keys fifo 498 fifo = prepare_fifo_access( L, -1); // out fifos keys fifo
499 lua_pop( L, 1); // out fifos keys 499 lua_pop( L, 1); // out fifos keys
500 if( fifo) 500 if( fifo != NULL)
501 { 501 {
502 lua_pushinteger( L, fifo->count); // out fifos keys count 502 lua_pushinteger( L, fifo->count); // out fifos keys count
503 lua_rawset( L, 1); // out fifos keys 503 lua_rawset( L, 1); // out fifos keys
@@ -540,14 +540,17 @@ void close_keepers( void)
540 for( i = 0; i < GNbKeepers; ++ i) 540 for( i = 0; i < GNbKeepers; ++ i)
541 { 541 {
542 lua_State* L = GKeepers[i].L; 542 lua_State* L = GKeepers[i].L;
543 GKeepers[i].L = 0; 543 GKeepers[i].L = NULL;
544 lua_close( L); 544 lua_close( L);
545 } 545 }
546 for( i = 0; i < GNbKeepers; ++ i) 546 for( i = 0; i < GNbKeepers; ++ i)
547 { 547 {
548 MUTEX_FREE( &GKeepers[i].lock_); 548 MUTEX_FREE( &GKeepers[i].lock_);
549 } 549 }
550 if( GKeepers) free( GKeepers); 550 if( GKeepers != NULL)
551 {
552 free( GKeepers);
553 }
551 GKeepers = NULL; 554 GKeepers = NULL;
552 GNbKeepers = 0; 555 GNbKeepers = 0;
553} 556}
@@ -560,20 +563,29 @@ void close_keepers( void)
560* Note: Any problems would be design flaws; the created Lua state is left 563* Note: Any problems would be design flaws; the created Lua state is left
561* unclosed, because it does not really matter. In production code, this 564* unclosed, because it does not really matter. In production code, this
562* function never fails. 565* function never fails.
566* settings table is at position 1 on the stack
563*/ 567*/
564char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers) 568char const* init_keepers( lua_State* L)
565{ 569{
566 int i; 570 int i, on_state_create;
567 assert( _nbKeepers >= 1); 571 STACK_CHECK( L);
568 GNbKeepers = _nbKeepers; 572 lua_getfield( L, 1, "nb_keepers");
569 GKeepers = malloc( _nbKeepers * sizeof( struct s_Keeper)); 573 GNbKeepers = lua_tointeger( L, -1);
570 for( i = 0; i < _nbKeepers; ++ i) 574 lua_pop( L, 1);
575 STACK_MID( L, 0);
576 assert( GNbKeepers >= 1);
577
578 lua_getfield( L, 1, "on_state_create");
579 on_state_create = lua_isnil( L, -1) ? -1 : lua_absindex( L, -1);
580
581 GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper));
582 for( i = 0; i < GNbKeepers; ++ i)
571 { 583 {
572 lua_State* K; 584 lua_State* K;
573 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d BEGIN\n" INDENT_END, i)); 585 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d BEGIN\n" INDENT_END, i));
574 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 586 DEBUGSPEW_CODE( ++ debugspew_indent_depth);
575 // we don't need any libs in the keeper states 587 // we don't need any libs in the keeper states
576 K = luaG_newstate( L, _on_state_create, NULL); 588 K = luaG_newstate( L, on_state_create, NULL);
577 589
578 STACK_CHECK( K); 590 STACK_CHECK( K);
579 591
@@ -596,6 +608,8 @@ char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepe
596 GKeepers[i].L = K; 608 GKeepers[i].L = K;
597 //GKeepers[i].count = 0; 609 //GKeepers[i].count = 0;
598 } 610 }
611 lua_pop( L, 1);
612 STACK_END( L, 0);
599#if HAVE_KEEPER_ATEXIT_DESINIT 613#if HAVE_KEEPER_ATEXIT_DESINIT
600 atexit( atexit_close_keepers); 614 atexit( atexit_close_keepers);
601#endif // HAVE_KEEPER_ATEXIT_DESINIT 615#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
13// problem: maybe on some platforms (linux) atexit() is called after DLL/so are unloaded... 13// problem: maybe on some platforms (linux) atexit() is called after DLL/so are unloaded...
14#define HAVE_KEEPER_ATEXIT_DESINIT 0 14#define HAVE_KEEPER_ATEXIT_DESINIT 0
15 15
16char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers); 16char const* init_keepers( lua_State* L);
17#if !HAVE_KEEPER_ATEXIT_DESINIT 17#if !HAVE_KEEPER_ATEXIT_DESINIT
18void close_keepers( void); 18void close_keepers( void);
19#endif // HAVE_KEEPER_ATEXIT_DESINIT 19#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 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.6.6"; 55char const* VERSION = "3.7.0";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -1932,7 +1932,7 @@ LUAG_FUNC( thread_new)
1932 uint_t required = lua_isnoneornil( L, 8) ? 0 : 8; 1932 uint_t required = lua_isnoneornil( L, 8) ? 0 : 8;
1933 1933
1934#define FIXED_ARGS 8 1934#define FIXED_ARGS 8
1935 uint_t args= lua_gettop(L) - FIXED_ARGS; 1935 uint_t args = lua_gettop(L) - FIXED_ARGS;
1936 1936
1937 if( prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) 1937 if( prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX)
1938 { 1938 {
@@ -2002,8 +2002,19 @@ LUAG_FUNC( thread_new)
2002 } 2002 }
2003 else 2003 else
2004 { 2004 {
2005 // if is it "lanes" or "lanes.core", make sure we have copied the initial settings over
2006 // which might not be the case if the libs list didn't include lanes.core or "*"
2007 if( strncmp( name, "lanes.core", len) == 0) // this works both both "lanes" and "lanes.core" because of len
2008 {
2009 luaG_copy_one_time_settings( L, L2, name);
2010 }
2005 lua_pushlstring( L2, name, len); // require() name 2011 lua_pushlstring( L2, name, len); // require() name
2006 lua_pcall( L2, 1, 1, 0); // ret 2012 if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode
2013 {
2014 // propagate error to main state if any
2015 luaG_inter_move( L2, L, 1, eLM_LaneBody); //
2016 return lua_error( L);
2017 }
2007 STACK_MID( L2, 1); 2018 STACK_MID( L2, 1);
2008 // after requiring the module, register the functions it exported in our name<->function database 2019 // after requiring the module, register the functions it exported in our name<->function database
2009 populate_func_lookup_table( L2, -1, name); 2020 populate_func_lookup_table( L2, -1, name);
@@ -2110,7 +2121,7 @@ LUAG_FUNC( thread_new)
2110 ASSERT_L( s); 2121 ASSERT_L( s);
2111 2122
2112 //memset( s, 0, sizeof(struct s_lane) ); 2123 //memset( s, 0, sizeof(struct s_lane) );
2113 s->L= L2; 2124 s->L = L2;
2114 s->status= PENDING; 2125 s->status= PENDING;
2115 s->waiting_on = NULL; 2126 s->waiting_on = NULL;
2116 s->debug_name = NULL; 2127 s->debug_name = NULL;
@@ -2128,8 +2139,8 @@ LUAG_FUNC( thread_new)
2128 2139
2129 // Set metatable for the userdata 2140 // Set metatable for the userdata
2130 // 2141 //
2131 lua_pushvalue( L, lua_upvalueindex(1) ); 2142 lua_pushvalue( L, lua_upvalueindex( 1));
2132 lua_setmetatable( L, -2 ); 2143 lua_setmetatable( L, -2);
2133 STACK_MID( L, 1); 2144 STACK_MID( L, 1);
2134 2145
2135 // Clear environment for the userdata 2146 // Clear environment for the userdata
@@ -2140,11 +2151,11 @@ LUAG_FUNC( thread_new)
2140 // Place 's' in registry, for 'cancel_test()' (even if 'cs'==0 we still 2151 // Place 's' in registry, for 'cancel_test()' (even if 'cs'==0 we still
2141 // do cancel tests at pending send/receive). 2152 // do cancel tests at pending send/receive).
2142 // 2153 //
2143 lua_pushlightuserdata( L2, CANCEL_TEST_KEY ); 2154 lua_pushlightuserdata( L2, CANCEL_TEST_KEY);
2144 lua_pushlightuserdata( L2, s ); 2155 lua_pushlightuserdata( L2, s);
2145 lua_rawset( L2, LUA_REGISTRYINDEX ); 2156 lua_rawset( L2, LUA_REGISTRYINDEX);
2146 2157
2147 if (cs) 2158 if( cs)
2148 { 2159 {
2149 lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cs ); 2160 lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cs );
2150 } 2161 }
@@ -2632,9 +2643,6 @@ LUAG_FUNC( wakeup_conv )
2632static const struct luaL_Reg lanes_functions [] = { 2643static const struct luaL_Reg lanes_functions [] = {
2633 {"linda", LG_linda}, 2644 {"linda", LG_linda},
2634 {"now_secs", LG_now_secs}, 2645 {"now_secs", LG_now_secs},
2635#if HAVE_LANE_TRACKING
2636 {"threads", LG_threads},
2637#endif // HAVE_LANE_TRACKING
2638 {"wakeup_conv", LG_wakeup_conv}, 2646 {"wakeup_conv", LG_wakeup_conv},
2639 {"nameof", luaG_nameof}, 2647 {"nameof", luaG_nameof},
2640 {"set_singlethreaded", LG_set_singlethreaded}, 2648 {"set_singlethreaded", LG_set_singlethreaded},
@@ -2644,10 +2652,18 @@ static const struct luaL_Reg lanes_functions [] = {
2644 2652
2645/* 2653/*
2646** One-time initializations 2654** One-time initializations
2655 * settings table it at position 1 on the stack
2647*/ 2656*/
2648static 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) 2657static void init_once_LOCKED( lua_State* L)
2649{ 2658{
2650 GVerboseErrors = verbose_errors; 2659 STACK_CHECK( L);
2660
2661 lua_getfield( L, 1, "verbose_errors");
2662 GVerboseErrors = lua_toboolean( L, -1);
2663 lua_pop( L, 1);
2664
2665 STACK_MID( L, 0);
2666
2651#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 2667#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2652 now_secs(); // initialize 'now_secs()' internal offset 2668 now_secs(); // initialize 'now_secs()' internal offset
2653#endif 2669#endif
@@ -2657,26 +2673,27 @@ static void init_once_LOCKED( lua_State* L, int const _on_state_create, int cons
2657#endif 2673#endif
2658 2674
2659#if HAVE_LANE_TRACKING 2675#if HAVE_LANE_TRACKING
2660 tracking_first = _track_lanes ? TRACKING_END : NULL; 2676 MUTEX_INIT( &tracking_cs);
2677 lua_getfield( L, 1, "track_lanes");
2678 tracking_first = lua_toboolean( L, -1) ? TRACKING_END : NULL;
2679 lua_pop( L, 1);
2680 STACK_MID( L, 0);
2661#endif // HAVE_LANE_TRACKING 2681#endif // HAVE_LANE_TRACKING
2662 2682
2663 // Locks for 'tools.c' inc/dec counters 2683 // Locks for 'tools.c' inc/dec counters
2664 // 2684 //
2665 MUTEX_INIT( &deep_lock ); 2685 MUTEX_INIT( &deep_lock);
2666 MUTEX_INIT( &mtid_lock ); 2686 MUTEX_INIT( &mtid_lock);
2667 2687
2668 // Serialize calls to 'require' from now on, also in the primary state 2688 // Serialize calls to 'require' from now on, also in the primary state
2669 // 2689 //
2670 MUTEX_RECURSIVE_INIT( &require_cs ); 2690 MUTEX_RECURSIVE_INIT( &require_cs);
2671 2691
2672 serialize_require( L); 2692 serialize_require( L);
2673 2693
2674 // Linked chains handling 2694 // Linked chains handling
2675 // 2695 //
2676 MUTEX_INIT( &selfdestruct_cs ); 2696 MUTEX_INIT( &selfdestruct_cs);
2677#if HAVE_LANE_TRACKING
2678 MUTEX_INIT( &tracking_cs);
2679#endif // HAVE_LANE_TRACKING
2680 2697
2681 //--- 2698 //---
2682 // Linux needs SCHED_RR to change thread priorities, and that is only 2699 // 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
2702#endif // LINUX_SCHED_RR 2719#endif // LINUX_SCHED_RR
2703#endif // PLATFORM_LINUX 2720#endif // PLATFORM_LINUX
2704 { 2721 {
2705 char const* err = init_keepers( L, _on_state_create, nbKeepers); 2722 char const* err = init_keepers( L);
2706 if (err) 2723 if (err)
2707 { 2724 {
2708 (void) luaL_error( L, "Unable to initialize: %s", err ); 2725 (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
2713 // 2730 //
2714 ASSERT_L( timer_deep == NULL); 2731 ASSERT_L( timer_deep == NULL);
2715 2732
2716 STACK_CHECK( L); 2733 // proxy_ud= deep_userdata( idfunc )
2717 { 2734 //
2718 // proxy_ud= deep_userdata( idfunc ) 2735 lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes
2719 // 2736 luaG_deep_userdata( L, linda_id);
2720 lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes 2737 STACK_MID( L, 2);
2721 luaG_deep_userdata( L, linda_id); 2738 lua_remove( L, -2); // remove the name as we no longer need it
2722 STACK_MID( L, 2);
2723 lua_remove( L, -2); // remove the name as we no longer need it
2724
2725 ASSERT_L( lua_isuserdata(L,-1) );
2726 2739
2727 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer 2740 ASSERT_L( lua_isuserdata(L,-1));
2728 //
2729 timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1);
2730 ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep);
2731 2741
2732 // The host Lua state must always have a reference to this Linda object in order for the timer_deep pointer to be valid. 2742 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer
2733 // So store a reference that we will never actually use. 2743 //
2734 // at the same time, use this object as a 'desinit' marker: 2744 timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1);
2735 // when the main lua State is closed, this object will be GC'ed 2745 ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep);
2736 {
2737 lua_newuserdata( L, 1);
2738 lua_newtable( L);
2739 lua_pushnumber( L, _shutdown_timeout);
2740 lua_pushcclosure( L, selfdestruct_gc, 1);
2741 lua_setfield( L, -2, "__gc");
2742 lua_pushliteral( L, "AtExit");
2743 lua_setfield( L, -2, "__metatable");
2744 lua_setmetatable( L, -2);
2745 }
2746 lua_insert( L, -2); // Swap key with the Linda object
2747 lua_rawset( L, LUA_REGISTRYINDEX);
2748 2746
2747 // The host Lua state must always have a reference to this Linda object in order for the timer_deep pointer to be valid.
2748 // So store a reference that we will never actually use.
2749 // at the same time, use this object as a 'desinit' marker:
2750 // when the main lua State is closed, this object will be GC'ed
2751 {
2752 lua_newuserdata( L, 1);
2753 lua_newtable( L);
2754 lua_getfield( L, 1, "shutdown_timeout");
2755 lua_pushcclosure( L, selfdestruct_gc, 1);
2756 lua_setfield( L, -2, "__gc");
2757 lua_pushliteral( L, "AtExit");
2758 lua_setfield( L, -2, "__metatable");
2759 lua_setmetatable( L, -2);
2749 } 2760 }
2761 lua_insert( L, -2); // Swap key with the Linda object
2762 lua_rawset( L, LUA_REGISTRYINDEX);
2763
2764 // we'll need this everytime we transfer some C function from/to this state
2765 lua_newtable( L);
2766 lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY);
2767
2750 STACK_END( L, 0); 2768 STACK_END( L, 0);
2751} 2769}
2752 2770
@@ -2754,23 +2772,19 @@ static volatile long s_initCount = 0;
2754 2772
2755// upvalue 1: module name 2773// upvalue 1: module name
2756// upvalue 2: module table 2774// upvalue 2: module table
2775// param 1: settings table
2757LUAG_FUNC( configure) 2776LUAG_FUNC( configure)
2758{ 2777{
2759 char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); 2778 char const* name = luaL_checkstring( L, lua_upvalueindex( 1));
2760 // all parameter checks are done lua-side 2779 _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE);
2761 int const nbKeepers = (int)lua_tointeger( L, 1); 2780 STACK_CHECK( L);
2762 int const on_state_create = lua_isfunction( L, 2) ? 2 : 0;
2763 lua_Number shutdown_timeout = lua_tonumber( L, 3);
2764 bool_t track_lanes = lua_toboolean( L, 4);
2765 bool_t protect_allocator = lua_toboolean( L, 5);
2766 bool_t verbose_errors = lua_toboolean( L, 6);
2767 2781
2768 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L)); 2782 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L));
2769 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 2783 DEBUGSPEW_CODE( ++ debugspew_indent_depth);
2770 STACK_CHECK( L);
2771 2784
2772 // not in init_once_LOCKED because we can have several hosted "master" Lua states where Lanes is require()d. 2785 // not in init_once_LOCKED because we can have several hosted "master" Lua states where Lanes is require()d.
2773 if( protect_allocator) 2786 lua_getfield( L, 1, "protect_allocator"); // settings protect_allocator
2787 if( lua_toboolean( L, -1))
2774 { 2788 {
2775 void* ud; 2789 void* ud;
2776 lua_Alloc allocf = lua_getallocf( L, &ud); 2790 lua_Alloc allocf = lua_getallocf( L, &ud);
@@ -2783,6 +2797,7 @@ LUAG_FUNC( configure)
2783 lua_setallocf( L, protected_lua_Alloc, s); 2797 lua_setallocf( L, protected_lua_Alloc, s);
2784 } 2798 }
2785 } 2799 }
2800 lua_pop( L, 1); // settings
2786 STACK_MID( L, 0); 2801 STACK_MID( L, 0);
2787 2802
2788 /* 2803 /*
@@ -2797,7 +2812,7 @@ LUAG_FUNC( configure)
2797 static volatile int /*bool*/ go_ahead; // = 0 2812 static volatile int /*bool*/ go_ahead; // = 0
2798 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) 2813 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
2799 { 2814 {
2800 init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); 2815 init_once_LOCKED( L);
2801 go_ahead = 1; // let others pass 2816 go_ahead = 1; // let others pass
2802 } 2817 }
2803 else 2818 else
@@ -2815,7 +2830,7 @@ LUAG_FUNC( configure)
2815 // 2830 //
2816 if( s_initCount == 0) 2831 if( s_initCount == 0)
2817 { 2832 {
2818 init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); 2833 init_once_LOCKED( L);
2819 s_initCount = 1; 2834 s_initCount = 1;
2820 } 2835 }
2821 } 2836 }
@@ -2824,56 +2839,64 @@ LUAG_FUNC( configure)
2824#endif // THREADAPI == THREADAPI_PTHREAD 2839#endif // THREADAPI == THREADAPI_PTHREAD
2825 2840
2826 // Retrieve main module interface table 2841 // Retrieve main module interface table
2827 lua_pushvalue( L, lua_upvalueindex( 2)); // ... M 2842 lua_pushvalue( L, lua_upvalueindex( 2)); // settings M
2828 // remove configure() (this function) from the module interface 2843 // remove configure() (this function) from the module interface
2829 lua_pushnil( L); // ... M nil 2844 lua_pushnil( L); // settings M nil
2830 lua_setfield( L, -2, "configure"); // ... M 2845 lua_setfield( L, -2, "configure"); // settings M
2831 // add functions to the module's table 2846 // add functions to the module's table
2832 luaG_registerlibfuncs( L, lanes_functions); 2847 luaG_registerlibfuncs( L, lanes_functions);
2848#if HAVE_LANE_TRACKING
2849 // register core.threads() only if settings say it should be available
2850 if( tracking_first != NULL)
2851 {
2852 lua_pushcfunction( L, LG_threads); // settings M LG_threads()
2853 lua_setfield( L, -2, "threads");
2854 }
2855#endif // HAVE_LANE_TRACKING
2833 STACK_MID( L, 1); 2856 STACK_MID( L, 1);
2834 2857
2835 ASSERT_L( timer_deep != NULL); // initialized by init_once_LOCKED 2858 ASSERT_L( timer_deep != NULL); // initialized by init_once_LOCKED
2836 luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // ... M timer_deep 2859 luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // settings M timer_deep
2837 lua_setfield( L, -2, "timer_gateway"); // ... M 2860 lua_setfield( L, -2, "timer_gateway"); // settings M
2838 STACK_MID( L, 1); 2861 STACK_MID( L, 1);
2839 2862
2840 // prepare the metatable for threads 2863 // prepare the metatable for threads
2841 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join } 2864 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join }
2842 // 2865 //
2843 lua_newtable( L); // ... M mt 2866 lua_newtable( L); // settings M mt
2844 lua_pushcfunction( L, LG_thread_gc); // ... M mt LG_thread_gc 2867 lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc
2845 lua_setfield( L, -2, "__gc"); // ... M mt 2868 lua_setfield( L, -2, "__gc"); // settings M mt
2846 lua_pushcfunction( L, LG_thread_index); // ... M mt LG_thread_index 2869 lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index
2847 lua_setfield( L, -2, "__index"); // ... M mt 2870 lua_setfield( L, -2, "__index"); // settings M mt
2848 lua_getglobal( L, "error"); // ... M mt error 2871 lua_getglobal( L, "error"); // settings M mt error
2849 ASSERT_L( lua_isfunction( L, -1)); 2872 ASSERT_L( lua_isfunction( L, -1));
2850 lua_setfield( L, -2, "cached_error"); // ... M mt 2873 lua_setfield( L, -2, "cached_error"); // settings M mt
2851 lua_getglobal( L, "tostring"); // ... M mt tostring 2874 lua_getglobal( L, "tostring"); // settings M mt tostring
2852 ASSERT_L( lua_isfunction( L, -1)); 2875 ASSERT_L( lua_isfunction( L, -1));
2853 lua_setfield( L, -2, "cached_tostring"); // ... M mt 2876 lua_setfield( L, -2, "cached_tostring"); // settings M mt
2854 lua_pushcfunction( L, LG_thread_join); // ... M mt LG_thread_join 2877 lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join
2855 lua_setfield( L, -2, "join"); // ... M mt 2878 lua_setfield( L, -2, "join"); // settings M mt
2856 lua_pushcfunction( L, LG_thread_cancel); // ... M mt LG_thread_cancel 2879 lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel
2857 lua_setfield( L, -2, "cancel"); // ... M mt 2880 lua_setfield( L, -2, "cancel"); // settings M mt
2858 lua_pushliteral( L, "Lane"); // ... M mt "Lane" 2881 lua_pushliteral( L, "Lane"); // settings M mt "Lane"
2859 lua_setfield( L, -2, "__metatable"); // ... M mt 2882 lua_setfield( L, -2, "__metatable"); // settings M mt
2860 2883
2861 lua_pushcclosure( L, LG_thread_new, 1); // ... M LG_thread_new 2884 lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new
2862 lua_setfield(L, -2, "thread_new"); // ... M 2885 lua_setfield(L, -2, "thread_new"); // settings M
2863 2886
2864 // we can't register 'lanes.require' normally because we want to create an upvalued closure 2887 // we can't register 'lanes.require' normally because we want to create an upvalued closure
2865 lua_getglobal( L, "require"); // ... M require 2888 lua_getglobal( L, "require"); // settings M require
2866 lua_pushcclosure( L, LG_require, 1); // ... M lanes.require 2889 lua_pushcclosure( L, LG_require, 1); // settings M lanes.require
2867 lua_setfield( L, -2, "require"); // ... M 2890 lua_setfield( L, -2, "require"); // settings M
2868 2891
2869 lua_pushstring(L, VERSION); // ... M VERSION 2892 lua_pushstring(L, VERSION); // settings M VERSION
2870 lua_setfield(L, -2, "version"); // ... M 2893 lua_setfield(L, -2, "version"); // settings M
2871 2894
2872 lua_pushinteger(L, THREAD_PRIO_MAX); // ... M THREAD_PRIO_MAX 2895 lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX
2873 lua_setfield(L, -2, "max_prio"); // ... M 2896 lua_setfield(L, -2, "max_prio"); // settings M
2874 2897
2875 lua_pushlightuserdata( L, CANCEL_ERROR); // ... M CANCEL_ERROR 2898 lua_pushlightuserdata( L, CANCEL_ERROR); // settings M CANCEL_ERROR
2876 lua_setfield(L, -2, "cancel_error"); // ... M 2899 lua_setfield(L, -2, "cancel_error"); // settings M
2877 2900
2878 // register all native functions found in that module in the transferable functions database 2901 // register all native functions found in that module in the transferable functions database
2879 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) 2902 // 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)
2882 2905
2883 // record all existing C/JIT-fast functions 2906 // record all existing C/JIT-fast functions
2884 // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack 2907 // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
2885 lua_pushglobaltable( L); // ... M _G 2908 lua_pushglobaltable( L); // settings M _G
2886 populate_func_lookup_table( L, -1, NULL); 2909 populate_func_lookup_table( L, -1, NULL);
2887 lua_pop( L, 2); // ... 2910 lua_pop( L, 1); // settings M
2911 // set _R[CONFIG_REGKEY] = settings
2912 lua_pushvalue( L, -2); // settings M settings
2913 lua_setfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // settings M
2914 lua_pop( L, 1); // settings
2888 STACK_END( L, 0); 2915 STACK_END( L, 0);
2889 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); 2916 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L));
2890 DEBUGSPEW_CODE( -- debugspew_indent_depth); 2917 DEBUGSPEW_CODE( -- debugspew_indent_depth);
2891 // Return nothing 2918 // Return the settings table
2892 return 0; 2919 return 1;
2893} 2920}
2894 2921
2895// helper to have correct callstacks when crashing a Win32 running on 64 bits Windows 2922// 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)
2920{ 2947{
2921 EnableCrashingOnCrashes(); 2948 EnableCrashingOnCrashes();
2922 2949
2923 STACK_GROW( L, 3); 2950 STACK_GROW( L, 4);
2924 STACK_CHECK( L); 2951 STACK_CHECK( L);
2925 2952
2926 // Create main module interface table 2953 // Create main module interface table
2927 // we only have 1 closure, which must be called to configure Lanes 2954 // we only have 1 closure, which must be called to configure Lanes
2928 lua_newtable( L); // M 2955 lua_newtable( L); // M
2929 lua_pushvalue( L, 1); // M "lanes.core" 2956 lua_pushvalue( L, 1); // M "lanes.core"
2930 lua_pushvalue( L, -2); // M "lanes.core" M 2957 lua_pushvalue( L, -2); // M "lanes.core" M
2931 lua_pushcclosure( L, LG_configure, 2); // M LG_configure() 2958 lua_pushcclosure( L, LG_configure, 2); // M LG_configure()
2932 lua_setfield( L, -2, "configure"); // M 2959 lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // M LG_configure() settings
2960 if( !lua_isnil( L, -1)) // this is not the first require "lanes.core": call configure() immediately
2961 {
2962 lua_pushvalue( L, -1); // M LG_configure() settings settings
2963 lua_setfield( L, -4, "settings"); // M LG_configure() settings
2964 lua_call( L, 1, 0); // M
2965 }
2966 else
2967 {
2968 // will do nothing on first invocation, as we haven't stored settings in the registry yet
2969 lua_setfield( L, -3, "settings"); // M LG_configure()
2970 lua_setfield( L, -2, "configure"); // M
2971 }
2933 2972
2934 STACK_END( L, 1); 2973 STACK_END( L, 1);
2935 return 1; 2974 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.
35=============================================================================== 35===============================================================================
36]]-- 36]]--
37 37
38local core = require "lanes.core"
38-- Lua 5.1: module() creates a global variable 39-- Lua 5.1: module() creates a global variable
39-- Lua 5.2: module() is gone 40-- Lua 5.2: module() is gone
40-- almost everything module() does is done by require() anyway 41-- almost everything module() does is done by require() anyway
41-- -> simply create a table, populate it, return it, and be done 42-- -> simply create a table, populate it, return it, and be done
42local lanes = {} 43local lanes = {}
43 44
44lanes.configure = function( _params) 45-- this function is available in the public interface until it is called, after which it disappears
46lanes.configure = function( settings_)
45 47
46 -- This check is for sublanes requiring Lanes 48 -- This check is for sublanes requiring Lanes
47 -- 49 --
@@ -68,7 +70,7 @@ lanes.configure = function( _params)
68 on_state_create = nil, 70 on_state_create = nil,
69 shutdown_timeout = 0.25, 71 shutdown_timeout = 0.25,
70 with_timers = true, 72 with_timers = true,
71 track_lanes = nil, 73 track_lanes = false,
72 verbose_errors = false, 74 verbose_errors = false,
73 -- LuaJIT provides a thread-unsafe allocator by default, so we need to protect it when used in parallel lanes 75 -- LuaJIT provides a thread-unsafe allocator by default, so we need to protect it when used in parallel lanes
74 protect_allocator = (jit and jit.version) and true or false 76 protect_allocator = (jit and jit.version) and true or false
@@ -117,35 +119,32 @@ lanes.configure = function( _params)
117 end 119 end
118 } 120 }
119 121
120 local params_checker = function( _params) 122 local params_checker = function( settings_)
121 if not _params then 123 if not settings_ then
122 return default_params 124 return default_params
123 end 125 end
124 if type( _params) ~= "table" then 126 -- make a copy of the table to leave the provided one unchanged, *and* to help ensure it won't change behind our back
125 error( "Bad parameter #1 to lanes.configure(), should be a table") 127 local settings = {}
128 if type( settings_) ~= "table" then
129 error "Bad parameter #1 to lanes.configure(), should be a table"
126 end 130 end
127 -- any setting not present in the provided parameters takes the default value 131 -- any setting not present in the provided parameters takes the default value
128 for key, value in pairs( default_params) do 132 for key, checker in pairs( param_checkers) do
129 local my_param = _params[key] 133 local my_param = settings_[key]
130 local param 134 local param
131 if my_param ~= nil then 135 if my_param ~= nil then
132 param = my_param 136 param = my_param
133 else 137 else
134 param = default_params[key] 138 param = default_params[key]
135 end 139 end
136 if not param_checkers[key]( param) then 140 if not checker( param) then
137 error( "Bad " .. key .. ": " .. tostring( param), 2) 141 error( "Bad " .. key .. ": " .. tostring( param), 2)
138 end 142 end
139 _params[key] = param 143 settings[key] = param
140 end 144 end
141 return _params 145 return settings
142 end 146 end
143 147 local settings = core.configure and core.configure( params_checker( settings_)) or core.settings
144 _params = params_checker( _params)
145
146 local core = require "lanes.core"
147 assert( type( core)=="table")
148 core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator, _params.verbose_errors)
149 local thread_new = assert( core.thread_new) 148 local thread_new = assert( core.thread_new)
150 local set_singlethreaded = assert( core.set_singlethreaded) 149 local set_singlethreaded = assert( core.set_singlethreaded)
151 local max_prio = assert( core.max_prio) 150 local max_prio = assert( core.max_prio)
@@ -316,8 +315,8 @@ local function gen( ... )
316 -- Lane generator 315 -- Lane generator
317 -- 316 --
318 return function(...) 317 return function(...)
319 return thread_new( func, libs, _params.on_state_create, cs, prio, g_tbl, package_tbl, required, ...) -- args 318 return thread_new( func, libs, settings.on_state_create, cs, prio, g_tbl, package_tbl, required, ...) -- args
320 end 319 end
321end 320end
322 321
323---=== Lindas ===--- 322---=== Lindas ===---
@@ -338,7 +337,7 @@ local timer = function() error "timers are not active" end
338local timer_lane = nil 337local timer_lane = nil
339local timers = timer 338local timers = timer
340 339
341if _params.with_timers ~= false then 340if settings.with_timers ~= false then
342 341
343local timer_gateway = assert( core.timer_gateway) 342local timer_gateway = assert( core.timer_gateway)
344-- 343--
@@ -364,6 +363,8 @@ timer_gateway:set(first_time_key,true)
364-- 363--
365if first_time then 364if first_time then
366 365
366 local now_secs = core.now_secs
367 assert( type( now_secs) == "function")
367 ----- 368 -----
368 -- Snore loop (run as a lane on the background) 369 -- Snore loop (run as a lane on the background)
369 -- 370 --
@@ -373,10 +374,7 @@ if first_time then
373 -- remains. 374 -- remains.
374 -- 375 --
375 local timer_body = function() 376 local timer_body = function()
376 -- require lanes.core inside the timer body to prevent pulling now_secs() through an uvpvalue 377 set_debug_threadname( "LanesTimer")
377 local core = require "lanes.core"
378 core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator, _params.verbose_errors)
379
380 -- 378 --
381 -- { [deep_linda_lightuserdata]= { [deep_linda_lightuserdata]=linda_h, 379 -- { [deep_linda_lightuserdata]= { [deep_linda_lightuserdata]=linda_h,
382 -- [key]= { wakeup_secs [,period_secs] } [, ...] }, 380 -- [key]= { wakeup_secs [,period_secs] } [, ...] },
@@ -463,8 +461,6 @@ if first_time then
463 end 461 end
464 end -- set_timer() 462 end -- set_timer()
465 463
466 local now_secs = core.now_secs
467 assert( type( now_secs) == "function")
468 ----- 464 -----
469 -- [next_wakeup_at]= check_timers() 465 -- [next_wakeup_at]= check_timers()
470 -- Check timers, and wake up the ones expired (if any) 466 -- Check timers, and wake up the ones expired (if any)
@@ -520,7 +516,6 @@ if first_time then
520 end -- check_timers() 516 end -- check_timers()
521 517
522 local timer_gateway_batched = timer_gateway.batched 518 local timer_gateway_batched = timer_gateway.batched
523 set_debug_threadname( "LanesTimer")
524 set_finalizer( function( err, stk) 519 set_finalizer( function( err, stk)
525 if err and type( err) ~= "userdata" then 520 if err and type( err) ~= "userdata" then
526 WR( "LanesTimer error: "..tostring(err)) 521 WR( "LanesTimer error: "..tostring(err))
@@ -601,7 +596,7 @@ timers = function()
601 return r 596 return r
602end 597end
603 598
604end -- _params.with_timers 599end -- settings.with_timers
605 600
606---=== Lock & atomic generators ===--- 601---=== Lock & atomic generators ===---
607 602
@@ -673,26 +668,23 @@ end
673 lanes.linda = core.linda 668 lanes.linda = core.linda
674 lanes.cancel_error = core.cancel_error 669 lanes.cancel_error = core.cancel_error
675 lanes.nameof = core.nameof 670 lanes.nameof = core.nameof
676 lanes.threads = (_params.track_lanes and core.threads) and core.threads or function() error "lane tracking is not available" end 671 lanes.threads = core.threads or function() error "lane tracking is not available" end -- core.threads isn't registered if settings.track_lanes is false
677 lanes.timer = timer 672 lanes.timer = timer
678 lanes.timer_lane = timer_lane 673 lanes.timer_lane = timer_lane
679 lanes.timers = timers 674 lanes.timers = timers
680 lanes.genlock = genlock 675 lanes.genlock = genlock
681 lanes.now_secs = core.now_secs 676 lanes.now_secs = core.now_secs
682 lanes.genatomic = genatomic 677 lanes.genatomic = genatomic
683 -- from now on, calling configure does nothing but checking that we don't call it with parameters that changed compared to the first invocation 678 lanes.configure = nil -- no need to call configure() ever again
684 lanes.configure = function( _params2)
685 _params2 = params_checker( _params2 or _params)
686 for key, value2 in pairs( _params2) do
687 local value = _params[key]
688 if value2 ~= value then
689 error( "mismatched configuration: " .. key .. " is " .. tostring( value2) .. " instead of " .. tostring( value))
690 end
691 end
692 return lanes
693 end
694 return lanes 679 return lanes
695end -- lanes.configure 680end -- lanes.configure
696 681
682-- no need to force calling configure() excepted the first time
683if core.settings then
684 return lanes.configure()
685else
686 return lanes
687end
688
697--the end 689--the end
698return lanes 690return 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.
84* error in _this_ code. 84* error in _this_ code.
85*/ 85*/
86#if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) 86#if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)
87static void FAIL( const char *funcname, int rc ) { 87static void FAIL( char const* funcname, int rc)
88 fprintf( stderr, "%s() failed! (%d)\n", funcname, rc ); 88{
89 fprintf( stderr, "%s() failed! (%d)\n", funcname, rc );
89#ifdef _MSC_VER 90#ifdef _MSC_VER
90 __debugbreak(); // give a chance to the debugger! 91 __debugbreak(); // give a chance to the debugger!
91#endif // _MSC_VER 92#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 };
97 #define SIGNAL_T CONDITION_VARIABLE 97 #define SIGNAL_T CONDITION_VARIABLE
98 #define MUTEX_T CRITICAL_SECTION 98 #define MUTEX_T CRITICAL_SECTION
99 #define MUTEX_INIT( ref) InitializeCriticalSection( ref) 99 #define MUTEX_INIT( ref) InitializeCriticalSection( ref)
100 #define MUTEX_FREE( ref) DeleteCriticalSection( ref) 100 #define MUTEX_FREE( ref) do{ DeleteCriticalSection( ref); *ref = INVALID_HANDLE_VALUE;} while(0)
101 #define MUTEX_LOCK( ref) EnterCriticalSection( ref) 101 #define MUTEX_LOCK( ref) EnterCriticalSection( ref)
102 #define MUTEX_UNLOCK( ref) LeaveCriticalSection( ref) 102 #define MUTEX_UNLOCK( ref) LeaveCriticalSection( ref)
103 103
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.
44#include <stdlib.h> 44#include <stdlib.h>
45#include <malloc.h> 45#include <malloc.h>
46 46
47/*
48 * ###############################################################################################
49 * ########################################### ASSERT ############################################
50 * ###############################################################################################
51 */
52void ASSERT_IMPL( lua_State* L, bool_t cond_, char const* file_, int const line_, char const* text_)
53{
54 if ( !cond_)
55 {
56 (void) luaL_error( L, "ASSERT failed: %s:%d '%s'", file_, line_, text_);
57 }
58}
59
47// for verbose errors 60// for verbose errors
48bool_t GVerboseErrors = FALSE; 61bool_t GVerboseErrors = FALSE;
49 62
63char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4";
64char const* const LOOKUP_REGKEY = "ddea37aa-50c7-4d3f-8e0b-fb7a9d62bac5";
65
66/*
67 * ###############################################################################################
68 * ######################################### Lua 5.1/5.2 #########################################
69 * ###############################################################################################
70 */
71
50/* 72/*
51** Copied from Lua 5.2 loadlib.c 73** Copied from Lua 5.2 loadlib.c
52*/ 74*/
@@ -137,6 +159,19 @@ void luaG_dump( lua_State* L ) {
137 fprintf( stderr, "\n" ); 159 fprintf( stderr, "\n" );
138} 160}
139 161
162// just like lua_xmove, args are (from, to)
163void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_)
164{
165 STACK_GROW( L, 1);
166 // copy settings from from source to destination registry
167 lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY);
168 if( luaG_inter_move( L, L2, 1, eLM_LaneBody) < 0) // error?
169 {
170 (void) luaL_error( L, "failed to copy settings when loading %s", name_);
171 }
172 lua_setfield( L2, LUA_REGISTRYINDEX, CONFIG_REGKEY);
173}
174
140 175
141/*---=== luaG_newstate ===---*/ 176/*---=== luaG_newstate ===---*/
142 177
@@ -171,24 +206,31 @@ static const luaL_Reg libs[] =
171 { NULL, NULL } 206 { NULL, NULL }
172}; 207};
173 208
174static void open1lib( lua_State* L, char const* name, size_t len) 209static void open1lib( lua_State* L, char const* name_, size_t len_, lua_State* from_)
175{ 210{
176 int i; 211 int i;
177 for( i = 0; libs[i].name; ++ i) 212 for( i = 0; libs[i].name; ++ i)
178 { 213 {
179 if( strncmp( name, libs[i].name, len) == 0) 214 if( strncmp( name_, libs[i].name, len_) == 0)
180 { 215 {
181 lua_CFunction libfunc = libs[i].func; 216 lua_CFunction libfunc = libs[i].func;
182 if( libfunc) 217 name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_
218 if( libfunc != NULL)
183 { 219 {
184 bool_t createGlobal = (libfunc != require_lanes_core) ? TRUE : FALSE; // don't want to create a global for "lanes.core" 220 bool_t const isLanesCore = (libfunc == require_lanes_core) ? TRUE : FALSE; // don't want to create a global for "lanes.core"
185 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, len, name)); 221 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, len_, name_));
186 STACK_CHECK( L); 222 STACK_CHECK( L);
223 if( isLanesCore == TRUE)
224 {
225 // copy settings from from source to destination registry
226 luaG_copy_one_time_settings( from_, L, name_);
227 }
187 // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) 228 // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack)
188 luaL_requiref( L, libs[i].name, libfunc, createGlobal); 229 luaL_requiref( L, name_, libfunc, !isLanesCore);
189 if( createGlobal == FALSE) 230 // lanes.core doesn't declare a global, so scan it here and now
231 if( isLanesCore == TRUE)
190 { 232 {
191 populate_func_lookup_table( L, -1, name); 233 populate_func_lookup_table( L, -1, name_);
192 } 234 }
193 lua_pop( L, 1); 235 lua_pop( L, 1);
194 STACK_END( L, 0); 236 STACK_END( L, 0);
@@ -473,14 +515,8 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_)
473 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 515 DEBUGSPEW_CODE( ++ debugspew_indent_depth);
474 STACK_GROW( L, 3); 516 STACK_GROW( L, 3);
475 STACK_CHECK( L); 517 STACK_CHECK( L);
476 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}? 518 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {}
477 if( lua_isnil( L, -1)) // nil 519 ASSERT_L( lua_istable( L, -1));
478 {
479 lua_pop( L, 1); //
480 lua_newtable( L); // {}
481 lua_pushvalue( L, -1); // {} {}
482 lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}
483 }
484 if( lua_type( L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function 520 if( lua_type( L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function
485 { 521 {
486 name_ = name_ ? name_ : "NULL"; 522 name_ = name_ ? name_ : "NULL";
@@ -538,17 +574,18 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
538 lua_Alloc allocF = lua_getallocf( _from, &allocUD); 574 lua_Alloc allocF = lua_getallocf( _from, &allocUD);
539 lua_State* L = lua_newstate( allocF, allocUD); 575 lua_State* L = lua_newstate( allocF, allocUD);
540 576
541 if( !L) 577 if( L == NULL)
542 { 578 {
543 luaL_error( _from, "'lua_newstate()' failed; out of memory"); 579 (void) luaL_error( _from, "'lua_newstate()' failed; out of memory");
544 } 580 }
545 581
546 // neither libs (not even 'base') nor special init func: we are done 582 // neither libs (not even 'base') nor special init func: we are done
547 if( libs == NULL && _on_state_create <= 0) 583 if( libs == NULL && _on_state_create <= 0)
548 { 584 {
585 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END));
549 return L; 586 return L;
550 } 587 }
551 // if we are here, no keeper state is involved (because libs == NULL when we init keepers) 588 // from this point, we are not creating a keeper state (because libs == NULL when we init keepers)
552 589
553 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END)); 590 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END));
554 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 591 DEBUGSPEW_CODE( ++ debugspew_indent_depth);
@@ -556,12 +593,15 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
556 STACK_GROW( L, 2); 593 STACK_GROW( L, 2);
557 STACK_CHECK( L); 594 STACK_CHECK( L);
558 // 'lua.c' stops GC during initialization so perhaps its a good idea. :) 595 // 'lua.c' stops GC during initialization so perhaps its a good idea. :)
559 // but do it after _on_state_create in case it does a lot of stuff...
560 lua_gc( L, LUA_GCSTOP, 0); 596 lua_gc( L, LUA_GCSTOP, 0);
561 597
598 // we'll need this everytime we transfer some C function from/to this state
599 lua_newtable( L);
600 lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY);
601
562 // Anything causes 'base' to be taken in 602 // Anything causes 'base' to be taken in
563 // 603 //
564 if( libs) 604 if( libs != NULL)
565 { 605 {
566 // special "*" case (mainly to help with LuaJIT compatibility) 606 // special "*" case (mainly to help with LuaJIT compatibility)
567 // as we are called from luaopen_lanes_core() already, and that would deadlock 607 // 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
570 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); 610 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END));
571 luaL_openlibs( L); 611 luaL_openlibs( L);
572 // don't forget lanes.core for regular lane states 612 // don't forget lanes.core for regular lane states
573 open1lib( L, "lanes.core", 10); 613 open1lib( L, "lanes.core", 10, _from);
574 libs = NULL; // done with libs 614 libs = NULL; // done with libs
575 } 615 }
576 else 616 else
@@ -604,7 +644,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
604 while( isalnum( p[len]) || p[len] == '.') 644 while( isalnum( p[len]) || p[len] == '.')
605 ++ len; 645 ++ len;
606 // open library 646 // open library
607 open1lib( L, p, len); 647 open1lib( L, p, len, _from);
608 } 648 }
609 serialize_require( L); 649 serialize_require( L);
610 } 650 }
@@ -612,7 +652,7 @@ lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char con
612 lua_gc( L, LUA_GCRESTART, 0); 652 lua_gc( L, LUA_GCRESTART, 0);
613 653
614 STACK_CHECK( L); 654 STACK_CHECK( L);
615 // call this after the base libraries are loaded! 655 // call this after the base libraries are loaded and GC is restarted
616 if( _on_state_create > 0) 656 if( _on_state_create > 0)
617 { 657 {
618 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); 658 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
633 // capture error and forward it to main state 673 // capture error and forward it to main state
634 if( lua_pcall( L, 0, 0, 0) != LUA_OK) 674 if( lua_pcall( L, 0, 0, 0) != LUA_OK)
635 { 675 {
636 luaL_error( _from, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1))); 676 (void) luaL_error( _from, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1)));
637 } 677 }
638 STACK_MID( L, 0); 678 STACK_MID( L, 0);
639 } 679 }
@@ -1486,7 +1526,7 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLoo
1486 else 1526 else
1487 { 1527 {
1488 // fetch the name from the source state's lookup table 1528 // fetch the name from the source state's lookup table
1489 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {} 1529 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // ... f ... {}
1490 ASSERT_L( lua_istable( L, -1)); 1530 ASSERT_L( lua_istable( L, -1));
1491 lua_pushvalue( L, i); // ... f ... {} f 1531 lua_pushvalue( L, i); // ... f ... {} f
1492 lua_rawget( L, -2); // ... f ... {} "f.q.n" 1532 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
1533 } 1573 }
1534 else 1574 else
1535 { 1575 {
1536 lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} 1576 lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {}
1537 ASSERT_L( lua_istable( L2, -1)); 1577 ASSERT_L( lua_istable( L2, -1));
1538 lua_pushlstring( L2, fqn, len); // {} "f.q.n" 1578 lua_pushlstring( L2, fqn, len); // {} "f.q.n"
1539 lua_rawget( L2, -2); // {} f 1579 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
1923 */ 1963 */
1924 if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL, mode_, valPath)) 1964 if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL, mode_, valPath))
1925 { 1965 {
1926 ASSERT_L( lua_istable(L2,-3)); 1966 ASSERT_L( lua_istable( L2, -3));
1927 lua_rawset( L2, -3); // add to table (pops key & val) 1967 lua_rawset( L2, -3); // add to table (pops key & val)
1928 } 1968 }
1929 else 1969 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;
56 #define STACK_END(L,c) /*nothing*/ 56 #define STACK_END(L,c) /*nothing*/
57 #define STACK_DUMP(L) /*nothing*/ 57 #define STACK_DUMP(L) /*nothing*/
58#else 58#else
59 #define _ASSERT_L(lua,c) do { if (!(c)) luaL_error( lua, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #c ); } while( 0) 59 void ASSERT_IMPL( lua_State* L, bool_t cond_, char const* file_, int const line_, char const* text_);
60 #define _ASSERT_L(lua,c) ASSERT_IMPL( lua, (c) != 0, __FILE__, __LINE__, #c)
60 // 61 //
61 #define STACK_CHECK(L) { int const _oldtop_##L = lua_gettop( L) 62 #define STACK_CHECK(L) { int const _oldtop_##L = lua_gettop( L)
62 #define STACK_MID(L,change) \ 63 #define STACK_MID(L,change) \
@@ -75,7 +76,7 @@ extern int debugspew_indent_depth;
75 76
76#define STACK_GROW(L,n) do { if (!lua_checkstack(L,n)) luaL_error( L, "Cannot grow stack!" ); } while( 0) 77#define STACK_GROW(L,n) do { if (!lua_checkstack(L,n)) luaL_error( L, "Cannot grow stack!" ); } while( 0)
77 78
78#define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State *L ) 79#define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State* L)
79 80
80#define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) 81#define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d))
81#define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i)) 82#define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i))
@@ -83,6 +84,7 @@ extern int debugspew_indent_depth;
83void luaG_dump( lua_State* L ); 84void luaG_dump( lua_State* L );
84 85
85lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs); 86lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs);
87void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_);
86 88
87typedef struct { 89typedef struct {
88 volatile int refcount; 90 volatile int refcount;
@@ -117,5 +119,7 @@ extern MUTEX_T require_cs;
117// for verbose errors 119// for verbose errors
118extern bool_t GVerboseErrors; 120extern bool_t GVerboseErrors;
119 121
120#endif 122char const* const CONFIG_REGKEY;
121 // TOOLS_H 123char const* const LOOKUP_REGKEY;
124
125#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 @@
12 12
13-- Need to say it's 'local' so it can be an upvalue 13-- Need to say it's 'local' so it can be an upvalue
14-- 14--
15local lanes = require "lanes" 15local lanes = require "lanes".configure{ nb_keepers =1, with_timers = false}
16lanes.configure{ nb_keepers =1, with_timers = false}
17 16
18local function WR(str) 17local function WR(str)
19 io.stderr:write( str.."\n" ) 18 io.stderr:write( str.."\n" )
@@ -33,7 +32,7 @@ end
33-- 32--
34local function fib( n ) 33local function fib( n )
35 set_debug_threadname( "fib(" .. n .. ")") 34 set_debug_threadname( "fib(" .. n .. ")")
36 local lanes = require"lanes".configure() 35 local lanes = require"lanes"
37 -- 36 --
38 local sum 37 local sum
39 local floor= assert(math.floor) 38 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 @@
1local lanes = require "lanes".configure{ nb_keepers = 1, with_timers = false}
1-- 2--
2-- Bugs filed by irayo Jul-2008 3-- Bugs filed by irayo Jul-2008
3-- 4--
@@ -8,10 +9,9 @@ local function recurse()
8 print("level "..i); 9 print("level "..i);
9 if i > 10 then return "finished" end 10 if i > 10 then return "finished" end
10 11
11 local lanes = require "lanes" 12 --local lanes = require "lanes"
12 lanes.configure{ nb_keepers = 1, with_timers = false}
13 13
14 local lane = lanes.gen( "*", { globals = { ["i"]= i + 1 } }, recurse ) () 14 local lane = lanes.gen( "base,string,lanes.core", { globals = { ["i"]= i + 1 } }, recurse ) ()
15 return lane[1] 15 return lane[1]
16end 16end
17 17
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 )
12 end 12 end
13 13
14 local lanes = require "lanes" 14 local lanes = require "lanes"
15 -- lanes.configure() is gone after we call it... 15 -- lanes.configure() is available only at the first require()
16 lanes.configure() 16 if lanes.configure then
17 lanes = lanes.configure()
18 end
17 local lane= lanes.gen("*", func)( depth+1 ) 19 local lane= lanes.gen("*", func)( depth+1 )
18 return lane[1] 20 return lane[1]
19end 21end