aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2018-11-08 17:32:05 +0100
committerBenoit Germain <bnt.germain@gmail.com>2018-11-08 17:32:05 +0100
commit0cc1c9c9dcea5955f7dab921d9a2fff78c4e1729 (patch)
tree5c35acf11087f9b60b24599695f1d3c348ebaa25 /src
parenta142eb1e1ee81919d10b55bb7fa2e33636098d85 (diff)
downloadlanes-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.c11
-rw-r--r--src/keeper.h1
-rw-r--r--src/lanes.c99
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
189int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) 189int 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)
718Keeper* 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
718Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) 725Keeper* 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;
29void init_keepers( Universe* U, lua_State* L); 29void init_keepers( Universe* U, lua_State* L);
30void close_keepers( Universe* U, lua_State* L); 30void close_keepers( Universe* U, lua_State* L);
31 31
32Keeper* which_keeper( Keepers* keepers_, ptrdiff_t magic_);
32Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_); 33Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_);
33#define KEEPER_MAGIC_SHIFT 3 34#define KEEPER_MAGIC_SHIFT 3
34void keeper_release( Keeper* K); 35void 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
456LUAG_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);