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-09-27 20:34:51 +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-09-27 20:34:51 +0200 |
commit | 623a8f48a624510a0461b0893da647e22e08cdd7 (patch) | |
tree | d414e72f4dedb4d196a24a9b0adc8c4393bbd46c /src | |
parent | f823c6887e28c815234f8b4bd355887b4f554857 (diff) | |
download | lanes-623a8f48a624510a0461b0893da647e22e08cdd7.tar.gz lanes-623a8f48a624510a0461b0893da647e22e08cdd7.tar.bz2 lanes-623a8f48a624510a0461b0893da647e22e08cdd7.zip |
version 3.6.6
no longer call core.configure with dummy params when requiring lanes
more than once (fixes potential multithreading issues with LuaJIT
allocator)
activated EnableCrashingOnCrashes() Win32 debug builds
fixed some comments in code
Diffstat (limited to 'src')
-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 |
4 files changed, 64 insertions, 85 deletions
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)) |