diff options
-rw-r--r-- | src/lanes.c | 65 |
1 files changed, 45 insertions, 20 deletions
diff --git a/src/lanes.c b/src/lanes.c index 7d4f9e7..5ccc05a 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -326,7 +326,7 @@ static void lane_cleanup( struct s_lane* s) | |||
326 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR | 326 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR |
327 | 327 | ||
328 | #if HAVE_LANE_TRACKING | 328 | #if HAVE_LANE_TRACKING |
329 | if( tracking_first) | 329 | if( tracking_first != NULL) |
330 | { | 330 | { |
331 | // Lane was cleaned up, no need to handle at process termination | 331 | // Lane was cleaned up, no need to handle at process termination |
332 | tracking_remove( s); | 332 | tracking_remove( s); |
@@ -452,17 +452,17 @@ LUAG_FUNC( linda_send) | |||
452 | 452 | ||
453 | // change status of lane to "waiting" | 453 | // change status of lane to "waiting" |
454 | { | 454 | { |
455 | struct s_lane *s; | 455 | struct s_lane* s; |
456 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings | 456 | enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings |
457 | STACK_GROW(L, 1); | 457 | STACK_GROW( L, 1); |
458 | 458 | ||
459 | STACK_CHECK( L); | 459 | STACK_CHECK( L); |
460 | lua_pushlightuserdata( L, CANCEL_TEST_KEY); | 460 | lua_pushlightuserdata( L, CANCEL_TEST_KEY); |
461 | lua_rawget( L, LUA_REGISTRYINDEX); | 461 | lua_rawget( L, LUA_REGISTRYINDEX); |
462 | s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) or nil if in the main Lua state | 462 | s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) or nil if in the main Lua state |
463 | lua_pop(L, 1); | 463 | lua_pop( L, 1); |
464 | STACK_END( L, 0); | 464 | STACK_END( L, 0); |
465 | if( s) | 465 | if( s != NULL) |
466 | { | 466 | { |
467 | prev_status = s->status; // RUNNING, most likely | 467 | prev_status = s->status; // RUNNING, most likely |
468 | ASSERT_L( prev_status == RUNNING); // but check, just in case | 468 | ASSERT_L( prev_status == RUNNING); // but check, just in case |
@@ -473,14 +473,14 @@ LUAG_FUNC( linda_send) | |||
473 | // could not send because no room: wait until some data was read before trying again, or until timeout is reached | 473 | // could not send because no room: wait until some data was read before trying again, or until timeout is reached |
474 | if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout)) | 474 | if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout)) |
475 | { | 475 | { |
476 | if( s) | 476 | if( s != NULL) |
477 | { | 477 | { |
478 | s->waiting_on = NULL; | 478 | s->waiting_on = NULL; |
479 | s->status = prev_status; | 479 | s->status = prev_status; |
480 | } | 480 | } |
481 | break; | 481 | break; |
482 | } | 482 | } |
483 | if( s) | 483 | if( s != NULL) |
484 | { | 484 | { |
485 | s->waiting_on = NULL; | 485 | s->waiting_on = NULL; |
486 | s->status = prev_status; | 486 | s->status = prev_status; |
@@ -621,7 +621,7 @@ LUAG_FUNC( linda_receive) | |||
621 | s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) or nil if in the main Lua state | 621 | s = lua_touserdata( L, -1); // lightuserdata (true 's_lane' pointer) or nil if in the main Lua state |
622 | lua_pop( L, 1); | 622 | lua_pop( L, 1); |
623 | STACK_END( L, 0); | 623 | STACK_END( L, 0); |
624 | if( s) | 624 | if( s != NULL) |
625 | { | 625 | { |
626 | prev_status = s->status; // RUNNING, most likely | 626 | prev_status = s->status; // RUNNING, most likely |
627 | ASSERT_L( prev_status == RUNNING); // but check, just in case | 627 | ASSERT_L( prev_status == RUNNING); // but check, just in case |
@@ -632,14 +632,14 @@ LUAG_FUNC( linda_receive) | |||
632 | // not enough data to read: wakeup when data was sent, or when timeout is reached | 632 | // not enough data to read: wakeup when data was sent, or when timeout is reached |
633 | if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout)) | 633 | if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout)) |
634 | { | 634 | { |
635 | if( s) | 635 | if( s != NULL) |
636 | { | 636 | { |
637 | s->waiting_on = NULL; | 637 | s->waiting_on = NULL; |
638 | s->status = prev_status; | 638 | s->status = prev_status; |
639 | } | 639 | } |
640 | break; | 640 | break; |
641 | } | 641 | } |
642 | if( s) | 642 | if( s != NULL) |
643 | { | 643 | { |
644 | s->waiting_on = NULL; | 644 | s->waiting_on = NULL; |
645 | s->status = prev_status; | 645 | s->status = prev_status; |
@@ -837,7 +837,7 @@ static int linda_tostring( lua_State* L, int _idx, bool_t _opt) | |||
837 | { | 837 | { |
838 | luaL_argcheck( L, linda, _idx, "expected a linda object!"); | 838 | luaL_argcheck( L, linda, _idx, "expected a linda object!"); |
839 | } | 839 | } |
840 | if( linda) | 840 | if( linda != NULL) |
841 | { | 841 | { |
842 | char text[32]; | 842 | char text[32]; |
843 | int len; | 843 | int len; |
@@ -1245,6 +1245,10 @@ static MUTEX_T selfdestruct_cs; | |||
1245 | 1245 | ||
1246 | struct s_lane* volatile selfdestruct_first = SELFDESTRUCT_END; | 1246 | struct s_lane* volatile selfdestruct_first = SELFDESTRUCT_END; |
1247 | 1247 | ||
1248 | // After a lane has removed itself from the chain, it still performs some processing. | ||
1249 | // The terminal desinit sequence should wait for all such processing to terminate before force-killing threads | ||
1250 | int volatile selfdestructing_count = 0; | ||
1251 | |||
1248 | /* | 1252 | /* |
1249 | * Add the lane to selfdestruct chain; the ones still running at the end of the | 1253 | * Add the lane to selfdestruct chain; the ones still running at the end of the |
1250 | * whole process will be cancelled. | 1254 | * whole process will be cancelled. |
@@ -1280,6 +1284,8 @@ static bool_t selfdestruct_remove( struct s_lane *s ) | |||
1280 | if (*ref == s) { | 1284 | if (*ref == s) { |
1281 | *ref= s->selfdestruct_next; | 1285 | *ref= s->selfdestruct_next; |
1282 | s->selfdestruct_next= NULL; | 1286 | s->selfdestruct_next= NULL; |
1287 | // the terminal shutdown should wait until the lane is done with its lua_close() | ||
1288 | ++ selfdestructing_count; | ||
1283 | found= TRUE; | 1289 | found= TRUE; |
1284 | break; | 1290 | break; |
1285 | } | 1291 | } |
@@ -1325,10 +1331,10 @@ static int selfdestruct_gc( lua_State* L) | |||
1325 | { | 1331 | { |
1326 | // Signal _all_ still running threads to exit (including the timer thread) | 1332 | // Signal _all_ still running threads to exit (including the timer thread) |
1327 | // | 1333 | // |
1328 | MUTEX_LOCK( &selfdestruct_cs ); | 1334 | MUTEX_LOCK( &selfdestruct_cs); |
1329 | { | 1335 | { |
1330 | struct s_lane* s = selfdestruct_first; | 1336 | struct s_lane* s = selfdestruct_first; |
1331 | while( s != SELFDESTRUCT_END ) | 1337 | while( s != SELFDESTRUCT_END) |
1332 | { | 1338 | { |
1333 | // attempt a regular unforced hard cancel with a small timeout | 1339 | // attempt a regular unforced hard cancel with a small timeout |
1334 | bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( s, 0.0001, FALSE); | 1340 | bool_t cancelled = THREAD_ISNULL( s->thread) || thread_cancel( s, 0.0001, FALSE); |
@@ -1344,7 +1350,7 @@ static int selfdestruct_gc( lua_State* L) | |||
1344 | s = s->selfdestruct_next; | 1350 | s = s->selfdestruct_next; |
1345 | } | 1351 | } |
1346 | } | 1352 | } |
1347 | MUTEX_UNLOCK( &selfdestruct_cs ); | 1353 | MUTEX_UNLOCK( &selfdestruct_cs); |
1348 | 1354 | ||
1349 | // When noticing their cancel, the lanes will remove themselves from | 1355 | // When noticing their cancel, the lanes will remove themselves from |
1350 | // the selfdestruct chain. | 1356 | // the selfdestruct chain. |
@@ -1384,7 +1390,7 @@ static int selfdestruct_gc( lua_State* L) | |||
1384 | MUTEX_UNLOCK( &selfdestruct_cs); | 1390 | MUTEX_UNLOCK( &selfdestruct_cs); |
1385 | // if timeout elapsed, or we know all threads have acted, stop waiting | 1391 | // if timeout elapsed, or we know all threads have acted, stop waiting |
1386 | t_now = now_secs(); | 1392 | t_now = now_secs(); |
1387 | if( n == 0 || ( t_now >= t_until)) | 1393 | if( n == 0 || (t_now >= t_until)) |
1388 | { | 1394 | { |
1389 | DEBUGSPEW_CODE( fprintf( stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, shutdown_timeout - (t_until - t_now))); | 1395 | DEBUGSPEW_CODE( fprintf( stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, shutdown_timeout - (t_until - t_now))); |
1390 | break; | 1396 | break; |
@@ -1393,6 +1399,19 @@ static int selfdestruct_gc( lua_State* L) | |||
1393 | } | 1399 | } |
1394 | } | 1400 | } |
1395 | 1401 | ||
1402 | // If some lanes are currently cleaning after themselves, wait until they are done. | ||
1403 | // They are no longer listed in the selfdestruct chain, but they still have to lua_close(). | ||
1404 | { | ||
1405 | bool_t again = TRUE; | ||
1406 | do | ||
1407 | { | ||
1408 | MUTEX_LOCK( &selfdestruct_cs); | ||
1409 | again = (selfdestructing_count > 0) ? TRUE : FALSE; | ||
1410 | MUTEX_UNLOCK( &selfdestruct_cs); | ||
1411 | YIELD(); | ||
1412 | } while( again); | ||
1413 | } | ||
1414 | |||
1396 | //--- | 1415 | //--- |
1397 | // Kill the still free running threads | 1416 | // Kill the still free running threads |
1398 | // | 1417 | // |
@@ -1404,7 +1423,7 @@ static int selfdestruct_gc( lua_State* L) | |||
1404 | // these are not running, and the state can be closed | 1423 | // these are not running, and the state can be closed |
1405 | MUTEX_LOCK( &selfdestruct_cs); | 1424 | MUTEX_LOCK( &selfdestruct_cs); |
1406 | { | 1425 | { |
1407 | struct s_lane* s= selfdestruct_first; | 1426 | struct s_lane* s = selfdestruct_first; |
1408 | while( s != SELFDESTRUCT_END) | 1427 | while( s != SELFDESTRUCT_END) |
1409 | { | 1428 | { |
1410 | struct s_lane* next_s = s->selfdestruct_next; | 1429 | struct s_lane* next_s = s->selfdestruct_next; |
@@ -1830,10 +1849,14 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1830 | { | 1849 | { |
1831 | // We're a free-running thread and no-one's there to clean us up. | 1850 | // We're a free-running thread and no-one's there to clean us up. |
1832 | // | 1851 | // |
1833 | lua_close( s->L ); | 1852 | lua_close( s->L); |
1834 | s->L = L = 0; | 1853 | s->L = L = 0; |
1835 | 1854 | ||
1836 | lane_cleanup( s); | 1855 | lane_cleanup( s); |
1856 | MUTEX_LOCK( &selfdestruct_cs); | ||
1857 | // done with lua_close(), terminal shutdown sequence may proceed | ||
1858 | -- selfdestructing_count; | ||
1859 | MUTEX_UNLOCK( &selfdestruct_cs); | ||
1837 | } | 1860 | } |
1838 | else | 1861 | else |
1839 | { | 1862 | { |
@@ -1920,7 +1943,7 @@ LUAG_FUNC( thread_new) | |||
1920 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: setup\n" INDENT_END)); | 1943 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: setup\n" INDENT_END)); |
1921 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 1944 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
1922 | 1945 | ||
1923 | // populate with selected libraries at the same time | 1946 | // populate with selected libraries at the same time |
1924 | // | 1947 | // |
1925 | L2 = luaG_newstate( L, on_state_create, libs); | 1948 | L2 = luaG_newstate( L, on_state_create, libs); |
1926 | 1949 | ||
@@ -1935,7 +1958,7 @@ LUAG_FUNC( thread_new) | |||
1935 | 1958 | ||
1936 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: update 'package'\n" INDENT_END)); | 1959 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: update 'package'\n" INDENT_END)); |
1937 | // package | 1960 | // package |
1938 | if( package) | 1961 | if( package != 0) |
1939 | { | 1962 | { |
1940 | luaG_inter_copy_package( L, L2, package, eLM_LaneBody); | 1963 | luaG_inter_copy_package( L, L2, package, eLM_LaneBody); |
1941 | } | 1964 | } |
@@ -1944,7 +1967,7 @@ LUAG_FUNC( thread_new) | |||
1944 | 1967 | ||
1945 | STACK_CHECK( L); | 1968 | STACK_CHECK( L); |
1946 | STACK_CHECK( L2); | 1969 | STACK_CHECK( L2); |
1947 | if( required) | 1970 | if( required != 0) |
1948 | { | 1971 | { |
1949 | int nbRequired = 1; | 1972 | int nbRequired = 1; |
1950 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: require 'required' list\n" INDENT_END)); | 1973 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: require 'required' list\n" INDENT_END)); |
@@ -2068,7 +2091,9 @@ LUAG_FUNC( thread_new) | |||
2068 | res = luaG_inter_copy( L, L2, args, eLM_LaneBody); // L->L2 | 2091 | res = luaG_inter_copy( L, L2, args, eLM_LaneBody); // L->L2 |
2069 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 2092 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
2070 | if( res != 0) | 2093 | if( res != 0) |
2094 | { | ||
2071 | return luaL_error( L, "tried to copy unsupported types"); | 2095 | return luaL_error( L, "tried to copy unsupported types"); |
2096 | } | ||
2072 | } | 2097 | } |
2073 | STACK_MID( L, 0); | 2098 | STACK_MID( L, 0); |
2074 | 2099 | ||