aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2011-02-21 20:33:39 +0100
committerBenoit Germain <bnt.germain@gmail.com>2011-02-21 20:33:39 +0100
commit974aa4343cf900938b5d357d10798d91faf60f5a (patch)
treeb71a342e26ce04c447955f2fc135b69760ab7837
parent1760eafa1d2ebce8f07e11414a53d4a251af5b8e (diff)
downloadlanes-974aa4343cf900938b5d357d10798d91faf60f5a.tar.gz
lanes-974aa4343cf900938b5d357d10798d91faf60f5a.tar.bz2
lanes-974aa4343cf900938b5d357d10798d91faf60f5a.zip
Make the number of internal keeper states selectable by an optional parameter passed to require.
-rw-r--r--CHANGES11
-rw-r--r--docs/index.html41
-rw-r--r--src/keeper.c39
-rw-r--r--src/keeper.h2
-rw-r--r--src/lanes.c33
-rw-r--r--src/lanes.lua2
6 files changed, 71 insertions, 57 deletions
diff --git a/CHANGES b/CHANGES
index 1850415..bc0368a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,9 +3,12 @@ CHANGES:
3 3
4CHANGE X: 4CHANGE X:
5 5
6CHANGE 29 BGe 21-Feb-2011
7 Make the number of internal keeper states selectable by an optional parameter passed to require.
8
6CHANGE 28 BGe 18-Feb-2011 9CHANGE 28 BGe 18-Feb-2011
7 - moved keeper-related code in a separate source file 10 Moved keeper-related code in a separate source file
8 - keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility 11 keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility
9 12
10CHANGE 27 BGe 17-Feb-2011 13CHANGE 27 BGe 17-Feb-2011
11 - we know Lanes is loaded in the master state, so we don't force it 14 - we know Lanes is loaded in the master state, so we don't force it
@@ -26,7 +29,7 @@ CHANGE 26 BGe 14-Feb-2011:
26 inter-state data copy for unsupported types 29 inter-state data copy for unsupported types
27 30
28CHANGE 25 BGe 12-Feb-2011: 31CHANGE 25 BGe 12-Feb-2011:
29 Changed idfunc signature and contract to clarify that fact it is not lua-callable 32 Changed idfunc signature and contract to clarify the fact it is not lua-callable
30 and to be able to require the module it was exported from in the target lanes 33 and to be able to require the module it was exported from in the target lanes
31 34
32CHANGE 24 DPtr 25-Jan-2011: 35CHANGE 24 DPtr 25-Jan-2011:
@@ -56,7 +59,7 @@ CHANGE 19 BGe 2-Dec-2010:
56 59
57CHANGE 18 BGe 6-Oct-2010: 60CHANGE 18 BGe 6-Oct-2010:
58 Fixed 'memory leak' in some situations where a free running lane is collected before application shutdown 61 Fixed 'memory leak' in some situations where a free running lane is collected before application shutdown
59 A bit of code cleanup 62 A bit of code cleanup
60 63
61CHANGE 17 BGe 21-Sept-2010: 64CHANGE 17 BGe 21-Sept-2010:
62 Fixed stupid compilation errors. 65 Fixed stupid compilation errors.
diff --git a/docs/index.html b/docs/index.html
index a28dd41..3d2ecf2 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -56,7 +56,7 @@
56 56
57<p><br/><font size="-1"><i>Copyright &copy; 2007-11 Asko Kauppi. All rights reserved.</i> 57<p><br/><font size="-1"><i>Copyright &copy; 2007-11 Asko Kauppi. All rights reserved.</i>
58 <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1. 58 <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1.
59 </p><p>This document was revised on 12-Feb-11, and applies to version 2.0.11. 59 </p><p>This document was revised on 21-Feb-11, and applies to version 2.1.0.
60</font></p> 60</font></p>
61 61
62</center> 62</center>
@@ -817,12 +817,12 @@ can be used for custom userdata as well. Here's what to do.
817 <tt>"delete"</tt>: receives this same pointer on the stack, and should cleanup the object.</li> 817 <tt>"delete"</tt>: receives this same pointer on the stack, and should cleanup the object.</li>
818 <li> 818 <li>
819 <tt>"metatable"</tt>: should build a metatable for the object. Don't cache the metatable 819 <tt>"metatable"</tt>: should build a metatable for the object. Don't cache the metatable
820yourself, Lanes takes care of it ("metatable" should only be invoked once).</li> 820 yourself, Lanes takes care of it ("metatable" should only be invoked once).</li>
821 <li> 821 <li>
822 <tt>"module"</tt>: is the name of the module that exports the idfunc, 822 <tt>"module"</tt>: is the name of the module that exports the idfunc,
823to be pushed on the stack as a string. It is necessary so that Lanes can require it in 823 to be pushed on the stack as a string. It is necessary so that Lanes can require it in
824any Lane and keeper state that receives a userdata. This is to prevent crashes in situations 824 any Lane and keeper state that receives a userdata. This is to prevent crashes in situations
825where the module could be unloaded while the idfunc pointer is still held.</li> 825 where the module could be unloaded while the idfunc pointer is still held.</li>
826</ul> 826</ul>
827Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>. 827Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>.
828 </li> 828 </li>
@@ -917,10 +917,10 @@ Here are some things one should consider, if best performance is vital:
917 merged into one main timer state (see <tt>timer.lua</tt>); no OS side 917 merged into one main timer state (see <tt>timer.lua</tt>); no OS side
918 timers are utilized. 918 timers are utilized.
919 </li> 919 </li>
920 <li>Lindas are hashed to a fixed number of "keeper states", which are a locking entity. 920 <li>Lindas are hashed to a number of "keeper states", which are a locking entity.
921 If you are using a lot of Linda objects, 921 If you are using a lot of Linda objects, it may be useful to try having more of
922 it may be useful to try having more of these keeper states. By default, 922 these keeper states. By default, only one is used but this is an implementation detail.
923 only one is used (see <tt>KEEPER_STATES_N</tt>), but this is an implementation detail. 923 It is possible to <tt>require( "lanes", N)</tt> to use more keeper states.
924 </li> 924 </li>
925</ul> 925</ul>
926</p> 926</p>
@@ -952,6 +952,29 @@ its actual value.
952<h2 id="changes">Change log</h2> 952<h2 id="changes">Change log</h2>
953 953
954<p> 954<p>
955Feb-2011 (2.1.0)
956<ul>
957 <li>Added an auto-require mechanism to ensure any deep userdata transiting in a lane causes its parent module to be required in that lane
958 <ul>
959 <li>Changed idfunc signature and contract to clarify the fact it is not lua-callable and to be able to require the module it was exported from in the target lanes</li>
960 <li>When a deep userdata idfunc requests a module to be required, manually check that it is not loaded before requiring it instead of relying on the require function's loop detection feature</li>
961 <li>When a module must be required, raise an error if the 'require' function is not found in the target state</li>
962 <li>We know Lanes is loaded in the master state, so we don't force it to be required in every lane too when a linda deep userdata is copied</li>
963 </ul>
964 </li>
965 <li>Fixed application hang-up because keeper state was not released in case of errors thrown by inter-state data copy for unsupported types</li>
966 <li>Refactor lane proxy implementation: it is now a full userdata instead of a table, and its methods are implemented in C instead of Lua
967 <ul>
968 <li>its metatable is no longer accessible</li>
969 <li>writing to the proxy raises an error</li>
970 <li>it is no longer possible to overwrite its join() and cancel() methods</li>
971 </ul>
972 </li>
973 <li>Moved keeper-related code in a separate source file</li>
974 <li>keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility</li>
975 <li>Make the number of internal keeper states selctable by an optional parameter passed to require.</li>
976</ul>
977
955Feb-2011 (2.0.11): 978Feb-2011 (2.0.11):
956<ul> 979<ul>
957 <li>Fixed bug where reference to Linda object was dropped for a short time (crashing if GC was run during that time).</li> 980 <li>Fixed bug where reference to Linda object was dropped for a short time (crashing if GC was run during that time).</li>
diff --git a/src/keeper.c b/src/keeper.c
index f19beed..f89c638 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -53,12 +53,6 @@
53/*---=== Keeper states ===--- 53/*---=== Keeper states ===---
54*/ 54*/
55 55
56/* The selected number is not optimal; needs to be tested. Even using just
57* one keeper state may be good enough (depends on the number of Lindas used
58* in the applications).
59*/
60#define KEEPER_STATES_N 1 // 6
61
62/* 56/*
63* Pool of keeper states 57* Pool of keeper states
64* 58*
@@ -66,12 +60,8 @@
66* bigger the pool, the less chances of unnecessary waits. Lindas map to the 60* bigger the pool, the less chances of unnecessary waits. Lindas map to the
67* keepers randomly, by a hash. 61* keepers randomly, by a hash.
68*/ 62*/
69static struct s_Keeper GKeepers[KEEPER_STATES_N]; 63static struct s_Keeper *GKeepers = NULL;
70 64static int GNbKeepers = 0;
71/* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
72* checking for a lightuserdata is faster.
73*/
74static bool_t nil_sentinel = 0;
75 65
76/* 66/*
77* Lua code for the keeper states (baked in) 67* Lua code for the keeper states (baked in)
@@ -88,10 +78,13 @@ static char const keeper_chunk[]=
88* unclosed, because it does not really matter. In production code, this 78* unclosed, because it does not really matter. In production code, this
89* function never fails. 79* function never fails.
90*/ 80*/
91const char *init_keepers(void) 81char const *init_keepers( int const _nbKeepers)
92{ 82{
93 unsigned int i; 83 int i;
94 for( i=0; i<KEEPER_STATES_N; i++ ) 84 assert( _nbKeepers >= 1);
85 GNbKeepers = _nbKeepers;
86 GKeepers = malloc( _nbKeepers * sizeof( struct s_Keeper));
87 for( i = 0; i < _nbKeepers; ++ i)
95 { 88 {
96 89
97 // Initialize Keeper states with bare minimum of libs (those required 90 // Initialize Keeper states with bare minimum of libs (those required
@@ -104,8 +97,11 @@ const char *init_keepers(void)
104 luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs 97 luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs
105 serialize_require( L); 98 serialize_require( L);
106 99
107 lua_pushlightuserdata( L, &nil_sentinel ); 100 /* We could use an empty table in 'keeper.lua' as the sentinel, but maybe
108 lua_setglobal( L, "nil_sentinel" ); 101 * checking for a lightuserdata is faster. (any unique value will do -> take the address of some global of ours)
102 */
103 lua_pushlightuserdata( L, &GNbKeepers);
104 lua_setglobal( L, "nil_sentinel");
109 105
110 // Read in the preloaded chunk (and run it) 106 // Read in the preloaded chunk (and run it)
111 // 107 //
@@ -131,12 +127,12 @@ const char *init_keepers(void)
131struct s_Keeper *keeper_acquire( const void *ptr) 127struct s_Keeper *keeper_acquire( const void *ptr)
132{ 128{
133 /* 129 /*
134 * Any hashing will do that maps pointers to 0..KEEPER_STATES_N-1 130 * Any hashing will do that maps pointers to 0..GNbKeepers-1
135 * consistently. 131 * consistently.
136 * 132 *
137 * Pointers are often aligned by 8 or so - ignore the low order bits 133 * Pointers are often aligned by 8 or so - ignore the low order bits
138 */ 134 */
139 unsigned int i= ((unsigned long)(ptr) >> 3) % KEEPER_STATES_N; 135 unsigned int i= ((unsigned long)(ptr) >> 3) % GNbKeepers;
140 struct s_Keeper *K= &GKeepers[i]; 136 struct s_Keeper *K= &GKeepers[i];
141 137
142 MUTEX_LOCK( &K->lock_); 138 MUTEX_LOCK( &K->lock_);
@@ -190,10 +186,13 @@ int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda,
190void close_keepers(void) 186void close_keepers(void)
191{ 187{
192 int i; 188 int i;
193 for(i=0;i<KEEPER_STATES_N;i++) 189 for( i = 0; i < GNbKeepers; ++ i)
194 { 190 {
195 lua_close( GKeepers[i].L); 191 lua_close( GKeepers[i].L);
196 GKeepers[i].L = 0; 192 GKeepers[i].L = 0;
197 //assert( GKeepers[i].count == 0); 193 //assert( GKeepers[i].count == 0);
198 } 194 }
195 if( GKeepers) free( GKeepers);
196 GKeepers = NULL;
197 GNbKeepers = 0;
199} 198}
diff --git a/src/keeper.h b/src/keeper.h
index 66d8d7e..e959c7c 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -8,7 +8,7 @@ struct s_Keeper
8 //int count; 8 //int count;
9}; 9};
10 10
11const char *init_keepers(void); 11const char *init_keepers( int const _nbKeepers);
12struct s_Keeper *keeper_acquire( const void *ptr); 12struct s_Keeper *keeper_acquire( const void *ptr);
13void keeper_release( struct s_Keeper *K); 13void keeper_release( struct s_Keeper *K);
14int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index); 14int keeper_call( lua_State *K, char const *func_name, lua_State *L, void *linda, uint_t starting_index);
diff --git a/src/lanes.c b/src/lanes.c
index a8aba71..8b62532 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -4,20 +4,7 @@
4 * Multithreading in Lua. 4 * Multithreading in Lua.
5 * 5 *
6 * History: 6 * History:
7 * 3-Jan-11 (2.0.10): linda_send bugfix, was waiting on the wrong signal 7 * See CHANGES
8 * 3-Dec-10 (2.0.9): Added support to generate a lane from a string
9 * 2-Dec-10 (2.0.8): Fix LuaJIT2 incompatibility (no 'tostring' hijack anymore)
10 * ???????? (2.0.7): Fixed 'memory leak' in some situations where a free running
11 * lane is collected before application shutdown
12 * 24-Aug-10 (2.0.6): Mem fixes, argument checking (lua_toLinda result), thread name
13 * 24-Jun-09 (2.0.4): Made friendly to already multithreaded host apps.
14 * 20-Oct-08 (2.0.2): Added closing of free-running threads, but it does
15 * not seem to eliminate the occasional segfaults at process
16 * exit.
17 * ...
18 * 24-Jun-08 .. 14-Aug-08 AKa: Major revise, Lanes 2008 version (2.0 rc1)
19 * ...
20 * 18-Sep-06 AKa: Started the module.
21 * 8 *
22 * Platforms (tested internally): 9 * Platforms (tested internally):
23 * OS X (10.5.7 PowerPC/Intel) 10 * OS X (10.5.7 PowerPC/Intel)
@@ -64,7 +51,7 @@
64 * ... 51 * ...
65 */ 52 */
66 53
67const char *VERSION= "2.0.11"; 54const char *VERSION= "2.1.0";
68 55
69/* 56/*
70=============================================================================== 57===============================================================================
@@ -1913,7 +1900,7 @@ static const struct luaL_reg lanes_functions [] = {
1913/* 1900/*
1914* One-time initializations 1901* One-time initializations
1915*/ 1902*/
1916static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ref ) 1903static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ref, int const nbKeepers)
1917{ 1904{
1918 const char *err; 1905 const char *err;
1919 1906
@@ -1964,7 +1951,7 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
1964 } 1951 }
1965 #endif 1952 #endif
1966#endif 1953#endif
1967 err= init_keepers(); 1954 err= init_keepers( nbKeepers);
1968 if (err) 1955 if (err)
1969 { 1956 {
1970 luaL_error( L, "Unable to initialize: %s", err ); 1957 luaL_error( L, "Unable to initialize: %s", err );
@@ -2001,8 +1988,11 @@ int
2001#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 1988#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2002__declspec(dllexport) 1989__declspec(dllexport)
2003#endif 1990#endif
2004 luaopen_lanes( lua_State *L ) { 1991luaopen_lanes( lua_State *L )
2005 1992{
1993 static volatile int /*bool*/ go_ahead; // = 0
1994 int const nbKeepers = luaL_optint( L, 2, 1);
1995 luaL_argcheck( L, nbKeepers > 0, 2, "Number of keeper states must be > 0");
2006 /* 1996 /*
2007 * Making one-time initializations. 1997 * Making one-time initializations.
2008 * 1998 *
@@ -2010,7 +2000,6 @@ __declspec(dllexport)
2010 * there is no problem. But if the host is multithreaded, we need to lock around the 2000 * there is no problem. But if the host is multithreaded, we need to lock around the
2011 * initializations. 2001 * initializations.
2012 */ 2002 */
2013 static volatile int /*bool*/ go_ahead; // = 0
2014#ifdef PLATFORM_WIN32 2003#ifdef PLATFORM_WIN32
2015 { 2004 {
2016 // TBD: Someone please replace this with reliable Win32 API code. Problem is, 2005 // TBD: Someone please replace this with reliable Win32 API code. Problem is,
@@ -2022,7 +2011,7 @@ __declspec(dllexport)
2022 static volatile unsigned my_number; // = 0 2011 static volatile unsigned my_number; // = 0
2023 2012
2024 if (my_number++ == 0) { // almost atomic 2013 if (my_number++ == 0) { // almost atomic
2025 init_once_LOCKED(L, &timer_deep); 2014 init_once_LOCKED(L, &timer_deep, nbKeepers);
2026 go_ahead= 1; // let others pass 2015 go_ahead= 1; // let others pass
2027 } else { 2016 } else {
2028 while( !go_ahead ) { Sleep(1); } // changes threads 2017 while( !go_ahead ) { Sleep(1); } // changes threads
@@ -2036,7 +2025,7 @@ __declspec(dllexport)
2036 // Recheck now that we're within the lock 2025 // Recheck now that we're within the lock
2037 // 2026 //
2038 if (!go_ahead) { 2027 if (!go_ahead) {
2039 init_once_LOCKED(L, &timer_deep); 2028 init_once_LOCKED(L, &timer_deep, nbKeepers);
2040 go_ahead= 1; 2029 go_ahead= 1;
2041 } 2030 }
2042 } 2031 }
diff --git a/src/lanes.lua b/src/lanes.lua
index 95bdeeb..78582f9 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -52,7 +52,6 @@ local _version= assert(mm._version)
52 52
53local now_secs= assert( mm.now_secs ) 53local now_secs= assert( mm.now_secs )
54local wakeup_conv= assert( mm.wakeup_conv ) 54local wakeup_conv= assert( mm.wakeup_conv )
55local timer_gateway= assert( mm.timer_gateway )
56 55
57local max_prio= assert( mm.max_prio ) 56local max_prio= assert( mm.max_prio )
58 57
@@ -239,6 +238,7 @@ linda = mm.linda
239 238
240---=== Timers ===--- 239---=== Timers ===---
241 240
241local timer_gateway= assert( mm.timer_gateway )
242-- 242--
243-- On first 'require "lanes"', a timer lane is spawned that will maintain 243-- On first 'require "lanes"', a timer lane is spawned that will maintain
244-- timer tables and sleep in between the timer events. All interaction with 244-- timer tables and sleep in between the timer events. All interaction with