aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c156
1 files changed, 96 insertions, 60 deletions
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 }