aboutsummaryrefslogtreecommitdiff
path: root/src/tools.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt period germain arrobase gmail period com>2014-06-17 16:34:31 +0200
committerBenoit Germain <bnt period germain arrobase gmail period com>2014-06-17 16:34:31 +0200
commit77630de350fc89038378c798cd482ed751280fc2 (patch)
treef804d15dab8cd6ba1d57508719e738c12327eba9 /src/tools.c
parent55e53f8a24ce42cadfd2887e50bf0248eb10d301 (diff)
downloadlanes-77630de350fc89038378c798cd482ed751280fc2.tar.gz
lanes-77630de350fc89038378c798cd482ed751280fc2.tar.bz2
lanes-77630de350fc89038378c798cd482ed751280fc2.zip
Deep userdata changes
* bumped version to 3.9.6 * separate deep userdata code in a dedicated file to allow external modules to implement Lanes-compatible deep userdata without requiring a binary dependency against the Lanes module. because of this linda_id function(eDO_metatable) must push 2 values on the stack: a metatable and a deep version string obtained from luaG_pushdeepversion()
Diffstat (limited to 'src/tools.c')
-rw-r--r--src/tools.c472
1 files changed, 4 insertions, 468 deletions
diff --git a/src/tools.c b/src/tools.c
index becf31e..628b277 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -44,6 +44,10 @@ THE SOFTWARE.
44#include <malloc.h> 44#include <malloc.h>
45#endif 45#endif
46 46
47// functions implemented in deep.c
48extern luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int index, enum eLookupMode mode_);
49extern void push_registry_subtable( lua_State* L, void* key_);
50
47void* const UNIVERSE_REGKEY = (void*) luaopen_lanes_core; 51void* const UNIVERSE_REGKEY = (void*) luaopen_lanes_core;
48 52
49/* 53/*
@@ -708,477 +712,9 @@ lua_State* luaG_newstate( struct s_Universe* U, lua_State* from_, char const* li
708 712
709 713
710 714
711/*---=== Deep userdata ===---*/
712
713/* The deep portion must be allocated separately of any Lua state's; it's
714* lifespan may be longer than that of the creating state.
715*/
716#define DEEP_MALLOC malloc
717#define DEEP_FREE free
718
719/*
720* 'registry[REGKEY]' is a two-way lookup table for 'idfunc's and those type's
721* metatables:
722*
723* metatable -> idfunc
724* idfunc -> metatable
725*/
726#define DEEP_LOOKUP_KEY ((void*)set_deep_lookup)
727 // any unique light userdata
728
729
730/*
731* The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying
732*/
733#define DEEP_PROXY_CACHE_KEY ((void*)push_deep_proxy)
734
735static void push_registry_subtable_mode( lua_State *L, void *token, const char* mode );
736static void push_registry_subtable( lua_State *L, void *token );
737
738/*
739* Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists.
740* Pops the both values off the stack.
741*/
742static void set_deep_lookup( lua_State* L)
743{
744 STACK_GROW( L, 3);
745 STACK_CHECK( L); // a b
746 push_registry_subtable( L, DEEP_LOOKUP_KEY); // a b {}
747 STACK_MID( L, 1);
748 lua_insert( L, -3); // {} a b
749 lua_pushvalue( L, -1); // {} a b b
750 lua_pushvalue( L,-3); // {} a b b a
751 lua_rawset( L, -5); // {} a b
752 lua_rawset( L, -3); // {}
753 lua_pop( L, 1); //
754 STACK_END( L, -2);
755}
756
757/*
758* Pops the key (metatable or idfunc) off the stack, and replaces with the
759* deep lookup value (idfunc/metatable/nil).
760*/
761static void get_deep_lookup( lua_State* L)
762{
763 STACK_GROW( L, 1);
764 STACK_CHECK( L); // a
765 lua_pushlightuserdata( L, DEEP_LOOKUP_KEY); // a DLK
766 lua_rawget( L, LUA_REGISTRYINDEX); // a {}
767
768 if( !lua_isnil( L, -1))
769 {
770 lua_insert( L, -2); // {} a
771 lua_rawget( L, -2); // {} b
772 }
773 lua_remove( L, -2); // a|b
774 STACK_END( L, 0);
775}
776
777/*
778* Return the registered ID function for 'index' (deep userdata proxy),
779* or NULL if 'index' is not a deep userdata proxy.
780*/
781static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupMode mode_)
782{
783 // when looking inside a keeper, we are 100% sure the object is a deep userdata
784 if( mode_ == eLM_FromKeeper)
785 {
786 DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, index);
787 // we can (and must) cast and fetch the internally stored idfunc
788 return (*proxy)->idfunc;
789 }
790 else
791 {
792 // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/idfunc database
793 // it is the only way to ensure that the userdata is indeed a deep userdata!
794 // of course, we could just trust the caller, but we won't
795 luaG_IdFunction ret;
796 STACK_GROW( L, 1);
797 STACK_CHECK( L);
798
799 if( !lua_getmetatable( L, index)) // deep ... metatable?
800 {
801 return NULL; // no metatable: can't be a deep userdata object!
802 }
803
804 // replace metatable with the idfunc pointer, if it is actually a deep userdata
805 get_deep_lookup( L); // deep ... idfunc|nil
806
807 ret = (luaG_IdFunction) lua_touserdata( L, -1); // NULL if not a userdata
808 lua_pop( L, 1);
809 STACK_END( L, 0);
810 return ret;
811 }
812}
813
814
815void free_deep_prelude( lua_State* L, DEEP_PRELUDE* prelude_)
816{
817 // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup
818 lua_pushlightuserdata( L, prelude_->deep);
819 ASSERT_L( prelude_->idfunc);
820 prelude_->idfunc( L, eDO_delete);
821 DEEP_FREE( (void*) prelude_);
822}
823
824
825/*
826* void= mt.__gc( proxy_ud )
827*
828* End of life for a proxy object; reduce the deep reference count and clean
829* it up if reaches 0.
830*/
831static int deep_userdata_gc( lua_State* L)
832{
833 DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, 1);
834 DEEP_PRELUDE* p = *proxy;
835 struct s_Universe* U = get_universe( L);
836 int v;
837
838 *proxy = 0; // make sure we don't use it any more
839
840 MUTEX_LOCK( &U->deep_lock);
841 v = -- (p->refcount);
842 MUTEX_UNLOCK( &U->deep_lock);
843
844 if( v == 0)
845 {
846 // 'idfunc' expects a clean stack to work on
847 lua_settop( L, 0);
848 free_deep_prelude( L, p);
849
850 // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything!
851 if ( lua_gettop( L) > 1)
852 {
853 luaL_error( L, "Bad idfunc(eDO_delete): should not push anything");
854 }
855 }
856 return 0;
857}
858
859
860/*
861 * Push a proxy userdata on the stack.
862 * returns NULL if ok, else some error string related to bad idfunc behavior or module require problem
863 * (error cannot happen with mode_ == eLM_ToKeeper)
864 *
865 * Initializes necessary structures if it's the first time 'idfunc' is being
866 * used in this Lua state (metatable, registring it). Otherwise, increments the
867 * reference count.
868 */
869char const* push_deep_proxy( struct s_Universe* U, lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_)
870{
871 DEEP_PRELUDE** proxy;
872
873 // Check if a proxy already exists
874 push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC
875 lua_pushlightuserdata( L, prelude->deep); // DPC deep
876 lua_rawget( L, -2); // DPC proxy
877 if ( !lua_isnil( L, -1))
878 {
879 lua_remove( L, -2); // proxy
880 return NULL;
881 }
882 else
883 {
884 lua_pop( L, 1); // DPC
885 }
886
887 MUTEX_LOCK( &U->deep_lock);
888 ++ (prelude->refcount); // one more proxy pointing to this deep data
889 MUTEX_UNLOCK( &U->deep_lock);
890
891 STACK_GROW( L, 7);
892 STACK_CHECK( L);
893
894 proxy = lua_newuserdata( L, sizeof( DEEP_PRELUDE*)); // DPC proxy
895 ASSERT_L( proxy);
896 *proxy = prelude;
897
898 // Get/create metatable for 'idfunc' (in this state)
899 lua_pushlightuserdata( L, prelude->idfunc); // DPC proxy idfunc
900 get_deep_lookup( L); // DPC proxy metatable?
901
902 if( lua_isnil( L, -1)) // // No metatable yet.
903 {
904 char const* modname;
905 int oldtop = lua_gettop( L); // DPC proxy nil
906 lua_pop( L, 1); // DPC proxy
907 // 1 - make one and register it
908 if( mode_ != eLM_ToKeeper)
909 {
910 prelude->idfunc( L, eDO_metatable); // DPC proxy metatable
911 if( lua_gettop( L) - oldtop != 0 || !lua_istable( L, -1))
912 {
913 lua_pop( L, 3); //
914 return "Bad idfunc(eOP_metatable): unexpected pushed value";
915 }
916 // make sure the idfunc didn't export __gc, as we will store our own
917 lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc
918 if( !lua_isnil( L, -1))
919 {
920 lua_pop( L, 4); //
921 return "idfunc-created metatable shouldn't contain __gc";
922 }
923 lua_pop( L, 1); // DPC proxy metatable
924 }
925 else
926 {
927 // keepers need a minimal metatable that only contains __gc
928 lua_newtable( L); // DPC proxy metatable
929 }
930 // Add our own '__gc' method
931 lua_pushcfunction( L, deep_userdata_gc); // DPC proxy metatable __gc
932 lua_setfield( L, -2, "__gc"); // DPC proxy metatable
933
934 // Memorize for later rounds
935 lua_pushvalue( L, -1); // DPC proxy metatable metatable
936 lua_pushlightuserdata( L, prelude->idfunc); // DPC proxy metatable metatable idfunc
937 set_deep_lookup( L); // DPC proxy metatable
938
939 // 2 - cause the target state to require the module that exported the idfunc
940 // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc
941 {
942 int oldtop = lua_gettop( L);
943 modname = (char const*) prelude->idfunc( L, eDO_module); // DPC proxy metatable
944 // make sure the function pushed nothing on the stack!
945 if( lua_gettop( L) - oldtop != 0)
946 {
947 lua_pop( L, 3); //
948 return "Bad idfunc(eOP_module): should not push anything";
949 }
950 }
951 if( modname) // we actually got a module name
952 {
953 // somehow, L.registry._LOADED can exist without having registered the 'package' library.
954 lua_getglobal( L, "require"); // DPC proxy metatable require()
955 // check that the module is already loaded (or being loaded, we are happy either way)
956 if( lua_isfunction( L, -1))
957 {
958 lua_pushstring( L, modname); // DPC proxy metatable require() "module"
959 lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED"); // DPC proxy metatable require() "module" _R._LOADED
960 if( lua_istable( L, -1))
961 {
962 bool_t alreadyloaded;
963 lua_pushvalue( L, -2); // DPC proxy metatable require() "module" _R._LOADED "module"
964 lua_rawget( L, -2); // DPC proxy metatable require() "module" _R._LOADED module
965 alreadyloaded = lua_toboolean( L, -1);
966 if( !alreadyloaded) // not loaded
967 {
968 int require_result;
969 lua_pop( L, 2); // DPC proxy metatable require() "module"
970 // require "modname"
971 require_result = lua_pcall( L, 1, 0, 0); // DPC proxy metatable error?
972 if( require_result != LUA_OK)
973 {
974 // failed, return the error message
975 lua_pushfstring( L, "error while requiring '%s' identified by idfunc(eOP_module): ", modname);
976 lua_insert( L, -2); // DPC proxy metatable prefix error
977 lua_concat( L, 2); // DPC proxy metatable error
978 return lua_tostring( L, -1);
979 }
980 }
981 else // already loaded, we are happy
982 {
983 lua_pop( L, 4); // DPC proxy metatable
984 }
985 }
986 else // no L.registry._LOADED; can this ever happen?
987 {
988 lua_pop( L, 6); //
989 return "unexpected error while requiring a module identified by idfunc(eOP_module)";
990 }
991 }
992 else // a module name, but no require() function :-(
993 {
994 lua_pop( L, 4); //
995 return "lanes receiving deep userdata should register the 'package' library";
996 }
997 }
998 }
999 STACK_MID( L, 2); // DPC proxy metatable
1000 ASSERT_L( lua_isuserdata( L, -2));
1001 ASSERT_L( lua_istable( L, -1));
1002 lua_setmetatable( L, -2); // DPC proxy
1003
1004 // If we're here, we obviously had to create a new proxy, so cache it.
1005 lua_pushlightuserdata( L, (*proxy)->deep); // DPC proxy deep
1006 lua_pushvalue( L, -2); // DPC proxy deep proxy
1007 lua_rawset( L, -4); // DPC proxy
1008 lua_remove( L, -2); // proxy
1009 ASSERT_L( lua_isuserdata( L, -1));
1010 STACK_END( L, 0);
1011 return NULL;
1012}
1013
1014
1015/*
1016* Create a deep userdata
1017*
1018* proxy_ud= deep_userdata( idfunc [, ...] )
1019*
1020* Creates a deep userdata entry of the type defined by 'idfunc'.
1021* Other parameters are passed on to the 'idfunc' "new" invocation.
1022*
1023* 'idfunc' must fulfill the following features:
1024*
1025* lightuserdata = idfunc( eDO_new [, ...] ) -- creates a new deep data instance
1026* void = idfunc( eDO_delete, lightuserdata ) -- releases a deep data instance
1027* tbl = idfunc( eDO_metatable ) -- gives metatable for userdata proxies
1028*
1029* Reference counting and true userdata proxying are taken care of for the
1030* actual data type.
1031*
1032* Types using the deep userdata system (and only those!) can be passed between
1033* separate Lua states via 'luaG_inter_move()'.
1034*
1035* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()'
1036*/
1037int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc)
1038{
1039 char const* errmsg;
1040 DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(DEEP_PRELUDE));
1041 if( prelude == NULL)
1042 {
1043 return luaL_error( L, "couldn't not allocate deep prelude: out of memory");
1044 }
1045
1046 prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1
1047 prelude->idfunc = idfunc;
1048
1049 STACK_GROW( L, 1);
1050 STACK_CHECK( L);
1051 {
1052 int oldtop = lua_gettop( L);
1053 prelude->deep = idfunc( L, eDO_new);
1054 if( prelude->deep == NULL)
1055 {
1056 luaL_error( L, "idfunc(eDO_new) failed to create deep userdata (out of memory)");
1057 }
1058
1059 if( lua_gettop( L) - oldtop != 0)
1060 {
1061 luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack");
1062 }
1063 }
1064 errmsg = push_deep_proxy( get_universe( L), L, prelude, eLM_LaneBody); // proxy
1065 if( errmsg != NULL)
1066 {
1067 luaL_error( L, errmsg);
1068 }
1069 STACK_END( L, 1);
1070 return 1;
1071}
1072
1073
1074/*
1075* Access deep userdata through a proxy.
1076*
1077* Reference count is not changed, and access to the deep userdata is not
1078* serialized. It is the module's responsibility to prevent conflicting usage.
1079*/
1080void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index)
1081{
1082 DEEP_PRELUDE** proxy;
1083
1084 STACK_CHECK( L);
1085 // ensure it is actually a deep userdata
1086 if( get_idfunc( L, index, eLM_LaneBody) != idfunc)
1087 {
1088 return NULL; // no metatable, or wrong kind
1089 }
1090
1091 proxy = (DEEP_PRELUDE**) lua_touserdata( L, index);
1092 STACK_END( L, 0);
1093
1094 return (*proxy)->deep;
1095}
1096
1097
1098/*
1099 * Copy deep userdata between two separate Lua states (from L to L2)
1100 *
1101 * Returns:
1102 * the id function of the copied value, or NULL for non-deep userdata
1103 * (not copied)
1104 */
1105static luaG_IdFunction copydeep( struct s_Universe* U, lua_State* L, lua_State* L2, int index, enum eLookupMode mode_)
1106{
1107 char const* errmsg;
1108 luaG_IdFunction idfunc = get_idfunc( L, index, mode_);
1109 if( idfunc == NULL)
1110 {
1111 return NULL; // not a deep userdata
1112 }
1113
1114 errmsg = push_deep_proxy( U, L2, *(DEEP_PRELUDE**) lua_touserdata( L, index), mode_);
1115 if( errmsg != NULL)
1116 {
1117 // raise the error in the proper state (not the keeper)
1118 lua_State* errL = (mode_ == eLM_FromKeeper) ? L2 : L;
1119 luaL_error( errL, errmsg);
1120 }
1121 return idfunc;
1122}
1123
1124 715
1125/*---=== Inter-state copying ===---*/ 716/*---=== Inter-state copying ===---*/
1126 717
1127/*-- Metatable copying --*/
1128
1129/*
1130 * 'reg[ REG_MT_KNOWN ]'= {
1131 * [ table ]= id_uint,
1132 * ...
1133 * [ id_uint ]= table,
1134 * ...
1135 * }
1136 */
1137
1138/*
1139* Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it
1140*/
1141static void push_registry_subtable_mode( lua_State* L, void* key_, const char* mode_)
1142{
1143 STACK_GROW( L, 3);
1144 STACK_CHECK( L);
1145
1146 lua_pushlightuserdata( L, key_); // key
1147 lua_rawget( L, LUA_REGISTRYINDEX); // {}|nil
1148
1149 if( lua_isnil( L, -1))
1150 {
1151 lua_pop( L, 1); //
1152 lua_newtable( L); // {}
1153 lua_pushlightuserdata( L, key_); // {} key
1154 lua_pushvalue( L, -2); // {} key {}
1155
1156 // _R[key_] = {}
1157 lua_rawset( L, LUA_REGISTRYINDEX); // {}
1158
1159 // Set its metatable if requested
1160 if( mode_)
1161 {
1162 lua_newtable( L); // {} mt
1163 lua_pushliteral( L, "__mode"); // {} mt "__mode"
1164 lua_pushstring( L, mode_); // {} mt "__mode" mode
1165 lua_rawset( L, -3); // {} mt
1166 lua_setmetatable( L, -2); // {}
1167 }
1168 }
1169 STACK_END( L, 1);
1170 ASSERT_L( lua_istable( L, -1));
1171}
1172
1173/*
1174* Push a registry subtable (keyed by unique 'key_') onto the stack.
1175* If the subtable does not exist, it is created and chained.
1176*/
1177static inline void push_registry_subtable( lua_State* L, void* key_)
1178{
1179 push_registry_subtable_mode( L, key_, NULL);
1180}
1181
1182#define REG_MTID ( (void*) get_mt_id ) 718#define REG_MTID ( (void*) get_mt_id )
1183 719
1184/* 720/*