diff options
-rw-r--r-- | CHANGES | 6 | ||||
-rw-r--r-- | docs/index.html | 2 | ||||
-rw-r--r-- | src/keeper.c | 2 | ||||
-rw-r--r-- | src/lanes.c | 120 | ||||
-rw-r--r-- | src/lanes.lua | 19 | ||||
-rw-r--r-- | src/tools.c | 8 |
6 files changed, 71 insertions, 86 deletions
@@ -1,5 +1,11 @@ | |||
1 | CHANGES: | 1 | CHANGES: |
2 | 2 | ||
3 | CHANGE 70: BGe 27-Step-13 | ||
4 | * version 3.6.6 | ||
5 | * no longer call core.configure with dummy params when requiring lanes more than once (fixes potential multithreading issues with LuaJIT allocator) | ||
6 | * activated EnableCrashingOnCrashes() is active on Win32 debug builds | ||
7 | * fixed some comments in code | ||
8 | |||
3 | CHANGE 69: BGe 26-Sept-13 | 9 | CHANGE 69: BGe 26-Sept-13 |
4 | * version 3.6.5 | 10 | * version 3.6.5 |
5 | * Reduce memory footprint, simplify module order setup in conjuction with Lanes, and send over native functions a bit faster as well | 11 | * Reduce memory footprint, simplify module order setup in conjuction with Lanes, and send over native functions a bit faster as well |
diff --git a/docs/index.html b/docs/index.html index ac4fa6b..b0ef8a3 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 26-Sept-13, and applies to version <tt>3.6.5</tt>. | 73 | This document was revised on 27-Sept-13, and applies to version <tt>3.6.6</tt>. |
74 | </p> | 74 | </p> |
75 | </font> | 75 | </font> |
76 | </center> | 76 | </center> |
diff --git a/src/keeper.c b/src/keeper.c index 8d9f7ec..bd232cd 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -572,8 +572,6 @@ char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepe | |||
572 | lua_State* K; | 572 | lua_State* K; |
573 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d BEGIN\n" INDENT_END, i)); | 573 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "### init_keepers %d BEGIN\n" INDENT_END, i)); |
574 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 574 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
575 | // We need to load all base libraries in the keeper states so that the transfer databases are populated properly | ||
576 | // | ||
577 | // we don't need any libs in the keeper states | 575 | // we don't need any libs in the keeper states |
578 | K = luaG_newstate( L, _on_state_create, NULL); | 576 | K = luaG_newstate( L, _on_state_create, NULL); |
579 | 577 | ||
diff --git a/src/lanes.c b/src/lanes.c index dc1eeed..f4427a4 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.5"; | 55 | char const* VERSION = "3.6.6"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
@@ -414,8 +414,8 @@ LUAG_FUNC( linda_send) | |||
414 | 414 | ||
415 | STACK_GROW(L, 1); | 415 | STACK_GROW(L, 1); |
416 | { | 416 | { |
417 | struct s_Keeper *K = keeper_acquire( linda); | 417 | struct s_Keeper* K = keeper_acquire( linda); |
418 | lua_State *KL = K->L; // need to do this for 'STACK_CHECK' | 418 | lua_State* KL = K->L; // need to do this for 'STACK_CHECK' |
419 | STACK_CHECK( KL); | 419 | STACK_CHECK( KL); |
420 | for( ;;) | 420 | for( ;;) |
421 | { | 421 | { |
@@ -2734,7 +2734,6 @@ LUAG_FUNC( configure) | |||
2734 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); | 2734 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); |
2735 | // all parameter checks are done lua-side | 2735 | // all parameter checks are done lua-side |
2736 | int const nbKeepers = (int)lua_tointeger( L, 1); | 2736 | int const nbKeepers = (int)lua_tointeger( L, 1); |
2737 | // all these can be nil when lanes.core is required internally! (but are only processed at first init anyway) | ||
2738 | int const on_state_create = lua_isfunction( L, 2) ? 2 : 0; | 2737 | int const on_state_create = lua_isfunction( L, 2) ? 2 : 0; |
2739 | lua_Number shutdown_timeout = lua_tonumber( L, 3); | 2738 | lua_Number shutdown_timeout = lua_tonumber( L, 3); |
2740 | bool_t track_lanes = lua_toboolean( L, 4); | 2739 | bool_t track_lanes = lua_toboolean( L, 4); |
@@ -2759,6 +2758,45 @@ LUAG_FUNC( configure) | |||
2759 | lua_setallocf( L, protected_lua_Alloc, s); | 2758 | lua_setallocf( L, protected_lua_Alloc, s); |
2760 | } | 2759 | } |
2761 | } | 2760 | } |
2761 | STACK_MID( L, 0); | ||
2762 | |||
2763 | /* | ||
2764 | ** Making one-time initializations. | ||
2765 | ** | ||
2766 | ** When the host application is single-threaded (and all threading happens via Lanes) | ||
2767 | ** there is no problem. But if the host is multithreaded, we need to lock around the | ||
2768 | ** initializations. | ||
2769 | */ | ||
2770 | #if THREADAPI == THREADAPI_WINDOWS | ||
2771 | { | ||
2772 | static volatile int /*bool*/ go_ahead; // = 0 | ||
2773 | if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) | ||
2774 | { | ||
2775 | init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); | ||
2776 | go_ahead = 1; // let others pass | ||
2777 | } | ||
2778 | else | ||
2779 | { | ||
2780 | while( !go_ahead) { Sleep(1); } // changes threads | ||
2781 | } | ||
2782 | } | ||
2783 | #else // THREADAPI == THREADAPI_PTHREAD | ||
2784 | if( s_initCount == 0) | ||
2785 | { | ||
2786 | static pthread_mutex_t my_lock = PTHREAD_MUTEX_INITIALIZER; | ||
2787 | pthread_mutex_lock( &my_lock); | ||
2788 | { | ||
2789 | // Recheck now that we're within the lock | ||
2790 | // | ||
2791 | if( s_initCount == 0) | ||
2792 | { | ||
2793 | init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); | ||
2794 | s_initCount = 1; | ||
2795 | } | ||
2796 | } | ||
2797 | pthread_mutex_unlock( &my_lock); | ||
2798 | } | ||
2799 | #endif // THREADAPI == THREADAPI_PTHREAD | ||
2762 | 2800 | ||
2763 | // Create main module interface table | 2801 | // Create main module interface table |
2764 | lua_pushvalue( L, lua_upvalueindex( 2)); // ... M | 2802 | lua_pushvalue( L, lua_upvalueindex( 2)); // ... M |
@@ -2818,49 +2856,7 @@ LUAG_FUNC( configure) | |||
2818 | populate_func_lookup_table( L, -1, NULL); | 2856 | populate_func_lookup_table( L, -1, NULL); |
2819 | lua_pop( L, 1); // ... M | 2857 | lua_pop( L, 1); // ... M |
2820 | 2858 | ||
2821 | STACK_MID( L, 1); | 2859 | ASSERT_L( timer_deep != NULL); |
2822 | /* | ||
2823 | ** Making one-time initializations. | ||
2824 | ** | ||
2825 | ** When the host application is single-threaded (and all threading happens via Lanes) | ||
2826 | ** there is no problem. But if the host is multithreaded, we need to lock around the | ||
2827 | ** initializations. | ||
2828 | ** we must do this after the populate_func_lookup_table is called, else populating the keepers will fail | ||
2829 | ** because this makes a copy of packages.loaders, which requires the lookup tables to exist! | ||
2830 | */ | ||
2831 | #if THREADAPI == THREADAPI_WINDOWS | ||
2832 | { | ||
2833 | static volatile int /*bool*/ go_ahead; // = 0 | ||
2834 | if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) | ||
2835 | { | ||
2836 | init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); | ||
2837 | go_ahead = 1; // let others pass | ||
2838 | } | ||
2839 | else | ||
2840 | { | ||
2841 | while( !go_ahead ) { Sleep(1); } // changes threads | ||
2842 | } | ||
2843 | } | ||
2844 | #else // THREADAPI == THREADAPI_PTHREAD | ||
2845 | if( s_initCount == 0) | ||
2846 | { | ||
2847 | static pthread_mutex_t my_lock = PTHREAD_MUTEX_INITIALIZER; | ||
2848 | pthread_mutex_lock( &my_lock); | ||
2849 | { | ||
2850 | // Recheck now that we're within the lock | ||
2851 | // | ||
2852 | if( s_initCount == 0) | ||
2853 | { | ||
2854 | init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors); | ||
2855 | s_initCount = 1; | ||
2856 | } | ||
2857 | } | ||
2858 | pthread_mutex_unlock( &my_lock); | ||
2859 | } | ||
2860 | #endif // THREADAPI == THREADAPI_PTHREAD | ||
2861 | STACK_MID( L, 1); | ||
2862 | |||
2863 | assert( timer_deep != NULL); | ||
2864 | // init_once_LOCKED initializes timer_deep, so we must do this after, of course | 2860 | // init_once_LOCKED initializes timer_deep, so we must do this after, of course |
2865 | luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // ... M timer_deep | 2861 | luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // ... M timer_deep |
2866 | lua_setfield( L, -2, "timer_gateway"); // ... M | 2862 | lua_setfield( L, -2, "timer_gateway"); // ... M |
@@ -2875,9 +2871,9 @@ LUAG_FUNC( configure) | |||
2875 | 2871 | ||
2876 | // helper to have correct callstacks when crashing a Win32 running on 64 bits Windows | 2872 | // helper to have correct callstacks when crashing a Win32 running on 64 bits Windows |
2877 | // don't forget to toggle Debug/Exceptions/Win32 in visual Studio too! | 2873 | // don't forget to toggle Debug/Exceptions/Win32 in visual Studio too! |
2878 | void EnableCrashingOnCrashes() | 2874 | static void EnableCrashingOnCrashes( void) |
2879 | { | 2875 | { |
2880 | #if 0 && defined PLATFORM_WIN32 | 2876 | #if defined PLATFORM_WIN32 && !defined NDEBUG |
2881 | typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); | 2877 | typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); |
2882 | typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); | 2878 | typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); |
2883 | const DWORD EXCEPTION_SWALLOWING = 0x1; | 2879 | const DWORD EXCEPTION_SWALLOWING = 0x1; |
@@ -2885,13 +2881,13 @@ void EnableCrashingOnCrashes() | |||
2885 | HMODULE kernel32 = LoadLibraryA("kernel32.dll"); | 2881 | HMODULE kernel32 = LoadLibraryA("kernel32.dll"); |
2886 | tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy"); | 2882 | tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy"); |
2887 | tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy"); | 2883 | tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy"); |
2888 | if (pGetPolicy && pSetPolicy) | 2884 | if( pGetPolicy && pSetPolicy) |
2889 | { | 2885 | { |
2890 | DWORD dwFlags; | 2886 | DWORD dwFlags; |
2891 | if (pGetPolicy(&dwFlags)) | 2887 | if( pGetPolicy( &dwFlags)) |
2892 | { | 2888 | { |
2893 | // Turn off the filter | 2889 | // Turn off the filter |
2894 | pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); | 2890 | pSetPolicy( dwFlags & ~EXCEPTION_SWALLOWING); |
2895 | } | 2891 | } |
2896 | } | 2892 | } |
2897 | #endif // PLATFORM_WIN32 | 2893 | #endif // PLATFORM_WIN32 |
@@ -2906,21 +2902,11 @@ int LANES_API luaopen_lanes_core( lua_State* L) | |||
2906 | 2902 | ||
2907 | // Create main module interface table | 2903 | // Create main module interface table |
2908 | // we only have 1 closure, which must be called to configure Lanes | 2904 | // we only have 1 closure, which must be called to configure Lanes |
2909 | lua_newtable(L); // M | 2905 | lua_newtable( L); // M |
2910 | lua_pushvalue(L, 1); // M "lanes.core" | 2906 | lua_pushvalue( L, 1); // M "lanes.core" |
2911 | lua_pushvalue(L, -2); // M "lanes.core" M | 2907 | lua_pushvalue( L, -2); // M "lanes.core" M |
2912 | lua_pushcclosure( L, LG_configure, 2); // M LG_configure() | 2908 | lua_pushcclosure( L, LG_configure, 2); // M LG_configure() |
2913 | if( s_initCount == 0) | 2909 | lua_setfield( L, -2, "configure"); // M |
2914 | { | ||
2915 | lua_setfield( L, -2, "configure"); // M | ||
2916 | } | ||
2917 | else // already initialized: call it immediately and be done | ||
2918 | { | ||
2919 | // any parameter value will do, they will be ignored | ||
2920 | lua_pushinteger( L, 666); // M LG_configure() 666 | ||
2921 | lua_pushnil( L); // M LG_configure() 666 nil | ||
2922 | lua_call( L, 2, 0); // M | ||
2923 | } | ||
2924 | 2910 | ||
2925 | STACK_END( L, 1); | 2911 | STACK_END( L, 1); |
2926 | return 1; | 2912 | return 1; |
diff --git a/src/lanes.lua b/src/lanes.lua index 175002a..173db00 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
@@ -145,23 +145,18 @@ lanes.configure = function( _params) | |||
145 | 145 | ||
146 | local core = require "lanes.core" | 146 | local core = require "lanes.core" |
147 | assert( type( core)=="table") | 147 | assert( type( core)=="table") |
148 | 148 | core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator, _params.verbose_errors) | |
149 | -- configure() is available only the first time lanes.core is required process-wide, and we *must* call it to have the other functions in the interface | ||
150 | if core.configure then core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator, _params.verbose_errors) end | ||
151 | |||
152 | local thread_new = assert( core.thread_new) | 149 | local thread_new = assert( core.thread_new) |
153 | |||
154 | local set_singlethreaded = assert( core.set_singlethreaded) | 150 | local set_singlethreaded = assert( core.set_singlethreaded) |
155 | |||
156 | local max_prio = assert( core.max_prio) | 151 | local max_prio = assert( core.max_prio) |
157 | 152 | ||
158 | lanes.ABOUT= | 153 | lanes.ABOUT = |
159 | { | 154 | { |
160 | author= "Asko Kauppi <akauppi@gmail.com>, Benoit Germain <bnt.germain@gmail.com>", | 155 | author= "Asko Kauppi <akauppi@gmail.com>, Benoit Germain <bnt.germain@gmail.com>", |
161 | description= "Running multiple Lua states in parallel", | 156 | description= "Running multiple Lua states in parallel", |
162 | license= "MIT/X11", | 157 | license= "MIT/X11", |
163 | copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-12, Benoit Germain", | 158 | copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-13, Benoit Germain", |
164 | version = assert( core.version) | 159 | version = assert( core.version) |
165 | } | 160 | } |
166 | 161 | ||
167 | 162 | ||
diff --git a/src/tools.c b/src/tools.c index a957f41..49194d0 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -1461,12 +1461,12 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLoo | |||
1461 | { | 1461 | { |
1462 | char const* fqn; // L // L2 | 1462 | char const* fqn; // L // L2 |
1463 | size_t len; | 1463 | size_t len; |
1464 | _ASSERT_L( L, lua_isfunction( L, i)); // ... f ... | 1464 | ASSERT_L( lua_isfunction( L, i)); // ... f ... |
1465 | STACK_CHECK( L); | 1465 | STACK_CHECK( L); |
1466 | if( mode_ == eLM_FromKeeper) | 1466 | if( mode_ == eLM_FromKeeper) |
1467 | { | 1467 | { |
1468 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be sentinelfunc! | 1468 | lua_CFunction f = lua_tocfunction( L, i); // should *always* be sentinelfunc! |
1469 | _ASSERT_L( L, f == sentinelfunc); | 1469 | ASSERT_L( f == sentinelfunc); |
1470 | lua_getupvalue( L, i, 1); // ... f ... "f.q.n" | 1470 | lua_getupvalue( L, i, 1); // ... f ... "f.q.n" |
1471 | fqn = lua_tolstring( L, -1, &len); | 1471 | fqn = lua_tolstring( L, -1, &len); |
1472 | } | 1472 | } |
@@ -1474,7 +1474,7 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLoo | |||
1474 | { | 1474 | { |
1475 | // fetch the name from the source state's lookup table | 1475 | // fetch the name from the source state's lookup table |
1476 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {} | 1476 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {} |
1477 | _ASSERT_L( L, lua_istable( L, -1)); | 1477 | ASSERT_L( lua_istable( L, -1)); |
1478 | lua_pushvalue( L, i); // ... f ... {} f | 1478 | lua_pushvalue( L, i); // ... f ... {} f |
1479 | lua_rawget( L, -2); // ... f ... {} "f.q.n" | 1479 | lua_rawget( L, -2); // ... f ... {} "f.q.n" |
1480 | fqn = lua_tolstring( L, -1, &len); | 1480 | fqn = lua_tolstring( L, -1, &len); |
@@ -1521,7 +1521,7 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLoo | |||
1521 | else | 1521 | else |
1522 | { | 1522 | { |
1523 | lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} | 1523 | lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} |
1524 | _ASSERT_L( L2, lua_istable( L2, -1)); | 1524 | ASSERT_L( lua_istable( L2, -1)); |
1525 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" | 1525 | lua_pushlstring( L2, fqn, len); // {} "f.q.n" |
1526 | lua_rawget( L2, -2); // {} f | 1526 | lua_rawget( L2, -2); // {} f |
1527 | if( !lua_isfunction( L2, -1)) | 1527 | if( !lua_isfunction( L2, -1)) |