aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--docs/index.html81
-rw-r--r--src/lanes.c111
-rw-r--r--src/lanes.lua14
-rw-r--r--tests/basic.lua36
5 files changed, 169 insertions, 78 deletions
diff --git a/CHANGES b/CHANGES
index c2b14ed..8575e8d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,10 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 94: BGe 22-Jan-14
4 * version 3.8.2
5 * new lane launcher option gc_cb to set a callback that is invoked when a lane is garbage collected
6 * Fix more invalid memory accesses when fetching the name of a joined lane with lanes:threads() (because its lua_State is closed)
7
3CHANGE 93: BGe 20-Jan-14 8CHANGE 93: BGe 20-Jan-14
4 * slightly improve linda performance when the producer/consumer scenario leaves leave the key empty 9 * slightly improve linda performance when the producer/consumer scenario leaves leave the key empty
5 10
diff --git a/docs/index.html b/docs/index.html
index 7078b13..c662a14 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -63,14 +63,14 @@
63 63
64 <font size="-1"> 64 <font size="-1">
65 <p> 65 <p>
66 <br> 66 <br/>
67 <i>Copyright &copy; 2007-14 Asko Kauppi, Benoit Germain. All rights reserved.</i> 67 <i>Copyright &copy; 2007-14 Asko Kauppi, Benoit Germain. All rights reserved.</i>
68 <br> 68 <br/>
69 Lua Lanes is published under the same <a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a> as Lua 5.1 and 5.2. 69 Lua Lanes is published under the same <a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a> as Lua 5.1 and 5.2.
70 </p> 70 </p>
71 71
72 <p> 72 <p>
73 This document was revised on 20-Jan-14, and applies to version <tt>3.8.1</tt>. 73 This document was revised on 22-Jan-14, and applies to version <tt>3.8.2</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -386,7 +386,7 @@
386 386
387<p> 387<p>
388 (Since v3.5.0) Once Lanes is configured, one should register with Lanes the modules exporting functions that will be transferred either during lane generation or through <a href="#lindas">lindas</a>. 388 (Since v3.5.0) Once Lanes is configured, one should register with Lanes the modules exporting functions that will be transferred either during lane generation or through <a href="#lindas">lindas</a>.
389 <br> 389 <br/>
390 Use <tt>lanes.require()</tt> for this purpose. This will call the original <tt>require()</tt>, then add the result to the lookup databases. 390 Use <tt>lanes.require()</tt> for this purpose. This will call the original <tt>require()</tt>, then add the result to the lookup databases.
391</p> 391</p>
392 392
@@ -418,7 +418,7 @@
418 </td> 418 </td>
419 </tr> 419 </tr>
420</table> 420</table>
421<br> 421<br/>
422<table border=1 bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> 422<table border=1 bgcolor="#E0E0FF" cellpadding="10" style="width:50%">
423 <tr> 423 <tr>
424 <td> 424 <td>
@@ -596,10 +596,19 @@
596 These tables are built from the modules listed here. <tt>required</tt> must be a list of strings, each one being the name of a module to be required. Each module is required with <tt>require()</tt> before the lanes function is invoked. 596 These tables are built from the modules listed here. <tt>required</tt> must be a list of strings, each one being the name of a module to be required. Each module is required with <tt>require()</tt> before the lanes function is invoked.
597 So, from the required module's point of view, requiring it manually from inside the lane body or having it required this way doesn't change anything. From the lane body's point of view, the only difference is that a module not creating a global won't be accessible. 597 So, from the required module's point of view, requiring it manually from inside the lane body or having it required this way doesn't change anything. From the lane body's point of view, the only difference is that a module not creating a global won't be accessible.
598 Therefore, a lane body will also have to require a module manually, but this won't do anything more (see Lua's <tt>require</tt> documentation). 598 Therefore, a lane body will also have to require a module manually, but this won't do anything more (see Lua's <tt>require</tt> documentation).
599 <br> 599 <br/>
600 ATTEMPTING TO TRANSFER A FUNCTION REGISTERED BY A MODULE NOT LISTED HERE WILL RAISE AN ERROR. 600 ATTEMPTING TO TRANSFER A FUNCTION REGISTERED BY A MODULE NOT LISTED HERE WILL RAISE AN ERROR.
601 </td> 601 </td>
602 </tr> 602 </tr>
603 <tr id="Tr1" valign=top>
604 <td>
605 <code>.gc_cb</code>
606 </td>
607 <td>function</td>
608 <td>
609 (Since version 3.8.2) Callback that gets invoked when the lane is garbage collected. The function receives two arguments (the lane name and a string, either <tt>"closed"</tt> or <tt>"selfdestruct"</tt>).
610 </td>
611 </tr>
603 <tr valign=top> 612 <tr valign=top>
604 <td> 613 <td>
605 <code>.priority</code> 614 <code>.priority</code>
@@ -608,9 +617,9 @@
608 <td> 617 <td>
609 The priority of lanes generated in the range -3..+3 (default is 0). 618 The priority of lanes generated in the range -3..+3 (default is 0).
610 These values are a mapping over the actual priority range of the underlying implementation. 619 These values are a mapping over the actual priority range of the underlying implementation.
611 <br> 620 <br/>
612 Implementation and dependability of priorities varies by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode. 621 Implementation and dependability of priorities varies by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode.
613 <br> 622 <br/>
614 A lane can also change its own thread priority dynamically with <a href="#priority"><tt>lanes.set_thread_priority()</tt></a>. 623 A lane can also change its own thread priority dynamically with <a href="#priority"><tt>lanes.set_thread_priority()</tt></a>.
615 </td> 624 </td>
616 </tr> 625 </tr>
@@ -621,9 +630,9 @@
621 <td> table</td> 630 <td> table</td>
622 <td> 631 <td>
623 Introduced at version 3.0. 632 Introduced at version 3.0.
624 <br> 633 <br/>
625 Specifying it when <code>libs_str</code> doesn't cause the <code>package</code> library to be loaded will generate an error. 634 Specifying it when <code>libs_str</code> doesn't cause the <code>package</code> library to be loaded will generate an error.
626 <br> 635 <br/>
627 If not specified, the created lane will receive the current values of <tt>package</tt>. Only <tt>path</tt>, <tt>cpath</tt>, <tt>preload</tt> and <tt>loaders</tt> (Lua 5.1)/<tt>searchers</tt> (Lua 5.2) are transfered. 636 If not specified, the created lane will receive the current values of <tt>package</tt>. Only <tt>path</tt>, <tt>cpath</tt>, <tt>preload</tt> and <tt>loaders</tt> (Lua 5.1)/<tt>searchers</tt> (Lua 5.2) are transfered.
628 </td> 637 </td>
629 </tr> 638 </tr>
@@ -678,7 +687,7 @@
678 </table> 687 </table>
679<p> 688<p>
680 Besides setting a default priority in the generator <a href="#generator_settings">settings</a>, each thread can change its own priority at will. This is also true for the main Lua state. 689 Besides setting a default priority in the generator <a href="#generator_settings">settings</a>, each thread can change its own priority at will. This is also true for the main Lua state.
681 <br> 690 <br/>
682 The priority must be in the range <tt>[-3,+3]</tt>. 691 The priority must be in the range <tt>[-3,+3]</tt>.
683</p> 692</p>
684 693
@@ -793,7 +802,7 @@
793 802
794<p> 803<p>
795 Only available if lane tracking feature is compiled (see <tt>HAVE_LANE_TRACKING</tt> in <tt>lanes.c</tt>) and <a href="#track_lanes"><tt>track_lanes</tt></a> is set. 804 Only available if lane tracking feature is compiled (see <tt>HAVE_LANE_TRACKING</tt> in <tt>lanes.c</tt>) and <a href="#track_lanes"><tt>track_lanes</tt></a> is set.
796 <br> 805 <br/>
797 Returns a table where keys are a lane's name and values are the lane's status. Returns <tt>nil</tt> if no lane is running. 806 Returns a table where keys are a lane's name and values are the lane's status. Returns <tt>nil</tt> if no lane is running.
798</p> 807</p>
799 808
@@ -820,7 +829,7 @@
820 829
821<p> 830<p>
822 Makes sure lane has finished, and gives its first (maybe only) return value. Other return values will be available in other <tt>lane_h</tt> indices. 831 Makes sure lane has finished, and gives its first (maybe only) return value. Other return values will be available in other <tt>lane_h</tt> indices.
823 <br> 832 <br/>
824 If the lane ended in an error, it is propagated to master state at this place. 833 If the lane ended in an error, it is propagated to master state at this place.
825</p> 834</p>
826 835
@@ -835,9 +844,9 @@
835 844
836<p> 845<p>
837 <tt>stack_tbl</tt> is a table describing where the error was thrown. 846 <tt>stack_tbl</tt> is a table describing where the error was thrown.
838 <br> 847 <br/>
839 In <tt>"extended"</tt> mode, <tt>stack_tbl</tt> is an array of tables containing info gathered with <tt>lua_getinfo()</tt> (<tt>"source"</tt>,<tt>"currentline"</tt>,<tt>"name"</tt>,<tt>"namewhat"</tt>,<tt>"what"</tt>). 848 In <tt>"extended"</tt> mode, <tt>stack_tbl</tt> is an array of tables containing info gathered with <tt>lua_getinfo()</tt> (<tt>"source"</tt>,<tt>"currentline"</tt>,<tt>"name"</tt>,<tt>"namewhat"</tt>,<tt>"what"</tt>).
840 <br> 849 <br/>
841 In <tt>"basic mode"</tt>, <tt>stack_tbl</tt> is an array of "&lt;filename&gt;:&lt;line&gt;" strings. Use <tt>table.concat()</tt> to format it to your liking (or just ignore it). 850 In <tt>"basic mode"</tt>, <tt>stack_tbl</tt> is an array of "&lt;filename&gt;:&lt;line&gt;" strings. Use <tt>table.concat()</tt> to format it to your liking (or just ignore it).
842</p> 851</p>
843 852
@@ -908,11 +917,11 @@
908 917
909<p> 918<p>
910 Cancellation is tested <u>before</u> going to sleep in <tt>receive()</tt> or <tt>send()</tt> calls and after executing <tt>cancelstep</tt> Lua statements. Starting with version 3.0-beta, a pending <tt>receive()</tt>or <tt>send()</tt> call is awakened. 919 Cancellation is tested <u>before</u> going to sleep in <tt>receive()</tt> or <tt>send()</tt> calls and after executing <tt>cancelstep</tt> Lua statements. Starting with version 3.0-beta, a pending <tt>receive()</tt>or <tt>send()</tt> call is awakened.
911 <br> 920 <br/>
912 This means the execution of the lane will resume although the operation has not completed, to give the lane a chance to detect cancellation (even in the case the code waits on a <a href="#lindas">linda</a> with infinite timeout). 921 This means the execution of the lane will resume although the operation has not completed, to give the lane a chance to detect cancellation (even in the case the code waits on a <a href="#lindas">linda</a> with infinite timeout).
913 <br> 922 <br/>
914 The code should be able to handle this situation appropriately if required (in other words, it should gracefully handle the fact that it didn't receive the expected values). 923 The code should be able to handle this situation appropriately if required (in other words, it should gracefully handle the fact that it didn't receive the expected values).
915 <br> 924 <br/>
916 It is also possible to manually test for cancel requests with <tt>cancel_test()</tt>. 925 It is also possible to manually test for cancel requests with <tt>cancel_test()</tt>.
917</p> 926</p>
918 927
@@ -1103,13 +1112,13 @@
1103 1112
1104<p> 1113<p>
1105 Returns some information about the contents of the linda. 1114 Returns some information about the contents of the linda.
1106 <br> 1115 <br/>
1107 If no key is specified, and the linda is empty, returns nothing. 1116 If no key is specified, and the linda is empty, returns nothing.
1108 <br> 1117 <br/>
1109 If no key is specified, and the linda is not empty, returns a table of key/count pairs that counts the number of items in each of the exiting keys of the linda. This count can be 0 if the key has been used but is empty. 1118 If no key is specified, and the linda is not empty, returns a table of key/count pairs that counts the number of items in each of the exiting keys of the linda. This count can be 0 if the key has been used but is empty.
1110 <br> 1119 <br/>
1111 If a single key is specified, returns the number of pending items, or nothing if the key is unknown. 1120 If a single key is specified, returns the number of pending items, or nothing if the key is unknown.
1112 <br> 1121 <br/>
1113 If more than one key is specified, return a table of key/count pairs for the known keys. 1122 If more than one key is specified, return a table of key/count pairs for the known keys.
1114</p> 1123</p>
1115 1124
@@ -1125,17 +1134,17 @@
1125 1134
1126<p> 1135<p>
1127 A linda is a gateway to read and write data inside some hidden Lua states, called keeper states. Lindas are hashed to a fixed number of keeper states, which are a locking entity. 1136 A linda is a gateway to read and write data inside some hidden Lua states, called keeper states. Lindas are hashed to a fixed number of keeper states, which are a locking entity.
1128 <br> 1137 <br/>
1129 The data sent through a linda is stored inside the associated keeper state in a Lua table where each linda slot is the key to another table containing a FIFO for that slot. 1138 The data sent through a linda is stored inside the associated keeper state in a Lua table where each linda slot is the key to another table containing a FIFO for that slot.
1130 <br> 1139 <br/>
1131 Each keeper state is associated with an OS mutex, to prevent concurrent access to the keeper state. The linda itself uses two signals to be made aware of operations occuring on it. 1140 Each keeper state is associated with an OS mutex, to prevent concurrent access to the keeper state. The linda itself uses two signals to be made aware of operations occuring on it.
1132 <br> 1141 <br/>
1133 Whenever Lua code reads from or writes to a linda, the mutex is acquired. If linda limits don't block the operation, it is fulfilled, then the mutex is released. 1142 Whenever Lua code reads from or writes to a linda, the mutex is acquired. If linda limits don't block the operation, it is fulfilled, then the mutex is released.
1134 <br> 1143 <br/>
1135 If the linda has to block, the mutex is released and the OS thread sleeps, waiting for a linda operation to be signalled. When an operation occurs on the same linda, possibly fufilling the condition, or a timeout expires, the thread wakes up. 1144 If the linda has to block, the mutex is released and the OS thread sleeps, waiting for a linda operation to be signalled. When an operation occurs on the same linda, possibly fufilling the condition, or a timeout expires, the thread wakes up.
1136 <br> 1145 <br/>
1137 If the thread is woken but the condition is not yet fulfilled, it goes back to sleep, until the timeout expires. 1146 If the thread is woken but the condition is not yet fulfilled, it goes back to sleep, until the timeout expires.
1138 <br> 1147 <br/>
1139 When a lane is cancelled, the signal it is waiting on (if any) is signalled. In that case, the linda operation will return no data. 1148 When a lane is cancelled, the signal it is waiting on (if any) is signalled. In that case, the linda operation will return no data.
1140</p> 1149</p>
1141 1150
@@ -1264,9 +1273,9 @@ events to a common Linda, but... :).</font>
1264 1273
1265<p> 1274<p>
1266 The generated function acquires M tokens from the N available, or releases them if the value is negative. The acquiring call will suspend the lane, if necessary. Use <tt>M=N=1</tt> for a critical section lock (only one lane allowed to enter). 1275 The generated function acquires M tokens from the N available, or releases them if the value is negative. The acquiring call will suspend the lane, if necessary. Use <tt>M=N=1</tt> for a critical section lock (only one lane allowed to enter).
1267 <br> 1276 <br/>
1268 When passsing <tt>"try"</tt> as second argument when acquiring, then <tt>lock_func</tt> operates on the linda with a timeout of 0 to emulate a TryLock() operation. If locking fails, <tt>lock_func</tt> returns <tt>false</tt>. <tt>"try"</tt> is ignored when releasing (as it it not expected to ever have to wait unless the acquisition/release pairs are not properly matched). 1277 When passsing <tt>"try"</tt> as second argument when acquiring, then <tt>lock_func</tt> operates on the linda with a timeout of 0 to emulate a TryLock() operation. If locking fails, <tt>lock_func</tt> returns <tt>false</tt>. <tt>"try"</tt> is ignored when releasing (as it it not expected to ever have to wait unless the acquisition/release pairs are not properly matched).
1269 <br> 1278 <br/>
1270 Upon successful lock/unlock, <tt>lock_func</tt> returns <tt>true</tt> (always the case when block-waiting for completion). 1279 Upon successful lock/unlock, <tt>lock_func</tt> returns <tt>true</tt> (always the case when block-waiting for completion).
1271</p> 1280</p>
1272 1281
@@ -1364,7 +1373,7 @@ events to a common Linda, but... :).</font>
1364 1373
1365<p> 1374<p>
1366 This has the main drawback of not being LuaJIT-compatible, because some functions registered by LuaJIT are not regular C functions, but specially optimized implementations. As a result, <tt>lua_tocfunction()</tt> returns <tt>NULL</tt> for them. 1375 This has the main drawback of not being LuaJIT-compatible, because some functions registered by LuaJIT are not regular C functions, but specially optimized implementations. As a result, <tt>lua_tocfunction()</tt> returns <tt>NULL</tt> for them.
1367 <br> 1376 <br/>
1368 Therefore, Lanes no longer transfers functions that way. Instead, functions are transfered as follows (more or less): 1377 Therefore, Lanes no longer transfers functions that way. Instead, functions are transfered as follows (more or less):
1369</p> 1378</p>
1370 1379
@@ -1385,15 +1394,15 @@ events to a common Linda, but... :).</font>
1385 1394
1386<p> 1395<p>
1387 Since functions are first class values, they don't have a name. All we know for sure is that when a C module registers some functions, they are accessible to the script that required the module through some exposed variables. 1396 Since functions are first class values, they don't have a name. All we know for sure is that when a C module registers some functions, they are accessible to the script that required the module through some exposed variables.
1388 <br> 1397 <br/>
1389 For example, loading the <tt>string</tt> base library creates a table accessible when indexing the global environment with key <tt>"string"</tt>. Indexing this table with <tt>"match"</tt>, <tt>"gsub"</tt>, etc. will give us a function. 1398 For example, loading the <tt>string</tt> base library creates a table accessible when indexing the global environment with key <tt>"string"</tt>. Indexing this table with <tt>"match"</tt>, <tt>"gsub"</tt>, etc. will give us a function.
1390 <br> 1399 <br/>
1391 When a lane generator creates a lane and performs initializations described by the list of base libraries and the list of required modules, it recursively scans the table created by the initialisation of the module, looking for all values that are C functions. 1400 When a lane generator creates a lane and performs initializations described by the list of base libraries and the list of required modules, it recursively scans the table created by the initialisation of the module, looking for all values that are C functions.
1392 <br> 1401 <br/>
1393 Each time a function is encountered, the sequence of keys that reached that function is contatenated in a (hopefully) unique name. The [name, function] and [function, name] pairs are both stored in a lookup table in all involved Lua states (main Lua state and lanes states). 1402 Each time a function is encountered, the sequence of keys that reached that function is contatenated in a (hopefully) unique name. The [name, function] and [function, name] pairs are both stored in a lookup table in all involved Lua states (main Lua state and lanes states).
1394 <br> 1403 <br/>
1395 Then when a function is transfered from one state to another, all we have to do is retrieve the name associated to a function in the source Lua state, then with that name retrieve the equivalent function that already exists in the destination state. 1404 Then when a function is transfered from one state to another, all we have to do is retrieve the name associated to a function in the source Lua state, then with that name retrieve the equivalent function that already exists in the destination state.
1396 <br> 1405 <br/>
1397 Note that there is no need to transfer upvalues, as they are already bound to the function registered in the destination state. (And in any event, it is not possible to create a closure from a C function pushed on the stack, it can only be created with a <tt>lua_CFunction</tt> pointer). 1406 Note that there is no need to transfer upvalues, as they are already bound to the function registered in the destination state. (And in any event, it is not possible to create a closure from a C function pushed on the stack, it can only be created with a <tt>lua_CFunction</tt> pointer).
1398</p> 1407</p>
1399 1408
diff --git a/src/lanes.c b/src/lanes.c
index 604e43d..a806c16 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.8.1"; 55char const* VERSION = "3.8.2";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -209,6 +209,19 @@ static inline struct s_lane* get_lane_from_registry( lua_State* L)
209 return s; 209 return s;
210} 210}
211 211
212// intern the debug name in the specified lua state so that the pointer remains valid when the lane's state is closed
213static void securize_debug_threadname( lua_State* L, struct s_lane* s)
214{
215 STACK_CHECK( L);
216 STACK_GROW( L, 3);
217 lua_getuservalue( L, 1);
218 lua_newtable( L);
219 s->debug_name = lua_pushstring( L, s->debug_name);
220 lua_rawset( L, -3);
221 lua_pop( L, 1);
222 STACK_END( L, 0);
223}
224
212/* 225/*
213* Check if the thread in question ('L') has been signalled for cancel. 226* Check if the thread in question ('L') has been signalled for cancel.
214* 227*
@@ -1766,7 +1779,7 @@ LUAG_FUNC( get_debug_threadname)
1766{ 1779{
1767 struct s_lane* const s = lua_toLane( L, 1); 1780 struct s_lane* const s = lua_toLane( L, 1);
1768 luaL_argcheck( L, lua_gettop( L) == 1, 2, "too many arguments"); 1781 luaL_argcheck( L, lua_gettop( L) == 1, 2, "too many arguments");
1769 lua_pushstring( L, s->debug_name ? s->debug_name : "<unnamed>"); 1782 lua_pushstring( L, s->debug_name);
1770 return 1; 1783 return 1;
1771} 1784}
1772 1785
@@ -1998,6 +2011,8 @@ LUAG_FUNC( require)
1998 return 1; 2011 return 1;
1999} 2012}
2000 2013
2014LUAG_FUNC( thread_gc);
2015#define GCCB_KEY (void*)LG_thread_gc
2001//--- 2016//---
2002// lane_ud= thread_new( function, [libs_str], 2017// lane_ud= thread_new( function, [libs_str],
2003// [cancelstep_uint=0], 2018// [cancelstep_uint=0],
@@ -2005,6 +2020,7 @@ LUAG_FUNC( require)
2005// [globals_tbl], 2020// [globals_tbl],
2006// [package_tbl], 2021// [package_tbl],
2007// [required], 2022// [required],
2023// [gc_cb],
2008// [... args ...] ) 2024// [... args ...] )
2009// 2025//
2010// Upvalues: metatable to use for 'lane_ud' 2026// Upvalues: metatable to use for 'lane_ud'
@@ -2022,8 +2038,9 @@ LUAG_FUNC( thread_new)
2022 uint_t glob = lua_isnoneornil( L, 5) ? 0 : 5; 2038 uint_t glob = lua_isnoneornil( L, 5) ? 0 : 5;
2023 uint_t package = lua_isnoneornil( L, 6) ? 0 : 6; 2039 uint_t package = lua_isnoneornil( L, 6) ? 0 : 6;
2024 uint_t required = lua_isnoneornil( L, 7) ? 0 : 7; 2040 uint_t required = lua_isnoneornil( L, 7) ? 0 : 7;
2041 uint_t gc_cb = lua_isnoneornil( L, 8) ? 0 : 8;
2025 2042
2026#define FIXED_ARGS 7 2043#define FIXED_ARGS 8
2027 uint_t args = lua_gettop(L) - FIXED_ARGS; 2044 uint_t args = lua_gettop(L) - FIXED_ARGS;
2028 2045
2029 // public Lanes API accepts a generic range -3/+3 2046 // public Lanes API accepts a generic range -3/+3
@@ -2203,7 +2220,7 @@ LUAG_FUNC( thread_new)
2203 } 2220 }
2204 STACK_MID( L, 0); 2221 STACK_MID( L, 0);
2205 2222
2206 ASSERT_L( (uint_t)lua_gettop( L2) == 1+args); 2223 ASSERT_L( (uint_t)lua_gettop( L2) == 1 + args);
2207 ASSERT_L( lua_isfunction( L2, 1)); 2224 ASSERT_L( lua_isfunction( L2, 1));
2208 2225
2209 // 's' is allocated from heap, not Lua, since its life span may surpass 2226 // 's' is allocated from heap, not Lua, since its life span may surpass
@@ -2217,9 +2234,9 @@ LUAG_FUNC( thread_new)
2217 2234
2218 //memset( s, 0, sizeof(struct s_lane) ); 2235 //memset( s, 0, sizeof(struct s_lane) );
2219 s->L = L2; 2236 s->L = L2;
2220 s->status= PENDING; 2237 s->status = PENDING;
2221 s->waiting_on = NULL; 2238 s->waiting_on = NULL;
2222 s->debug_name = NULL; 2239 s->debug_name = "<unnamed>";
2223 s->cancel_request = CANCEL_NONE; 2240 s->cancel_request = CANCEL_NONE;
2224 2241
2225#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 2242#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
@@ -2238,25 +2255,32 @@ LUAG_FUNC( thread_new)
2238 lua_setmetatable( L, -2); 2255 lua_setmetatable( L, -2);
2239 STACK_MID( L, 1); 2256 STACK_MID( L, 1);
2240 2257
2241 // Clear environment for the userdata 2258 // Create uservalue for the userdata
2242 // 2259 // (this is where lane body return values will be stored when the handle is indexed by a numeric key)
2243 lua_newtable( L); 2260 lua_newtable( L);
2261
2262 // Store the gc_cb callback in the uservalue
2263 if( gc_cb > 0)
2264 {
2265 lua_pushlightuserdata( L, GCCB_KEY);
2266 lua_pushvalue( L, gc_cb);
2267 lua_rawset( L, -3);
2268 }
2269
2244 lua_setuservalue( L, -2); 2270 lua_setuservalue( L, -2);
2245 2271
2246 // Place 's' in registry, for 'cancel_test()' (even if 'cs'==0 we still 2272 // Store 's' in the lane's registry, for 'cancel_test()' (even if 'cs'==0 we still do cancel tests at pending send/receive).
2247 // do cancel tests at pending send/receive).
2248 //
2249 lua_pushlightuserdata( L2, CANCEL_TEST_KEY); 2273 lua_pushlightuserdata( L2, CANCEL_TEST_KEY);
2250 lua_pushlightuserdata( L2, s); 2274 lua_pushlightuserdata( L2, s);
2251 lua_rawset( L2, LUA_REGISTRYINDEX); 2275 lua_rawset( L2, LUA_REGISTRYINDEX);
2252 2276
2253 if( cs) 2277 if( cs)
2254 { 2278 {
2255 lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cs ); 2279 lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cs);
2256 } 2280 }
2257 2281
2258 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: launching thread\n" INDENT_END)); 2282 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: launching thread\n" INDENT_END));
2259 THREAD_CREATE( &s->thread, lane_main, s, prio ); 2283 THREAD_CREATE( &s->thread, lane_main, s, prio);
2260 STACK_END( L, 1); 2284 STACK_END( L, 1);
2261 2285
2262 DEBUGSPEW_CODE( -- debugspew_indent_depth); 2286 DEBUGSPEW_CODE( -- debugspew_indent_depth);
@@ -2279,7 +2303,23 @@ LUAG_FUNC( thread_new)
2279// 2303//
2280LUAG_FUNC( thread_gc) 2304LUAG_FUNC( thread_gc)
2281{ 2305{
2282 struct s_lane* s = lua_toLane( L, 1); 2306 bool_t have_gc_cb = FALSE;
2307 struct s_lane* s = lua_toLane( L, 1); // ud
2308
2309 // if there a gc callback?
2310 lua_getuservalue( L, 1); // ud uservalue
2311 lua_pushlightuserdata( L, GCCB_KEY); // ud uservalue __gc
2312 lua_rawget( L, -2); // ud uservalue gc_cb|nil
2313 if( !lua_isnil( L, -1))
2314 {
2315 lua_remove( L, -2); // ud gc_cb|nil
2316 lua_pushstring( L, s->debug_name); // ud gc_cb name
2317 have_gc_cb = TRUE;
2318 }
2319 else
2320 {
2321 lua_pop( L, 2); // ud
2322 }
2283 2323
2284 // We can read 's->status' without locks, but not wait for it 2324 // We can read 's->status' without locks, but not wait for it
2285 // test KILLED state first, as it doesn't need to enter the selfdestruct chain 2325 // test KILLED state first, as it doesn't need to enter the selfdestruct chain
@@ -2291,13 +2331,17 @@ LUAG_FUNC( thread_gc)
2291 DEBUGSPEW_CODE( fprintf( stderr, "** Joining with a killed thread (needs testing) **")); 2331 DEBUGSPEW_CODE( fprintf( stderr, "** Joining with a killed thread (needs testing) **"));
2292 // make sure the thread is no longer running, just like thread_join() 2332 // make sure the thread is no longer running, just like thread_join()
2293 if(! THREAD_ISNULL( s->thread)) 2333 if(! THREAD_ISNULL( s->thread))
2334 {
2294 THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status); 2335 THREAD_WAIT( &s->thread, -1, &s->done_signal, &s->done_lock, &s->status);
2295 // we know the thread was killed while the Lua VM was not doing anything: we should be able to close it without crashing 2336 }
2296 // now, thread_cancel() will not forcefully kill a lane with s->status >= DONE, so I am not sure it can ever happen
2297 if( s->status >= DONE && s->L) 2337 if( s->status >= DONE && s->L)
2298 { 2338 {
2339 // we know the thread was killed while the Lua VM was not doing anything: we should be able to close it without crashing
2340 // now, thread_cancel() will not forcefully kill a lane with s->status >= DONE, so I am not sure it can ever happen
2299 lua_close( s->L); 2341 lua_close( s->L);
2300 s->L = 0; 2342 s->L = 0;
2343 // just in case, but s will be freed soon so...
2344 s->debug_name = "<gc>";
2301 } 2345 }
2302 DEBUGSPEW_CODE( fprintf( stderr, "** Joined ok **")); 2346 DEBUGSPEW_CODE( fprintf( stderr, "** Joined ok **"));
2303 } 2347 }
@@ -2306,18 +2350,31 @@ LUAG_FUNC( thread_gc)
2306 // still running: will have to be cleaned up later 2350 // still running: will have to be cleaned up later
2307 selfdestruct_add( s); 2351 selfdestruct_add( s);
2308 assert( s->selfdestruct_next); 2352 assert( s->selfdestruct_next);
2353 if( have_gc_cb)
2354 {
2355 lua_pushliteral( L, "selfdestruct"); // ud gc_cb name status
2356 lua_call( L, 2, 0); // ud
2357 }
2309 return 0; 2358 return 0;
2310
2311 } 2359 }
2312 else if( s->L) 2360 else if( s->L)
2313 { 2361 {
2314 // no longer accessing the Lua VM: we can close right now 2362 // no longer accessing the Lua VM: we can close right now
2315 lua_close( s->L); 2363 lua_close( s->L);
2316 s->L = 0; 2364 s->L = 0;
2365 // just in case, but s will be freed soon so...
2366 s->debug_name = "<gc>";
2317 } 2367 }
2318 2368
2319 // Clean up after a (finished) thread 2369 // Clean up after a (finished) thread
2320 lane_cleanup( s); 2370 lane_cleanup( s);
2371
2372 // do this after lane cleanup in case the callback triggers an error
2373 if( have_gc_cb)
2374 {
2375 lua_pushliteral( L, "closed"); // ud gc_cb name status
2376 lua_call( L, 2, 0); // ud
2377 }
2321 return 0; 2378 return 0;
2322} 2379}
2323 2380
@@ -2422,23 +2479,26 @@ LUAG_FUNC( thread_join)
2422 bool_t done; 2479 bool_t done;
2423 2480
2424 done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status); 2481 done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status);
2425 if (!done || !L2) 2482 if( !done || !L2)
2483 {
2426 return 0; // timeout: pushes none, leaves 'L2' alive 2484 return 0; // timeout: pushes none, leaves 'L2' alive
2485 }
2427 2486
2428 // Thread is DONE/ERROR_ST/CANCELLED; all ours now 2487 // Thread is DONE/ERROR_ST/CANCELLED; all ours now
2429 2488
2430 STACK_GROW( L, 1);
2431
2432 if( s->mstatus == KILLED) // OS thread was killed if thread_cancel was forced 2489 if( s->mstatus == KILLED) // OS thread was killed if thread_cancel was forced
2433 { 2490 {
2434 // in that case, even if the thread was killed while DONE/ERROR_ST/CANCELLED, ignore regular return values 2491 // in that case, even if the thread was killed while DONE/ERROR_ST/CANCELLED, ignore regular return values
2435 2492 STACK_GROW( L, 1);
2436 lua_pushnil( L); 2493 lua_pushnil( L);
2437 lua_pushliteral( L, "killed"); 2494 lua_pushliteral( L, "killed");
2438 ret = 2; 2495 ret = 2;
2439 } 2496 }
2440 else 2497 else
2441 { 2498 {
2499 // debug_name is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed
2500 // so store it in the userdata uservalue at a key that can't possibly collide
2501 securize_debug_threadname( L, s);
2442 switch( s->status) 2502 switch( s->status)
2443 { 2503 {
2444 case DONE: 2504 case DONE:
@@ -2467,11 +2527,9 @@ LUAG_FUNC( thread_join)
2467 2527
2468 default: 2528 default:
2469 DEBUGSPEW_CODE( fprintf( stderr, "Status: %d\n", s->status)); 2529 DEBUGSPEW_CODE( fprintf( stderr, "Status: %d\n", s->status));
2470 ASSERT_L( FALSE ); ret= 0; 2530 ASSERT_L( FALSE); ret = 0;
2471 } 2531 }
2472 lua_close( L2); 2532 lua_close( L2);
2473 // debug_name is a pointer to an interned string, that no longer exists when the state is closed
2474 s->debug_name = "<closed>";
2475 } 2533 }
2476 s->L = 0; 2534 s->L = 0;
2477 2535
@@ -2652,10 +2710,7 @@ LUAG_FUNC( threads)
2652 lua_newtable( L); // {} 2710 lua_newtable( L); // {}
2653 while( s != TRACKING_END) 2711 while( s != TRACKING_END)
2654 { 2712 {
2655 if( s->debug_name) 2713 lua_pushstring( L, s->debug_name); // {} "name"
2656 lua_pushstring( L, s->debug_name); // {} "name"
2657 else
2658 lua_pushfstring( L, "Lane %p", s); // {} "name"
2659 push_thread_status( L, s); // {} "name" "status" 2714 push_thread_status( L, s); // {} "name" "status"
2660 lua_rawset( L, -3); // {} 2715 lua_rawset( L, -3); // {}
2661 s = s->tracking_next; 2716 s = s->tracking_next;
diff --git a/src/lanes.lua b/src/lanes.lua
index 9a0287d..1286099 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -196,7 +196,10 @@ end
196-- 196--
197-- .globals: table of globals to set for a new thread (passed by value) 197-- .globals: table of globals to set for a new thread (passed by value)
198-- 198--
199-- .required: table of packages to require 199-- .required: table of packages to require
200--
201-- .gc_cb: function called when the lane handle is collected
202--
200-- ... (more options may be introduced later) ... 203-- ... (more options may be introduced later) ...
201-- 204--
202-- Calling with a function parameter ('lane_func') ends the string/table 205-- Calling with a function parameter ('lane_func') ends the string/table
@@ -272,10 +275,11 @@ local function gen( ... )
272 end 275 end
273 end 276 end
274 277
275 local prio, cs, g_tbl, package_tbl, required 278 local prio, cs, g_tbl, package_tbl, required, gc_cb
276 279
277 for k,v in pairs(opt) do 280 for k,v in pairs(opt) do
278 if k=="priority" then prio= v 281 if k == "priority" then
282 prio = (type( v) == "number") and v or error( "Bad 'prio' option: expecting number, got " .. type( v), lev)
279 elseif k=="cancelstep" then 283 elseif k=="cancelstep" then
280 cs = (v==true) and 100 or 284 cs = (v==true) and 100 or
281 (v==false) and 0 or 285 (v==false) and 0 or
@@ -286,6 +290,8 @@ local function gen( ... )
286 package_tbl = (type( v) == "table") and v or error( "Bad package: " .. tostring( v), lev) 290 package_tbl = (type( v) == "table") and v or error( "Bad package: " .. tostring( v), lev)
287 elseif k=="required" then 291 elseif k=="required" then
288 required= (type( v) == "table") and v or error( "Bad 'required' option: expecting table, got " .. type( v), lev) 292 required= (type( v) == "table") and v or error( "Bad 'required' option: expecting table, got " .. type( v), lev)
293 elseif k == "gc_cb" then
294 gc_cb = (type( v) == "function") and v or error( "Bad 'gc_cb' option: expecting function, got " .. type( v), lev)
289 --.. 295 --..
290 elseif k==1 then error( "unkeyed option: ".. tostring(v), lev ) 296 elseif k==1 then error( "unkeyed option: ".. tostring(v), lev )
291 else error( "Bad option: ".. tostring(k), lev ) 297 else error( "Bad option: ".. tostring(k), lev )
@@ -296,7 +302,7 @@ local function gen( ... )
296 -- Lane generator 302 -- Lane generator
297 -- 303 --
298 return function(...) 304 return function(...)
299 return thread_new( func, libs, cs, prio, g_tbl, package_tbl, required, ...) -- args 305 return thread_new( func, libs, cs, prio, g_tbl, package_tbl, required, gc_cb, ...) -- args
300 end 306 end
301end 307end
302 308
diff --git a/tests/basic.lua b/tests/basic.lua
index 5b0d8a7..16919a3 100644
--- a/tests/basic.lua
+++ b/tests/basic.lua
@@ -25,6 +25,11 @@ local function PRINT(...)
25 end 25 end
26end 26end
27 27
28local gc_cb = function( name_, status_)
29 PRINT( " ---> lane '" .. name_ .. "' collected with status " .. status_)
30end
31--gc_cb = nil
32
28 33
29---=== Local helpers ===--- 34---=== Local helpers ===---
30 35
@@ -71,7 +76,7 @@ local function task( a, b, c )
71 return v, hey 76 return v, hey
72end 77end
73 78
74local task_launch= lanes_gen( "", { globals={hey=true} }, task ) 79local task_launch= lanes_gen( "", { globals={hey=true}, gc_cb = gc_cb}, task )
75 -- base stdlibs, normal priority 80 -- base stdlibs, normal priority
76 81
77-- 'task_launch' is a factory of multithreaded tasks, we can launch several: 82-- 'task_launch' is a factory of multithreaded tasks, we can launch several:
@@ -100,6 +105,8 @@ assert( v2_hey == true )
100 105
101assert( lane1.status == "done" ) 106assert( lane1.status == "done" )
102assert( lane1.status == "done" ) 107assert( lane1.status == "done" )
108lane1, lane2 = nil
109collectgarbage()
103 110
104--############################################################## 111--##############################################################
105--############################################################## 112--##############################################################
@@ -107,7 +114,7 @@ assert( lane1.status == "done" )
107 114
108PRINT( "\n\n", "---=== Tasking (cancelling) ===---", "\n\n") 115PRINT( "\n\n", "---=== Tasking (cancelling) ===---", "\n\n")
109 116
110local task_launch2= lanes_gen( "", { cancelstep=100, globals={hey=true} }, task ) 117local task_launch2= lanes_gen( "", { cancelstep=100, globals={hey=true}, gc_cb = gc_cb}, task )
111 118
112local N=999999999 119local N=999999999
113local lane9= task_launch2(1,N,1) -- huuuuuuge... 120local lane9= task_launch2(1,N,1) -- huuuuuuge...
@@ -196,7 +203,7 @@ PRINT( "\n\n", "---=== Communications ===---", "\n\n")
196local function WR(...) io.stderr:write(...) end 203local function WR(...) io.stderr:write(...) end
197 204
198local chunk= function( linda ) 205local chunk= function( linda )
199 206 set_debug_threadname "chunk"
200 local function receive() return linda:receive( "->" ) end 207 local function receive() return linda:receive( "->" ) end
201 local function send(...) linda:send( "<-", ... ) end 208 local function send(...) linda:send( "<-", ... ) end
202 209
@@ -226,7 +233,7 @@ local function PEEK() return linda:get("<-") end
226local function SEND(...) linda:send( "->", ... ) end 233local function SEND(...) linda:send( "->", ... ) end
227local function RECEIVE() local k,v = linda:receive( 1, "<-" ) return v end 234local function RECEIVE() local k,v = linda:receive( 1, "<-" ) return v end
228 235
229local t= lanes_gen("io",chunk)(linda) -- prepare & launch 236local t= lanes_gen("io", {gc_cb = gc_cb}, chunk)(linda) -- prepare & launch
230 237
231SEND(1); WR( "1 sent\n" ) 238SEND(1); WR( "1 sent\n" )
232SEND(2); WR( "2 sent\n" ) 239SEND(2); WR( "2 sent\n" )
@@ -256,6 +263,8 @@ assert( tables_match( a, {'a','b','c',d=10} ) )
256assert( PEEK() == nil ) 263assert( PEEK() == nil )
257SEND(4) 264SEND(4)
258 265
266t = nil
267collectgarbage()
259-- wait 268-- wait
260linda: receive( 1, "wait") 269linda: receive( 1, "wait")
261 270
@@ -266,6 +275,7 @@ linda: receive( 1, "wait")
266PRINT( "\n\n", "---=== Stdlib naming ===---", "\n\n") 275PRINT( "\n\n", "---=== Stdlib naming ===---", "\n\n")
267 276
268local function dump_g( _x) 277local function dump_g( _x)
278 set_debug_threadname "dump_g"
269 assert(print) 279 assert(print)
270 print( "### dumping _G for '" .. _x .. "'") 280 print( "### dumping _G for '" .. _x .. "'")
271 for k, v in pairs( _G) do 281 for k, v in pairs( _G) do
@@ -275,6 +285,7 @@ local function dump_g( _x)
275end 285end
276 286
277local function io_os_f( _x) 287local function io_os_f( _x)
288 set_debug_threadname "io_os_f"
278 assert(print) 289 assert(print)
279 print( "### checking io and os libs existence for '" .. _x .. "'") 290 print( "### checking io and os libs existence for '" .. _x .. "'")
280 assert(io) 291 assert(io)
@@ -283,13 +294,14 @@ local function io_os_f( _x)
283end 294end
284 295
285local function coro_f( _x) 296local function coro_f( _x)
297 set_debug_threadname "coro_f"
286 assert(print) 298 assert(print)
287 print( "### checking coroutine lib existence for '" .. _x .. "'") 299 print( "### checking coroutine lib existence for '" .. _x .. "'")
288 assert(coroutine) 300 assert(coroutine)
289 return true 301 return true
290end 302end
291 303
292assert.fails( function() lanes_gen( "xxx", io_os_f ) end ) 304assert.fails( function() lanes_gen( "xxx", {gc_cb = gc_cb}, io_os_f ) end )
293 305
294local stdlib_naming_tests = 306local stdlib_naming_tests =
295{ 307{
@@ -305,10 +317,12 @@ local stdlib_naming_tests =
305} 317}
306 318
307for _, t in ipairs( stdlib_naming_tests) do 319for _, t in ipairs( stdlib_naming_tests) do
308 local f= lanes_gen( t[1], t[2]) -- any delimiter will do 320 local f= lanes_gen( t[1], {gc_cb = gc_cb}, t[2]) -- any delimiter will do
309 assert( f(t[1])[1] ) 321 assert( f(t[1])[1] )
310end 322end
311 323
324collectgarbage()
325
312--############################################################## 326--##############################################################
313--############################################################## 327--##############################################################
314--############################################################## 328--##############################################################
@@ -317,9 +331,9 @@ PRINT( "\n\n", "---=== Comms criss cross ===---", "\n\n")
317 331
318-- We make two identical lanes, which are using the same Linda channel. 332-- We make two identical lanes, which are using the same Linda channel.
319-- 333--
320local tc= lanes_gen( "io", 334local tc= lanes_gen( "io", {gc_cb = gc_cb},
321 function( linda, ch_in, ch_out ) 335 function( linda, ch_in, ch_out )
322 336 set_debug_threadname( "criss cross " .. ch_in .. " -> " .. ch_out)
323 local function STAGE(str) 337 local function STAGE(str)
324 io.stderr:write( ch_in..": "..str.."\n" ) 338 io.stderr:write( ch_in..": "..str.."\n" )
325 linda:send( nil, ch_out, str ) 339 linda:send( nil, ch_out, str )
@@ -338,6 +352,8 @@ local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twis
338 352
339local _= a[1],b[1] -- waits until they are both ready 353local _= a[1],b[1] -- waits until they are both ready
340 354
355a, b = nil
356collectgarbage()
341 357
342--############################################################## 358--##############################################################
343--############################################################## 359--##############################################################
@@ -378,7 +394,7 @@ local function chunk2( linda )
378end 394end
379 395
380local linda= lanes.linda() 396local linda= lanes.linda()
381local t2= lanes_gen( "debug,string,io", chunk2 )(linda) -- prepare & launch 397local t2= lanes_gen( "debug,string,io", {gc_cb = gc_cb}, chunk2 )(linda) -- prepare & launch
382linda:send( "down", function(linda) linda:send( "up", "ready!" ) end, 398linda:send( "down", function(linda) linda:send( "up", "ready!" ) end,
383 "ok" ) 399 "ok" )
384-- wait to see if the tiny function gets executed 400-- wait to see if the tiny function gets executed
@@ -411,7 +427,7 @@ PRINT( "\n\n", "---=== :join test ===---", "\n\n")
411-- (unless [1..n] has been read earlier, in which case it would seemingly 427-- (unless [1..n] has been read earlier, in which case it would seemingly
412-- work). 428-- work).
413 429
414local S= lanes_gen( "table", 430local S= lanes_gen( "table", {gc_cb = gc_cb},
415 function(arg) 431 function(arg)
416 set_debug_threadname "join test lane" 432 set_debug_threadname "join test lane"
417 set_finalizer( function() end) 433 set_finalizer( function() end)