diff options
Diffstat (limited to 'src/keeper.c')
-rw-r--r-- | src/keeper.c | 83 |
1 files changed, 60 insertions, 23 deletions
diff --git a/src/keeper.c b/src/keeper.c index 8aa734a..a1505b7 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -122,7 +122,7 @@ static void fifo_push( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | |||
122 | static void fifo_peek( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | 122 | static void fifo_peek( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) |
123 | { | 123 | { |
124 | lua_Integer i; | 124 | lua_Integer i; |
125 | STACK_GROW( L, count_); | 125 | STACK_GROW( L, (int) count_); |
126 | for( i = 0; i < count_; ++ i) | 126 | for( i = 0; i < count_; ++ i) |
127 | { | 127 | { |
128 | lua_rawgeti( L, 1, (int)( fifo_->first + i)); | 128 | lua_rawgeti( L, 1, (int)( fifo_->first + i)); |
@@ -136,7 +136,7 @@ static void fifo_pop( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | |||
136 | int const fifo_idx = lua_gettop( L); // ... fifo | 136 | int const fifo_idx = lua_gettop( L); // ... fifo |
137 | int i; | 137 | int i; |
138 | // each iteration pushes a value on the stack! | 138 | // each iteration pushes a value on the stack! |
139 | STACK_GROW( L, count_ + 2); | 139 | STACK_GROW( L, (int) count_ + 2); |
140 | // skip first item, we will push it last | 140 | // skip first item, we will push it last |
141 | for( i = 1; i < count_; ++ i) | 141 | for( i = 1; i < count_; ++ i) |
142 | { | 142 | { |
@@ -169,7 +169,7 @@ static void fifo_pop( lua_State* L, keeper_fifo* fifo_, lua_Integer count_) | |||
169 | static DECLARE_CONST_UNIQUE_KEY( FIFOS_KEY, 0xdce50bbc351cd465); | 169 | static DECLARE_CONST_UNIQUE_KEY( FIFOS_KEY, 0xdce50bbc351cd465); |
170 | static void push_table( lua_State* L, int idx_) | 170 | static void push_table( lua_State* L, int idx_) |
171 | { | 171 | { |
172 | STACK_GROW( L, 4); | 172 | STACK_GROW( L, 5); |
173 | STACK_CHECK( L, 0); | 173 | STACK_CHECK( L, 0); |
174 | idx_ = lua_absindex( L, idx_); | 174 | idx_ = lua_absindex( L, idx_); |
175 | REGISTRY_GET( L, FIFOS_KEY); // ud fifos | 175 | REGISTRY_GET( L, FIFOS_KEY); // ud fifos |
@@ -189,7 +189,7 @@ static void push_table( lua_State* L, int idx_) | |||
189 | STACK_END( L, 1); | 189 | STACK_END( L, 1); |
190 | } | 190 | } |
191 | 191 | ||
192 | int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) | 192 | int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, uintptr_t magic_) |
193 | { | 193 | { |
194 | Keeper* const K = which_keeper( U->keepers, magic_); | 194 | Keeper* const K = which_keeper( U->keepers, magic_); |
195 | lua_State* const KL = K ? K->L : NULL; | 195 | lua_State* const KL = K ? K->L : NULL; |
@@ -557,7 +557,7 @@ int keepercall_count( lua_State* L) | |||
557 | { | 557 | { |
558 | lua_pop( L, 1); // out fifos keys | 558 | lua_pop( L, 1); // out fifos keys |
559 | } | 559 | } |
560 | } | 560 | } // all keys are exhausted // out fifos |
561 | lua_pop( L, 1); // out | 561 | lua_pop( L, 1); // out |
562 | } | 562 | } |
563 | ASSERT_L( lua_gettop( L) == 1); | 563 | ASSERT_L( lua_gettop( L) == 1); |
@@ -633,6 +633,7 @@ void init_keepers( Universe* U, lua_State* L) | |||
633 | { | 633 | { |
634 | int i; | 634 | int i; |
635 | int nb_keepers; | 635 | int nb_keepers; |
636 | int keepers_gc_threshold; | ||
636 | 637 | ||
637 | STACK_CHECK( L, 0); // L K | 638 | STACK_CHECK( L, 0); // L K |
638 | lua_getfield( L, 1, "nb_keepers"); // nb_keepers | 639 | lua_getfield( L, 1, "nb_keepers"); // nb_keepers |
@@ -642,6 +643,12 @@ void init_keepers( Universe* U, lua_State* L) | |||
642 | { | 643 | { |
643 | (void) luaL_error( L, "Bad number of keepers (%d)", nb_keepers); | 644 | (void) luaL_error( L, "Bad number of keepers (%d)", nb_keepers); |
644 | } | 645 | } |
646 | STACK_MID(L, 0); | ||
647 | |||
648 | lua_getfield(L, 1, "keepers_gc_threshold"); // keepers_gc_threshold | ||
649 | keepers_gc_threshold = (int) lua_tointeger(L, -1); | ||
650 | lua_pop(L, 1); // | ||
651 | STACK_MID(L, 0); | ||
645 | 652 | ||
646 | // Keepers contains an array of 1 s_Keeper, adjust for the actual number of keeper states | 653 | // Keepers contains an array of 1 s_Keeper, adjust for the actual number of keeper states |
647 | { | 654 | { |
@@ -656,6 +663,7 @@ void init_keepers( Universe* U, lua_State* L) | |||
656 | return; | 663 | return; |
657 | } | 664 | } |
658 | memset( U->keepers, 0, bytes); | 665 | memset( U->keepers, 0, bytes); |
666 | U->keepers->gc_threshold = keepers_gc_threshold; | ||
659 | U->keepers->nb_keepers = nb_keepers; | 667 | U->keepers->nb_keepers = nb_keepers; |
660 | } | 668 | } |
661 | for( i = 0; i < nb_keepers; ++ i) // keepersUD | 669 | for( i = 0; i < nb_keepers; ++ i) // keepersUD |
@@ -669,10 +677,12 @@ void init_keepers( Universe* U, lua_State* L) | |||
669 | } | 677 | } |
670 | 678 | ||
671 | U->keepers->keeper_array[i].L = K; | 679 | U->keepers->keeper_array[i].L = K; |
672 | // we can trigger a GC from inside keeper_call(), where a keeper is acquired | 680 | MUTEX_INIT( &U->keepers->keeper_array[i].keeper_cs); |
673 | // from there, GC can collect a linda, which would acquire the keeper again, and deadlock the thread. | 681 | |
674 | // therefore, we need a recursive mutex. | 682 | if (U->keepers->gc_threshold >= 0) |
675 | MUTEX_RECURSIVE_INIT( &U->keepers->keeper_array[i].keeper_cs); | 683 | { |
684 | lua_gc(K, LUA_GCSTOP, 0); | ||
685 | } | ||
676 | 686 | ||
677 | STACK_CHECK( K, 0); | 687 | STACK_CHECK( K, 0); |
678 | 688 | ||
@@ -693,7 +703,7 @@ void init_keepers( Universe* U, lua_State* L) | |||
693 | if( !lua_isnil( L, -1)) | 703 | if( !lua_isnil( L, -1)) |
694 | { | 704 | { |
695 | // when copying with mode eLM_ToKeeper, error message is pushed at the top of the stack, not raised immediately | 705 | // when copying with mode eLM_ToKeeper, error message is pushed at the top of the stack, not raised immediately |
696 | if( luaG_inter_copy_package( U, L, K, -1, eLM_ToKeeper)) | 706 | if( luaG_inter_copy_package( U, L, K, -1, eLM_ToKeeper) != eICR_Success) |
697 | { | 707 | { |
698 | // if something went wrong, the error message is at the top of the stack | 708 | // if something went wrong, the error message is at the top of the stack |
699 | lua_remove( L, -2); // error_msg | 709 | lua_remove( L, -2); // error_msg |
@@ -721,22 +731,22 @@ void init_keepers( Universe* U, lua_State* L) | |||
721 | } | 731 | } |
722 | 732 | ||
723 | // should be called only when inside a keeper_acquire/keeper_release pair (see linda_protected_call) | 733 | // should be called only when inside a keeper_acquire/keeper_release pair (see linda_protected_call) |
724 | Keeper* which_keeper(Keepers* keepers_, ptrdiff_t magic_) | 734 | Keeper* which_keeper(Keepers* keepers_, uintptr_t magic_) |
725 | { | 735 | { |
726 | int const nbKeepers = keepers_->nb_keepers; | 736 | int const nbKeepers = keepers_->nb_keepers; |
727 | unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); | 737 | if (nbKeepers) |
728 | return &keepers_->keeper_array[i]; | 738 | { |
739 | unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers); | ||
740 | return &keepers_->keeper_array[i]; | ||
741 | } | ||
742 | return NULL; | ||
729 | } | 743 | } |
730 | 744 | ||
731 | Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) | 745 | Keeper* keeper_acquire( Keepers* keepers_, uintptr_t magic_) |
732 | { | 746 | { |
733 | int const nbKeepers = keepers_->nb_keepers; | 747 | int const nbKeepers = keepers_->nb_keepers; |
734 | // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) | 748 | // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers) |
735 | if( nbKeepers == 0) | 749 | if( nbKeepers) |
736 | { | ||
737 | return NULL; | ||
738 | } | ||
739 | else | ||
740 | { | 750 | { |
741 | /* | 751 | /* |
742 | * Any hashing will do that maps pointers to 0..GNbKeepers-1 | 752 | * Any hashing will do that maps pointers to 0..GNbKeepers-1 |
@@ -752,12 +762,13 @@ Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) | |||
752 | //++ K->count; | 762 | //++ K->count; |
753 | return K; | 763 | return K; |
754 | } | 764 | } |
765 | return NULL; | ||
755 | } | 766 | } |
756 | 767 | ||
757 | void keeper_release( Keeper* K) | 768 | void keeper_release( Keeper* K_) |
758 | { | 769 | { |
759 | //-- K->count; | 770 | //-- K->count; |
760 | if( K) MUTEX_UNLOCK( &K->keeper_cs); | 771 | if( K_) MUTEX_UNLOCK( &K_->keeper_cs); |
761 | } | 772 | } |
762 | 773 | ||
763 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mode_) | 774 | void keeper_toggle_nil_sentinels( lua_State* L, int val_i_, LookupMode const mode_) |
@@ -805,7 +816,7 @@ int keeper_call( Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, vo | |||
805 | 816 | ||
806 | lua_pushlightuserdata( K, linda); | 817 | lua_pushlightuserdata( K, linda); |
807 | 818 | ||
808 | if( (args == 0) || luaG_inter_copy( U, L, K, args, eLM_ToKeeper) == 0) // L->K | 819 | if( (args == 0) || luaG_inter_copy( U, L, K, args, eLM_ToKeeper) == eICR_Success) // L->K |
809 | { | 820 | { |
810 | lua_call( K, 1 + args, LUA_MULTRET); | 821 | lua_call( K, 1 + args, LUA_MULTRET); |
811 | 822 | ||
@@ -814,12 +825,38 @@ int keeper_call( Universe* U, lua_State* K, keeper_api_t func_, lua_State* L, vo | |||
814 | // this may interrupt a lane, causing the destruction of the underlying OS thread | 825 | // this may interrupt a lane, causing the destruction of the underlying OS thread |
815 | // after this, another lane making use of this keeper can get an error code from the mutex-locking function | 826 | // after this, another lane making use of this keeper can get an error code from the mutex-locking function |
816 | // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) | 827 | // when attempting to grab the mutex again (WINVER <= 0x400 does this, but locks just fine, I don't know about pthread) |
817 | if( (retvals > 0) && luaG_inter_move( U, K, L, retvals, eLM_FromKeeper) != 0) // K->L | 828 | if( (retvals > 0) && luaG_inter_move( U, K, L, retvals, eLM_FromKeeper) != eICR_Success) // K->L |
818 | { | 829 | { |
819 | retvals = -1; | 830 | retvals = -1; |
820 | } | 831 | } |
821 | } | 832 | } |
822 | // whatever happens, restore the stack to where it was at the origin | 833 | // whatever happens, restore the stack to where it was at the origin |
823 | lua_settop( K, Ktos); | 834 | lua_settop( K, Ktos); |
835 | |||
836 | |||
837 | // don't do this for this particular function, as it is only called during Linda destruction, and we don't want to raise an error, ever | ||
838 | if (func_ != KEEPER_API(clear)) | ||
839 | { | ||
840 | // since keeper state GC is stopped, let's run a step once in a while if required | ||
841 | int const gc_threshold = U->keepers->gc_threshold; | ||
842 | if (gc_threshold == 0) | ||
843 | { | ||
844 | lua_gc(K, LUA_GCSTEP, 0); | ||
845 | } | ||
846 | else if (gc_threshold > 0) | ||
847 | { | ||
848 | int const gc_usage = lua_gc(K, LUA_GCCOUNT, 0); | ||
849 | if (gc_usage >= gc_threshold) | ||
850 | { | ||
851 | lua_gc(K, LUA_GCCOLLECT, 0); | ||
852 | int const gc_usage_after = lua_gc(K, LUA_GCCOUNT, 0); | ||
853 | if (gc_usage_after > gc_threshold) | ||
854 | { | ||
855 | luaL_error(L, "Keeper GC threshold is too low, need at least %d", gc_usage_after); | ||
856 | } | ||
857 | } | ||
858 | } | ||
859 | } | ||
860 | |||
824 | return retvals; | 861 | return retvals; |
825 | } | 862 | } |