aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2012-12-14 15:35:26 +0100
committerBenoit Germain <bnt.germain@gmail.com>2012-12-14 15:35:26 +0100
commit11b19bf4d7dfc883e18ea579d978c620865d843f (patch)
tree602da3de630e4b247b4463c26a846683cad4d074 /src/lanes.c
parent5107a671f9b47f1576412f4898457edf98384acd (diff)
downloadlanes-11b19bf4d7dfc883e18ea579d978c620865d843f.tar.gz
lanes-11b19bf4d7dfc883e18ea579d978c620865d843f.tar.bz2
lanes-11b19bf4d7dfc883e18ea579d978c620865d843f.zip
lanes.threads(): core implementation
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c143
1 files changed, 112 insertions, 31 deletions
diff --git a/src/lanes.c b/src/lanes.c
index 6789e4e..161de59 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -103,6 +103,11 @@ THE SOFTWARE.
103# include <sys/types.h> 103# include <sys/types.h>
104#endif 104#endif
105 105
106/*
107 * Do we want to activate full lane tracking feature? (EXPERIMENTAL)
108 */
109#define HAVE_LANE_TRACKING 1
110
106/* Do you want full call stacks, or just the line where the error happened? 111/* Do you want full call stacks, or just the line where the error happened?
107* 112*
108* TBD: The full stack feature does not seem to work (try 'make error'). 113* TBD: The full stack feature does not seem to work (try 'make error').
@@ -118,7 +123,9 @@ struct s_lane {
118 // M: sub-thread OS thread 123 // M: sub-thread OS thread
119 // S: not used 124 // S: not used
120 125
121 lua_State *L; 126 char const* debug_name;
127
128 lua_State* L;
122 // 129 //
123 // M: prepares the state, and reads results 130 // M: prepares the state, and reads results
124 // S: while S is running, M must keep out of modifying the state 131 // S: while S is running, M must keep out of modifying the state
@@ -164,8 +171,8 @@ struct s_lane {
164 // S: cleans up after itself if non-NULL at lane exit 171 // S: cleans up after itself if non-NULL at lane exit
165}; 172};
166 173
167static bool_t cancel_test( lua_State *L ); 174static bool_t cancel_test( lua_State*L );
168static void cancel_error( lua_State *L ); 175static void cancel_error( lua_State*L );
169 176
170#define CANCEL_TEST_KEY ((void*)cancel_test) // used as registry key 177#define CANCEL_TEST_KEY ((void*)cancel_test) // used as registry key
171#define CANCEL_ERROR ((void*)cancel_error) // 'cancel_error' sentinel 178#define CANCEL_ERROR ((void*)cancel_error) // 'cancel_error' sentinel
@@ -204,7 +211,7 @@ struct s_Linda;
204* Returns: TRUE if a table was pushed 211* Returns: TRUE if a table was pushed
205* FALSE if no table found, not created, and nothing pushed 212* FALSE if no table found, not created, and nothing pushed
206*/ 213*/
207static bool_t push_registry_table( lua_State *L, void *key, bool_t create ) { 214static bool_t push_registry_table( lua_State*L, void *key, bool_t create ) {
208 215
209 STACK_GROW(L,3); 216 STACK_GROW(L,3);
210 217
@@ -247,7 +254,7 @@ static void linda_id( lua_State*, char const * const which);
247#define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, linda_id, n )) 254#define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, linda_id, n ))
248 255
249 256
250static void check_key_types( lua_State *L, int _start, int _end) 257static void check_key_types( lua_State*L, int _start, int _end)
251{ 258{
252 int i; 259 int i;
253 for( i = _start; i <= _end; ++ i) 260 for( i = _start; i <= _end; ++ i)
@@ -305,7 +312,7 @@ LUAG_FUNC( linda_send)
305 STACK_GROW(L, 1); 312 STACK_GROW(L, 1);
306 { 313 {
307 struct s_Keeper *K = keeper_acquire( linda); 314 struct s_Keeper *K = keeper_acquire( linda);
308 lua_State *KL = K->L; // need to do this for 'STACK_CHECK' 315 lua_State*KL = K->L; // need to do this for 'STACK_CHECK'
309 STACK_CHECK( KL) 316 STACK_CHECK( KL)
310 for( ;;) 317 for( ;;)
311 { 318 {
@@ -720,8 +727,6 @@ LUAG_FUNC( linda_deep ) {
720 727
721static int linda_tostring( lua_State* L, int _idx, bool_t _opt) 728static int linda_tostring( lua_State* L, int _idx, bool_t _opt)
722{ 729{
723 char text[32];
724 int len;
725 struct s_Linda* linda = lua_toLinda( L, _idx); 730 struct s_Linda* linda = lua_toLinda( L, _idx);
726 if( !_opt) 731 if( !_opt)
727 { 732 {
@@ -729,6 +734,8 @@ static int linda_tostring( lua_State* L, int _idx, bool_t _opt)
729 } 734 }
730 if( linda) 735 if( linda)
731 { 736 {
737 char text[32];
738 int len;
732 if( linda->name[0]) 739 if( linda->name[0])
733 len = sprintf( text, "Linda: %.*s", (int)sizeof(text) - 8, linda->name); 740 len = sprintf( text, "Linda: %.*s", (int)sizeof(text) - 8, linda->name);
734 else 741 else
@@ -808,7 +815,7 @@ LUAG_FUNC( linda_dump)
808* For any other strings, the ID function must not react at all. This allows 815* For any other strings, the ID function must not react at all. This allows
809* future extensions of the system. 816* future extensions of the system.
810*/ 817*/
811static void linda_id( lua_State *L, char const * const which) 818static void linda_id( lua_State*L, char const * const which)
812{ 819{
813 if (strcmp( which, "new" )==0) 820 if (strcmp( which, "new" )==0)
814 { 821 {
@@ -981,7 +988,7 @@ LUAG_FUNC( set_finalizer )
981// 988//
982// TBD: should we add stack trace on failing finalizer, wouldn't be hard.. 989// TBD: should we add stack trace on failing finalizer, wouldn't be hard..
983// 990//
984static int run_finalizers( lua_State *L, int lua_rc ) 991static int run_finalizers( lua_State*L, int lua_rc )
985{ 992{
986 unsigned error_index, tbl_index; 993 unsigned error_index, tbl_index;
987 unsigned n; 994 unsigned n;
@@ -1176,7 +1183,7 @@ volatile DEEP_PRELUDE *timer_deep; // = NULL
1176/* 1183/*
1177* Process end; cancel any still free-running threads 1184* Process end; cancel any still free-running threads
1178*/ 1185*/
1179static int selfdestruct_gc( lua_State *L) 1186static int selfdestruct_gc( lua_State*L)
1180{ 1187{
1181 (void)L; // unused 1188 (void)L; // unused
1182 if (selfdestruct_first == SELFDESTRUCT_END) return 0; // no free-running threads 1189 if (selfdestruct_first == SELFDESTRUCT_END) return 0; // no free-running threads
@@ -1341,7 +1348,7 @@ static int selfdestruct_gc( lua_State *L)
1341* Returns TRUE if any locks are to be exited, and 'cancel_error()' called, 1348* Returns TRUE if any locks are to be exited, and 'cancel_error()' called,
1342* to make execution of the lane end. 1349* to make execution of the lane end.
1343*/ 1350*/
1344static bool_t cancel_test( lua_State *L ) { 1351static bool_t cancel_test( lua_State*L ) {
1345 struct s_lane *s; 1352 struct s_lane *s;
1346 1353
1347 STACK_GROW(L,1); 1354 STACK_GROW(L,1);
@@ -1358,13 +1365,13 @@ static bool_t cancel_test( lua_State *L ) {
1358 return s && s->cancel_request; 1365 return s && s->cancel_request;
1359} 1366}
1360 1367
1361static void cancel_error( lua_State *L ) { 1368static void cancel_error( lua_State*L ) {
1362 STACK_GROW(L,1); 1369 STACK_GROW(L,1);
1363 lua_pushlightuserdata( L, CANCEL_ERROR ); // special error value 1370 lua_pushlightuserdata( L, CANCEL_ERROR ); // special error value
1364 lua_error(L); // no return 1371 lua_error(L); // no return
1365} 1372}
1366 1373
1367static void cancel_hook( lua_State *L, lua_Debug *ar ) { 1374static void cancel_hook( lua_State*L, lua_Debug *ar ) {
1368 (void)ar; 1375 (void)ar;
1369 if (cancel_test(L)) cancel_error(L); 1376 if (cancel_test(L)) cancel_error(L);
1370} 1377}
@@ -1546,19 +1553,39 @@ static int lane_error( lua_State* L)
1546 1553
1547LUAG_FUNC( set_debug_threadname) 1554LUAG_FUNC( set_debug_threadname)
1548{ 1555{
1549 luaL_checktype( L, -1, LUA_TSTRING); 1556 struct s_lane* s = lua_touserdata( L, lua_upvalueindex( 1));
1550 THREAD_SETNAME( lua_tostring( L, -1)); 1557 luaL_checktype( L, -1, LUA_TSTRING); // "name"
1558 // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global...
1559 lua_pushlightuserdata( L, LG_set_debug_threadname); // "name" lud
1560 lua_pushvalue( L, -2); // "name" lud "name"
1561 lua_rawset( L, LUA_REGISTRYINDEX); // "name"
1562 s->debug_name = lua_tostring( L, -1);
1563 // keep a direct pointer on the string
1564 THREAD_SETNAME( s->debug_name);
1551 // to see VM name in Decoda debugger Virtual Machine window 1565 // to see VM name in Decoda debugger Virtual Machine window
1552 lua_setglobal( L, "decoda_name"); 1566 lua_setglobal( L, "decoda_name"); //
1553 return 0; 1567 return 0;
1554} 1568}
1555 1569
1570#if HAVE_LANE_TRACKING
1571static bool_t GTrackLanes = FALSE;
1572#endif // HAVE_LANE_TRACKING
1573
1556//--- 1574//---
1557static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) 1575static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1558{ 1576{
1559 struct s_lane *s= (struct s_lane *)vs; 1577 struct s_lane *s= (struct s_lane *)vs;
1560 int rc, rc2; 1578 int rc, rc2;
1561 lua_State *L= s->L; 1579 lua_State*L= s->L;
1580
1581#if HAVE_LANE_TRACKING
1582 if( GTrackLanes)
1583 {
1584 // If we track lanes, we add them right now to the list so that its traversal hits all known lanes
1585 // (else we get only the still running lanes for which GC was called, IOW not accessible anymore from a script)
1586 selfdestruct_add( s);
1587 }
1588#endif // HAVE_LANE_TRACKING
1562 1589
1563 s->status= RUNNING; // PENDING -> RUNNING 1590 s->status= RUNNING; // PENDING -> RUNNING
1564 1591
@@ -1569,7 +1596,8 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1569 1596
1570 // Tie "set_debug_threadname()" to the state 1597 // Tie "set_debug_threadname()" to the state
1571 // 1598 //
1572 lua_pushcfunction( L, LG_set_debug_threadname); 1599 lua_pushlightuserdata( L, s);
1600 lua_pushcclosure( L, LG_set_debug_threadname, 1);
1573 lua_setglobal( L, "set_debug_threadname" ); 1601 lua_setglobal( L, "set_debug_threadname" );
1574 1602
1575 // Tie "cancel_test()" to the state 1603 // Tie "cancel_test()" to the state
@@ -1704,7 +1732,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1704 1732
1705// helper function to require a module in the keeper states and in the target state 1733// helper function to require a module in the keeper states and in the target state
1706// source state contains module name at the top of the stack 1734// source state contains module name at the top of the stack
1707static void require_one_module( lua_State *L, lua_State *L2, bool_t _fatal) 1735static void require_one_module( lua_State*L, lua_State*L2, bool_t _fatal)
1708{ 1736{
1709 size_t len; 1737 size_t len;
1710 char const *name = lua_tolstring( L, -1, &len); 1738 char const *name = lua_tolstring( L, -1, &len);
@@ -1728,7 +1756,7 @@ static void require_one_module( lua_State *L, lua_State *L2, bool_t _fatal)
1728 1756
1729LUAG_FUNC( thread_new ) 1757LUAG_FUNC( thread_new )
1730{ 1758{
1731 lua_State *L2; 1759 lua_State*L2;
1732 struct s_lane *s; 1760 struct s_lane *s;
1733 struct s_lane **ud; 1761 struct s_lane **ud;
1734 1762
@@ -1918,6 +1946,7 @@ LUAG_FUNC( thread_new )
1918 s->L= L2; 1946 s->L= L2;
1919 s->status= PENDING; 1947 s->status= PENDING;
1920 s->waiting_on = NULL; 1948 s->waiting_on = NULL;
1949 s->debug_name = NULL;
1921 s->cancel_request= FALSE; 1950 s->cancel_request= FALSE;
1922 1951
1923#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 1952#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
@@ -1995,9 +2024,14 @@ LUAG_FUNC( thread_gc)
1995 } 2024 }
1996 else if( s->status < DONE) 2025 else if( s->status < DONE)
1997 { 2026 {
1998 // still running: will have to be cleaned up later 2027#if HAVE_LANE_TRACKING
1999 selfdestruct_add( s); 2028 if( !GTrackLanes)
2000 assert( s->selfdestruct_next); 2029#endif // HAVE_LANE_TRACKING
2030 {
2031 // still running: will have to be cleaned up later
2032 selfdestruct_add( s);
2033 assert( s->selfdestruct_next);
2034 }
2001 return 0; 2035 return 0;
2002 2036
2003 } 2037 }
@@ -2008,6 +2042,14 @@ LUAG_FUNC( thread_gc)
2008 s->L = 0; 2042 s->L = 0;
2009 } 2043 }
2010 2044
2045#if HAVE_LANE_TRACKING
2046 if( GTrackLanes)
2047 {
2048 // Lane was cleaned up, no need to handle at process termination
2049 selfdestruct_remove( s);
2050 }
2051#endif // HAVE_LANE_TRACKING
2052
2011 // Clean up after a (finished) thread 2053 // Clean up after a (finished) thread
2012 // 2054 //
2013#if THREADWAIT_METHOD == THREADWAIT_CONDVAR 2055#if THREADWAIT_METHOD == THREADWAIT_CONDVAR
@@ -2091,7 +2133,7 @@ static char const * thread_status_string( struct s_lane *s)
2091 return str; 2133 return str;
2092} 2134}
2093 2135
2094static int push_thread_status( lua_State *L, struct s_lane *s) 2136static int push_thread_status( lua_State*L, struct s_lane *s)
2095{ 2137{
2096 char const * const str = thread_status_string( s); 2138 char const * const str = thread_status_string( s);
2097 ASSERT_L( str); 2139 ASSERT_L( str);
@@ -2113,7 +2155,7 @@ LUAG_FUNC( thread_join)
2113{ 2155{
2114 struct s_lane* const s = lua_toLane( L, 1); 2156 struct s_lane* const s = lua_toLane( L, 1);
2115 double wait_secs= luaL_optnumber(L,2,-1.0); 2157 double wait_secs= luaL_optnumber(L,2,-1.0);
2116 lua_State *L2= s->L; 2158 lua_State*L2= s->L;
2117 int ret; 2159 int ret;
2118 bool_t done; 2160 bool_t done;
2119 2161
@@ -2329,6 +2371,37 @@ LUAG_FUNC( thread_index)
2329 return 0; 2371 return 0;
2330} 2372}
2331 2373
2374#if HAVE_LANE_TRACKING
2375//---
2376// threads() -> {}|nil
2377//
2378// Return a list of all known lanes
2379LUAG_FUNC( threads)
2380{
2381 int const top = lua_gettop( L);
2382 // List _all_ still running threads
2383 //
2384 MUTEX_LOCK( &selfdestruct_cs);
2385 if( selfdestruct_first != SELFDESTRUCT_END)
2386 {
2387 struct s_lane* s = selfdestruct_first;
2388 lua_newtable( L); // {}
2389 while( s != SELFDESTRUCT_END)
2390 {
2391 if( s->debug_name)
2392 lua_pushstring( L, s->debug_name); // {} "name"
2393 else
2394 lua_pushfstring( L, "Lane %p", s); // {} "name"
2395 push_thread_status( L, s); // {} "name" "status"
2396 lua_rawset( L, -3); // {}
2397 s = s->selfdestruct_next;
2398 }
2399 }
2400 MUTEX_UNLOCK( &selfdestruct_cs);
2401 return lua_gettop( L) - top;
2402}
2403#endif // HAVE_LANE_TRACKING
2404
2332/* 2405/*
2333 * ############################################################################################### 2406 * ###############################################################################################
2334 * ######################################## Timer support ######################################## 2407 * ######################################## Timer support ########################################
@@ -2401,6 +2474,9 @@ LUAG_FUNC( wakeup_conv )
2401static const struct luaL_Reg lanes_functions [] = { 2474static const struct luaL_Reg lanes_functions [] = {
2402 {"linda", LG_linda}, 2475 {"linda", LG_linda},
2403 {"now_secs", LG_now_secs}, 2476 {"now_secs", LG_now_secs},
2477#if HAVE_LANE_TRACKING
2478 {"threads", LG_threads},
2479#endif // HAVE_LANE_TRACKING
2404 {"wakeup_conv", LG_wakeup_conv}, 2480 {"wakeup_conv", LG_wakeup_conv},
2405 {"nameof", luaG_nameof}, 2481 {"nameof", luaG_nameof},
2406 {"set_singlethreaded", LG_set_singlethreaded}, 2482 {"set_singlethreaded", LG_set_singlethreaded},
@@ -2410,7 +2486,7 @@ static const struct luaL_Reg lanes_functions [] = {
2410/* 2486/*
2411* One-time initializations 2487* One-time initializations
2412*/ 2488*/
2413static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_ref, int const nbKeepers, lua_CFunction _on_state_create, lua_Number _shutdown_timeout) 2489static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_ref, int const nbKeepers, lua_CFunction _on_state_create, lua_Number _shutdown_timeout, bool_t _track_lanes)
2414{ 2490{
2415 const char *err; 2491 const char *err;
2416 2492
@@ -2421,7 +2497,11 @@ static void init_once_LOCKED( lua_State* L, volatile DEEP_PRELUDE** timer_deep_r
2421#if (defined PLATFORM_OSX) && (defined _UTILBINDTHREADTOCPU) 2497#if (defined PLATFORM_OSX) && (defined _UTILBINDTHREADTOCPU)
2422 chudInitialize(); 2498 chudInitialize();
2423#endif 2499#endif
2424 2500
2501#if HAVE_LANE_TRACKING
2502 GTrackLanes = _track_lanes;
2503#endif // HAVE_LANE_TRACKING
2504
2425 // Locks for 'tools.c' inc/dec counters 2505 // Locks for 'tools.c' inc/dec counters
2426 // 2506 //
2427 MUTEX_INIT( &deep_lock ); 2507 MUTEX_INIT( &deep_lock );
@@ -2516,6 +2596,7 @@ LUAG_FUNC( configure )
2516 int const nbKeepers = (int)lua_tointeger( L, 1); 2596 int const nbKeepers = (int)lua_tointeger( L, 1);
2517 lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL; 2597 lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL;
2518 lua_Number shutdown_timeout = lua_tonumber( L, 3); 2598 lua_Number shutdown_timeout = lua_tonumber( L, 3);
2599 bool_t track_lanes = lua_toboolean( L, 4);
2519 /* 2600 /*
2520 * Making one-time initializations. 2601 * Making one-time initializations.
2521 * 2602 *
@@ -2528,7 +2609,7 @@ LUAG_FUNC( configure )
2528 static volatile int /*bool*/ go_ahead; // = 0 2609 static volatile int /*bool*/ go_ahead; // = 0
2529 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) 2610 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
2530 { 2611 {
2531 init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create, shutdown_timeout); 2612 init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create, shutdown_timeout, track_lanes);
2532 go_ahead= 1; // let others pass 2613 go_ahead= 1; // let others pass
2533 } 2614 }
2534 else 2615 else
@@ -2546,7 +2627,7 @@ LUAG_FUNC( configure )
2546 // 2627 //
2547 if( s_initCount == 0) 2628 if( s_initCount == 0)
2548 { 2629 {
2549 init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create, shutdown_timeout); 2630 init_once_LOCKED( L, &timer_deep, nbKeepers, on_state_create, shutdown_timeout, track_lanes);
2550 s_initCount = 1; 2631 s_initCount = 1;
2551 } 2632 }
2552 } 2633 }
@@ -2569,7 +2650,7 @@ LUAG_FUNC( configure )
2569 lua_newtable( L); 2650 lua_newtable( L);
2570 lua_pushcfunction( L, LG_thread_gc); 2651 lua_pushcfunction( L, LG_thread_gc);
2571 lua_setfield( L, -2, "__gc"); 2652 lua_setfield( L, -2, "__gc");
2572 lua_pushcfunction( L, LG_thread_index); 2653 lua_pushcfunction( L, LG_thread_index);
2573 lua_setfield( L, -2, "__index"); 2654 lua_setfield( L, -2, "__index");
2574 lua_getglobal( L, "error"); 2655 lua_getglobal( L, "error");
2575 ASSERT_L( lua_isfunction( L, -1)); 2656 ASSERT_L( lua_isfunction( L, -1));