diff options
author | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2013-10-11 20:08:32 +0200 |
---|---|---|
committer | Benoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m> | 2013-10-11 20:08:32 +0200 |
commit | 44540b9335f3bbd2f6fda3e13329b28ec76b6d7a (patch) | |
tree | 4b6d659c0976e58f6cbd907b673c2b9d769b9e88 /src | |
parent | 938ee19cfcac09bfcfa1dd2a7861690436024410 (diff) | |
download | lanes-44540b9335f3bbd2f6fda3e13329b28ec76b6d7a.tar.gz lanes-44540b9335f3bbd2f6fda3e13329b28ec76b6d7a.tar.bz2 lanes-44540b9335f3bbd2f6fda3e13329b28ec76b6d7a.zip |
version 3.7.0
* fix lanes.threads() not being available in a lane where
lanes.configure() settings didn't contain track_lanes although the
initial configure() call did.
* require "lanes".configure() sequence is only necessary at the first
require "lanes".
* fix a crash at application shutdown where in some situations we could
deinitialize the protected allocator mutex while a lane was still using
it.
* fix timers broken by change 69
Diffstat (limited to 'src')
-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 |
8 files changed, 288 insertions, 198 deletions
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 | ||