aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES14
-rw-r--r--Makefile4
-rw-r--r--docs/index.html72
-rw-r--r--src/keeper.c6
-rw-r--r--src/lanes.c238
-rw-r--r--src/lanes.lua4
-rw-r--r--tests/atexit.lua45
7 files changed, 250 insertions, 133 deletions
diff --git a/CHANGES b/CHANGES
index bc0368a..58b6061 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,12 +3,14 @@ CHANGES:
3 3
4CHANGE X: 4CHANGE X:
5 5
6CHANGE 29 BGe 21-Feb-2011 6CHANGE 29 BGe 1-Mar-2011
7 Make the number of internal keeper states selectable by an optional parameter passed to require. 7 fixed potential crash at application shutdown when calling lua_close() on a killed thread's VM.
8 exposed cancel_test() in the lanes to enable manual testing for cancellation requests.
9 removed kludgy {globals={threadName}} support, replaced with a new function set_debug_threadname().
8 10
9CHANGE 28 BGe 18-Feb-2011 11CHANGE 28 BGe 18-Feb-2011
10 Moved keeper-related code in a separate source file 12 - moved keeper-related code in a separate source file
11 keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility 13 - keeper.lua is now embedded in text form instead of bytecode to improve LuaJIT2-compatibility
12 14
13CHANGE 27 BGe 17-Feb-2011 15CHANGE 27 BGe 17-Feb-2011
14 - we know Lanes is loaded in the master state, so we don't force it 16 - we know Lanes is loaded in the master state, so we don't force it
@@ -29,7 +31,7 @@ CHANGE 26 BGe 14-Feb-2011:
29 inter-state data copy for unsupported types 31 inter-state data copy for unsupported types
30 32
31CHANGE 25 BGe 12-Feb-2011: 33CHANGE 25 BGe 12-Feb-2011:
32 Changed idfunc signature and contract to clarify the fact it is not lua-callable 34 Changed idfunc signature and contract to clarify that fact it is not lua-callable
33 and to be able to require the module it was exported from in the target lanes 35 and to be able to require the module it was exported from in the target lanes
34 36
35CHANGE 24 DPtr 25-Jan-2011: 37CHANGE 24 DPtr 25-Jan-2011:
@@ -59,7 +61,7 @@ CHANGE 19 BGe 2-Dec-2010:
59 61
60CHANGE 18 BGe 6-Oct-2010: 62CHANGE 18 BGe 6-Oct-2010:
61 Fixed 'memory leak' in some situations where a free running lane is collected before application shutdown 63 Fixed 'memory leak' in some situations where a free running lane is collected before application shutdown
62 A bit of code cleanup 64 A bit of code cleanup
63 65
64CHANGE 17 BGe 21-Sept-2010: 66CHANGE 17 BGe 21-Sept-2010:
65 Fixed stupid compilation errors. 67 Fixed stupid compilation errors.
diff --git a/Makefile b/Makefile
index f27404a..ddd8675 100644
--- a/Makefile
+++ b/Makefile
@@ -84,6 +84,7 @@ test:
84 $(MAKE) fibonacci 84 $(MAKE) fibonacci
85 $(MAKE) recursive 85 $(MAKE) recursive
86 $(MAKE) func_is_string 86 $(MAKE) func_is_string
87 $(MAKE) atexit
87 88
88basic: tests/basic.lua $(_TARGET_SO) 89basic: tests/basic.lua $(_TARGET_SO)
89 $(_PREFIX) $(LUA) $< 90 $(_PREFIX) $(LUA) $<
@@ -154,6 +155,9 @@ appendud: tests/appendud.lua $(_TARGET_SO)
154func_is_string: tests/func_is_string.lua $(_TARGET_SO) 155func_is_string: tests/func_is_string.lua $(_TARGET_SO)
155 $(_PREFIX) $(LUA) $< 156 $(_PREFIX) $(LUA) $<
156 157
158atexit: tests/atexit.lua $(_TARGET_SO)
159 $(_PREFIX) $(LUA) $<
160
157#--- 161#---
158perftest-plain: tests/perftest.lua $(_TARGET_SO) 162perftest-plain: tests/perftest.lua $(_TARGET_SO)
159 $(MAKE) _perftest ARGS="$< $(N) -plain" 163 $(MAKE) _perftest ARGS="$< $(N) -plain"
diff --git a/docs/index.html b/docs/index.html
index 3d2ecf2..ba25515 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 21-Feb-11, and applies to version 2.1.0. 59 </p><p>This document was revised on 1-Mar-11, and applies to version 2.1.0.
60</font></p> 60</font></p>
61 61
62</center> 62</center>
@@ -243,6 +243,7 @@ also in the new lanes.
243 <tt>:receive()</tt> or <tt>:send()</tt> call. 243 <tt>:receive()</tt> or <tt>:send()</tt> call.
244 With this option, one can set cancellation check to occur every <tt>N</tt> 244 With this option, one can set cancellation check to occur every <tt>N</tt>
245 Lua statements. The value <tt>true</tt> uses a default value (100). 245 Lua statements. The value <tt>true</tt> uses a default value (100).
246 It is also possible to manually test for cancel requests with <tt>cancel_test()</tt>.
246 </td></tr> 247 </td></tr>
247 248
248 <tr valign=top><td/><td> 249 <tr valign=top><td/><td>
@@ -250,20 +251,21 @@ also in the new lanes.
250 <td> 251 <td>
251 Sets the globals table for the launched threads. This can be used for giving 252 Sets the globals table for the launched threads. This can be used for giving
252 them constants. 253 them constants.
253 </p><p> 254 <br>
254 The global values of different lanes are in no manner connected; 255 The global values of different lanes are in no manner connected;
255 modifying one will only affect the particular lane. Settings the variable 'threadName' in this table makes VS display the sent name instead of the normal thread name while debugging. 256 modifying one will only affect the particular lane.
256 </td></tr> 257 </td></tr>
257 258
258 <tr valign=top><td width=40><td> 259 <tr valign=top><td width=40><td>
259 <code>.priority</code> <br/><nobr>-2..+2</nobr></td> 260 <code>.priority</code> <br/><nobr>-2..+2</nobr></td>
260 <td>The priority of lanes generated. -2 is lowest, +2 is highest. 261 <td>The priority of lanes generated. -2 is lowest, +2 is highest.
261 <p> 262 <br>
262 Implementation and dependability of priorities varies 263 Implementation and dependability of priorities varies
263 by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode. 264 by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode.
264 </td></tr> 265 </td></tr>
265 </table> 266 </table>
266 267 <p>Each lane also gets a function <tt>set_debug_threadname()</tt> that it can use anytime to do as the name says.
268Supported debuggers are Microsoft Visual Studio (for the C side) and Decoda (for the Lua side).
267</p> 269</p>
268 270
269<h3>Free running lanes</h3> 271<h3>Free running lanes</h3>
@@ -374,10 +376,15 @@ that id over a Linda once that thread is done (as the last thing you do).
374<h2 id="cancelling">Cancelling</h2> 376<h2 id="cancelling">Cancelling</h2>
375 377
376<table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> 378<table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td>
377 <code>bool= lane_h:cancel( [timeout_secs=0.0,] [force_kill_bool=false] )</code> 379 <code>bool= lane_h:cancel( [timeout_secs=0.0,] [force_kill_bool=false] )
380 <br/>
381 <br/>
382 <code>
383 bool= cancel_test()
384 </code>
378</table> 385</table>
379 386
380<p>Sends a cancellation request to the lane. If <tt>timeout_secs</tt> is non-zero, waits 387<p><tt>cancel()</tt>sends a cancellation request to the lane. If <tt>timeout_secs</tt> is non-zero, waits
381for the request to be processed, or a timeout to occur. 388for the request to be processed, or a timeout to occur.
382Returns <tt>true</tt> if the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status) 389Returns <tt>true</tt> if the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status)
383or if the cancellation was fruitful within timeout period. 390or if the cancellation was fruitful within timeout period.
@@ -387,8 +394,9 @@ OS thread running the lane is forcefully killed. This means no GC, and should
387generally be the last resort. 394generally be the last resort.
388</p> 395</p>
389<p>Cancellation is tested <u>before</u> going to sleep in <tt>receive()</tt> or <tt>send()</tt> calls 396<p>Cancellation is tested <u>before</u> going to sleep in <tt>receive()</tt> or <tt>send()</tt> calls
390and after executing <tt>cancelstep</tt> Lua statements. A currently pending <tt>receive</tt> 397and after executing <tt>cancelstep</tt> Lua statements. A currently pending <tt>receive()</tt>
391or <tt>send</tt> call is currently not awakened, and may be a reason for a non-detected cancel. 398or <tt>send()</tt> call is currently not awakened, and may be a reason for a non-detected cancel.
399It is also possible to manually test for cancel requests with <tt>cancel_test()</tt>.
392</p> 400</p>
393 401
394 402
@@ -799,7 +807,7 @@ can be used for custom userdata as well. Here's what to do.
799</p> 807</p>
800<ol> 808<ol>
801 <li>Provide an <i>identity function</i> for your userdata, in C. This function is 809 <li>Provide an <i>identity function</i> for your userdata, in C. This function is
802 used for creation and deletion of your deep userdata (the shared resource), 810used for creation and deletion of your deep userdata (the shared resource),
803 and for making metatables for the state-specific proxies for accessing it. The 811 and for making metatables for the state-specific proxies for accessing it. The
804 prototype is 812 prototype is
805 <table border="1" bgcolor="#E0E0FF" cellpadding="10"> 813 <table border="1" bgcolor="#E0E0FF" cellpadding="10">
@@ -817,12 +825,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> 825 <tt>"delete"</tt>: receives this same pointer on the stack, and should cleanup the object.</li>
818 <li> 826 <li>
819 <tt>"metatable"</tt>: should build a metatable for the object. Don't cache the metatable 827 <tt>"metatable"</tt>: should build a metatable for the object. Don't cache the metatable
820 yourself, Lanes takes care of it ("metatable" should only be invoked once).</li> 828yourself, Lanes takes care of it ("metatable" should only be invoked once).</li>
821 <li> 829 <li>
822 <tt>"module"</tt>: is the name of the module that exports the idfunc, 830 <tt>"module"</tt>: is the name of the module that exports the idfunc,
823 to be pushed on the stack as a string. It is necessary so that Lanes can require it in 831to be pushed on the stack as a string. It is necessary so that Lanes can require it in
824 any Lane and keeper state that receives a userdata. This is to prevent crashes in situations 832any Lane and keeper state that receives a userdata. This is to prevent crashes in situations
825 where the module could be unloaded while the idfunc pointer is still held.</li> 833where the module could be unloaded while the idfunc pointer is still held.</li>
826</ul> 834</ul>
827Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>. 835Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>.
828 </li> 836 </li>
@@ -917,10 +925,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 925 merged into one main timer state (see <tt>timer.lua</tt>); no OS side
918 timers are utilized. 926 timers are utilized.
919 </li> 927 </li>
920 <li>Lindas are hashed to a number of "keeper states", which are a locking entity. 928 <li>Lindas are hashed to a fixed number of "keeper states", which are a locking entity.
921 If you are using a lot of Linda objects, it may be useful to try having more of 929 If you are using a lot of Linda objects,
922 these keeper states. By default, only one is used but this is an implementation detail. 930 it may be useful to try having more of these keeper states. By default,
923 It is possible to <tt>require( "lanes", N)</tt> to use more keeper states. 931 only one is used (see <tt>KEEPER_STATES_N</tt>), but this is an implementation detail.
924 </li> 932 </li>
925</ul> 933</ul>
926</p> 934</p>
@@ -952,31 +960,15 @@ its actual value.
952<h2 id="changes">Change log</h2> 960<h2 id="changes">Change log</h2>
953 961
954<p> 962<p>
955Feb-2011 (2.1.0) 963
964Mar-2011 (2.1.0)
956<ul> 965<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 966 <li>fixed potential crash at application shutdown when calling lua_close() on a killed thread's VM.</li>
958 <ul> 967 <li>exposed cancel_test() in the lanes to enable manual testing for cancellation requests.</li>
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> 968 <li>removed kludgy {globals={threadName}} support, replaced with a new function set_debug_threadname().</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> 969</ul>
977
978Feb-2011 (2.0.11): 970Feb-2011 (2.0.11):
979<ul> 971 <ul>
980 <li>Fixed bug where reference to Linda object was dropped for a short time (crashing if GC was run during that time).</li> 972 <li>Fixed bug where reference to Linda object was dropped for a short time (crashing if GC was run during that time).</li>
981 <li>Changed the atexit code to trip the timer thread's write signal.</li> 973 <li>Changed the atexit code to trip the timer thread's write signal.</li>
982 <li>Changed lanes.c to export functions as a module rather than writing them directly to the globals table.</li> 974 <li>Changed lanes.c to export functions as a module rather than writing them directly to the globals table.</li>
diff --git a/src/keeper.c b/src/keeper.c
index f89c638..01e8880 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -94,6 +94,12 @@ char const *init_keepers( int const _nbKeepers)
94 if (!L) 94 if (!L)
95 return "out of memory"; 95 return "out of memory";
96 96
97 // to see VM name in Decoda debugger
98 lua_pushliteral( L, "Keeper #");
99 lua_pushinteger( L, i + 1);
100 lua_concat( L, 2);
101 lua_setglobal( L, "decoda_name");
102
97 luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs 103 luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs
98 serialize_require( L); 104 serialize_require( L);
99 105
diff --git a/src/lanes.c b/src/lanes.c
index 8b62532..e5a2987 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -119,8 +119,6 @@ struct s_lane {
119 // 119 //
120 // M: sub-thread OS thread 120 // M: sub-thread OS thread
121 // S: not used 121 // S: not used
122
123 char threadName[64]; //Optional, for debugging and such. owerflowable by a strcpy.
124 122
125 lua_State *L; 123 lua_State *L;
126 // 124 //
@@ -132,6 +130,10 @@ struct s_lane {
132 // M: sets to PENDING (before launching) 130 // M: sets to PENDING (before launching)
133 // S: updates -> RUNNING/WAITING -> DONE/ERROR_ST/CANCELLED 131 // S: updates -> RUNNING/WAITING -> DONE/ERROR_ST/CANCELLED
134 132
133 volatile SIGNAL_T waiting_on;
134 //
135 // When status is WAITING, points on the linda's signal the thread waits on, else NULL
136
135 volatile bool_t cancel_request; 137 volatile bool_t cancel_request;
136 // 138 //
137 // M: sets to FALSE, flags TRUE for cancel request 139 // M: sets to FALSE, flags TRUE for cancel request
@@ -333,17 +335,21 @@ LUAG_FUNC( linda_send)
333 { 335 {
334 prev_status = s->status; 336 prev_status = s->status;
335 s->status = WAITING; 337 s->status = WAITING;
338 ASSERT_L( s->waiting_on == NULL);
339 s->waiting_on = &linda->read_happened;
336 } 340 }
337 if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout)) 341 if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout))
338 { 342 {
339 if( s) 343 if( s)
340 { 344 {
345 s->waiting_on = NULL;
341 s->status = prev_status; 346 s->status = prev_status;
342 } 347 }
343 break; 348 break;
344 } 349 }
345 if( s) 350 if( s)
346 { 351 {
352 s->waiting_on = NULL;
347 s->status = prev_status; 353 s->status = prev_status;
348 } 354 }
349 } 355 }
@@ -450,17 +456,21 @@ LUAG_FUNC( linda_receive)
450 { 456 {
451 prev_status = s->status; 457 prev_status = s->status;
452 s->status = WAITING; 458 s->status = WAITING;
459 ASSERT_L( s->waiting_on == NULL);
460 s->waiting_on = &linda->write_happened;
453 } 461 }
454 if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout)) 462 if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout))
455 { 463 {
456 if( s) 464 if( s)
457 { 465 {
466 s->waiting_on = NULL;
458 s->status = prev_status; 467 s->status = prev_status;
459 } 468 }
460 break; 469 break;
461 } 470 }
462 if( s) 471 if( s)
463 { 472 {
473 s->waiting_on = NULL;
464 s->status = prev_status; 474 s->status = prev_status;
465 } 475 }
466 } 476 }
@@ -870,28 +880,33 @@ volatile DEEP_PRELUDE *timer_deep; // = NULL
870/* 880/*
871* Process end; cancel any still free-running threads 881* Process end; cancel any still free-running threads
872*/ 882*/
873static void selfdestruct_atexit( void ) { 883static void selfdestruct_atexit( void )
874 884{
875 if (selfdestruct_first == SELFDESTRUCT_END) return; // no free-running threads 885 if (selfdestruct_first == SELFDESTRUCT_END) return; // no free-running threads
876 886
877 // Signal _all_ still running threads to exit 887 // Signal _all_ still running threads to exit (including the timer thread)
878 // 888 //
879 MUTEX_LOCK( &selfdestruct_cs ); 889 MUTEX_LOCK( &selfdestruct_cs );
880 { 890 {
881 struct s_lane *s= selfdestruct_first; 891 struct s_lane *s= selfdestruct_first;
882 while( s != SELFDESTRUCT_END ) { 892 while( s != SELFDESTRUCT_END )
883 s->cancel_request= TRUE; 893 {
884 s= s->selfdestruct_next; 894 // attempt a regular unforced cancel with a small timeout
895 bool_t cancelled = thread_cancel( s, 0.0001, FALSE);
896 // if we failed, and we know the thread is waiting on a linda
897 if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL)
898 {
899 // signal the linda the wake up the thread so that it can react to the cancel query
900 // let us hope we never land here with a pointer on a linda that has been destroyed...
901 SIGNAL_T waiting_on = s->waiting_on;
902 s->waiting_on = NULL;
903 SIGNAL_ALL( waiting_on);
904 }
905 s = s->selfdestruct_next;
885 } 906 }
886 } 907 }
887 MUTEX_UNLOCK( &selfdestruct_cs ); 908 MUTEX_UNLOCK( &selfdestruct_cs );
888 909
889 // Tell the timer thread to check it's cancel request
890 {
891 struct s_Linda *td = timer_deep->deep;
892 SIGNAL_ALL( &td->write_happened);
893 }
894
895 // When noticing their cancel, the lanes will remove themselves from 910 // When noticing their cancel, the lanes will remove themselves from
896 // the selfdestruct chain. 911 // the selfdestruct chain.
897 912
@@ -914,15 +929,37 @@ static void selfdestruct_atexit( void ) {
914 // -- AKa 25-Oct-2008 929 // -- AKa 25-Oct-2008
915 // 930 //
916 #ifndef ATEXIT_WAIT_SECS 931 #ifndef ATEXIT_WAIT_SECS
917 # define ATEXIT_WAIT_SECS (0.1) 932 # define ATEXIT_WAIT_SECS (0.25)
918 #endif 933 #endif
919 { 934 {
920 double t_until= now_secs() + ATEXIT_WAIT_SECS; 935 double t_until= now_secs() + ATEXIT_WAIT_SECS;
921 936
922 while( selfdestruct_first != SELFDESTRUCT_END ) { 937 while( selfdestruct_first != SELFDESTRUCT_END )
938 {
923 YIELD(); // give threads time to act on their cancel 939 YIELD(); // give threads time to act on their cancel
924 940 {
925 if (now_secs() >= t_until) break; 941 // count the number of cancelled thread that didn't have the time to act yet
942 int n = 0;
943 double t_now = 0.0;
944 MUTEX_LOCK( &selfdestruct_cs );
945 {
946 struct s_lane *s = selfdestruct_first;
947 while( s != SELFDESTRUCT_END)
948 {
949 if( s->cancel_request)
950 ++ n;
951 s = s->selfdestruct_next;
952 }
953 }
954 MUTEX_UNLOCK( &selfdestruct_cs );
955 // if timeout elapsed, or we know all threads have acted, stop waiting
956 t_now = now_secs();
957 if( n == 0 || ( t_now >= t_until))
958 {
959 DEBUGEXEC(fprintf( stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, ATEXIT_WAIT_SECS - (t_until - t_now)));
960 break;
961 }
962 }
926 } 963 }
927 } 964 }
928#endif 965#endif
@@ -951,18 +988,21 @@ static void selfdestruct_atexit( void ) {
951 // 988 //
952 DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n )); 989 DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n ));
953#else 990#else
991 // first thing we did was to raise the linda signals the threads were waiting on (if any)
992 // therefore, any well-behaved thread should be in CANCELLED state
993 // these are not running, and the state can be closed
954 n=0; 994 n=0;
955 MUTEX_LOCK( &selfdestruct_cs ); 995 MUTEX_LOCK( &selfdestruct_cs );
956 { 996 {
957 struct s_lane *s= selfdestruct_first; 997 struct s_lane *s= selfdestruct_first;
958 while( s != SELFDESTRUCT_END ) { 998 while( s != SELFDESTRUCT_END)
999 {
959 struct s_lane *next_s= s->selfdestruct_next; 1000 struct s_lane *next_s= s->selfdestruct_next;
960 s->selfdestruct_next= NULL; // detach from selfdestruct chain 1001 s->selfdestruct_next= NULL; // detach from selfdestruct chain
961 1002 THREAD_KILL( &s->thread);
962 THREAD_KILL( &s->thread ); 1003 // NO lua_close() in this case because we don't know where execution of the state was interrupted
963 lua_close(s->L); 1004 free( s);
964 free(s); 1005 s = next_s;
965 s= next_s;
966 n++; 1006 n++;
967 } 1007 }
968 selfdestruct_first= SELFDESTRUCT_END; 1008 selfdestruct_first= SELFDESTRUCT_END;
@@ -1022,6 +1062,19 @@ static void cancel_hook( lua_State *L, lua_Debug *ar ) {
1022 1062
1023 1063
1024//--- 1064//---
1065// bool= cancel_test()
1066//
1067// Available inside the global namespace of lanes
1068// returns a boolean saying if a cancel request is pending
1069//
1070LUAG_FUNC( cancel_test)
1071{
1072 bool_t test = cancel_test( L);
1073 lua_pushboolean( L, test);
1074 return 1;
1075}
1076
1077//---
1025// = _single( [cores_uint=1] ) 1078// = _single( [cores_uint=1] )
1026// 1079//
1027// Limits the process to use only 'cores' CPU cores. To be used for performance 1080// Limits the process to use only 'cores' CPU cores. To be used for performance
@@ -1131,12 +1184,12 @@ typedef struct tagTHREADNAME_INFO
1131} THREADNAME_INFO; 1184} THREADNAME_INFO;
1132#pragma pack(pop) 1185#pragma pack(pop)
1133 1186
1134void SetThreadName( DWORD dwThreadID, char* threadName) 1187void SetThreadName( DWORD dwThreadID, char const *_threadName)
1135{ 1188{
1136 THREADNAME_INFO info; 1189 THREADNAME_INFO info;
1137 Sleep(10); 1190 Sleep(10);
1138 info.dwType = 0x1000; 1191 info.dwType = 0x1000;
1139 info.szName = threadName; 1192 info.szName = _threadName;
1140 info.dwThreadID = dwThreadID; 1193 info.dwThreadID = dwThreadID;
1141 info.dwFlags = 0; 1194 info.dwFlags = 0;
1142 1195
@@ -1150,6 +1203,22 @@ void SetThreadName( DWORD dwThreadID, char* threadName)
1150} 1203}
1151#endif 1204#endif
1152 1205
1206LUAG_FUNC( set_debug_threadname)
1207{
1208 char const *threadName;
1209 luaL_checktype( L, -1, LUA_TSTRING);
1210 threadName = lua_tostring( L, -1);
1211
1212#if defined PLATFORM_WIN32 && !defined __GNUC__
1213 // to see thead name in Visual Studio C debugger
1214 SetThreadName(-1, threadName);
1215#endif
1216
1217 // to see VM name in Decoda debugger Virtual Machine window
1218 lua_setglobal( L, "decoda_name");
1219
1220 return 0;
1221}
1153 1222
1154//--- 1223//---
1155#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 1224#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
@@ -1162,11 +1231,6 @@ void SetThreadName( DWORD dwThreadID, char* threadName)
1162 int rc, rc2; 1231 int rc, rc2;
1163 lua_State *L= s->L; 1232 lua_State *L= s->L;
1164 1233
1165
1166#if defined PLATFORM_WIN32 && !defined __GNUC__
1167 SetThreadName(-1, s->threadName);
1168#endif
1169
1170 s->status= RUNNING; // PENDING -> RUNNING 1234 s->status= RUNNING; // PENDING -> RUNNING
1171 1235
1172 // Tie "set_finalizer()" to the state 1236 // Tie "set_finalizer()" to the state
@@ -1174,6 +1238,16 @@ void SetThreadName( DWORD dwThreadID, char* threadName)
1174 lua_pushcfunction( L, LG_set_finalizer ); 1238 lua_pushcfunction( L, LG_set_finalizer );
1175 lua_setglobal( L, "set_finalizer" ); 1239 lua_setglobal( L, "set_finalizer" );
1176 1240
1241 // Tie "set_debug_threadname()" to the state
1242 //
1243 lua_pushcfunction( L, LG_set_debug_threadname);
1244 lua_setglobal( L, "set_debug_threadname" );
1245
1246 // Tie "cancel_test()" to the state
1247 //
1248 lua_pushcfunction( L, LG_cancel_test);
1249 lua_setglobal( L, "cancel_test" );
1250
1177#ifdef ERROR_FULL_STACK 1251#ifdef ERROR_FULL_STACK
1178 STACK_GROW( L, 1 ); 1252 STACK_GROW( L, 1 );
1179 lua_pushcfunction( L, lane_error ); 1253 lua_pushcfunction( L, lane_error );
@@ -1240,7 +1314,7 @@ void SetThreadName( DWORD dwThreadID, char* threadName)
1240 // 1314 //
1241 lua_newtable(L); 1315 lua_newtable(L);
1242 } 1316 }
1243 1317 s->waiting_on = NULL; // just in case
1244 if (s->selfdestruct_next != NULL) { 1318 if (s->selfdestruct_next != NULL) {
1245 // We're a free-running thread and no-one's there to clean us up. 1319 // We're a free-running thread and no-one's there to clean us up.
1246 // 1320 //
@@ -1276,7 +1350,6 @@ void SetThreadName( DWORD dwThreadID, char* threadName)
1276 MUTEX_UNLOCK( &s->done_lock_ ); 1350 MUTEX_UNLOCK( &s->done_lock_ );
1277 #endif 1351 #endif
1278 } 1352 }
1279
1280 return 0; // ignored 1353 return 0; // ignored
1281} 1354}
1282 1355
@@ -1295,7 +1368,6 @@ LUAG_FUNC( thread_new )
1295 lua_State *L2; 1368 lua_State *L2;
1296 struct s_lane *s; 1369 struct s_lane *s;
1297 struct s_lane **ud; 1370 struct s_lane **ud;
1298 const char *threadName = 0;
1299 1371
1300 const char *libs= lua_tostring( L, 2 ); 1372 const char *libs= lua_tostring( L, 2 );
1301 uint_t cs= luaG_optunsigned( L, 3,0); 1373 uint_t cs= luaG_optunsigned( L, 3,0);
@@ -1330,10 +1402,7 @@ LUAG_FUNC( thread_new )
1330 luaL_error( L, "Expected table, got %s", luaG_typename(L,glob) ); 1402 luaL_error( L, "Expected table, got %s", luaG_typename(L,glob) );
1331 1403
1332 lua_pushvalue( L, glob ); 1404 lua_pushvalue( L, glob );
1333 lua_pushstring( L, "threadName"); 1405
1334 lua_gettable( L, -2);
1335 threadName = lua_tostring( L, -1);
1336 lua_pop( L, 1);
1337 luaG_inter_move( L, L2, 1); // moves the table to L2 1406 luaG_inter_move( L, L2, 1); // moves the table to L2
1338 1407
1339 // L2 [-1]: table of globals 1408 // L2 [-1]: table of globals
@@ -1398,11 +1467,9 @@ LUAG_FUNC( thread_new )
1398 //memset( s, 0, sizeof(struct s_lane) ); 1467 //memset( s, 0, sizeof(struct s_lane) );
1399 s->L= L2; 1468 s->L= L2;
1400 s->status= PENDING; 1469 s->status= PENDING;
1470 s->waiting_on = NULL;
1401 s->cancel_request= FALSE; 1471 s->cancel_request= FALSE;
1402 1472
1403 threadName = threadName ? threadName : "<unnamed thread>";
1404 strcpy(s->threadName, threadName);
1405
1406#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) ) 1473#if !( (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) )
1407 MUTEX_INIT( &s->done_lock_ ); 1474 MUTEX_INIT( &s->done_lock_ );
1408 SIGNAL_INIT( &s->done_signal_ ); 1475 SIGNAL_INIT( &s->done_signal_ );
@@ -1484,7 +1551,7 @@ LUAG_FUNC( thread_gc )
1484#if 0 1551#if 0
1485 lua_close( s->L ); 1552 lua_close( s->L );
1486 s->L = 0; 1553 s->L = 0;
1487#else 1554#else // 0
1488 DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" )); 1555 DEBUGEXEC(fprintf( stderr, "** Joining with a killed thread (needs testing) **" ));
1489#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 1556#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN)
1490 THREAD_WAIT( &s->thread, -1 ); 1557 THREAD_WAIT( &s->thread, -1 );
@@ -1492,7 +1559,7 @@ LUAG_FUNC( thread_gc )
1492 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, -1 ); 1559 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, -1 );
1493#endif 1560#endif
1494 DEBUGEXEC(fprintf( stderr, "** Joined ok **" )); 1561 DEBUGEXEC(fprintf( stderr, "** Joined ok **" ));
1495#endif 1562#endif // 0
1496 } 1563 }
1497 else if( s->L) 1564 else if( s->L)
1498 { 1565 {
@@ -1529,54 +1596,55 @@ LUAG_FUNC( thread_gc )
1529// managed to cancel it. 1596// managed to cancel it.
1530// false if the cancellation timed out, or a kill was needed. 1597// false if the cancellation timed out, or a kill was needed.
1531// 1598//
1532LUAG_FUNC( thread_cancel ) 1599static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force)
1533{ 1600{
1534 struct s_lane *s= lua_toLane(L,1); 1601 bool_t done= TRUE;
1535 double secs= 0.0; 1602 // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN)
1536 uint_t force_i=2; 1603 //
1537 bool_t force, done= TRUE; 1604 if( s->status < DONE)
1538 1605 {
1539 if (lua_isnumber(L,2)) { 1606 s->cancel_request = TRUE; // it's now signalled to stop
1540 secs= lua_tonumber(L,2); 1607 done=
1541 force_i++;
1542 } else if (lua_isnil(L,2))
1543 force_i++;
1544
1545 force= lua_toboolean(L,force_i); // FALSE if nothing there
1546
1547 // We can read 's->status' without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN)
1548 //
1549 if (s->status < DONE) {
1550 s->cancel_request= TRUE; // it's now signalled to stop
1551
1552 done= thread_cancel( s, secs, force );
1553 }
1554
1555 lua_pushboolean( L, done );
1556 return 1;
1557}
1558
1559static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force )
1560{
1561 bool_t done=
1562#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 1608#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN)
1563 THREAD_WAIT( &s->thread, secs ); 1609 THREAD_WAIT( &s->thread, secs);
1564#else 1610#else
1565 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, secs ); 1611 THREAD_WAIT( &s->thread, &s->done_signal_, &s->done_lock_, &s->status, secs);
1566#endif 1612#endif
1567 1613
1568 if ((!done) && force) { 1614 if ((!done) && force)
1569 // Killing is asynchronous; we _will_ wait for it to be done at 1615 {
1570 // GC, to make sure the data structure can be released (alternative 1616 // Killing is asynchronous; we _will_ wait for it to be done at
1571 // would be use of "cancellation cleanup handlers" that at least 1617 // GC, to make sure the data structure can be released (alternative
1572 // PThread seems to have). 1618 // would be use of "cancellation cleanup handlers" that at least
1573 // 1619 // PThread seems to have).
1574 THREAD_KILL( &s->thread ); 1620 //
1575 s->mstatus= KILLED; // mark 'gc' to wait for it 1621 THREAD_KILL( &s->thread);
1576 } 1622 s->mstatus= KILLED; // mark 'gc' to wait for it
1577 return done; 1623 }
1624 }
1625 return done;
1578} 1626}
1579 1627
1628LUAG_FUNC( thread_cancel)
1629{
1630 struct s_lane *s= lua_toLane(L,1);
1631 double secs= 0.0;
1632 uint_t force_i=2;
1633 bool_t force, done= TRUE;
1634
1635 if (lua_isnumber(L,2)) {
1636 secs= lua_tonumber(L,2);
1637 force_i++;
1638 } else if (lua_isnil(L,2))
1639 force_i++;
1640
1641 force= lua_toboolean(L,force_i); // FALSE if nothing there
1642
1643 done = thread_cancel( s, secs, force);
1644
1645 lua_pushboolean( L, done);
1646 return 1;
1647}
1580 1648
1581//--- 1649//---
1582// str= thread_status( lane ) 1650// str= thread_status( lane )
diff --git a/src/lanes.lua b/src/lanes.lua
index 78582f9..704559a 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -399,8 +399,8 @@ if first_time then
399 -- We let the timer lane be a "free running" thread; no handle to it 399 -- We let the timer lane be a "free running" thread; no handle to it
400 -- remains. 400 -- remains.
401 -- 401 --
402 gen( "io,package", { priority=max_prio, globals={threadName="LanesTimer"} }, function() 402 gen( "io,package", { priority=max_prio}, function()
403 403 set_debugger_threadname( "LanesTimer")
404 while true do 404 while true do
405 local next_wakeup= check_timers() 405 local next_wakeup= check_timers()
406 406
diff --git a/tests/atexit.lua b/tests/atexit.lua
new file mode 100644
index 0000000..fb4f34a
--- /dev/null
+++ b/tests/atexit.lua
@@ -0,0 +1,45 @@
1require "lanes"
2
3-- create a free-running lane
4
5local linda = lanes.linda()
6
7local f = function( _linda)
8 _linda:receive("oy")
9end
10
11local g = function()
12 local cancelled
13 repeat
14 cancelled = cancel_test()
15 until cancelled
16 print "User cancellation detected!"
17end
18
19local genF = lanes.gen( "", {globals = {threadName = "mylane"}}, f)
20local genG = lanes.gen( "", g)
21
22
23-- launch a good batch of free running lanes
24for i = 1, 10 do
25 -- if i%50 == 0 then print( i) end
26 local h = genF( linda)
27 local status
28 repeat
29 status = h.status
30 --print( status)
31 until status == "waiting"
32
33 -- [[
34 local h = genG()
35 local status
36 repeat
37 status = h.status
38 --print( status)
39 until status == "running"
40 --]]
41end
42
43print "exiting"
44
45-- let process end terminate them and see what happens \ No newline at end of file