diff options
| author | Benoit Germain <bnt.germain@gmail.com> | 2018-11-08 17:32:05 +0100 |
|---|---|---|
| committer | Benoit Germain <bnt.germain@gmail.com> | 2018-11-08 17:32:05 +0100 |
| commit | 0cc1c9c9dcea5955f7dab921d9a2fff78c4e1729 (patch) | |
| tree | 5c35acf11087f9b60b24599695f1d3c348ebaa25 /src | |
| parent | a142eb1e1ee81919d10b55bb7fa2e33636098d85 (diff) | |
| download | lanes-0cc1c9c9dcea5955f7dab921d9a2fff78c4e1729.tar.gz lanes-0cc1c9c9dcea5955f7dab921d9a2fff78c4e1729.tar.bz2 lanes-0cc1c9c9dcea5955f7dab921d9a2fff78c4e1729.zip | |
Make sure any linda operation that can raise an error won't ever leave a mutex unreleased
Diffstat (limited to 'src')
| -rw-r--r-- | src/keeper.c | 11 | ||||
| -rw-r--r-- | src/keeper.h | 1 | ||||
| -rw-r--r-- | src/lanes.c | 99 |
3 files changed, 68 insertions, 43 deletions
diff --git a/src/keeper.c b/src/keeper.c index 715583b..b67bee2 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
| @@ -188,7 +188,7 @@ static void push_table( lua_State* L, int idx_) | |||
| 188 | 188 | ||
| 189 | int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) | 189 | int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) |
| 190 | { | 190 | { |
| 191 | Keeper* const K = keeper_acquire( U->keepers, magic_); | 191 | Keeper* const K = which_keeper( U->keepers, magic_); |
| 192 | lua_State* const KL = K ? K->L : NULL; | 192 | lua_State* const KL = K ? K->L : NULL; |
| 193 | if( KL == NULL) return 0; | 193 | if( KL == NULL) return 0; |
| 194 | STACK_GROW( KL, 4); | 194 | STACK_GROW( KL, 4); |
| @@ -233,7 +233,6 @@ int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t | |||
| 233 | STACK_END( L, 1); | 233 | STACK_END( L, 1); |
| 234 | lua_pop( KL, 1); // | 234 | lua_pop( KL, 1); // |
| 235 | STACK_END( KL, 0); | 235 | STACK_END( KL, 0); |
| 236 | keeper_release( K); | ||
| 237 | return 1; | 236 | return 1; |
| 238 | } | 237 | } |
| 239 | 238 | ||
| @@ -715,6 +714,14 @@ void init_keepers( Universe* U, lua_State* L) | |||
| 715 | STACK_END( L, 0); | 714 | STACK_END( L, 0); |
| 716 | } | 715 | } |
| 717 | 716 | ||
| 717 | // should be called only when inside a keeper_acquire/keeper_release pair (see linda_protected_call) | ||
| 718 | Keeper* which_keeper(Keepers* keepers_, ptrdiff_t magic_) | ||
| 719 | { | ||
| 720 | int const nbKeepers = keepers_->nb_keepers; | ||
| 721 | unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); | ||
| 722 | return &keepers_->keeper_array[i]; | ||
| 723 | } | ||
| 724 | |||
| 718 | Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) | 725 | Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) |
| 719 | { | 726 | { |
| 720 | int const nbKeepers = keepers_->nb_keepers; | 727 | int const nbKeepers = keepers_->nb_keepers; |
diff --git a/src/keeper.h b/src/keeper.h index 37922fb..60410da 100644 --- a/src/keeper.h +++ b/src/keeper.h | |||
| @@ -29,6 +29,7 @@ typedef struct s_Keepers Keepers; | |||
| 29 | void init_keepers( Universe* U, lua_State* L); | 29 | void init_keepers( Universe* U, lua_State* L); |
| 30 | void close_keepers( Universe* U, lua_State* L); | 30 | void close_keepers( Universe* U, lua_State* L); |
| 31 | 31 | ||
| 32 | Keeper* which_keeper( Keepers* keepers_, ptrdiff_t magic_); | ||
| 32 | Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_); | 33 | Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_); |
| 33 | #define KEEPER_MAGIC_SHIFT 3 | 34 | #define KEEPER_MAGIC_SHIFT 3 |
| 34 | void keeper_release( Keeper* K); | 35 | void keeper_release( Keeper* K); |
diff --git a/src/lanes.c b/src/lanes.c index c3e64fb..72f9dd6 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
| @@ -453,6 +453,34 @@ static void check_key_types( lua_State* L, int start_, int end_) | |||
| 453 | } | 453 | } |
| 454 | } | 454 | } |
| 455 | 455 | ||
| 456 | LUAG_FUNC( linda_protected_call) | ||
| 457 | { | ||
| 458 | int rc = LUA_OK; | ||
| 459 | struct s_Linda* linda = lua_toLinda( L, 1); | ||
| 460 | |||
| 461 | // acquire the keeper | ||
| 462 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED(linda)); | ||
| 463 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' | ||
| 464 | if( KL == NULL) return 0; | ||
| 465 | |||
| 466 | // retrieve the actual function to be called and move it before the arguments | ||
| 467 | lua_pushvalue( L, lua_upvalueindex( 1)); | ||
| 468 | lua_insert( L, 1); | ||
| 469 | // do a protected call | ||
| 470 | rc = lua_pcall( L, lua_gettop( L) - 1, LUA_MULTRET, 0); | ||
| 471 | |||
| 472 | // release the keeper | ||
| 473 | keeper_release( K); | ||
| 474 | |||
| 475 | // if there was an error, forward it | ||
| 476 | if( rc != LUA_OK) | ||
| 477 | { | ||
| 478 | return lua_error( L); | ||
| 479 | } | ||
| 480 | // return whatever the actual operation provided | ||
| 481 | return lua_gettop( L); | ||
| 482 | } | ||
| 483 | |||
| 456 | /* | 484 | /* |
| 457 | * bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... ) | 485 | * bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... ) |
| 458 | * | 486 | * |
| @@ -514,7 +542,7 @@ LUAG_FUNC( linda_send) | |||
| 514 | { | 542 | { |
| 515 | bool_t try_again = TRUE; | 543 | bool_t try_again = TRUE; |
| 516 | Lane* const s = get_lane_from_registry( L); | 544 | Lane* const s = get_lane_from_registry( L); |
| 517 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 545 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 518 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' | 546 | lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' |
| 519 | if( KL == NULL) return 0; | 547 | if( KL == NULL) return 0; |
| 520 | STACK_CHECK( KL); | 548 | STACK_CHECK( KL); |
| @@ -578,10 +606,8 @@ LUAG_FUNC( linda_send) | |||
| 578 | } | 606 | } |
| 579 | } | 607 | } |
| 580 | STACK_END( KL, 0); | 608 | STACK_END( KL, 0); |
| 581 | keeper_release( K); | ||
| 582 | } | 609 | } |
| 583 | 610 | ||
| 584 | // must trigger error after keeper state has been released | ||
| 585 | if( pushed < 0) | 611 | if( pushed < 0) |
| 586 | { | 612 | { |
| 587 | return luaL_error( L, "tried to copy unsupported types"); | 613 | return luaL_error( L, "tried to copy unsupported types"); |
| @@ -676,7 +702,7 @@ LUAG_FUNC( linda_receive) | |||
| 676 | { | 702 | { |
| 677 | bool_t try_again = TRUE; | 703 | bool_t try_again = TRUE; |
| 678 | Lane* const s = get_lane_from_registry( L); | 704 | Lane* const s = get_lane_from_registry( L); |
| 679 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 705 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 680 | if( K == NULL) return 0; | 706 | if( K == NULL) return 0; |
| 681 | for( ;;) | 707 | for( ;;) |
| 682 | { | 708 | { |
| @@ -735,10 +761,8 @@ LUAG_FUNC( linda_receive) | |||
| 735 | } | 761 | } |
| 736 | } | 762 | } |
| 737 | } | 763 | } |
| 738 | keeper_release( K); | ||
| 739 | } | 764 | } |
| 740 | 765 | ||
| 741 | // must trigger error after keeper state has been released | ||
| 742 | if( pushed < 0) | 766 | if( pushed < 0) |
| 743 | { | 767 | { |
| 744 | return luaL_error( L, "tried to copy unsupported types"); | 768 | return luaL_error( L, "tried to copy unsupported types"); |
| @@ -779,8 +803,7 @@ LUAG_FUNC( linda_set) | |||
| 779 | check_key_types( L, 2, 2); | 803 | check_key_types( L, 2, 2); |
| 780 | 804 | ||
| 781 | { | 805 | { |
| 782 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 806 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 783 | if( K == NULL) return 0; | ||
| 784 | 807 | ||
| 785 | if( linda->simulate_cancel == CANCEL_NONE) | 808 | if( linda->simulate_cancel == CANCEL_NONE) |
| 786 | { | 809 | { |
| @@ -813,7 +836,6 @@ LUAG_FUNC( linda_set) | |||
| 813 | push_unique_key( L, CANCEL_ERROR); | 836 | push_unique_key( L, CANCEL_ERROR); |
| 814 | pushed = 1; | 837 | pushed = 1; |
| 815 | } | 838 | } |
| 816 | keeper_release( K); | ||
| 817 | } | 839 | } |
| 818 | 840 | ||
| 819 | // must trigger any error after keeper state has been released | 841 | // must trigger any error after keeper state has been released |
| @@ -835,10 +857,8 @@ LUAG_FUNC( linda_count) | |||
| 835 | check_key_types( L, 2, lua_gettop( L)); | 857 | check_key_types( L, 2, lua_gettop( L)); |
| 836 | 858 | ||
| 837 | { | 859 | { |
| 838 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 860 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 839 | if( K == NULL) return 0; | ||
| 840 | pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2); | 861 | pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2); |
| 841 | keeper_release( K); | ||
| 842 | if( pushed < 0) | 862 | if( pushed < 0) |
| 843 | { | 863 | { |
| 844 | return luaL_error( L, "tried to count an invalid key"); | 864 | return luaL_error( L, "tried to count an invalid key"); |
| @@ -864,8 +884,7 @@ LUAG_FUNC( linda_get) | |||
| 864 | // make sure the key is of a valid type (throws an error if not the case) | 884 | // make sure the key is of a valid type (throws an error if not the case) |
| 865 | check_key_types( L, 2, 2); | 885 | check_key_types( L, 2, 2); |
| 866 | { | 886 | { |
| 867 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 887 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 868 | if( K == NULL) return 0; | ||
| 869 | 888 | ||
| 870 | if( linda->simulate_cancel == CANCEL_NONE) | 889 | if( linda->simulate_cancel == CANCEL_NONE) |
| 871 | { | 890 | { |
| @@ -881,9 +900,7 @@ LUAG_FUNC( linda_get) | |||
| 881 | push_unique_key( L, CANCEL_ERROR); | 900 | push_unique_key( L, CANCEL_ERROR); |
| 882 | pushed = 1; | 901 | pushed = 1; |
| 883 | } | 902 | } |
| 884 | keeper_release( K); | 903 | // an error can be raised if we attempt to read an unregistered function |
| 885 | // must trigger error after keeper state has been released | ||
| 886 | // (an error can be raised if we attempt to read an unregistered function) | ||
| 887 | if( pushed < 0) | 904 | if( pushed < 0) |
| 888 | { | 905 | { |
| 889 | return luaL_error( L, "tried to copy unsupported types"); | 906 | return luaL_error( L, "tried to copy unsupported types"); |
| @@ -913,8 +930,7 @@ LUAG_FUNC( linda_limit) | |||
| 913 | check_key_types( L, 2, 2); | 930 | check_key_types( L, 2, 2); |
| 914 | 931 | ||
| 915 | { | 932 | { |
| 916 | Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 933 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 917 | if( K == NULL) return 0; | ||
| 918 | 934 | ||
| 919 | if( linda->simulate_cancel == CANCEL_NONE) | 935 | if( linda->simulate_cancel == CANCEL_NONE) |
| 920 | { | 936 | { |
| @@ -932,7 +948,6 @@ LUAG_FUNC( linda_limit) | |||
| 932 | push_unique_key( L, CANCEL_ERROR); | 948 | push_unique_key( L, CANCEL_ERROR); |
| 933 | pushed = 1; | 949 | pushed = 1; |
| 934 | } | 950 | } |
| 935 | keeper_release( K); | ||
| 936 | } | 951 | } |
| 937 | // propagate pushed boolean if any | 952 | // propagate pushed boolean if any |
| 938 | return pushed; | 953 | return pushed; |
| @@ -948,15 +963,11 @@ LUAG_FUNC( linda_cancel) | |||
| 948 | { | 963 | { |
| 949 | struct s_Linda* linda = lua_toLinda( L, 1); | 964 | struct s_Linda* linda = lua_toLinda( L, 1); |
| 950 | char const* who = luaL_optstring( L, 2, "both"); | 965 | char const* who = luaL_optstring( L, 2, "both"); |
| 951 | Keeper* K; | 966 | Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 952 | 967 | ||
| 953 | // make sure we got 3 arguments: the linda, a key and a limit | 968 | // make sure we got 3 arguments: the linda, a key and a limit |
| 954 | luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments"); | 969 | luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments"); |
| 955 | 970 | ||
| 956 | // signalling must be done from inside the K locking area | ||
| 957 | K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | ||
| 958 | if( K == NULL) return 0; | ||
| 959 | |||
| 960 | linda->simulate_cancel = CANCEL_SOFT; | 971 | linda->simulate_cancel = CANCEL_SOFT; |
| 961 | if( strcmp( who, "both") == 0) // tell everyone writers to wake up | 972 | if( strcmp( who, "both") == 0) // tell everyone writers to wake up |
| 962 | { | 973 | { |
| @@ -977,14 +988,6 @@ LUAG_FUNC( linda_cancel) | |||
| 977 | } | 988 | } |
| 978 | else | 989 | else |
| 979 | { | 990 | { |
| 980 | // error ... | ||
| 981 | linda = NULL; | ||
| 982 | } | ||
| 983 | keeper_release( K); | ||
| 984 | |||
| 985 | // ... but we must raise it outside the lock | ||
| 986 | if( !linda) | ||
| 987 | { | ||
| 988 | return luaL_error( L, "unknown wake hint '%s'", who); | 991 | return luaL_error( L, "unknown wake hint '%s'", who); |
| 989 | } | 992 | } |
| 990 | return 0; | 993 | return 0; |
| @@ -1184,18 +1187,16 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
| 1184 | struct s_Linda* linda = lua_touserdata( L, 1); | 1187 | struct s_Linda* linda = lua_touserdata( L, 1); |
| 1185 | ASSERT_L( linda); | 1188 | ASSERT_L( linda); |
| 1186 | 1189 | ||
| 1187 | /* Clean associated structures in the keeper state. | 1190 | // Clean associated structures in the keeper state. |
| 1188 | */ | ||
| 1189 | K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); | 1191 | K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); |
| 1190 | if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) | 1192 | if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) |
| 1191 | { | 1193 | { |
| 1194 | // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... | ||
| 1192 | keeper_call( linda->U, K->L, KEEPER_API( clear), L, linda, 0); | 1195 | keeper_call( linda->U, K->L, KEEPER_API( clear), L, linda, 0); |
| 1193 | } | 1196 | } |
| 1194 | keeper_release( K); | 1197 | keeper_release( K); |
| 1195 | 1198 | ||
| 1196 | /* There aren't any lanes waiting on these lindas, since all proxies | 1199 | // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right? |
| 1197 | * have been gc'ed. Right? | ||
| 1198 | */ | ||
| 1199 | SIGNAL_FREE( &linda->read_happened); | 1200 | SIGNAL_FREE( &linda->read_happened); |
| 1200 | SIGNAL_FREE( &linda->write_happened); | 1201 | SIGNAL_FREE( &linda->write_happened); |
| 1201 | free( linda); | 1202 | free( linda); |
| @@ -1225,34 +1226,46 @@ static void* linda_id( lua_State* L, DeepOp op_) | |||
| 1225 | lua_pushcfunction( L, LG_linda_concat); | 1226 | lua_pushcfunction( L, LG_linda_concat); |
| 1226 | lua_setfield( L, -2, "__concat"); | 1227 | lua_setfield( L, -2, "__concat"); |
| 1227 | 1228 | ||
| 1228 | // [-1]: linda metatable | 1229 | // protected calls, to ensure associated keeper is always released even in case of error |
| 1230 | // all function are the protected call wrapper, where the actual operation is provided as upvalue | ||
| 1231 | // note that this kind of thing can break function lookup as we use the function pointer here and there | ||
| 1232 | |||
| 1229 | lua_pushcfunction( L, LG_linda_send); | 1233 | lua_pushcfunction( L, LG_linda_send); |
| 1234 | lua_pushcclosure( L, LG_linda_protected_call, 1); | ||
| 1230 | lua_setfield( L, -2, "send"); | 1235 | lua_setfield( L, -2, "send"); |
| 1231 | 1236 | ||
| 1232 | lua_pushcfunction( L, LG_linda_receive); | 1237 | lua_pushcfunction( L, LG_linda_receive); |
| 1238 | lua_pushcclosure( L, LG_linda_protected_call, 1); | ||
| 1233 | lua_setfield( L, -2, "receive"); | 1239 | lua_setfield( L, -2, "receive"); |
| 1234 | 1240 | ||
| 1235 | lua_pushcfunction( L, LG_linda_limit); | 1241 | lua_pushcfunction( L, LG_linda_limit); |
| 1242 | lua_pushcclosure( L, LG_linda_protected_call, 1); | ||
| 1236 | lua_setfield( L, -2, "limit"); | 1243 | lua_setfield( L, -2, "limit"); |
| 1237 | 1244 | ||
| 1238 | lua_pushcfunction( L, LG_linda_set); | 1245 | lua_pushcfunction( L, LG_linda_set); |
| 1246 | lua_pushcclosure( L, LG_linda_protected_call, 1); | ||
| 1239 | lua_setfield( L, -2, "set"); | 1247 | lua_setfield( L, -2, "set"); |
| 1240 | 1248 | ||
| 1241 | lua_pushcfunction( L, LG_linda_count); | 1249 | lua_pushcfunction( L, LG_linda_count); |
| 1250 | lua_pushcclosure( L, LG_linda_protected_call, 1); | ||
| 1242 | lua_setfield( L, -2, "count"); | 1251 | lua_setfield( L, -2, "count"); |
| 1243 | 1252 | ||
| 1244 | lua_pushcfunction( L, LG_linda_get); | 1253 | lua_pushcfunction( L, LG_linda_get); |
| 1254 | lua_pushcclosure( L, LG_linda_protected_call, 1); | ||
| 1245 | lua_setfield( L, -2, "get"); | 1255 | lua_setfield( L, -2, "get"); |
| 1246 | 1256 | ||
| 1247 | lua_pushcfunction( L, LG_linda_cancel); | 1257 | lua_pushcfunction( L, LG_linda_cancel); |
| 1258 | lua_pushcclosure( L, LG_linda_protected_call, 1); | ||
| 1248 | lua_setfield( L, -2, "cancel"); | 1259 | lua_setfield( L, -2, "cancel"); |
| 1249 | 1260 | ||
| 1250 | lua_pushcfunction( L, LG_linda_deep); | 1261 | lua_pushcfunction( L, LG_linda_deep); |
| 1251 | lua_setfield( L, -2, "deep"); | 1262 | lua_setfield( L, -2, "deep"); |
| 1252 | 1263 | ||
| 1253 | lua_pushcfunction( L, LG_linda_dump); | 1264 | lua_pushcfunction( L, LG_linda_dump); |
| 1265 | lua_pushcclosure( L, LG_linda_protected_call, 1); | ||
| 1254 | lua_setfield( L, -2, "dump"); | 1266 | lua_setfield( L, -2, "dump"); |
| 1255 | 1267 | ||
| 1268 | // some constants | ||
| 1256 | lua_pushliteral( L, BATCH_SENTINEL); | 1269 | lua_pushliteral( L, BATCH_SENTINEL); |
| 1257 | lua_setfield(L, -2, "batched"); | 1270 | lua_setfield(L, -2, "batched"); |
| 1258 | 1271 | ||
| @@ -2074,13 +2087,14 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs) | |||
| 2074 | // But don't register it in the lookup database because of the s_lane pointer upvalue | 2087 | // But don't register it in the lookup database because of the s_lane pointer upvalue |
| 2075 | lua_pushlightuserdata( L, s); | 2088 | lua_pushlightuserdata( L, s); |
| 2076 | lua_pushcclosure( L, LG_set_debug_threadname, 1); | 2089 | lua_pushcclosure( L, LG_set_debug_threadname, 1); |
| 2077 | lua_setglobal( L, "set_debug_threadname" ); | 2090 | lua_setglobal( L, "set_debug_threadname"); |
| 2078 | 2091 | ||
| 2079 | // Tie "cancel_test()" to the state | 2092 | // Tie "cancel_test()" to the state |
| 2080 | lua_pushcfunction( L, LG_cancel_test); | 2093 | lua_pushcfunction( L, LG_cancel_test); |
| 2081 | populate_func_lookup_table( L, -1, "cancel_test"); | 2094 | populate_func_lookup_table( L, -1, "cancel_test"); |
| 2082 | lua_setglobal( L, "cancel_test"); | 2095 | lua_setglobal( L, "cancel_test"); |
| 2083 | 2096 | ||
| 2097 | // this could be done in lane_new before the lane body function is pushed on the stack to avoid unnecessary stack slot shifting around | ||
| 2084 | #if ERROR_FULL_STACK | 2098 | #if ERROR_FULL_STACK |
| 2085 | // Tie "set_error_reporting()" to the state | 2099 | // Tie "set_error_reporting()" to the state |
| 2086 | lua_pushcfunction( L, LG_set_error_reporting); | 2100 | lua_pushcfunction( L, LG_set_error_reporting); |
| @@ -2654,7 +2668,10 @@ LUAG_FUNC( thread_join) | |||
| 2654 | bool_t done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status); | 2668 | bool_t done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status); |
| 2655 | if( !done || !L2) | 2669 | if( !done || !L2) |
| 2656 | { | 2670 | { |
| 2657 | return 0; // timeout: pushes none, leaves 'L2' alive | 2671 | STACK_GROW( L, 2); |
| 2672 | lua_pushnil( L); | ||
| 2673 | lua_pushliteral( L, "timeout"); | ||
| 2674 | return 2; | ||
| 2658 | } | 2675 | } |
| 2659 | 2676 | ||
| 2660 | STACK_CHECK( L); | 2677 | STACK_CHECK( L); |
