aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES10
-rw-r--r--docs/index.html35
-rw-r--r--lanes-3.6.3-1.rockspec (renamed from lanes-3.6.2-1.rockspec)4
-rw-r--r--src/lanes.c156
-rw-r--r--src/lanes.lua11
-rw-r--r--src/tools.c168
-rw-r--r--src/tools.h3
-rw-r--r--tests/fifo.lua7
-rw-r--r--tests/linda_perf.lua5
-rw-r--r--tests/require.lua7
10 files changed, 281 insertions, 125 deletions
diff --git a/CHANGES b/CHANGES
index 538acba..134b64f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,15 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 67: BGe 2-Aug-13
4 * version 3.6.3
5 * lane:cancel(<negative-timeout>) only causes cancel_test() to return true but won't interrupt execution of the lane during linda operations
6
7CHANGE 66: BGe 31-Jul-13
8 * more explicit errors when trying to transfer unknown source functions (with new configure option verbose_errors)
9
10CHANGE 65: BGe 23-Jul-13
11 * default options wrap allocator around a mutex when run by LuaJIT
12
3CHANGE 64: BGe 20-Jul-13 13CHANGE 64: BGe 20-Jul-13
4 * WIN32 builds against pre-Vista versions no longer use PulseEvent to fix occasional hangs when a wake event is missed 14 * WIN32 builds against pre-Vista versions no longer use PulseEvent to fix occasional hangs when a wake event is missed
5 15
diff --git a/docs/index.html b/docs/index.html
index 617403a..0e32504 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -70,7 +70,7 @@
70 </p> 70 </p>
71 71
72 <p> 72 <p>
73 This document was revised on 20-May-13, and applies to version <tt>3.6.2</tt>. 73 This document was revised on 02-Aug-13, and applies to version <tt>3.6.3</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -294,6 +294,19 @@
294 294
295 <tr valign=top> 295 <tr valign=top>
296 <td> 296 <td>
297 <code>.verbose_errors</code>
298 </td>
299 <td>
300 <tt>nil</tt>/<tt>false</tt>/<tt>true</tt>
301 </td>
302 <td>
303 (Since v3.6.3) If equal to <tt>true</tt>, Lanes will collect more information when transfering stuff across Lua states to help identify errors (with a cost).
304 Default is <tt>false</tt>.
305 </td>
306 </tr>
307
308 <tr valign=top>
309 <td>
297 <code>.protect_allocator</code> 310 <code>.protect_allocator</code>
298 </td> 311 </td>
299 <td> 312 <td>
@@ -539,7 +552,7 @@
539 </td> 552 </td>
540 <td>integer >= 1/<tt>true</tt></td> 553 <td>integer >= 1/<tt>true</tt></td>
541 <td> 554 <td>
542 By default, lanes are only cancellable when they <u>enter</u> a pending <tt>:receive()</tt> or <tt>:send()</tt> call. With this option, one can set cancellation check to occur every <tt>N</tt> Lua statements. The value <tt>true</tt> uses a default value (100). 555 By default, lanes are only cancellable when they <u>enter</u> a pending <tt>:receive()</tt> or <tt>:send()</tt> call. With this option, one can set <a href="#cancelling">cancellation</a> check to occur every <tt>N</tt> Lua statements. The value <tt>true</tt> uses a default value (100).
543 It is also possible to manually test for cancel requests with <tt>cancel_test()</tt>. 556 It is also possible to manually test for cancel requests with <tt>cancel_test()</tt>.
544 </td> 557 </td>
545 </tr> 558 </tr>
@@ -705,7 +718,7 @@
705 </td> 718 </td>
706 <td/> 719 <td/>
707 <td> 720 <td>
708 received cancellation and finished itself. 721 received <a href="#cancelling">cancellation</a> and finished itself.
709 </td> 722 </td>
710 </tr> 723 </tr>
711 <tr> 724 <tr>
@@ -833,8 +846,10 @@
833</pre></td></tr></table> 846</pre></td></tr></table>
834 847
835<p> 848<p>
836 <tt>cancel()</tt>sends a cancellation request to the lane. If <tt>timeout_secs</tt> is non-zero, waits for the request to be processed, or a timeout to occur. 849 <tt>cancel()</tt>sends a cancellation request to the lane.<br/>
837 Returns <tt>true</tt> if the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status) or if the cancellation was fruitful within timeout period. 850 If <tt>timeout_secs</tt> is positive (aka "hard cancel"), waits for the request to be processed, or a timeout to occur.<br/>
851 If <tt>timeout_secs</tt> is negative (aka "soft cancel"), starting with version 3.6.3, will only cause <tt>cancel_test()</tt> to return true, so that the lane can cleanup manually. You can't provide a second argument in that case.<br/>
852 Returns <tt>true</tt> if soft cancelling, or the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status), or the cancellation was fruitful within timeout period.
838</p> 853</p>
839 854
840<p> 855<p>
@@ -887,7 +902,7 @@
887 -- no special error: true error 902 -- no special error: true error
888 print( " error: "..tostring(err)) 903 print( " error: "..tostring(err))
889 elseif type( err) == "userdata" then 904 elseif type( err) == "userdata" then
890 -- lane cancellation is performed by throwing a special userdata as error 905 -- lane <a href="#cancelling">cancellation</a> is performed by throwing a special userdata as error
891 print( "after cancel") 906 print( "after cancel")
892 else 907 else
893 -- no error: we just got finalized 908 -- no error: we just got finalized
@@ -977,11 +992,15 @@
977</p> 992</p>
978 993
979<p> 994<p>
980 <tt>send</tt> returns <tt>true</tt> if the sending succeeded, and <tt>false</tt> if the queue limit was met, and the queue did not empty enough during the given timeout, or the operation was <a href="#cancelling">cancelled</a>. 995 <a href="#cancelling">Hard cancellation</a> will cause pending linda operations to abort execution of the lane through a cancellation error. This means that you have to install a <a href="#finalizers">finalizer</a> in your lane if you want to run some code in that situation.
996</p>
997
998<p>
999 <tt>send</tt> returns <tt>true</tt> if the sending succeeded, and <tt>false</tt> if the queue limit was met, and the queue did not empty enough during the given timeout.
981</p> 1000</p>
982 1001
983<p> 1002<p>
984 Equally, <tt>receive</tt> returns a key and the value extracted from it, or nothing for timeout or <a href="#cancelling">cancellation</a>. Note that <tt>nil</tt>s can be sent and received; the <tt>key</tt> value will tell it apart from a timeout. 1003 Equally, <tt>receive</tt> returns a key and the value extracted from it, or nothing for timeout. Note that <tt>nil</tt>s can be sent and received; the <tt>key</tt> value will tell it apart from a timeout.
985 <br> 1004 <br>
986 Version 3.4.0 introduces an API change in the returned values: <tt>receive</tt> returns the key followed by the value(s), in that order, and not the other way around. 1005 Version 3.4.0 introduces an API change in the returned values: <tt>receive</tt> returns the key followed by the value(s), in that order, and not the other way around.
987</p> 1006</p>
diff --git a/lanes-3.6.2-1.rockspec b/lanes-3.6.3-1.rockspec
index 8679c08..18bae0a 100644
--- a/lanes-3.6.2-1.rockspec
+++ b/lanes-3.6.3-1.rockspec
@@ -7,11 +7,11 @@
7 7
8package = "Lanes" 8package = "Lanes"
9 9
10version = "3.6.2-1" 10version = "3.6.3-1"
11 11
12source= { 12source= {
13 url= "git://github.com/LuaLanes/lanes.git", 13 url= "git://github.com/LuaLanes/lanes.git",
14 branch= "v3.6.2" 14 branch= "v3.6.3"
15} 15}
16 16
17description = { 17description = {
diff --git a/src/lanes.c b/src/lanes.c
index 08bdb9a..e36a073 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.6.2"; 55char const* VERSION = "3.6.3";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -115,10 +115,21 @@ THE SOFTWARE.
115*/ 115*/
116#define ERROR_FULL_STACK 116#define ERROR_FULL_STACK
117 117
118/*
119 * Lane cancellation request modes
120 */
121enum e_cancel_request
122{
123 CANCEL_NONE, // no pending cancel request
124 CANCEL_SOFT, // user wants the lane to cancel itself manually on cancel_test()
125 CANCEL_HARD // user wants the lane to be interrupted (meaning code won't return from those functions) from inside linda:send/receive calls
126};
127
118// NOTE: values to be changed by either thread, during execution, without 128// NOTE: values to be changed by either thread, during execution, without
119// locking, are marked "volatile" 129// locking, are marked "volatile"
120// 130//
121struct s_lane { 131struct s_lane
132{
122 THREAD_T thread; 133 THREAD_T thread;
123 // 134 //
124 // M: sub-thread OS thread 135 // M: sub-thread OS thread
@@ -140,7 +151,7 @@ struct s_lane {
140 // 151 //
141 // When status is WAITING, points on the linda's signal the thread waits on, else NULL 152 // When status is WAITING, points on the linda's signal the thread waits on, else NULL
142 153
143 volatile bool_t cancel_request; 154 volatile enum e_cancel_request cancel_request;
144 // 155 //
145 // M: sets to FALSE, flags TRUE for cancel request 156 // M: sets to FALSE, flags TRUE for cancel request
146 // S: reads to see if cancel is requested 157 // S: reads to see if cancel is requested
@@ -178,7 +189,7 @@ struct s_lane {
178 // For tracking only 189 // For tracking only
179}; 190};
180 191
181static bool_t cancel_test( lua_State*L ); 192static enum e_cancel_request cancel_test( lua_State* L);
182static void cancel_error( lua_State*L ); 193static void cancel_error( lua_State*L );
183 194
184#define CANCEL_TEST_KEY ((void*)cancel_test) // used as registry key 195#define CANCEL_TEST_KEY ((void*)cancel_test) // used as registry key
@@ -372,7 +383,7 @@ LUAG_FUNC( linda_send)
372{ 383{
373 struct s_Linda *linda = lua_toLinda( L, 1); 384 struct s_Linda *linda = lua_toLinda( L, 1);
374 bool_t ret; 385 bool_t ret;
375 bool_t cancel = FALSE; 386 enum e_cancel_request cancel = CANCEL_NONE;
376 int pushed; 387 int pushed;
377 time_d timeout= -1.0; 388 time_d timeout= -1.0;
378 uint_t key_i = 2; // index of first key, if timeout not there 389 uint_t key_i = 2; // index of first key, if timeout not there
@@ -434,7 +445,7 @@ LUAG_FUNC( linda_send)
434 /* limit faced; push until timeout */ 445 /* limit faced; push until timeout */
435 446
436 cancel = cancel_test( L); // testing here causes no delays 447 cancel = cancel_test( L); // testing here causes no delays
437 if (cancel) 448 if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without sending anything
438 { 449 {
439 break; 450 break;
440 } 451 }
@@ -486,7 +497,8 @@ LUAG_FUNC( linda_send)
486 return luaL_error( L, "tried to copy unsupported types"); 497 return luaL_error( L, "tried to copy unsupported types");
487 } 498 }
488 499
489 if( cancel) 500 // raise an error interrupting execution only in case of hard cancel
501 if( cancel == CANCEL_HARD)
490 cancel_error( L); 502 cancel_error( L);
491 503
492 lua_pushboolean( L, ret); 504 lua_pushboolean( L, ret);
@@ -510,7 +522,7 @@ LUAG_FUNC( linda_receive)
510{ 522{
511 struct s_Linda *linda = lua_toLinda( L, 1); 523 struct s_Linda *linda = lua_toLinda( L, 1);
512 int pushed, expected_pushed_min, expected_pushed_max; 524 int pushed, expected_pushed_min, expected_pushed_max;
513 bool_t cancel = FALSE; 525 enum e_cancel_request cancel = CANCEL_NONE;
514 keeper_api_t keeper_receive; 526 keeper_api_t keeper_receive;
515 527
516 time_d timeout = -1.0; 528 time_d timeout = -1.0;
@@ -592,16 +604,16 @@ LUAG_FUNC( linda_receive)
592 /* nothing received; wait until timeout */ 604 /* nothing received; wait until timeout */
593 605
594 cancel = cancel_test( L); // testing here causes no delays 606 cancel = cancel_test( L); // testing here causes no delays
595 if( cancel) 607 if( cancel != CANCEL_NONE) // if user wants to cancel, the call returns without providing anything
596 { 608 {
597 break; 609 break;
598 } 610 }
599 611
600 // change status of lane to "waiting" 612 // change status of lane to "waiting"
601 { 613 {
602 struct s_lane *s; 614 struct s_lane* s;
603 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings 615 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
604 STACK_GROW(L,1); 616 STACK_GROW( L, 1);
605 617
606 STACK_CHECK( L); 618 STACK_CHECK( L);
607 lua_pushlightuserdata( L, CANCEL_TEST_KEY); 619 lua_pushlightuserdata( L, CANCEL_TEST_KEY);
@@ -643,7 +655,8 @@ LUAG_FUNC( linda_receive)
643 return luaL_error( L, "tried to copy unsupported types"); 655 return luaL_error( L, "tried to copy unsupported types");
644 } 656 }
645 657
646 if( cancel) 658 // raise an error interrupting execution only in case of hard cancel
659 if( cancel == CANCEL_HARD)
647 cancel_error( L); 660 cancel_error( L);
648 661
649 return pushed; 662 return pushed;
@@ -1176,31 +1189,41 @@ static cancel_result thread_cancel( struct s_lane *s, double secs, bool_t force)
1176 } 1189 }
1177 else if( s->status < DONE) 1190 else if( s->status < DONE)
1178 { 1191 {
1179 s->cancel_request = TRUE; // it's now signaled to stop
1180 // signal the linda the wake up the thread so that it can react to the cancel query 1192 // signal the linda the wake up the thread so that it can react to the cancel query
1181 // let us hope we never land here with a pointer on a linda that has been destroyed... 1193 // let us hope we never land here with a pointer on a linda that has been destroyed...
1194 if( secs < 0.0)
1195 {
1196 s->cancel_request = CANCEL_SOFT; // it's now signaled to stop
1197 // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own
1198 // say we succeeded though
1199 result = CR_Cancelled;
1200 }
1201 else
1182 { 1202 {
1183 SIGNAL_T *waiting_on = s->waiting_on; 1203 s->cancel_request = CANCEL_HARD; // it's now signaled to stop
1184 if( s->status == WAITING && waiting_on != NULL)
1185 { 1204 {
1186 SIGNAL_ALL( waiting_on); 1205 SIGNAL_T *waiting_on = s->waiting_on;
1206 if( s->status == WAITING && waiting_on != NULL)
1207 {
1208 SIGNAL_ALL( waiting_on);
1209 }
1187 } 1210 }
1188 }
1189 1211
1190 result = THREAD_WAIT( &s->thread, secs, &s->done_signal, &s->done_lock, &s->status) ? CR_Cancelled : CR_Timeout; 1212 result = THREAD_WAIT( &s->thread, secs, &s->done_signal, &s->done_lock, &s->status) ? CR_Cancelled : CR_Timeout;
1191 1213
1192 if( (result == CR_Timeout) && force) 1214 if( (result == CR_Timeout) && force)
1193 { 1215 {
1194 // Killing is asynchronous; we _will_ wait for it to be done at 1216 // Killing is asynchronous; we _will_ wait for it to be done at
1195 // GC, to make sure the data structure can be released (alternative 1217 // GC, to make sure the data structure can be released (alternative
1196 // would be use of "cancellation cleanup handlers" that at least 1218 // would be use of "cancellation cleanup handlers" that at least
1197 // PThread seems to have). 1219 // PThread seems to have).
1198 // 1220 //
1199 THREAD_KILL( &s->thread); 1221 THREAD_KILL( &s->thread);
1200 s->mstatus = KILLED; // mark 'gc' to wait for it 1222 s->mstatus = KILLED; // mark 'gc' to wait for it
1201 // note that s->status value must remain to whatever it was at the time of the kill 1223 // note that s->status value must remain to whatever it was at the time of the kill
1202 // because we need to know if we can lua_close() the Lua State or not. 1224 // because we need to know if we can lua_close() the Lua State or not.
1203 result = CR_Killed; 1225 result = CR_Killed;
1226 }
1204 } 1227 }
1205 } 1228 }
1206 else 1229 else
@@ -1307,7 +1330,7 @@ static int selfdestruct_gc( lua_State* L)
1307 struct s_lane* s = selfdestruct_first; 1330 struct s_lane* s = selfdestruct_first;
1308 while( s != SELFDESTRUCT_END ) 1331 while( s != SELFDESTRUCT_END )
1309 { 1332 {
1310 // attempt a regular unforced cancel with a small timeout 1333 // attempt a regular unforced hard cancel with a small timeout
1311 bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( s, 0.0001, FALSE); 1334 bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( s, 0.0001, FALSE);
1312 // if we failed, and we know the thread is waiting on a linda 1335 // if we failed, and we know the thread is waiting on a linda
1313 if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL) 1336 if( cancelled == FALSE && s->status == WAITING && s->waiting_on != NULL)
@@ -1353,7 +1376,7 @@ static int selfdestruct_gc( lua_State* L)
1353 struct s_lane* s = selfdestruct_first; 1376 struct s_lane* s = selfdestruct_first;
1354 while( s != SELFDESTRUCT_END) 1377 while( s != SELFDESTRUCT_END)
1355 { 1378 {
1356 if( s->cancel_request) 1379 if( s->cancel_request == CANCEL_HARD)
1357 ++ n; 1380 ++ n;
1358 s = s->selfdestruct_next; 1381 s = s->selfdestruct_next;
1359 } 1382 }
@@ -1444,21 +1467,22 @@ static int selfdestruct_gc( lua_State* L)
1444* Returns TRUE if any locks are to be exited, and 'cancel_error()' called, 1467* Returns TRUE if any locks are to be exited, and 'cancel_error()' called,
1445* to make execution of the lane end. 1468* to make execution of the lane end.
1446*/ 1469*/
1447static bool_t cancel_test( lua_State*L ) { 1470static enum e_cancel_request cancel_test( lua_State* L)
1448 struct s_lane *s; 1471{
1472 struct s_lane* s;
1449 1473
1450 STACK_GROW(L,1); 1474 STACK_GROW( L, 1);
1451 1475
1452 STACK_CHECK( L); 1476 STACK_CHECK( L);
1453 lua_pushlightuserdata( L, CANCEL_TEST_KEY ); 1477 lua_pushlightuserdata( L, CANCEL_TEST_KEY);
1454 lua_rawget( L, LUA_REGISTRYINDEX ); 1478 lua_rawget( L, LUA_REGISTRYINDEX);
1455 s= lua_touserdata( L, -1 ); // lightuserdata (true 's_lane' pointer) / nil 1479 s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) / nil
1456 lua_pop(L,1); 1480 lua_pop( L, 1);
1457 STACK_END( L, 0); 1481 STACK_END( L, 0);
1458 1482
1459 // 's' is NULL for the original main state (no-one can cancel that) 1483 // 's' is NULL for the original main state (no-one can cancel that)
1460 // 1484 //
1461 return s && s->cancel_request; 1485 return s ? s->cancel_request : CANCEL_NONE;
1462} 1486}
1463 1487
1464static void cancel_error( lua_State*L ) { 1488static void cancel_error( lua_State*L ) {
@@ -1467,22 +1491,24 @@ static void cancel_error( lua_State*L ) {
1467 lua_error(L); // no return 1491 lua_error(L); // no return
1468} 1492}
1469 1493
1470static void cancel_hook( lua_State*L, lua_Debug *ar ) { 1494static void cancel_hook( lua_State*L, lua_Debug *ar )
1471 (void)ar; 1495{
1472 if (cancel_test(L)) cancel_error(L); 1496 (void)ar;
1497 if( cancel_test( L) != CANCEL_NONE)
1498 cancel_error( L);
1473} 1499}
1474 1500
1475 1501
1476//--- 1502//---
1477// bool= cancel_test() 1503// bool = cancel_test()
1478// 1504//
1479// Available inside the global namespace of lanes 1505// Available inside the global namespace of lanes
1480// returns a boolean saying if a cancel request is pending 1506// returns a boolean saying if a cancel request is pending
1481// 1507//
1482LUAG_FUNC( cancel_test) 1508LUAG_FUNC( cancel_test)
1483{ 1509{
1484 bool_t test = cancel_test( L); 1510 enum e_cancel_request test = cancel_test( L);
1485 lua_pushboolean( L, test); 1511 lua_pushboolean( L, test != CANCEL_NONE);
1486 return 1; 1512 return 1;
1487} 1513}
1488 1514
@@ -1724,7 +1750,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1724 // Tie "cancel_test()" to the state 1750 // Tie "cancel_test()" to the state
1725 // 1751 //
1726 lua_pushcfunction( L, LG_cancel_test); 1752 lua_pushcfunction( L, LG_cancel_test);
1727 lua_setglobal( L, "cancel_test" ); 1753 lua_setglobal( L, "cancel_test");
1728 1754
1729#ifdef ERROR_FULL_STACK 1755#ifdef ERROR_FULL_STACK
1730 // Tie "set_error_reporting()" to the state 1756 // Tie "set_error_reporting()" to the state
@@ -2065,7 +2091,7 @@ LUAG_FUNC( thread_new)
2065 s->status= PENDING; 2091 s->status= PENDING;
2066 s->waiting_on = NULL; 2092 s->waiting_on = NULL;
2067 s->debug_name = NULL; 2093 s->debug_name = NULL;
2068 s->cancel_request= FALSE; 2094 s->cancel_request = CANCEL_NONE;
2069 2095
2070#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 2096#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
2071 MUTEX_INIT( &s->done_lock); 2097 MUTEX_INIT( &s->done_lock);
@@ -2183,6 +2209,10 @@ LUAG_FUNC( thread_cancel)
2183 if( lua_isnumber( L, 2)) 2209 if( lua_isnumber( L, 2))
2184 { 2210 {
2185 secs = lua_tonumber( L, 2); 2211 secs = lua_tonumber( L, 2);
2212 if( secs < 0.0 && lua_gettop( L) > 2)
2213 {
2214 return luaL_error( L, "can't force a soft cancel");
2215 }
2186 ++ force_i; 2216 ++ force_i;
2187 } 2217 }
2188 else if( lua_isnil( L, 2)) 2218 else if( lua_isnil( L, 2))
@@ -2611,8 +2641,9 @@ void register_core_libfuncs_for_keeper( lua_State* L)
2611/* 2641/*
2612** One-time initializations 2642** One-time initializations
2613*/ 2643*/
2614static void init_once_LOCKED( lua_State* L, int const _on_state_create, int const nbKeepers, lua_Number _shutdown_timeout, bool_t _track_lanes) 2644static void init_once_LOCKED( lua_State* L, int const _on_state_create, int const nbKeepers, lua_Number _shutdown_timeout, bool_t _track_lanes, bool_t verbose_errors)
2615{ 2645{
2646 GVerboseErrors = verbose_errors;
2616#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 2647#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2617 now_secs(); // initialize 'now_secs()' internal offset 2648 now_secs(); // initialize 'now_secs()' internal offset
2618#endif 2649#endif
@@ -2724,10 +2755,12 @@ LUAG_FUNC( configure)
2724 char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); 2755 char const* name = luaL_checkstring( L, lua_upvalueindex( 1));
2725 // all parameter checks are done lua-side 2756 // all parameter checks are done lua-side
2726 int const nbKeepers = (int)lua_tointeger( L, 1); 2757 int const nbKeepers = (int)lua_tointeger( L, 1);
2758 // all these can be nil when lanes.core is required internally! (but are only processed at first init anyway)
2727 int const on_state_create = lua_isfunction( L, 2) ? 2 : 0; 2759 int const on_state_create = lua_isfunction( L, 2) ? 2 : 0;
2728 lua_Number shutdown_timeout = lua_tonumber( L, 3); 2760 lua_Number shutdown_timeout = lua_tonumber( L, 3);
2729 bool_t track_lanes = lua_toboolean( L, 4); 2761 bool_t track_lanes = lua_toboolean( L, 4);
2730 bool_t protect_allocator = lua_toboolean( L, 5); 2762 bool_t protect_allocator = lua_toboolean( L, 5);
2763 bool_t verbose_errors = lua_toboolean( L, 6);
2731 2764
2732 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L)); 2765 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L));
2733 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 2766 DEBUGSPEW_CODE( ++ debugspew_indent_depth);
@@ -2738,11 +2771,14 @@ LUAG_FUNC( configure)
2738 { 2771 {
2739 void* ud; 2772 void* ud;
2740 lua_Alloc allocf = lua_getallocf( L, &ud); 2773 lua_Alloc allocf = lua_getallocf( L, &ud);
2741 struct ProtectedAllocator_s* s = (struct ProtectedAllocator_s*) allocf( ud, NULL, 0, sizeof( struct ProtectedAllocator_s)); 2774 if( allocf != protected_lua_Alloc) // just in case
2742 s->allocf = allocf; 2775 {
2743 s->ud = ud; 2776 struct ProtectedAllocator_s* s = (struct ProtectedAllocator_s*) allocf( ud, NULL, 0, sizeof( struct ProtectedAllocator_s));
2744 MUTEX_INIT( &s->lock); 2777 s->allocf = allocf;
2745 lua_setallocf( L, protected_lua_Alloc, s); 2778 s->ud = ud;
2779 MUTEX_INIT( &s->lock);
2780 lua_setallocf( L, protected_lua_Alloc, s);
2781 }
2746 } 2782 }
2747 2783
2748 // Create main module interface table 2784 // Create main module interface table
@@ -2818,7 +2854,7 @@ LUAG_FUNC( configure)
2818 static volatile int /*bool*/ go_ahead; // = 0 2854 static volatile int /*bool*/ go_ahead; // = 0
2819 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) 2855 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
2820 { 2856 {
2821 init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes); 2857 init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors);
2822 go_ahead = 1; // let others pass 2858 go_ahead = 1; // let others pass
2823 } 2859 }
2824 else 2860 else
@@ -2836,7 +2872,7 @@ LUAG_FUNC( configure)
2836 // 2872 //
2837 if( s_initCount == 0) 2873 if( s_initCount == 0)
2838 { 2874 {
2839 init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes); 2875 init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes, verbose_errors);
2840 s_initCount = 1; 2876 s_initCount = 1;
2841 } 2877 }
2842 } 2878 }
diff --git a/src/lanes.lua b/src/lanes.lua
index ac3da26..175002a 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -69,6 +69,7 @@ lanes.configure = function( _params)
69 shutdown_timeout = 0.25, 69 shutdown_timeout = 0.25,
70 with_timers = true, 70 with_timers = true,
71 track_lanes = nil, 71 track_lanes = nil,
72 verbose_errors = false,
72 -- LuaJIT provides a thread-unsafe allocator by default, so we need to protect it when used in parallel lanes 73 -- LuaJIT provides a thread-unsafe allocator by default, so we need to protect it when used in parallel lanes
73 protect_allocator = (jit and jit.version) and true or false 74 protect_allocator = (jit and jit.version) and true or false
74 } 75 }
@@ -105,6 +106,14 @@ lanes.configure = function( _params)
105 track_lanes = function( _val) 106 track_lanes = function( _val)
106 -- track_lanes may be nil or boolean 107 -- track_lanes may be nil or boolean
107 return _val and type( _val) == "boolean" or true 108 return _val and type( _val) == "boolean" or true
109 end,
110 verbose_errors = function( _val)
111 -- verbose_errors may be nil or boolean
112 if _val then
113 return type( _val) == "boolean"
114 else
115 return true -- _val is either false or nil
116 end
108 end 117 end
109 } 118 }
110 119
@@ -138,7 +147,7 @@ lanes.configure = function( _params)
138 assert( type( core)=="table") 147 assert( type( core)=="table")
139 148
140 -- configure() is available only the first time lanes.core is required process-wide, and we *must* call it to have the other functions in the interface 149 -- configure() is available only the first time lanes.core is required process-wide, and we *must* call it to have the other functions in the interface
141 if core.configure then core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator) end 150 if core.configure then core.configure( _params.nb_keepers, _params.on_state_create, _params.shutdown_timeout, _params.track_lanes, _params.protect_allocator, _params.verbose_errors) end
142 151
143 local thread_new = assert( core.thread_new) 152 local thread_new = assert( core.thread_new)
144 153
diff --git a/src/tools.c b/src/tools.c
index d2dfdf5..a3cc6b7 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -42,6 +42,10 @@ THE SOFTWARE.
42#include <string.h> 42#include <string.h>
43#include <ctype.h> 43#include <ctype.h>
44#include <stdlib.h> 44#include <stdlib.h>
45#include <malloc.h>
46
47// for verbose errors
48bool_t GVerboseErrors = FALSE;
45 49
46/* 50/*
47** Copied from Lua 5.2 loadlib.c 51** Copied from Lua 5.2 loadlib.c
@@ -1285,9 +1289,9 @@ static bool_t push_cached_table( lua_State *L2, uint_t L2_cache_i, lua_State *L,
1285 * 1289 *
1286 * Always pushes a function to 'L2'. 1290 * Always pushes a function to 'L2'.
1287 */ 1291 */
1288static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i); 1292static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, char const* upName_);
1289 1293
1290static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i) 1294static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, char const* upName_)
1291{ 1295{
1292 void* const aspointer = (void*)lua_topointer( L, i); 1296 void* const aspointer = (void*)lua_topointer( L, i);
1293 // TBD: Merge this and same code for tables 1297 // TBD: Merge this and same code for tables
@@ -1319,7 +1323,7 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui
1319 // via upvalues 1323 // via upvalues
1320 // 1324 //
1321 // pushes a copy of the func, stores a reference in the cache 1325 // pushes a copy of the func, stores a reference in the cache
1322 inter_copy_func( L2, L2_cache_i, L, i); // ... {cache} ... function 1326 inter_copy_func( L2, L2_cache_i, L, i, upName_); // ... {cache} ... function
1323 } 1327 }
1324 else // found function in the cache 1328 else // found function in the cache
1325 { 1329 {
@@ -1363,16 +1367,19 @@ static int discover_object_name_recur( lua_State* L, int shortest_, int depth_)
1363 lua_pushinteger( L, 1); // o "r" {c} {fqn} ... {?} {?} 1 1367 lua_pushinteger( L, 1); // o "r" {c} {fqn} ... {?} {?} 1
1364 lua_rawset( L, cache); // o "r" {c} {fqn} ... {?} 1368 lua_rawset( L, cache); // o "r" {c} {fqn} ... {?}
1365 // scan table contents 1369 // scan table contents
1370 STACK_CHECK( L);
1366 lua_pushnil( L); // o "r" {c} {fqn} ... {?} nil 1371 lua_pushnil( L); // o "r" {c} {fqn} ... {?} nil
1367 while( lua_next( L, -2)) // o "r" {c} {fqn} ... {?} k v 1372 while( lua_next( L, -2)) // o "r" {c} {fqn} ... {?} k v
1368 { 1373 {
1369 //char const *const key = lua_tostring( L, -2); // only for debugging (BEWARE, IT MAY CHANGE THE VALUE IF IT IS CONVERTIBLE, AND WRECK THE LOOP ITERATION PROCESS!) 1374 //char const *const strKey = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : NULL; // only for debugging
1375 //lua_Number const numKey = (lua_type( L, -2) == LUA_TNUMBER) ? lua_tonumber( L, -2) : -6666; // only for debugging
1370 // append key name to fqn stack 1376 // append key name to fqn stack
1371 ++ depth_; 1377 ++ depth_;
1372 lua_pushvalue( L, -2); // o "r" {c} {fqn} ... {?} k v k 1378 lua_pushvalue( L, -2); // o "r" {c} {fqn} ... {?} k v k
1373 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k v 1379 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k v
1374 if( lua_rawequal( L, -1, what)) // is it what we are looking for? 1380 if( lua_rawequal( L, -1, what)) // is it what we are looking for?
1375 { 1381 {
1382 STACK_MID( L, 2);
1376 // update shortest name 1383 // update shortest name
1377 if( depth_ < shortest_) 1384 if( depth_ < shortest_)
1378 { 1385 {
@@ -1382,32 +1389,74 @@ static int discover_object_name_recur( lua_State* L, int shortest_, int depth_)
1382 } 1389 }
1383 // no need to search further at this level 1390 // no need to search further at this level
1384 lua_pop( L, 2); // o "r" {c} {fqn} ... {?} 1391 lua_pop( L, 2); // o "r" {c} {fqn} ... {?}
1392 STACK_MID( L, 0);
1385 break; 1393 break;
1386 } 1394 }
1387 else if( lua_istable( L, -1)) 1395 else if( lua_istable( L, -1)) // o "r" {c} {fqn} ... {?} k {}
1388 { 1396 {
1397 STACK_MID( L, 2);
1389 shortest_ = discover_object_name_recur( L, shortest_, depth_); 1398 shortest_ = discover_object_name_recur( L, shortest_, depth_);
1390 // search in the table's metatable too 1399 // search in the table's metatable too
1391 if( lua_getmetatable( L, -1)) 1400 if( lua_getmetatable( L, -1)) // o "r" {c} {fqn} ... {?} k {} {mt}
1392 { 1401 {
1393 if( lua_istable( L, -1)) 1402 if( lua_istable( L, -1))
1394 { 1403 {
1404 ++ depth_;
1405 lua_pushliteral( L, "__metatable"); // o "r" {c} {fqn} ... {?} k {} {mt} "__metatable"
1406 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k {} {mt}
1395 shortest_ = discover_object_name_recur( L, shortest_, depth_); 1407 shortest_ = discover_object_name_recur( L, shortest_, depth_);
1408 lua_pushnil( L); // o "r" {c} {fqn} ... {?} k {} {mt} nil
1409 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k {} {mt}
1410 -- depth_;
1396 } 1411 }
1397 lua_pop( L, 1); 1412 lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k {}
1413 STACK_MID( L, 2);
1398 } 1414 }
1399 } 1415 }
1400 else if( lua_isuserdata( L, -1)) 1416 else if( lua_isthread( L, -1)) // o "r" {c} {fqn} ... {?} k T
1401 { 1417 {
1418 // search in the object's uservalue if it is a table
1419 lua_getuservalue( L, -1); // o "r" {c} {fqn} ... {?} k T {u}
1420 if( lua_istable( L, -1))
1421 {
1422 shortest_ = discover_object_name_recur( L, shortest_, depth_);
1423 }
1424 lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k T
1425 STACK_MID( L, 2);
1426 }
1427 else if( lua_isuserdata( L, -1)) // o "r" {c} {fqn} ... {?} k U
1428 {
1429 STACK_MID( L, 2);
1402 // search in the object's metatable (some modules are built that way) 1430 // search in the object's metatable (some modules are built that way)
1403 if( lua_getmetatable( L, -1)) 1431 if( lua_getmetatable( L, -1)) // o "r" {c} {fqn} ... {?} k U {mt}
1404 { 1432 {
1405 if( lua_istable( L, -1)) 1433 if( lua_istable( L, -1))
1406 { 1434 {
1435 ++ depth_;
1436 lua_pushliteral( L, "__metatable"); // o "r" {c} {fqn} ... {?} k U {mt} "__metatable"
1437 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k U {mt}
1407 shortest_ = discover_object_name_recur( L, shortest_, depth_); 1438 shortest_ = discover_object_name_recur( L, shortest_, depth_);
1439 lua_pushnil( L); // o "r" {c} {fqn} ... {?} k U {mt} nil
1440 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k U {mt}
1441 -- depth_;
1408 } 1442 }
1409 lua_pop( L, 1); 1443 lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k U
1444 STACK_MID( L, 2);
1445 }
1446 // search in the object's uservalue if it is a table
1447 lua_getuservalue( L, -1); // o "r" {c} {fqn} ... {?} k U {u}
1448 if( lua_istable( L, -1))
1449 {
1450 ++ depth_;
1451 lua_pushliteral( L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue"
1452 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k v {u}
1453 shortest_ = discover_object_name_recur( L, shortest_, depth_);
1454 lua_pushnil( L); // o "r" {c} {fqn} ... {?} k v {u} nil
1455 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k v {u}
1456 -- depth_;
1410 } 1457 }
1458 lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k U
1459 STACK_MID( L, 2);
1411 } 1460 }
1412 // make ready for next iteration 1461 // make ready for next iteration
1413 lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k 1462 lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k
@@ -1416,6 +1465,7 @@ static int discover_object_name_recur( lua_State* L, int shortest_, int depth_)
1416 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k 1465 lua_rawseti( L, fqn, depth_); // o "r" {c} {fqn} ... {?} k
1417 -- depth_; 1466 -- depth_;
1418 } // o "r" {c} {fqn} ... {?} 1467 } // o "r" {c} {fqn} ... {?}
1468 STACK_END( L, 0);
1419 // remove the visited table from the cache, in case a shorter path to the searched object exists 1469 // remove the visited table from the cache, in case a shorter path to the searched object exists
1420 lua_pushvalue( L, -1); // o "r" {c} {fqn} ... {?} {?} 1470 lua_pushvalue( L, -1); // o "r" {c} {fqn} ... {?} {?}
1421 lua_pushnil( L); // o "r" {c} {fqn} ... {?} {?} nil 1471 lua_pushnil( L); // o "r" {c} {fqn} ... {?} {?} nil
@@ -1442,6 +1492,7 @@ int luaG_nameof( lua_State* L)
1442 lua_insert( L, -2); // "type" o 1492 lua_insert( L, -2); // "type" o
1443 return 2; 1493 return 2;
1444 } 1494 }
1495
1445 STACK_GROW( L, 4); 1496 STACK_GROW( L, 4);
1446 // this slot will contain the shortest name we found when we are done 1497 // this slot will contain the shortest name we found when we are done
1447 lua_pushnil( L); // o nil 1498 lua_pushnil( L); // o nil
@@ -1461,7 +1512,7 @@ int luaG_nameof( lua_State* L)
1461/* 1512/*
1462* Push a looked-up native/LuaJIT function. 1513* Push a looked-up native/LuaJIT function.
1463*/ 1514*/
1464static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i) 1515static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, char const* upName_)
1465{ 1516{
1466 char const* fqn; // L // L2 1517 char const* fqn; // L // L2
1467 size_t len; 1518 size_t len;
@@ -1478,14 +1529,28 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i)
1478 lua_pop( L, 2); // ... f ... 1529 lua_pop( L, 2); // ... f ...
1479 if( !fqn) 1530 if( !fqn)
1480 { 1531 {
1481 char const* from; 1532 char const *from, *typewhat, *what, *gotchaA, *gotchaB;
1482 // try to discover the name of the function we want to send 1533 // try to discover the name of the function we want to send
1483 lua_pushcfunction( L, luaG_nameof); // ... f ...luaG_nameof 1534 lua_getglobal( L, "decoda_name"); // ... f ... decoda_name
1484 lua_pushvalue( L, i); // ... f ... luaG_nameof f
1485 lua_call( L, 1, 2); // ... f ... "type" "name"
1486 lua_getglobal( L, "decoda_name"); // ... f ... "type" "name" decoda_name
1487 from = lua_tostring( L, -1); 1535 from = lua_tostring( L, -1);
1488 (void) luaL_error( L, "%s '%s' not found in %s origin transfer database.", lua_tostring( L, -3), lua_tostring( L, -2), from ? from : "main"); 1536 lua_pushcfunction( L, luaG_nameof); // ... f ... decoda_name luaG_nameof
1537 lua_pushvalue( L, i); // ... f ... decoda_name luaG_nameof f
1538 lua_call( L, 1, 2); // ... f ... decoda_name "type" "name"|nil
1539 typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2);
1540 // second return value can be nil if the function was not found
1541 // probable reason: the function was removed from the source Lua state before Lanes was required.
1542 if( lua_isnil( L, -1))
1543 {
1544 gotchaA = " referenced by";
1545 gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)";
1546 what = upName_;
1547 }
1548 else
1549 {
1550 gotchaB = "";
1551 what = (lua_type( L, -1) == LUA_TSTRING) ? lua_tostring( L, -1) : luaL_typename( L, -1);
1552 }
1553 (void) luaL_error( L, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB);
1489 return; 1554 return;
1490 } 1555 }
1491 STACK_END( L, 0); 1556 STACK_END( L, 0);
@@ -1516,9 +1581,9 @@ static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i)
1516enum e_vt { 1581enum e_vt {
1517 VT_NORMAL, VT_KEY, VT_METATABLE 1582 VT_NORMAL, VT_KEY, VT_METATABLE
1518}; 1583};
1519static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i, enum e_vt value_type ); 1584static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt value_type, char const* upName_);
1520 1585
1521static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i) 1586static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, char const* upName_)
1522{ 1587{
1523 FuncSubType funcSubType; 1588 FuncSubType funcSubType;
1524 /*lua_CFunction cfunc =*/ luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions 1589 /*lua_CFunction cfunc =*/ luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions
@@ -1612,14 +1677,14 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1612 * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state! 1677 * instead, the function shall have LUA_RIDX_GLOBALS taken in the destination state!
1613 */ 1678 */
1614 { 1679 {
1615 DEBUGSPEW_CODE( char const* upname); 1680 char const* upname;
1616#if LUA_VERSION_NUM == 502 1681#if LUA_VERSION_NUM == 502
1617 // With Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default) 1682 // With Lua 5.2, each Lua function gets its environment as one of its upvalues (named LUA_ENV, aka "_ENV" by default)
1618 // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state... 1683 // Generally this is LUA_RIDX_GLOBALS, which we don't want to copy from the source to the destination state...
1619 // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table 1684 // -> if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table
1620 lua_pushglobaltable( L); // ... _G 1685 lua_pushglobaltable( L); // ... _G
1621#endif // LUA_VERSION_NUM 1686#endif // LUA_VERSION_NUM
1622 for( n = 0; (DEBUGSPEW_CODE( upname =) lua_getupvalue( L, i, 1 + n)) != NULL; ++ n) 1687 for( n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != NULL; ++ n)
1623 { // ... _G up[n] 1688 { // ... _G up[n]
1624 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "UPNAME[%d]: %s\n" INDENT_END, n, upname)); 1689 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "UPNAME[%d]: %s\n" INDENT_END, n, upname));
1625#if LUA_VERSION_NUM == 502 1690#if LUA_VERSION_NUM == 502
@@ -1630,8 +1695,10 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1630 else 1695 else
1631#endif // LUA_VERSION_NUM 1696#endif // LUA_VERSION_NUM
1632 { 1697 {
1633 if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop( L), VT_NORMAL)) // ... {cache} ... function <upvalues> 1698 if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop( L), VT_NORMAL, upname)) // ... {cache} ... function <upvalues>
1699 {
1634 luaL_error( L, "Cannot copy upvalue type '%s'", luaL_typename( L, -1)); 1700 luaL_error( L, "Cannot copy upvalue type '%s'", luaL_typename( L, -1));
1701 }
1635 } 1702 }
1636 lua_pop( L, 1); // ... _G 1703 lua_pop( L, 1); // ... _G
1637 } 1704 }
@@ -1664,7 +1731,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1664 { 1731 {
1665 lua_pop( L2, 1); // ... {cache} ... 1732 lua_pop( L2, 1); // ... {cache} ...
1666 // No need to transfer upvalues for C/JIT functions since they weren't actually copied, only looked up 1733 // No need to transfer upvalues for C/JIT functions since they weren't actually copied, only looked up
1667 lookup_native_func( L2, L, i); // ... {cache} ... function 1734 lookup_native_func( L2, L, i, upName_); // ... {cache} ... function
1668 } 1735 }
1669 STACK_END( L, 0); 1736 STACK_END( L, 0);
1670} 1737}
@@ -1679,7 +1746,7 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1679* 1746*
1680* Returns TRUE if value was pushed, FALSE if its type is non-supported. 1747* Returns TRUE if value was pushed, FALSE if its type is non-supported.
1681*/ 1748*/
1682static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt) 1749static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, char const* upName_)
1683{ 1750{
1684 bool_t ret = TRUE; 1751 bool_t ret = TRUE;
1685 1752
@@ -1762,25 +1829,9 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u
1762 break; 1829 break;
1763 } 1830 }
1764 { 1831 {
1765 /* 1832 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "FUNCTION\n" INDENT_END));
1766 * Passing C functions is risky; if they refer to LUA_ENVIRONINDEX
1767 * and/or LUA_REGISTRYINDEX they might work unintended (not work)
1768 * at the target.
1769 *
1770 * On the other hand, NOT copying them causes many self tests not
1771 * to work (timer, hangtest, ...)
1772 *
1773 * The trouble is, we cannot KNOW if the function at hand is safe
1774 * or not. We cannot study it's behaviour. We could trust the user,
1775 * but they might not even know they're sending lua_CFunction over
1776 * (as upvalues etc.).
1777 */
1778#if 0
1779 if( lua_iscfunction( L, i))
1780 luaL_error( L, "Copying lua_CFunction between Lua states is risky, and currently disabled." );
1781#endif
1782 STACK_CHECK( L2); 1833 STACK_CHECK( L2);
1783 push_cached_func( L2, L2_cache_i, L, i); 1834 push_cached_func( L2, L2_cache_i, L, i, upName_);
1784 STACK_END( L2, 1); 1835 STACK_END( L2, 1);
1785 } 1836 }
1786 break; 1837 break;
@@ -1822,13 +1873,28 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u
1822 1873
1823 /* Only basic key types are copied over; others ignored 1874 /* Only basic key types are copied over; others ignored
1824 */ 1875 */
1825 if( inter_copy_one_( L2, 0 /*key*/, L, key_i, VT_KEY)) 1876 if( inter_copy_one_( L2, 0 /*key*/, L, key_i, VT_KEY, upName_))
1826 { 1877 {
1878 char* valPath = (char*) upName_;
1879 if( GVerboseErrors)
1880 {
1881 // for debug purposes, let's try to build a useful name
1882 if( lua_type( L, key_i) == LUA_TSTRING)
1883 {
1884 valPath = (char*) alloca( strlen( upName_) + strlen( lua_tostring( L, key_i)) + 2);
1885 sprintf( valPath, "%s.%s", upName_, lua_tostring( L, key_i));
1886 }
1887 else if( lua_type( L, key_i) == LUA_TNUMBER)
1888 {
1889 valPath = (char*) alloca( strlen( upName_) + 32 + 3);
1890 sprintf( valPath, "%s[" LUA_NUMBER_FMT "]", upName_, lua_tonumber( L, key_i));
1891 }
1892 }
1827 /* 1893 /*
1828 * Contents of metatables are copied with cache checking; 1894 * Contents of metatables are copied with cache checking;
1829 * important to detect loops. 1895 * important to detect loops.
1830 */ 1896 */
1831 if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL)) 1897 if( inter_copy_one_( L2, L2_cache_i, L, val_i, VT_NORMAL, valPath))
1832 { 1898 {
1833 ASSERT_L( lua_istable(L2,-3)); 1899 ASSERT_L( lua_istable(L2,-3));
1834 lua_rawset( L2, -3); // add to table (pops key & val) 1900 lua_rawset( L2, -3); // add to table (pops key & val)
@@ -1870,7 +1936,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u
1870 lua_pop( L2, 1); 1936 lua_pop( L2, 1);
1871 STACK_MID( L2, 2); 1937 STACK_MID( L2, 2);
1872 ASSERT_L( lua_istable(L,-1)); 1938 ASSERT_L( lua_istable(L,-1));
1873 if( inter_copy_one_( L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE)) 1939 if( inter_copy_one_( L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE, upName_))
1874 { 1940 {
1875 // 1941 //
1876 // L2 ([-3]: copied table) 1942 // L2 ([-3]: copied table)
@@ -1942,7 +2008,9 @@ int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n)
1942{ 2008{
1943 uint_t top_L = lua_gettop( L); 2009 uint_t top_L = lua_gettop( L);
1944 uint_t top_L2 = lua_gettop( L2); 2010 uint_t top_L2 = lua_gettop( L2);
1945 uint_t i; 2011 uint_t i, j;
2012 char tmpBuf[16];
2013 char* pBuf = GVerboseErrors ? tmpBuf : "?";
1946 bool_t copyok = TRUE; 2014 bool_t copyok = TRUE;
1947 2015
1948 if( n > top_L) 2016 if( n > top_L)
@@ -1960,9 +2028,13 @@ int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n)
1960 */ 2028 */
1961 lua_newtable( L2); 2029 lua_newtable( L2);
1962 2030
1963 for( i = top_L - n + 1; i <= top_L; ++ i) 2031 for( i = top_L - n + 1, j = 1; i <= top_L; ++ i, ++ j)
1964 { 2032 {
1965 copyok = inter_copy_one_( L2, top_L2 + 1, L, i, VT_NORMAL); 2033 if( GVerboseErrors)
2034 {
2035 sprintf( tmpBuf, "arg_%d", j);
2036 }
2037 copyok = inter_copy_one_( L2, top_L2 + 1, L, i, VT_NORMAL, pBuf);
1966 if( !copyok) 2038 if( !copyok)
1967 { 2039 {
1968 break; 2040 break;
diff --git a/src/tools.h b/src/tools.h
index 2fe7259..93ed92c 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -107,5 +107,8 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* _name);
107void serialize_require( lua_State *L); 107void serialize_require( lua_State *L);
108extern MUTEX_T require_cs; 108extern MUTEX_T require_cs;
109 109
110// for verbose errors
111extern bool_t GVerboseErrors;
112
110#endif 113#endif
111 // TOOLS_H 114 // TOOLS_H
diff --git a/tests/fifo.lua b/tests/fifo.lua
index b68d8a4..47db4c9 100644
--- a/tests/fifo.lua
+++ b/tests/fifo.lua
@@ -4,10 +4,9 @@
4-- Sample program for Lua Lanes 4-- Sample program for Lua Lanes
5-- 5--
6 6
7local lanes = require "lanes" 7local lanes = require "lanes".configure{shutdown_timeout=3,with_timers=true}
8lanes.configure()
9 8
10local linda= lanes.linda() 9local linda= lanes.linda( "atom")
11local atomic_inc= lanes.genatomic( linda, "FIFO_n" ) 10local atomic_inc= lanes.genatomic( linda, "FIFO_n" )
12 11
13assert( atomic_inc()==1 ) 12assert( atomic_inc()==1 )
@@ -46,3 +45,5 @@ print( B:receive( 2.0 ) )
46-- Note: A and B can be passed between threads, or used as upvalues 45-- Note: A and B can be passed between threads, or used as upvalues
47-- by multiple threads (other parts will be copied but the 'linda' 46-- by multiple threads (other parts will be copied but the 'linda'
48-- handle is shared userdata and will thus point to the single place) 47-- handle is shared userdata and will thus point to the single place)
48lanes.timer_lane:cancel()
49lanes.timer_lane:join() \ No newline at end of file
diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua
index be582ce..ebe9eac 100644
--- a/tests/linda_perf.lua
+++ b/tests/linda_perf.lua
@@ -84,8 +84,10 @@ local tests =
84 { 4000000, 0, 21}, 84 { 4000000, 0, 21},
85 { 4000000, 0, 44},]] 85 { 4000000, 0, 44},]]
86} 86}
87print "tests #1"
87for k, v in pairs( tests) do 88for k, v in pairs( tests) do
88 local pre, loop, batch = v[1], v[2], v[3] 89 local pre, loop, batch = v[1], v[2], v[3]
90 print( "testing", pre, loop, batch)
89 print( pre, loop, batch, "duration = " .. ziva( pre, loop, batch)) 91 print( pre, loop, batch, "duration = " .. ziva( pre, loop, batch))
90end 92end
91 93
@@ -188,8 +190,11 @@ local tests2 =
188 { 4000000, 0, 21}, 190 { 4000000, 0, 21},
189 { 4000000, 0, 44}, 191 { 4000000, 0, 44},
190} 192}
193
194print "tests #2"
191for k, v in pairs( tests2) do 195for k, v in pairs( tests2) do
192 local pre, loop, batch = v[1], v[2], v[3] 196 local pre, loop, batch = v[1], v[2], v[3]
197 print( "testing", pre, loop, batch)
193 print( pre, loop, batch, "duration = " .. ziva2( pre, loop, batch)) 198 print( pre, loop, batch, "duration = " .. ziva2( pre, loop, batch))
194end 199end
195 200
diff --git a/tests/require.lua b/tests/require.lua
index 1d081b4..656a7dd 100644
--- a/tests/require.lua
+++ b/tests/require.lua
@@ -4,9 +4,10 @@
4-- Test that 'require' works from sublanes 4-- Test that 'require' works from sublanes
5-- 5--
6lanes = require "lanes" 6lanes = require "lanes"
7lanes.configure() 7lanes.configure{with_timers = false}
8 8
9local function a_lane() 9local function a_lane()
10 print "IN A LANE"
10 -- To require 'math' we still actually need to have it initialized for 11 -- To require 'math' we still actually need to have it initialized for
11 -- the lane. 12 -- the lane.
12 -- 13 --
@@ -15,7 +16,7 @@ local function a_lane()
15 assert( math.sqrt(4)==2 ) 16 assert( math.sqrt(4)==2 )
16 17
17 assert( lanes==nil ) 18 assert( lanes==nil )
18 local lanes = require "lanes".configure() 19 local lanes = require "lanes".configure{with_timers = false}
19 assert( lanes and lanes.gen ) 20 assert( lanes and lanes.gen )
20 21
21 local h= lanes.gen( function() return 42 end ) () 22 local h= lanes.gen( function() return 42 end ) ()
@@ -24,7 +25,7 @@ local function a_lane()
24 return v==42 25 return v==42
25end 26end
26 27
27local gen= lanes.gen( "math,package,string,table", a_lane ) 28local gen= lanes.gen( "math,package,string,table", {package={}},a_lane )
28 29
29local h= gen() 30local h= gen()
30local ret= h[1] 31local ret= h[1]