aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lanes.c65
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
1246struct s_lane* volatile selfdestruct_first = SELFDESTRUCT_END; 1246struct 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
1250int 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