diff options
| -rw-r--r-- | CHANGES | 15 | ||||
| -rw-r--r-- | docs/index.html | 14 | ||||
| -rw-r--r-- | src/keeper.c | 46 | ||||
| -rw-r--r-- | src/keeper.h | 2 | ||||
| -rw-r--r-- | src/lanes.c | 251 | ||||
| -rw-r--r-- | src/lanes.lua | 72 | ||||
| -rw-r--r-- | src/threading.c | 5 | ||||
| -rw-r--r-- | src/threading.h | 2 | ||||
| -rw-r--r-- | src/tools.c | 96 | ||||
| -rw-r--r-- | src/tools.h | 12 | ||||
| -rw-r--r-- | tests/fibonacci.lua | 5 | ||||
| -rw-r--r-- | tests/irayo_recursive.lua | 6 | ||||
| -rw-r--r-- | tests/recursive.lua | 6 |
13 files changed, 319 insertions, 213 deletions
| @@ -1,6 +1,19 @@ | |||
| 1 | CHANGES: | 1 | CHANGES: |
| 2 | 2 | ||
| 3 | CHANGE 72: BGe 3-Ost-13 | 3 | CHANGE 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 | |||
| 7 | CHANGE 75: BGe 7-Oct-13 | ||
| 8 | * require "lanes".configure() sequence is only necessary at the first require "lanes". | ||
| 9 | |||
| 10 | CHANGE 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 | |||
| 13 | CHANGE 73: BGe 4-Oct-13 | ||
| 14 | * fix timers broken by change 69 | ||
| 15 | |||
| 16 | CHANGE 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 | ||
| 6 | CHANGE 71: BGe 30-Sept-13 | 19 | 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 @@ | |||
| 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 | |||
| 70 | static keeper_fifo* prepare_fifo_access( lua_State* L, int idx) | 70 | static 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 | */ |
| 564 | char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers) | 568 | char 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 | ||
| 16 | char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers); | 16 | char const* init_keepers( lua_State* L); |
| 17 | #if !HAVE_KEEPER_ATEXIT_DESINIT | 17 | #if !HAVE_KEEPER_ATEXIT_DESINIT |
| 18 | void close_keepers( void); | 18 | void 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 | ||
| 55 | char const* VERSION = "3.6.6"; | 55 | char 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 ) | |||
| 2632 | static const struct luaL_Reg lanes_functions [] = { | 2643 | static 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 | */ |
| 2648 | 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) | 2657 | static 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 | ||
| 2757 | LUAG_FUNC( configure) | 2776 | LUAG_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 | ||
| 38 | local 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 |
| 42 | local lanes = {} | 43 | local lanes = {} |
| 43 | 44 | ||
| 44 | lanes.configure = function( _params) | 45 | -- this function is available in the public interface until it is called, after which it disappears |
| 46 | lanes.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 |
| 321 | end | 320 | end |
| 322 | 321 | ||
| 323 | ---=== Lindas ===--- | 322 | ---=== Lindas ===--- |
| @@ -338,7 +337,7 @@ local timer = function() error "timers are not active" end | |||
| 338 | local timer_lane = nil | 337 | local timer_lane = nil |
| 339 | local timers = timer | 338 | local timers = timer |
| 340 | 339 | ||
| 341 | if _params.with_timers ~= false then | 340 | if settings.with_timers ~= false then |
| 342 | 341 | ||
| 343 | local timer_gateway = assert( core.timer_gateway) | 342 | local timer_gateway = assert( core.timer_gateway) |
| 344 | -- | 343 | -- |
| @@ -364,6 +363,8 @@ timer_gateway:set(first_time_key,true) | |||
| 364 | -- | 363 | -- |
| 365 | if first_time then | 364 | if 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 |
| 602 | end | 597 | end |
| 603 | 598 | ||
| 604 | end -- _params.with_timers | 599 | end -- 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 |
| 695 | end -- lanes.configure | 680 | end -- lanes.configure |
| 696 | 681 | ||
| 682 | -- no need to force calling configure() excepted the first time | ||
| 683 | if core.settings then | ||
| 684 | return lanes.configure() | ||
| 685 | else | ||
| 686 | return lanes | ||
| 687 | end | ||
| 688 | |||
| 697 | --the end | 689 | --the end |
| 698 | return lanes | 690 | 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. | |||
| 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) |
| 87 | static void FAIL( const char *funcname, int rc ) { | 87 | static 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 | */ | ||
| 52 | void 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 |
| 48 | bool_t GVerboseErrors = FALSE; | 61 | bool_t GVerboseErrors = FALSE; |
| 49 | 62 | ||
| 63 | char const* const CONFIG_REGKEY = "ee932492-a654-4506-9da8-f16540bdb5d4"; | ||
| 64 | char 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) | ||
| 163 | void 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 | ||
| 174 | static void open1lib( lua_State* L, char const* name, size_t len) | 209 | static 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; | |||
| 83 | void luaG_dump( lua_State* L ); | 84 | void luaG_dump( lua_State* L ); |
| 84 | 85 | ||
| 85 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs); | 86 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs); |
| 87 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_); | ||
| 86 | 88 | ||
| 87 | typedef struct { | 89 | typedef 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 |
| 118 | extern bool_t GVerboseErrors; | 120 | extern bool_t GVerboseErrors; |
| 119 | 121 | ||
| 120 | #endif | 122 | char const* const CONFIG_REGKEY; |
| 121 | // TOOLS_H | 123 | char 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 | -- |
| 15 | local lanes = require "lanes" | 15 | local lanes = require "lanes".configure{ nb_keepers =1, with_timers = false} |
| 16 | lanes.configure{ nb_keepers =1, with_timers = false} | ||
| 17 | 16 | ||
| 18 | local function WR(str) | 17 | local function WR(str) |
| 19 | io.stderr:write( str.."\n" ) | 18 | io.stderr:write( str.."\n" ) |
| @@ -33,7 +32,7 @@ end | |||
| 33 | -- | 32 | -- |
| 34 | local function fib( n ) | 33 | local 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 @@ | |||
| 1 | local 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] |
| 16 | end | 16 | end |
| 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] |
| 19 | end | 21 | end |
