aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c547
1 files changed, 260 insertions, 287 deletions
diff --git a/src/lanes.c b/src/lanes.c
index 9f90ff7..fdd2ab9 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.9.1"; 55char const* VERSION = "3.9.2";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -104,11 +104,6 @@ THE SOFTWARE.
104# include <sys/types.h> 104# include <sys/types.h>
105#endif 105#endif
106 106
107/*
108 * Do we want to activate full lane tracking feature? (EXPERIMENTAL)
109 */
110#define HAVE_LANE_TRACKING 1
111
112/* Do you want full call stacks, or just the line where the error happened? 107/* Do you want full call stacks, or just the line where the error happened?
113* 108*
114* TBD: The full stack feature does not seem to work (try 'make error'). 109* TBD: The full stack feature does not seem to work (try 'make error').
@@ -138,6 +133,7 @@ struct s_lane
138 char const* debug_name; 133 char const* debug_name;
139 134
140 lua_State* L; 135 lua_State* L;
136 struct s_Universe* U;
141 // 137 //
142 // M: prepares the state, and reads results 138 // M: prepares the state, and reads results
143 // S: while S is running, M must keep out of modifying the state 139 // S: while S is running, M must keep out of modifying the state
@@ -321,9 +317,6 @@ static bool_t push_registry_table( lua_State*L, void *key, bool_t create ) {
321 317
322#if HAVE_LANE_TRACKING 318#if HAVE_LANE_TRACKING
323 319
324static MUTEX_T tracking_cs;
325struct s_lane* volatile tracking_first = NULL; // will change to TRACKING_END if we want to activate tracking
326
327// The chain is ended by '(struct s_lane*)(-1)', not NULL: 320// The chain is ended by '(struct s_lane*)(-1)', not NULL:
328// 'tracking_first -> ... -> ... -> (-1)' 321// 'tracking_first -> ... -> ... -> (-1)'
329#define TRACKING_END ((struct s_lane *)(-1)) 322#define TRACKING_END ((struct s_lane *)(-1))
@@ -335,14 +328,14 @@ struct s_lane* volatile tracking_first = NULL; // will change to TRACKING_END if
335static void tracking_add( struct s_lane* s) 328static void tracking_add( struct s_lane* s)
336{ 329{
337 330
338 MUTEX_LOCK( &tracking_cs); 331 MUTEX_LOCK( &s->U->tracking_cs);
339 { 332 {
340 assert( s->tracking_next == NULL); 333 assert( s->tracking_next == NULL);
341 334
342 s->tracking_next = tracking_first; 335 s->tracking_next = s->U->tracking_first;
343 tracking_first = s; 336 s->U->tracking_first = s;
344 } 337 }
345 MUTEX_UNLOCK( &tracking_cs); 338 MUTEX_UNLOCK( &s->U->tracking_cs);
346} 339}
347 340
348/* 341/*
@@ -351,7 +344,7 @@ static void tracking_add( struct s_lane* s)
351static bool_t tracking_remove( struct s_lane* s) 344static bool_t tracking_remove( struct s_lane* s)
352{ 345{
353 bool_t found = FALSE; 346 bool_t found = FALSE;
354 MUTEX_LOCK( &tracking_cs); 347 MUTEX_LOCK( &s->U->tracking_cs);
355 { 348 {
356 // Make sure (within the MUTEX) that we actually are in the chain 349 // Make sure (within the MUTEX) that we actually are in the chain
357 // still (at process exit they will remove us from chain and then 350 // still (at process exit they will remove us from chain and then
@@ -359,7 +352,7 @@ static bool_t tracking_remove( struct s_lane* s)
359 // 352 //
360 if (s->tracking_next != NULL) 353 if (s->tracking_next != NULL)
361 { 354 {
362 struct s_lane** ref= (struct s_lane**) &tracking_first; 355 struct s_lane** ref = (struct s_lane**) &s->U->tracking_first;
363 356
364 while( *ref != TRACKING_END) 357 while( *ref != TRACKING_END)
365 { 358 {
@@ -375,7 +368,7 @@ static bool_t tracking_remove( struct s_lane* s)
375 assert( found); 368 assert( found);
376 } 369 }
377 } 370 }
378 MUTEX_UNLOCK( &tracking_cs); 371 MUTEX_UNLOCK( &s->U->tracking_cs);
379 return found; 372 return found;
380} 373}
381 374
@@ -394,7 +387,7 @@ static void lane_cleanup( struct s_lane* s)
394#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 387#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
395 388
396#if HAVE_LANE_TRACKING 389#if HAVE_LANE_TRACKING
397 if( tracking_first != NULL) 390 if( s->U->tracking_first != NULL)
398 { 391 {
399 // Lane was cleaned up, no need to handle at process termination 392 // Lane was cleaned up, no need to handle at process termination
400 tracking_remove( s); 393 tracking_remove( s);
@@ -418,8 +411,9 @@ struct s_Linda
418{ 411{
419 SIGNAL_T read_happened; 412 SIGNAL_T read_happened;
420 SIGNAL_T write_happened; 413 SIGNAL_T write_happened;
414 struct s_Universe* U; // the universe this linda belongs to
421 enum e_cancel_request simulate_cancel; 415 enum e_cancel_request simulate_cancel;
422 unsigned long group; 416 unsigned long group; // a group to control keeper allocation between lindas
423 char name[1]; 417 char name[1];
424}; 418};
425#define LINDA_KEEPER_HASHSEED( linda) (linda->group ? linda->group : (unsigned long)linda) 419#define LINDA_KEEPER_HASHSEED( linda) (linda->group ? linda->group : (unsigned long)linda)
@@ -491,7 +485,7 @@ LUAG_FUNC( linda_send)
491 { 485 {
492 bool_t try_again = TRUE; 486 bool_t try_again = TRUE;
493 struct s_lane* const s = get_lane_from_registry( L); 487 struct s_lane* const s = get_lane_from_registry( L);
494 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda)); 488 struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
495 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' 489 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK'
496 if( KL == NULL) return 0; 490 if( KL == NULL) return 0;
497 STACK_CHECK( KL); 491 STACK_CHECK( KL);
@@ -510,7 +504,7 @@ LUAG_FUNC( linda_send)
510 } 504 }
511 505
512 STACK_MID( KL, 0); 506 STACK_MID( KL, 0);
513 pushed = keeper_call( KL, KEEPER_API( send), L, linda, key_i); 507 pushed = keeper_call( linda->U, KL, KEEPER_API( send), L, linda, key_i);
514 if( pushed < 0) 508 if( pushed < 0)
515 { 509 {
516 ret = FALSE; 510 ret = FALSE;
@@ -547,7 +541,7 @@ LUAG_FUNC( linda_send)
547 s->waiting_on = &linda->read_happened; 541 s->waiting_on = &linda->read_happened;
548 } 542 }
549 // could not send because no room: wait until some data was read before trying again, or until timeout is reached 543 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
550 try_again = SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout); 544 try_again = SIGNAL_WAIT( &linda->read_happened, &K->keeper_cs, timeout);
551 if( s != NULL) 545 if( s != NULL)
552 { 546 {
553 s->waiting_on = NULL; 547 s->waiting_on = NULL;
@@ -654,7 +648,7 @@ LUAG_FUNC( linda_receive)
654 { 648 {
655 bool_t try_again = TRUE; 649 bool_t try_again = TRUE;
656 struct s_lane* const s = get_lane_from_registry( L); 650 struct s_lane* const s = get_lane_from_registry( L);
657 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda)); 651 struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
658 if( K == NULL) return 0; 652 if( K == NULL) return 0;
659 for( ;;) 653 for( ;;)
660 { 654 {
@@ -671,7 +665,7 @@ LUAG_FUNC( linda_receive)
671 } 665 }
672 666
673 // all arguments of receive() but the first are passed to the keeper's receive function 667 // all arguments of receive() but the first are passed to the keeper's receive function
674 pushed = keeper_call( K->L, keeper_receive, L, linda, key_i); 668 pushed = keeper_call( linda->U, K->L, keeper_receive, L, linda, key_i);
675 if( pushed < 0) 669 if( pushed < 0)
676 { 670 {
677 break; 671 break;
@@ -705,7 +699,7 @@ LUAG_FUNC( linda_receive)
705 s->waiting_on = &linda->write_happened; 699 s->waiting_on = &linda->write_happened;
706 } 700 }
707 // not enough data to read: wakeup when data was sent, or when timeout is reached 701 // not enough data to read: wakeup when data was sent, or when timeout is reached
708 try_again = SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout); 702 try_again = SIGNAL_WAIT( &linda->write_happened, &K->keeper_cs, timeout);
709 if( s != NULL) 703 if( s != NULL)
710 { 704 {
711 s->waiting_on = NULL; 705 s->waiting_on = NULL;
@@ -757,7 +751,7 @@ LUAG_FUNC( linda_set)
757 check_key_types( L, 2, 2); 751 check_key_types( L, 2, 2);
758 752
759 { 753 {
760 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda)); 754 struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
761 if( K == NULL) return 0; 755 if( K == NULL) return 0;
762 756
763 if( linda->simulate_cancel == CANCEL_NONE) 757 if( linda->simulate_cancel == CANCEL_NONE)
@@ -767,7 +761,7 @@ LUAG_FUNC( linda_set)
767 // convert nils to some special non-nil sentinel in sent values 761 // convert nils to some special non-nil sentinel in sent values
768 keeper_toggle_nil_sentinels( L, 3, eLM_ToKeeper); 762 keeper_toggle_nil_sentinels( L, 3, eLM_ToKeeper);
769 } 763 }
770 pushed = keeper_call( K->L, KEEPER_API( set), L, linda, 2); 764 pushed = keeper_call( linda->U, K->L, KEEPER_API( set), L, linda, 2);
771 if( pushed >= 0) // no error? 765 if( pushed >= 0) // no error?
772 { 766 {
773 ASSERT_L( pushed == 0 || pushed == 1); 767 ASSERT_L( pushed == 0 || pushed == 1);
@@ -813,9 +807,9 @@ LUAG_FUNC( linda_count)
813 check_key_types( L, 2, lua_gettop( L)); 807 check_key_types( L, 2, lua_gettop( L));
814 808
815 { 809 {
816 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda)); 810 struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
817 if( K == NULL) return 0; 811 if( K == NULL) return 0;
818 pushed = keeper_call( K->L, KEEPER_API( count), L, linda, 2); 812 pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2);
819 keeper_release( K); 813 keeper_release( K);
820 if( pushed < 0) 814 if( pushed < 0)
821 { 815 {
@@ -842,12 +836,12 @@ LUAG_FUNC( linda_get)
842 // make sure the key is of a valid type (throws an error if not the case) 836 // make sure the key is of a valid type (throws an error if not the case)
843 check_key_types( L, 2, 2); 837 check_key_types( L, 2, 2);
844 { 838 {
845 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda)); 839 struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
846 if( K == NULL) return 0; 840 if( K == NULL) return 0;
847 841
848 if( linda->simulate_cancel == CANCEL_NONE) 842 if( linda->simulate_cancel == CANCEL_NONE)
849 { 843 {
850 pushed = keeper_call( K->L, KEEPER_API( get), L, linda, 2); 844 pushed = keeper_call( linda->U, K->L, KEEPER_API( get), L, linda, 2);
851 if( pushed > 0) 845 if( pushed > 0)
852 { 846 {
853 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper); 847 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, eLM_FromKeeper);
@@ -892,12 +886,12 @@ LUAG_FUNC( linda_limit)
892 check_key_types( L, 2, 2); 886 check_key_types( L, 2, 2);
893 887
894 { 888 {
895 struct s_Keeper* K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda)); 889 struct s_Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
896 if( K == NULL) return 0; 890 if( K == NULL) return 0;
897 891
898 if( linda->simulate_cancel == CANCEL_NONE) 892 if( linda->simulate_cancel == CANCEL_NONE)
899 { 893 {
900 pushed = keeper_call( K->L, KEEPER_API( limit), L, linda, 2); 894 pushed = keeper_call( linda->U, K->L, KEEPER_API( limit), L, linda, 2);
901 ASSERT_L( pushed == 0 || pushed == 1); // no error, optional boolean value saying if we should wake blocked writer threads 895 ASSERT_L( pushed == 0 || pushed == 1); // no error, optional boolean value saying if we should wake blocked writer threads
902 if( pushed == 1) 896 if( pushed == 1)
903 { 897 {
@@ -933,7 +927,7 @@ LUAG_FUNC( linda_cancel)
933 luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments"); 927 luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments");
934 928
935 // signalling must be done from inside the K locking area 929 // signalling must be done from inside the K locking area
936 K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda)); 930 K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
937 if( K == NULL) return 0; 931 if( K == NULL) return 0;
938 932
939 linda->simulate_cancel = CANCEL_SOFT; 933 linda->simulate_cancel = CANCEL_SOFT;
@@ -1059,7 +1053,8 @@ LUAG_FUNC( linda_concat)
1059LUAG_FUNC( linda_dump) 1053LUAG_FUNC( linda_dump)
1060{ 1054{
1061 struct s_Linda* linda = lua_toLinda( L, 1); 1055 struct s_Linda* linda = lua_toLinda( L, 1);
1062 return keeper_push_linda_storage( L, linda, LINDA_KEEPER_HASHSEED( linda)); 1056 ASSERT_L( linda->U == get_universe( L));
1057 return keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda));
1063} 1058}
1064 1059
1065/* 1060/*
@@ -1129,6 +1124,7 @@ static void* linda_id( lua_State* L, enum eDeepOp op_)
1129 { 1124 {
1130 SIGNAL_INIT( &s->read_happened); 1125 SIGNAL_INIT( &s->read_happened);
1131 SIGNAL_INIT( &s->write_happened); 1126 SIGNAL_INIT( &s->write_happened);
1127 s->U = get_universe( L);
1132 s->simulate_cancel = CANCEL_NONE; 1128 s->simulate_cancel = CANCEL_NONE;
1133 s->group = linda_group << KEEPER_MAGIC_SHIFT; 1129 s->group = linda_group << KEEPER_MAGIC_SHIFT;
1134 s->name[0] = 0; 1130 s->name[0] = 0;
@@ -1145,10 +1141,10 @@ static void* linda_id( lua_State* L, enum eDeepOp op_)
1145 1141
1146 /* Clean associated structures in the keeper state. 1142 /* Clean associated structures in the keeper state.
1147 */ 1143 */
1148 K = keeper_acquire( LINDA_KEEPER_HASHSEED( linda)); 1144 K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
1149 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) 1145 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
1150 { 1146 {
1151 keeper_call( K->L, KEEPER_API( clear), L, linda, 0); 1147 keeper_call( linda->U, K->L, KEEPER_API( clear), L, linda, 0);
1152 } 1148 }
1153 keeper_release( K); 1149 keeper_release( K);
1154 1150
@@ -1467,7 +1463,6 @@ static cancel_result thread_cancel( lua_State* L, struct s_lane* s, double secs,
1467 return result; 1463 return result;
1468} 1464}
1469 1465
1470static MUTEX_T selfdestruct_cs;
1471 // 1466 //
1472 // Protects modifying the selfdestruct chain 1467 // Protects modifying the selfdestruct chain
1473 1468
@@ -1476,26 +1471,18 @@ static MUTEX_T selfdestruct_cs;
1476 // The chain is ended by '(struct s_lane*)(-1)', not NULL: 1471 // The chain is ended by '(struct s_lane*)(-1)', not NULL:
1477 // 'selfdestruct_first -> ... -> ... -> (-1)' 1472 // 'selfdestruct_first -> ... -> ... -> (-1)'
1478 1473
1479struct s_lane* volatile selfdestruct_first = SELFDESTRUCT_END;
1480
1481// After a lane has removed itself from the chain, it still performs some processing.
1482// The terminal desinit sequence should wait for all such processing to terminate before force-killing threads
1483int volatile selfdestructing_count = 0;
1484
1485/* 1474/*
1486 * Add the lane to selfdestruct chain; the ones still running at the end of the 1475 * Add the lane to selfdestruct chain; the ones still running at the end of the
1487 * whole process will be cancelled. 1476 * whole process will be cancelled.
1488 */ 1477 */
1489static void selfdestruct_add( struct s_lane* s) 1478static void selfdestruct_add( struct s_lane* s)
1490{ 1479{
1491 MUTEX_LOCK( &selfdestruct_cs ); 1480 MUTEX_LOCK( &s->U->selfdestruct_cs);
1492 { 1481 assert( s->selfdestruct_next == NULL);
1493 assert( s->selfdestruct_next == NULL );
1494 1482
1495 s->selfdestruct_next= selfdestruct_first; 1483 s->selfdestruct_next = s->U->selfdestruct_first;
1496 selfdestruct_first= s; 1484 s->U->selfdestruct_first= s;
1497 } 1485 MUTEX_UNLOCK( &s->U->selfdestruct_cs);
1498 MUTEX_UNLOCK( &selfdestruct_cs );
1499} 1486}
1500 1487
1501/* 1488/*
@@ -1503,38 +1490,36 @@ static void selfdestruct_add( struct s_lane* s)
1503 */ 1490 */
1504static bool_t selfdestruct_remove( struct s_lane* s) 1491static bool_t selfdestruct_remove( struct s_lane* s)
1505{ 1492{
1506 bool_t found = FALSE; 1493 bool_t found = FALSE;
1507 MUTEX_LOCK( &selfdestruct_cs ); 1494 MUTEX_LOCK( &s->U->selfdestruct_cs);
1508 { 1495 {
1509 // Make sure (within the MUTEX) that we actually are in the chain 1496 // Make sure (within the MUTEX) that we actually are in the chain
1510 // still (at process exit they will remove us from chain and then 1497 // still (at process exit they will remove us from chain and then
1511 // cancel/kill). 1498 // cancel/kill).
1512 // 1499 //
1513 if (s->selfdestruct_next != NULL) { 1500 if( s->selfdestruct_next != NULL)
1514 struct s_lane** ref= (struct s_lane**) &selfdestruct_first; 1501 {
1515 1502 struct s_lane** ref = (struct s_lane**) &s->U->selfdestruct_first;
1516 while( *ref != SELFDESTRUCT_END ) {
1517 if (*ref == s) {
1518 *ref= s->selfdestruct_next;
1519 s->selfdestruct_next= NULL;
1520 // the terminal shutdown should wait until the lane is done with its lua_close()
1521 ++ selfdestructing_count;
1522 found= TRUE;
1523 break;
1524 }
1525 ref= (struct s_lane**) &((*ref)->selfdestruct_next);
1526 }
1527 assert( found );
1528 }
1529 }
1530 MUTEX_UNLOCK( &selfdestruct_cs );
1531 return found;
1532}
1533 1503
1534// Initialized by 'init_once_LOCKED()': the deep userdata Linda object 1504 while( *ref != SELFDESTRUCT_END )
1535// used for timers (each lane will get a proxy to this) 1505 {
1536// 1506 if( *ref == s)
1537volatile DEEP_PRELUDE* timer_deep; // = NULL 1507 {
1508 *ref = s->selfdestruct_next;
1509 s->selfdestruct_next = NULL;
1510 // the terminal shutdown should wait until the lane is done with its lua_close()
1511 ++ s->U->selfdestructing_count;
1512 found = TRUE;
1513 break;
1514 }
1515 ref = (struct s_lane**) &((*ref)->selfdestruct_next);
1516 }
1517 assert( found);
1518 }
1519 }
1520 MUTEX_UNLOCK( &s->U->selfdestruct_cs);
1521 return found;
1522}
1538 1523
1539/* 1524/*
1540** mutex-protected allocator for use with Lua states that have non-threadsafe allocators (such as LuaJIT) 1525** mutex-protected allocator for use with Lua states that have non-threadsafe allocators (such as LuaJIT)
@@ -1560,13 +1545,15 @@ void * protected_lua_Alloc( void *ud, void *ptr, size_t osize, size_t nsize)
1560*/ 1545*/
1561static int selfdestruct_gc( lua_State* L) 1546static int selfdestruct_gc( lua_State* L)
1562{ 1547{
1563 while( selfdestruct_first != SELFDESTRUCT_END) // true at most once! 1548 struct s_Universe* U = (struct s_Universe*) lua_touserdata( L, 1);
1549
1550 while( U->selfdestruct_first != SELFDESTRUCT_END) // true at most once!
1564 { 1551 {
1565 // Signal _all_ still running threads to exit (including the timer thread) 1552 // Signal _all_ still running threads to exit (including the timer thread)
1566 // 1553 //
1567 MUTEX_LOCK( &selfdestruct_cs); 1554 MUTEX_LOCK( &U->selfdestruct_cs);
1568 { 1555 {
1569 struct s_lane* s = selfdestruct_first; 1556 struct s_lane* s = U->selfdestruct_first;
1570 while( s != SELFDESTRUCT_END) 1557 while( s != SELFDESTRUCT_END)
1571 { 1558 {
1572 // attempt a regular unforced hard cancel with a small timeout 1559 // attempt a regular unforced hard cancel with a small timeout
@@ -1583,7 +1570,7 @@ static int selfdestruct_gc( lua_State* L)
1583 s = s->selfdestruct_next; 1570 s = s->selfdestruct_next;
1584 } 1571 }
1585 } 1572 }
1586 MUTEX_UNLOCK( &selfdestruct_cs); 1573 MUTEX_UNLOCK( &U->selfdestruct_cs);
1587 1574
1588 // When noticing their cancel, the lanes will remove themselves from 1575 // When noticing their cancel, the lanes will remove themselves from
1589 // the selfdestruct chain. 1576 // the selfdestruct chain.
@@ -1603,16 +1590,16 @@ static int selfdestruct_gc( lua_State* L)
1603 lua_Number const shutdown_timeout = lua_tonumber( L, lua_upvalueindex( 1)); 1590 lua_Number const shutdown_timeout = lua_tonumber( L, lua_upvalueindex( 1));
1604 double const t_until = now_secs() + shutdown_timeout; 1591 double const t_until = now_secs() + shutdown_timeout;
1605 1592
1606 while( selfdestruct_first != SELFDESTRUCT_END) 1593 while( U->selfdestruct_first != SELFDESTRUCT_END)
1607 { 1594 {
1608 YIELD(); // give threads time to act on their cancel 1595 YIELD(); // give threads time to act on their cancel
1609 { 1596 {
1610 // count the number of cancelled thread that didn't have the time to act yet 1597 // count the number of cancelled thread that didn't have the time to act yet
1611 int n = 0; 1598 int n = 0;
1612 double t_now = 0.0; 1599 double t_now = 0.0;
1613 MUTEX_LOCK( &selfdestruct_cs); 1600 MUTEX_LOCK( &U->selfdestruct_cs);
1614 { 1601 {
1615 struct s_lane* s = selfdestruct_first; 1602 struct s_lane* s = U->selfdestruct_first;
1616 while( s != SELFDESTRUCT_END) 1603 while( s != SELFDESTRUCT_END)
1617 { 1604 {
1618 if( s->cancel_request == CANCEL_HARD) 1605 if( s->cancel_request == CANCEL_HARD)
@@ -1620,7 +1607,7 @@ static int selfdestruct_gc( lua_State* L)
1620 s = s->selfdestruct_next; 1607 s = s->selfdestruct_next;
1621 } 1608 }
1622 } 1609 }
1623 MUTEX_UNLOCK( &selfdestruct_cs); 1610 MUTEX_UNLOCK( &U->selfdestruct_cs);
1624 // if timeout elapsed, or we know all threads have acted, stop waiting 1611 // if timeout elapsed, or we know all threads have acted, stop waiting
1625 t_now = now_secs(); 1612 t_now = now_secs();
1626 if( n == 0 || (t_now >= t_until)) 1613 if( n == 0 || (t_now >= t_until))
@@ -1638,9 +1625,9 @@ static int selfdestruct_gc( lua_State* L)
1638 bool_t again = TRUE; 1625 bool_t again = TRUE;
1639 do 1626 do
1640 { 1627 {
1641 MUTEX_LOCK( &selfdestruct_cs); 1628 MUTEX_LOCK( &U->selfdestruct_cs);
1642 again = (selfdestructing_count > 0) ? TRUE : FALSE; 1629 again = (U->selfdestructing_count > 0) ? TRUE : FALSE;
1643 MUTEX_UNLOCK( &selfdestruct_cs); 1630 MUTEX_UNLOCK( &U->selfdestruct_cs);
1644 YIELD(); 1631 YIELD();
1645 } while( again); 1632 } while( again);
1646 } 1633 }
@@ -1648,15 +1635,15 @@ static int selfdestruct_gc( lua_State* L)
1648 //--- 1635 //---
1649 // Kill the still free running threads 1636 // Kill the still free running threads
1650 // 1637 //
1651 if( selfdestruct_first != SELFDESTRUCT_END) 1638 if( U->selfdestruct_first != SELFDESTRUCT_END)
1652 { 1639 {
1653 unsigned int n = 0; 1640 unsigned int n = 0;
1654 // first thing we did was to raise the linda signals the threads were waiting on (if any) 1641 // first thing we did was to raise the linda signals the threads were waiting on (if any)
1655 // therefore, any well-behaved thread should be in CANCELLED state 1642 // therefore, any well-behaved thread should be in CANCELLED state
1656 // these are not running, and the state can be closed 1643 // these are not running, and the state can be closed
1657 MUTEX_LOCK( &selfdestruct_cs); 1644 MUTEX_LOCK( &U->selfdestruct_cs);
1658 { 1645 {
1659 struct s_lane* s = selfdestruct_first; 1646 struct s_lane* s = U->selfdestruct_first;
1660 while( s != SELFDESTRUCT_END) 1647 while( s != SELFDESTRUCT_END)
1661 { 1648 {
1662 struct s_lane* next_s = s->selfdestruct_next; 1649 struct s_lane* next_s = s->selfdestruct_next;
@@ -1674,14 +1661,22 @@ static int selfdestruct_gc( lua_State* L)
1674 s = next_s; 1661 s = next_s;
1675 ++ n; 1662 ++ n;
1676 } 1663 }
1677 selfdestruct_first = SELFDESTRUCT_END; 1664 U->selfdestruct_first = SELFDESTRUCT_END;
1678 } 1665 }
1679 MUTEX_UNLOCK( &selfdestruct_cs); 1666 MUTEX_UNLOCK( &U->selfdestruct_cs);
1680 1667
1681 DEBUGSPEW_CODE( fprintf( stderr, "Killed %d lane(s) at process end.\n", n)); 1668 DEBUGSPEW_CODE( fprintf( stderr, "Killed %d lane(s) at process end.\n", n));
1682 } 1669 }
1683 } 1670 }
1684 close_keepers( L); 1671
1672 // necessary so that calling free_deep_prelude doesn't crash because linda_id expects a linda lightuserdata at absolute slot 1
1673 lua_settop( L, 0);
1674 // no need to mutex-protect this as all threads in the universe are gone at that point
1675 -- U->timer_deep->refcount; // should be 0 now
1676 free_deep_prelude( L, (DEEP_PRELUDE*) U->timer_deep);
1677 U->timer_deep = NULL;
1678
1679 close_keepers( U, L);
1685 1680
1686 // remove the protected allocator, if any 1681 // remove the protected allocator, if any
1687 { 1682 {
@@ -1697,6 +1692,16 @@ static int selfdestruct_gc( lua_State* L)
1697 } 1692 }
1698 } 1693 }
1699 1694
1695#if HAVE_LANE_TRACKING
1696 MUTEX_FREE( &U->tracking_cs);
1697#endif // HAVE_LANE_TRACKING
1698 // Linked chains handling
1699 MUTEX_FREE( &U->selfdestruct_cs);
1700 MUTEX_FREE( &U->require_cs);
1701 // Locks for 'tools.c' inc/dec counters
1702 MUTEX_FREE( &U->deep_lock);
1703 MUTEX_FREE( &U->mtid_lock);
1704
1700 return 0; 1705 return 0;
1701} 1706}
1702 1707
@@ -1961,8 +1966,9 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs)
1961 struct s_lane* s = (struct s_lane*) vs; 1966 struct s_lane* s = (struct s_lane*) vs;
1962 int rc, rc2; 1967 int rc, rc2;
1963 lua_State* L = s->L; 1968 lua_State* L = s->L;
1969 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L));
1964#if HAVE_LANE_TRACKING 1970#if HAVE_LANE_TRACKING
1965 if( tracking_first) 1971 if( s->U->tracking_first)
1966 { 1972 {
1967 tracking_add( s); 1973 tracking_add( s);
1968 } 1974 }
@@ -2072,10 +2078,10 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs)
2072 s->debug_name = "<closed>"; 2078 s->debug_name = "<closed>";
2073 2079
2074 lane_cleanup( s); 2080 lane_cleanup( s);
2075 MUTEX_LOCK( &selfdestruct_cs); 2081 MUTEX_LOCK( &s->U->selfdestruct_cs);
2076 // done with lua_close(), terminal shutdown sequence may proceed 2082 // done with lua_close(), terminal shutdown sequence may proceed
2077 -- selfdestructing_count; 2083 -- s->U->selfdestructing_count;
2078 MUTEX_UNLOCK( &selfdestruct_cs); 2084 MUTEX_UNLOCK( &s->U->selfdestruct_cs);
2079 } 2085 }
2080 else 2086 else
2081 { 2087 {
@@ -2112,15 +2118,16 @@ LUAG_FUNC( require)
2112{ 2118{
2113 char const* name = lua_tostring( L, 1); 2119 char const* name = lua_tostring( L, 1);
2114 int const nargs = lua_gettop( L); 2120 int const nargs = lua_gettop( L);
2121 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L));
2115 STACK_CHECK( L); 2122 STACK_CHECK( L);
2116 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); 2123 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name));
2117 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 2124 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2118 lua_pushvalue( L, lua_upvalueindex(1)); // "name" require 2125 lua_pushvalue( L, lua_upvalueindex(1)); // "name" require
2119 lua_insert( L, 1); // require "name" 2126 lua_insert( L, 1); // require "name"
2120 lua_call( L, nargs, 1); // module 2127 lua_call( L, nargs, 1); // module
2121 populate_func_lookup_table( L, -1, name); 2128 populate_func_lookup_table( L, -1, name);
2122 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s END\n" INDENT_END, name)); 2129 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s END\n" INDENT_END, name));
2123 DEBUGSPEW_CODE( -- debugspew_indent_depth); 2130 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2124 STACK_END( L, 0); 2131 STACK_END( L, 0);
2125 return 1; 2132 return 1;
2126} 2133}
@@ -2156,6 +2163,7 @@ LUAG_FUNC( thread_new)
2156 2163
2157#define FIXED_ARGS 8 2164#define FIXED_ARGS 8
2158 uint_t args = lua_gettop(L) - FIXED_ARGS; 2165 uint_t args = lua_gettop(L) - FIXED_ARGS;
2166 struct s_Universe* U = get_universe( L);
2159 2167
2160 // public Lanes API accepts a generic range -3/+3 2168 // public Lanes API accepts a generic range -3/+3
2161 // that will be remapped into the platform-specific scheduler priority scheme 2169 // that will be remapped into the platform-specific scheduler priority scheme
@@ -2167,11 +2175,10 @@ LUAG_FUNC( thread_new)
2167 2175
2168 /* --- Create and prepare the sub state --- */ 2176 /* --- Create and prepare the sub state --- */
2169 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: setup\n" INDENT_END)); 2177 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: setup\n" INDENT_END));
2170 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 2178 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2171 2179
2172 // populate with selected libraries at the same time 2180 // populate with selected libraries at the same time
2173 // 2181 L2 = luaG_newstate( U, L, libs);
2174 L2 = luaG_newstate( L, libs);
2175 2182
2176 STACK_GROW( L, 2); 2183 STACK_GROW( L, 2);
2177 STACK_GROW( L2, 3); 2184 STACK_GROW( L2, 3);
@@ -2187,7 +2194,7 @@ LUAG_FUNC( thread_new)
2187 if( package != 0) 2194 if( package != 0)
2188 { 2195 {
2189 // when copying with mode eLM_LaneBody, should raise an error in case of problem, not leave it one the stack 2196 // when copying with mode eLM_LaneBody, should raise an error in case of problem, not leave it one the stack
2190 (void) luaG_inter_copy_package( L, L2, package, eLM_LaneBody); 2197 (void) luaG_inter_copy_package( U, L, L2, package, eLM_LaneBody);
2191 } 2198 }
2192 2199
2193 // modules to require in the target lane *before* the function is transfered! 2200 // modules to require in the target lane *before* the function is transfered!
@@ -2198,7 +2205,7 @@ LUAG_FUNC( thread_new)
2198 { 2205 {
2199 int nbRequired = 1; 2206 int nbRequired = 1;
2200 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: require 'required' list\n" INDENT_END)); 2207 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: require 'required' list\n" INDENT_END));
2201 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 2208 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2202 // should not happen, was checked in lanes.lua before calling thread_new() 2209 // should not happen, was checked in lanes.lua before calling thread_new()
2203 if( lua_type( L, required) != LUA_TTABLE) 2210 if( lua_type( L, required) != LUA_TTABLE)
2204 { 2211 {
@@ -2233,13 +2240,13 @@ LUAG_FUNC( thread_new)
2233 // which might not be the case if the libs list didn't include lanes.core or "*" 2240 // which might not be the case if the libs list didn't include lanes.core or "*"
2234 if( strncmp( name, "lanes.core", len) == 0) // this works both both "lanes" and "lanes.core" because of len 2241 if( strncmp( name, "lanes.core", len) == 0) // this works both both "lanes" and "lanes.core" because of len
2235 { 2242 {
2236 luaG_copy_one_time_settings( L, L2); 2243 luaG_copy_one_time_settings( U, L, L2);
2237 } 2244 }
2238 lua_pushlstring( L2, name, len); // require() name 2245 lua_pushlstring( L2, name, len); // require() name
2239 if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode 2246 if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode
2240 { 2247 {
2241 // propagate error to main state if any 2248 // propagate error to main state if any
2242 luaG_inter_move( L2, L, 1, eLM_LaneBody); // 2249 luaG_inter_move( U, L2, L, 1, eLM_LaneBody); //
2243 return lua_error( L); 2250 return lua_error( L);
2244 } 2251 }
2245 STACK_MID( L2, 1); 2252 STACK_MID( L2, 1);
@@ -2253,7 +2260,7 @@ LUAG_FUNC( thread_new)
2253 lua_pop( L, 1); 2260 lua_pop( L, 1);
2254 ++ nbRequired; 2261 ++ nbRequired;
2255 } 2262 }
2256 DEBUGSPEW_CODE( -- debugspew_indent_depth); 2263 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2257 } 2264 }
2258 STACK_END( L2, 0); 2265 STACK_END( L2, 0);
2259 STACK_END( L, 0); 2266 STACK_END( L, 0);
@@ -2271,12 +2278,12 @@ LUAG_FUNC( thread_new)
2271 return luaL_error( L, "Expected table, got %s", luaL_typename( L, glob)); 2278 return luaL_error( L, "Expected table, got %s", luaL_typename( L, glob));
2272 } 2279 }
2273 2280
2274 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 2281 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2275 lua_pushnil( L); 2282 lua_pushnil( L);
2276 lua_pushglobaltable( L2); // Lua 5.2 wants us to push the globals table on the stack 2283 lua_pushglobaltable( L2); // Lua 5.2 wants us to push the globals table on the stack
2277 while( lua_next( L, glob)) 2284 while( lua_next( L, glob))
2278 { 2285 {
2279 luaG_inter_copy( L, L2, 2, eLM_LaneBody); // moves the key/value pair to the L2 stack 2286 luaG_inter_copy( U, L, L2, 2, eLM_LaneBody); // moves the key/value pair to the L2 stack
2280 // assign it in L2's globals table 2287 // assign it in L2's globals table
2281 lua_rawset( L2, -3); 2288 lua_rawset( L2, -3);
2282 lua_pop( L, 1); 2289 lua_pop( L, 1);
@@ -2285,7 +2292,7 @@ LUAG_FUNC( thread_new)
2285 2292
2286 STACK_END( L2, 0); 2293 STACK_END( L2, 0);
2287 STACK_END( L, 0); 2294 STACK_END( L, 0);
2288 DEBUGSPEW_CODE( -- debugspew_indent_depth); 2295 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2289 } 2296 }
2290 2297
2291 ASSERT_L( lua_gettop( L2) == 0); 2298 ASSERT_L( lua_gettop( L2) == 0);
@@ -2297,10 +2304,10 @@ LUAG_FUNC( thread_new)
2297 { 2304 {
2298 int res; 2305 int res;
2299 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane body\n" INDENT_END)); 2306 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane body\n" INDENT_END));
2300 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 2307 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2301 lua_pushvalue( L, 1); 2308 lua_pushvalue( L, 1);
2302 res = luaG_inter_move( L, L2, 1, eLM_LaneBody); // L->L2 2309 res = luaG_inter_move( U, L, L2, 1, eLM_LaneBody); // L->L2
2303 DEBUGSPEW_CODE( -- debugspew_indent_depth); 2310 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2304 if( res != 0) 2311 if( res != 0)
2305 { 2312 {
2306 return luaL_error( L, "tried to copy unsupported types"); 2313 return luaL_error( L, "tried to copy unsupported types");
@@ -2325,9 +2332,9 @@ LUAG_FUNC( thread_new)
2325 { 2332 {
2326 int res; 2333 int res;
2327 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane arguments\n" INDENT_END)); 2334 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane arguments\n" INDENT_END));
2328 DEBUGSPEW_CODE( ++ debugspew_indent_depth); 2335 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2329 res = luaG_inter_copy( L, L2, args, eLM_LaneBody); // L->L2 2336 res = luaG_inter_copy( U, L, L2, args, eLM_LaneBody); // L->L2
2330 DEBUGSPEW_CODE( -- debugspew_indent_depth); 2337 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2331 if( res != 0) 2338 if( res != 0)
2332 { 2339 {
2333 return luaL_error( L, "tried to copy unsupported types"); 2340 return luaL_error( L, "tried to copy unsupported types");
@@ -2348,8 +2355,8 @@ LUAG_FUNC( thread_new)
2348 return luaL_error( L, "could not create lane: out of memory"); 2355 return luaL_error( L, "could not create lane: out of memory");
2349 } 2356 }
2350 2357
2351 //memset( s, 0, sizeof(struct s_lane) );
2352 s->L = L2; 2358 s->L = L2;
2359 s->U = U;
2353 s->status = PENDING; 2360 s->status = PENDING;
2354 s->waiting_on = NULL; 2361 s->waiting_on = NULL;
2355 s->debug_name = "<unnamed>"; 2362 s->debug_name = "<unnamed>";
@@ -2399,7 +2406,7 @@ LUAG_FUNC( thread_new)
2399 THREAD_CREATE( &s->thread, lane_main, s, prio); 2406 THREAD_CREATE( &s->thread, lane_main, s, prio);
2400 STACK_END( L, 1); 2407 STACK_END( L, 1);
2401 2408
2402 DEBUGSPEW_CODE( -- debugspew_indent_depth); 2409 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2403 2410
2404 return 1; 2411 return 1;
2405} 2412}
@@ -2612,6 +2619,7 @@ LUAG_FUNC( thread_join)
2612 } 2619 }
2613 else 2620 else
2614 { 2621 {
2622 struct s_Universe* U = get_universe( L);
2615 // debug_name is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed 2623 // debug_name is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed
2616 // so store it in the userdata uservalue at a key that can't possibly collide 2624 // so store it in the userdata uservalue at a key that can't possibly collide
2617 securize_debug_threadname( L, s); 2625 securize_debug_threadname( L, s);
@@ -2620,7 +2628,7 @@ LUAG_FUNC( thread_join)
2620 case DONE: 2628 case DONE:
2621 { 2629 {
2622 uint_t n = lua_gettop( L2); // whole L2 stack 2630 uint_t n = lua_gettop( L2); // whole L2 stack
2623 if( (n > 0) && (luaG_inter_move( L2, L, n, eLM_LaneBody) != 0)) 2631 if( (n > 0) && (luaG_inter_move( U, L2, L, n, eLM_LaneBody) != 0))
2624 { 2632 {
2625 return luaL_error( L, "tried to copy unsupported types"); 2633 return luaL_error( L, "tried to copy unsupported types");
2626 } 2634 }
@@ -2629,8 +2637,9 @@ LUAG_FUNC( thread_join)
2629 break; 2637 break;
2630 2638
2631 case ERROR_ST: 2639 case ERROR_ST:
2640 STACK_GROW( L, 1);
2632 lua_pushnil( L); 2641 lua_pushnil( L);
2633 if( luaG_inter_move( L2, L, 1 + ERROR_FULL_STACK, eLM_LaneBody) != 0) // error message at [-2], stack trace at [-1] 2642 if( luaG_inter_move( U, L2, L, 1 + ERROR_FULL_STACK, eLM_LaneBody) != 0) // error message at [-2], stack trace at [-1]
2634 { 2643 {
2635 return luaL_error( L, "tried to copy unsupported types"); 2644 return luaL_error( L, "tried to copy unsupported types");
2636 } 2645 }
@@ -2638,12 +2647,13 @@ LUAG_FUNC( thread_join)
2638 break; 2647 break;
2639 2648
2640 case CANCELLED: 2649 case CANCELLED:
2641 ret= 0; 2650 ret = 0;
2642 break; 2651 break;
2643 2652
2644 default: 2653 default:
2645 DEBUGSPEW_CODE( fprintf( stderr, "Status: %d\n", s->status)); 2654 DEBUGSPEW_CODE( fprintf( stderr, "Status: %d\n", s->status));
2646 ASSERT_L( FALSE); ret = 0; 2655 ASSERT_L( FALSE);
2656 ret = 0;
2647 } 2657 }
2648 lua_close( L2); 2658 lua_close( L2);
2649 } 2659 }
@@ -2817,12 +2827,14 @@ LUAG_FUNC( thread_index)
2817LUAG_FUNC( threads) 2827LUAG_FUNC( threads)
2818{ 2828{
2819 int const top = lua_gettop( L); 2829 int const top = lua_gettop( L);
2830 struct s_Universe* U = get_universe( L);
2831
2820 // List _all_ still running threads 2832 // List _all_ still running threads
2821 // 2833 //
2822 MUTEX_LOCK( &tracking_cs); 2834 MUTEX_LOCK( &U->tracking_cs);
2823 if( tracking_first && tracking_first != TRACKING_END) 2835 if( U->tracking_first && U->tracking_first != TRACKING_END)
2824 { 2836 {
2825 struct s_lane* s = tracking_first; 2837 struct s_lane* s = U->tracking_first;
2826 lua_newtable( L); // {} 2838 lua_newtable( L); // {}
2827 while( s != TRACKING_END) 2839 while( s != TRACKING_END)
2828 { 2840 {
@@ -2832,7 +2844,7 @@ LUAG_FUNC( threads)
2832 s = s->tracking_next; 2844 s = s->tracking_next;
2833 } 2845 }
2834 } 2846 }
2835 MUTEX_UNLOCK( &tracking_cs); 2847 MUTEX_UNLOCK( &U->tracking_cs);
2836 return lua_gettop( L) - top; 2848 return lua_gettop( L) - top;
2837} 2849}
2838#endif // HAVE_LANE_TRACKING 2850#endif // HAVE_LANE_TRACKING
@@ -2922,18 +2934,8 @@ static const struct luaL_Reg lanes_functions [] = {
2922 * settings table it at position 1 on the stack 2934 * settings table it at position 1 on the stack
2923 * pushes an error string on the stack in case of problem 2935 * pushes an error string on the stack in case of problem
2924 */ 2936 */
2925static int init_once_LOCKED( lua_State* L) 2937static void init_once_LOCKED( void)
2926{ 2938{
2927 initialize_on_state_create( L);
2928
2929 STACK_CHECK( L);
2930
2931 lua_getfield( L, 1, "verbose_errors");
2932 GVerboseErrors = lua_toboolean( L, -1);
2933 lua_pop( L, 1);
2934
2935 STACK_MID( L, 0);
2936
2937#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 2939#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2938 now_secs(); // initialize 'now_secs()' internal offset 2940 now_secs(); // initialize 'now_secs()' internal offset
2939#endif 2941#endif
@@ -2942,29 +2944,6 @@ static int init_once_LOCKED( lua_State* L)
2942 chudInitialize(); 2944 chudInitialize();
2943#endif 2945#endif
2944 2946
2945#if HAVE_LANE_TRACKING
2946 MUTEX_INIT( &tracking_cs);
2947 lua_getfield( L, 1, "track_lanes");
2948 tracking_first = lua_toboolean( L, -1) ? TRACKING_END : NULL;
2949 lua_pop( L, 1);
2950 STACK_MID( L, 0);
2951#endif // HAVE_LANE_TRACKING
2952
2953 // Locks for 'tools.c' inc/dec counters
2954 //
2955 MUTEX_INIT( &deep_lock);
2956 MUTEX_INIT( &mtid_lock);
2957
2958 // Serialize calls to 'require' from now on, also in the primary state
2959 //
2960 MUTEX_RECURSIVE_INIT( &require_cs);
2961
2962 serialize_require( L);
2963
2964 // Linked chains handling
2965 //
2966 MUTEX_INIT( &selfdestruct_cs);
2967
2968 //--- 2947 //---
2969 // Linux needs SCHED_RR to change thread priorities, and that is only 2948 // Linux needs SCHED_RR to change thread priorities, and that is only
2970 // allowed for sudo'ers. SCHED_OTHER (default) has no priorities. 2949 // allowed for sudo'ers. SCHED_OTHER (default) has no priorities.
@@ -2990,52 +2969,6 @@ static int init_once_LOCKED( lua_State* L)
2990 } 2969 }
2991#endif // LINUX_SCHED_RR 2970#endif // LINUX_SCHED_RR
2992#endif // PLATFORM_LINUX 2971#endif // PLATFORM_LINUX
2993 {
2994 // returns non-0 if an error message was pushed on the stack
2995 int pushed_error = init_keepers( L);
2996 if( pushed_error)
2997 {
2998 return pushed_error;
2999 }
3000 }
3001
3002 // Initialize 'timer_deep'; a common Linda object shared by all states
3003 //
3004 ASSERT_L( timer_deep == NULL);
3005
3006 // proxy_ud= deep_userdata( idfunc )
3007 //
3008 lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes
3009 luaG_newdeepuserdata( L, linda_id);
3010 STACK_MID( L, 2);
3011 lua_remove( L, -2); // remove the name as we no longer need it
3012
3013 ASSERT_L( lua_isuserdata(L,-1));
3014
3015 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer
3016 //
3017 timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1);
3018 ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep && timer_deep->idfunc == linda_id);
3019
3020 // The host Lua state must always have a reference to this Linda object in order for the timer_deep pointer to be valid.
3021 // So store a reference that we will never actually use.
3022 // at the same time, use this object as a 'desinit' marker:
3023 // when the main lua State is closed, this object will be GC'ed
3024 {
3025 lua_newuserdata( L, 1);
3026 lua_newtable( L);
3027 lua_getfield( L, 1, "shutdown_timeout");
3028 lua_pushcclosure( L, selfdestruct_gc, 1);
3029 lua_setfield( L, -2, "__gc");
3030 lua_pushliteral( L, "AtExit");
3031 lua_setfield( L, -2, "__metatable");
3032 lua_setmetatable( L, -2);
3033 }
3034 lua_insert( L, -2); // Swap key with the Linda object
3035 lua_rawset( L, LUA_REGISTRYINDEX);
3036
3037 STACK_END( L, 0);
3038 return 0;
3039} 2972}
3040 2973
3041static volatile long s_initCount = 0; 2974static volatile long s_initCount = 0;
@@ -3045,32 +2978,9 @@ static volatile long s_initCount = 0;
3045// param 1: settings table 2978// param 1: settings table
3046LUAG_FUNC( configure) 2979LUAG_FUNC( configure)
3047{ 2980{
3048 // set to 1 if an error occured inside init_once_LOCKED(), and message is found at the top of the stack 2981 struct s_Universe* U = get_universe( L);
3049 int init_once_error = 0;
3050 char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); 2982 char const* name = luaL_checkstring( L, lua_upvalueindex( 1));
3051 _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE); 2983 _ASSERT_L( L, lua_type( L, 1) == LUA_TTABLE);
3052 STACK_CHECK( L);
3053
3054 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L));
3055 DEBUGSPEW_CODE( ++ debugspew_indent_depth);
3056
3057 // not in init_once_LOCKED because we can have several hosted "master" Lua states where Lanes is require()d.
3058 lua_getfield( L, 1, "protect_allocator"); // settings protect_allocator
3059 if( lua_toboolean( L, -1))
3060 {
3061 void* ud;
3062 lua_Alloc allocf = lua_getallocf( L, &ud);
3063 if( allocf != protected_lua_Alloc) // just in case
3064 {
3065 struct ProtectedAllocator_s* s = (struct ProtectedAllocator_s*) allocf( ud, NULL, 0, sizeof( struct ProtectedAllocator_s));
3066 s->allocf = allocf;
3067 s->ud = ud;
3068 MUTEX_INIT( &s->lock);
3069 lua_setallocf( L, protected_lua_Alloc, s);
3070 }
3071 }
3072 lua_pop( L, 1); // settings
3073 STACK_MID( L, 0);
3074 2984
3075 /* 2985 /*
3076 ** Making one-time initializations. 2986 ** Making one-time initializations.
@@ -3084,7 +2994,7 @@ LUAG_FUNC( configure)
3084 static volatile int /*bool*/ go_ahead; // = 0 2994 static volatile int /*bool*/ go_ahead; // = 0
3085 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) 2995 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
3086 { 2996 {
3087 init_once_error = init_once_LOCKED( L); 2997 init_once_LOCKED();
3088 go_ahead = 1; // let others pass 2998 go_ahead = 1; // let others pass
3089 } 2999 }
3090 else 3000 else
@@ -3102,7 +3012,7 @@ LUAG_FUNC( configure)
3102 // 3012 //
3103 if( s_initCount == 0) 3013 if( s_initCount == 0)
3104 { 3014 {
3105 init_once_error = init_once_LOCKED( L); 3015 init_once_LOCKED();
3106 s_initCount = 1; 3016 s_initCount = 1;
3107 } 3017 }
3108 } 3018 }
@@ -3110,85 +3020,148 @@ LUAG_FUNC( configure)
3110 } 3020 }
3111#endif // THREADAPI == THREADAPI_PTHREAD 3021#endif // THREADAPI == THREADAPI_PTHREAD
3112 3022
3113 // raise error outside the init-once mutex 3023 STACK_GROW( L, 4);
3114 if( init_once_error) 3024 STACK_CHECK( L);
3025
3026 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END, L));
3027 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
3028
3029 lua_getfield( L, 1, "protect_allocator"); // settings protect_allocator
3030 if( lua_toboolean( L, -1))
3115 { 3031 {
3116 // will raise an error if the error is not a string (should not happen) 3032 void* ud;
3117 char const* error = luaL_checkstring( L, -1); 3033 lua_Alloc allocf = lua_getallocf( L, &ud);
3118 // raises an error with the message found at the top of the stack 3034 if( allocf != protected_lua_Alloc) // just in case
3119 lua_error( L); 3035 {
3036 struct ProtectedAllocator_s* s = (struct ProtectedAllocator_s*) allocf( ud, NULL, 0, sizeof( struct ProtectedAllocator_s));
3037 s->allocf = allocf;
3038 s->ud = ud;
3039 MUTEX_INIT( &s->lock);
3040 lua_setallocf( L, protected_lua_Alloc, s);
3041 }
3042 }
3043 lua_pop( L, 1); // settings
3044 STACK_MID( L, 0);
3045
3046 // grab or create the universe
3047 if( U == NULL)
3048 {
3049 lua_pushlightuserdata( L, UNIVERSE_REGKEY); // settings UNIVERSE_REGKEY
3050 U = (struct s_Universe*) lua_newuserdata( L, sizeof( struct s_Universe)); // settings UNIVERSE_REGKEY universe
3051 memset( U, 0, sizeof( struct s_Universe));
3052 lua_newtable( L); // settings UNIVERSE_REGKEY universe mt
3053 lua_getfield( L, 1, "shutdown_timeout"); // settings UNIVERSE_REGKEY universe mt shutdown_timeout
3054 lua_pushcclosure( L, selfdestruct_gc, 1); // settings UNIVERSE_REGKEY universe mt selfdestruct_gc
3055 lua_setfield( L, -2, "__gc"); // settings UNIVERSE_REGKEY universe mt
3056 lua_setmetatable( L, -2); // settings UNIVERSE_REGKEY universe
3057 lua_rawset( L, LUA_REGISTRYINDEX); // settings
3058 lua_getfield( L, 1, "verbose_errors"); // settings verbose_errors
3059 U->verboseErrors = lua_toboolean( L, -1);
3060 lua_pop( L, 1); // settings
3061#if HAVE_LANE_TRACKING
3062 MUTEX_INIT( &U->tracking_cs);
3063 lua_getfield( L, 1, "track_lanes"); // settings track_lanes
3064 U->tracking_first = lua_toboolean( L, -1) ? TRACKING_END : NULL;
3065 lua_pop( L, 1); // settings
3066#endif // HAVE_LANE_TRACKING
3067 // Linked chains handling
3068 MUTEX_INIT( &U->selfdestruct_cs);
3069 MUTEX_RECURSIVE_INIT( &U->require_cs);
3070 // Locks for 'tools.c' inc/dec counters
3071 MUTEX_INIT( &U->deep_lock);
3072 MUTEX_INIT( &U->mtid_lock);
3073 U->selfdestruct_first = SELFDESTRUCT_END;
3074 initialize_on_state_create( U, L);
3075 init_keepers( U, L);
3076 STACK_MID( L, 0);
3077
3078 // Initialize 'timer_deep'; a common Linda object shared by all states
3079 lua_pushcfunction( L, LG_linda); // settings lanes.linda
3080 lua_pushliteral( L, "lanes-timer"); // settings lanes.linda "lanes-timer"
3081 lua_call( L, 1, 1); // settings linda
3082 STACK_MID( L, 1);
3083
3084 // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer
3085 U->timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1);
3086 ASSERT_L( U->timer_deep && (U->timer_deep->refcount == 1) && U->timer_deep->deep && U->timer_deep->idfunc == linda_id);
3087 // increment refcount that this linda remains alive as long as the universe is.
3088 ++ U->timer_deep->refcount;
3089 lua_pop( L, 1); // settings
3120 } 3090 }
3091 STACK_MID( L, 0);
3092
3093 // Serialize calls to 'require' from now on, also in the primary state
3094 serialize_require( L);
3121 3095
3122 // Retrieve main module interface table 3096 // Retrieve main module interface table
3123 lua_pushvalue( L, lua_upvalueindex( 2)); // settings M 3097 lua_pushvalue( L, lua_upvalueindex( 2)); // settings M
3124 // remove configure() (this function) from the module interface 3098 // remove configure() (this function) from the module interface
3125 lua_pushnil( L); // settings M nil 3099 lua_pushnil( L); // settings M nil
3126 lua_setfield( L, -2, "configure"); // settings M 3100 lua_setfield( L, -2, "configure"); // settings M
3127 // add functions to the module's table 3101 // add functions to the module's table
3128 luaG_registerlibfuncs( L, lanes_functions); 3102 luaG_registerlibfuncs( L, lanes_functions);
3129#if HAVE_LANE_TRACKING 3103#if HAVE_LANE_TRACKING
3130 // register core.threads() only if settings say it should be available 3104 // register core.threads() only if settings say it should be available
3131 if( tracking_first != NULL) 3105 if( U->tracking_first != NULL)
3132 { 3106 {
3133 lua_pushcfunction( L, LG_threads); // settings M LG_threads() 3107 lua_pushcfunction( L, LG_threads); // settings M LG_threads()
3134 lua_setfield( L, -2, "threads"); // settings M 3108 lua_setfield( L, -2, "threads"); // settings M
3135 } 3109 }
3136#endif // HAVE_LANE_TRACKING 3110#endif // HAVE_LANE_TRACKING
3137 STACK_MID( L, 1); 3111 STACK_MID( L, 1);
3138 3112
3139 { 3113 {
3140 char const* errmsg; 3114 char const* errmsg;
3141 ASSERT_L( timer_deep != NULL); // initialized by init_once_LOCKED 3115 errmsg = push_deep_proxy( U, L, (DEEP_PRELUDE*) U->timer_deep, eLM_LaneBody); // settings M timer_deep
3142 errmsg = push_deep_proxy( L, (DEEP_PRELUDE*) timer_deep, eLM_LaneBody); // settings M timer_deep
3143 if( errmsg != NULL) 3116 if( errmsg != NULL)
3144 { 3117 {
3145 luaL_error( L, errmsg); 3118 return luaL_error( L, errmsg);
3146 } 3119 }
3147 lua_setfield( L, -2, "timer_gateway"); // settings M 3120 lua_setfield( L, -2, "timer_gateway"); // settings M
3148 } 3121 }
3149 STACK_MID( L, 1); 3122 STACK_MID( L, 1);
3150 3123
3151 // prepare the metatable for threads 3124 // prepare the metatable for threads
3152 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname } 3125 // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname }
3153 // 3126 //
3154 if( luaL_newmetatable( L, "Lane")) // settings M mt 3127 if( luaL_newmetatable( L, "Lane")) // settings M mt
3155 { 3128 {
3156 lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc 3129 lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc
3157 lua_setfield( L, -2, "__gc"); // settings M mt 3130 lua_setfield( L, -2, "__gc"); // settings M mt
3158 lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index 3131 lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index
3159 lua_setfield( L, -2, "__index"); // settings M mt 3132 lua_setfield( L, -2, "__index"); // settings M mt
3160 lua_getglobal( L, "error"); // settings M mt error 3133 lua_getglobal( L, "error"); // settings M mt error
3161 ASSERT_L( lua_isfunction( L, -1)); 3134 ASSERT_L( lua_isfunction( L, -1));
3162 lua_setfield( L, -2, "cached_error"); // settings M mt 3135 lua_setfield( L, -2, "cached_error"); // settings M mt
3163 lua_getglobal( L, "tostring"); // settings M mt tostring 3136 lua_getglobal( L, "tostring"); // settings M mt tostring
3164 ASSERT_L( lua_isfunction( L, -1)); 3137 ASSERT_L( lua_isfunction( L, -1));
3165 lua_setfield( L, -2, "cached_tostring"); // settings M mt 3138 lua_setfield( L, -2, "cached_tostring"); // settings M mt
3166 lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join 3139 lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join
3167 lua_setfield( L, -2, "join"); // settings M mt 3140 lua_setfield( L, -2, "join"); // settings M mt
3168 lua_pushcfunction( L, LG_get_debug_threadname); // settings M mt LG_get_debug_threadname 3141 lua_pushcfunction( L, LG_get_debug_threadname); // settings M mt LG_get_debug_threadname
3169 lua_setfield( L, -2, "get_debug_threadname"); // settings M mt 3142 lua_setfield( L, -2, "get_debug_threadname"); // settings M mt
3170 lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel 3143 lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel
3171 lua_setfield( L, -2, "cancel"); // settings M mt 3144 lua_setfield( L, -2, "cancel"); // settings M mt
3172 lua_pushliteral( L, "Lane"); // settings M mt "Lane" 3145 lua_pushliteral( L, "Lane"); // settings M mt "Lane"
3173 lua_setfield( L, -2, "__metatable"); // settings M mt 3146 lua_setfield( L, -2, "__metatable"); // settings M mt
3174 } 3147 }
3175 3148
3176 lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new 3149 lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new
3177 lua_setfield( L, -2, "thread_new"); // settings M 3150 lua_setfield( L, -2, "thread_new"); // settings M
3178 3151
3179 // we can't register 'lanes.require' normally because we want to create an upvalued closure 3152 // we can't register 'lanes.require' normally because we want to create an upvalued closure
3180 lua_getglobal( L, "require"); // settings M require 3153 lua_getglobal( L, "require"); // settings M require
3181 lua_pushcclosure( L, LG_require, 1); // settings M lanes.require 3154 lua_pushcclosure( L, LG_require, 1); // settings M lanes.require
3182 lua_setfield( L, -2, "require"); // settings M 3155 lua_setfield( L, -2, "require"); // settings M
3183 3156
3184 lua_pushstring(L, VERSION); // settings M VERSION 3157 lua_pushstring(L, VERSION); // settings M VERSION
3185 lua_setfield( L, -2, "version"); // settings M 3158 lua_setfield( L, -2, "version"); // settings M
3186 3159
3187 lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX 3160 lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX
3188 lua_setfield( L, -2, "max_prio"); // settings M 3161 lua_setfield( L, -2, "max_prio"); // settings M
3189 3162
3190 lua_pushlightuserdata( L, CANCEL_ERROR); // settings M CANCEL_ERROR 3163 lua_pushlightuserdata( L, CANCEL_ERROR); // settings M CANCEL_ERROR
3191 lua_setfield( L, -2, "cancel_error"); // settings M 3164 lua_setfield( L, -2, "cancel_error"); // settings M
3192 3165
3193 // we'll need this every time we transfer some C function from/to this state 3166 // we'll need this every time we transfer some C function from/to this state
3194 lua_newtable( L); 3167 lua_newtable( L);
@@ -3201,16 +3174,16 @@ LUAG_FUNC( configure)
3201 3174
3202 // record all existing C/JIT-fast functions 3175 // record all existing C/JIT-fast functions
3203 // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack 3176 // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
3204 lua_pushglobaltable( L); // settings M _G 3177 lua_pushglobaltable( L); // settings M _G
3205 populate_func_lookup_table( L, -1, NULL); 3178 populate_func_lookup_table( L, -1, NULL);
3206 lua_pop( L, 1); // settings M 3179 lua_pop( L, 1); // settings M
3207 // set _R[CONFIG_REGKEY] = settings 3180 // set _R[CONFIG_REGKEY] = settings
3208 lua_pushvalue( L, -2); // settings M settings 3181 lua_pushvalue( L, -2); // settings M settings
3209 lua_setfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // settings M 3182 lua_setfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // settings M
3210 lua_pop( L, 1); // settings 3183 lua_pop( L, 1); // settings
3211 STACK_END( L, 0); 3184 STACK_END( L, 0);
3212 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); 3185 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L));
3213 DEBUGSPEW_CODE( -- debugspew_indent_depth); 3186 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
3214 // Return the settings table 3187 // Return the settings table
3215 return 1; 3188 return 1;
3216} 3189}