diff options
Diffstat (limited to 'src/lanes.c')
-rw-r--r-- | src/lanes.c | 547 |
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 | ||
55 | char const* VERSION = "3.9.1"; | 55 | char 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 | ||
324 | static MUTEX_T tracking_cs; | ||
325 | struct 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 | |||
335 | static void tracking_add( struct s_lane* s) | 328 | static 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) | |||
351 | static bool_t tracking_remove( struct s_lane* s) | 344 | static 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) | |||
1059 | LUAG_FUNC( linda_dump) | 1053 | LUAG_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 | ||
1470 | static 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 | ||
1479 | struct 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 | ||
1483 | int 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 | */ |
1489 | static void selfdestruct_add( struct s_lane* s) | 1478 | static 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 | */ |
1504 | static bool_t selfdestruct_remove( struct s_lane* s) | 1491 | static 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) |
1537 | volatile 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 | */ |
1561 | static int selfdestruct_gc( lua_State* L) | 1546 | static 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) | |||
2817 | LUAG_FUNC( threads) | 2827 | LUAG_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 | */ |
2925 | static int init_once_LOCKED( lua_State* L) | 2937 | static 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 | ||
3041 | static volatile long s_initCount = 0; | 2974 | static 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 |
3046 | LUAG_FUNC( configure) | 2979 | LUAG_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 | } |