diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/deep.h | 12 | ||||
-rw-r--r-- | src/keeper.c | 44 | ||||
-rw-r--r-- | src/lanes.c | 286 | ||||
-rw-r--r-- | src/tools.c | 791 | ||||
-rw-r--r-- | src/tools.h | 16 |
5 files changed, 575 insertions, 574 deletions
@@ -15,9 +15,17 @@ | |||
15 | #define LANES_API | 15 | #define LANES_API |
16 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) | 16 | #endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) |
17 | 17 | ||
18 | typedef void (*luaG_IdFunction)( lua_State* L, char const* const which); | 18 | enum eDeepOp |
19 | { | ||
20 | eDO_new, | ||
21 | eDO_delete, | ||
22 | eDO_metatable, | ||
23 | eDO_module, | ||
24 | }; | ||
19 | 25 | ||
20 | extern LANES_API int luaG_deep_userdata( lua_State* L, luaG_IdFunction idfunc); | 26 | typedef void* (*luaG_IdFunction)( lua_State* L, enum eDeepOp op_); |
27 | |||
28 | extern LANES_API int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc); | ||
21 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); | 29 | extern LANES_API void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index); |
22 | 30 | ||
23 | #endif // __LANES_DEEP_H__ | 31 | #endif // __LANES_DEEP_H__ |
diff --git a/src/keeper.c b/src/keeper.c index c22bfed..4eb8bb3 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <ctype.h> | 44 | #include <ctype.h> |
45 | 45 | ||
46 | #include "lua.h" | 46 | #include "lua.h" |
47 | #include "lualib.h" | ||
47 | #include "lauxlib.h" | 48 | #include "lauxlib.h" |
48 | 49 | ||
49 | #include "threading.h" | 50 | #include "threading.h" |
@@ -623,11 +624,10 @@ char const* init_keepers( lua_State* L) | |||
623 | int i; | 624 | int i; |
624 | PROPAGATE_ALLOCF_PREP( L); | 625 | PROPAGATE_ALLOCF_PREP( L); |
625 | 626 | ||
626 | STACK_CHECK( L); | 627 | STACK_CHECK( L); // L K |
627 | lua_getfield( L, 1, "nb_keepers"); | 628 | lua_getfield( L, 1, "nb_keepers"); // nb_keepers |
628 | GNbKeepers = (int) lua_tointeger( L, -1); | 629 | GNbKeepers = (int) lua_tointeger( L, -1); |
629 | lua_pop( L, 1); | 630 | lua_pop( L, 1); // |
630 | STACK_END( L, 0); | ||
631 | assert( GNbKeepers >= 1); | 631 | assert( GNbKeepers >= 1); |
632 | 632 | ||
633 | GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper)); | 633 | GKeepers = malloc( GNbKeepers * sizeof( struct s_Keeper)); |
@@ -640,16 +640,37 @@ char const* init_keepers( lua_State* L) | |||
640 | } | 640 | } |
641 | STACK_CHECK( K); | 641 | STACK_CHECK( K); |
642 | 642 | ||
643 | // make sure 'package' is initialized in keeper states, so that we have require() | ||
644 | // this because this is needed when transfering deep userdata object | ||
645 | luaL_requiref( K, "package", luaopen_package, 1); // package | ||
646 | lua_pop( K, 1); // | ||
647 | STACK_MID( K, 0); | ||
648 | serialize_require( K); | ||
649 | STACK_MID( K, 0); | ||
650 | |||
651 | // copy package.path and package.cpath from the source state | ||
652 | lua_getglobal( L, "package"); // package | ||
653 | if( !lua_isnil( L, -1)) | ||
654 | { | ||
655 | luaG_inter_copy_package( L, K, -1, eLM_ToKeeper); | ||
656 | } | ||
657 | lua_pop( L, 1); // | ||
658 | STACK_MID( L, 0); | ||
659 | |||
660 | // attempt to call on_state_create(), if we have one and it is a C function | ||
661 | // (only support a C function because we can't transfer executable Lua code in keepers) | ||
662 | call_on_state_create( K, L, eLM_ToKeeper); | ||
663 | |||
643 | // to see VM name in Decoda debugger | 664 | // to see VM name in Decoda debugger |
644 | lua_pushliteral( K, "Keeper #"); | 665 | lua_pushliteral( K, "Keeper #"); // "Keeper #" |
645 | lua_pushinteger( K, i + 1); | 666 | lua_pushinteger( K, i + 1); // "Keeper #" n |
646 | lua_concat( K, 2); | 667 | lua_concat( K, 2); // "Keeper #n" |
647 | lua_setglobal( K, "decoda_name"); | 668 | lua_setglobal( K, "decoda_name"); // |
648 | 669 | ||
649 | // create the fifos table in the keeper state | 670 | // create the fifos table in the keeper state |
650 | lua_pushlightuserdata( K, fifos_key); | 671 | lua_pushlightuserdata( K, fifos_key); // fifo_key |
651 | lua_newtable( K); | 672 | lua_newtable( K); // fifo_key {} |
652 | lua_rawset( K, LUA_REGISTRYINDEX); | 673 | lua_rawset( K, LUA_REGISTRYINDEX); // |
653 | 674 | ||
654 | STACK_END( K, 0); | 675 | STACK_END( K, 0); |
655 | // we can trigger a GC from inside keeper_call(), where a keeper is acquired | 676 | // we can trigger a GC from inside keeper_call(), where a keeper is acquired |
@@ -660,6 +681,7 @@ char const* init_keepers( lua_State* L) | |||
660 | #if HAVE_KEEPER_ATEXIT_DESINIT | 681 | #if HAVE_KEEPER_ATEXIT_DESINIT |
661 | atexit( atexit_close_keepers); | 682 | atexit( atexit_close_keepers); |
662 | #endif // HAVE_KEEPER_ATEXIT_DESINIT | 683 | #endif // HAVE_KEEPER_ATEXIT_DESINIT |
684 | STACK_END( L, 0); | ||
663 | return NULL; // ok | 685 | return NULL; // ok |
664 | } | 686 | } |
665 | 687 | ||
diff --git a/src/lanes.c b/src/lanes.c index dbb0a82..597ac4b 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -52,7 +52,7 @@ | |||
52 | * ... | 52 | * ... |
53 | */ | 53 | */ |
54 | 54 | ||
55 | char const* VERSION = "3.8.5"; | 55 | char const* VERSION = "3.9.0"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
@@ -422,11 +422,11 @@ struct s_Linda | |||
422 | char name[1]; | 422 | char name[1]; |
423 | }; | 423 | }; |
424 | 424 | ||
425 | static void linda_id( lua_State*, char const * const which); | 425 | static void* linda_id( lua_State*, enum eDeepOp); |
426 | 426 | ||
427 | static inline struct s_Linda* lua_toLinda( lua_State* L, int idx_) | 427 | static inline struct s_Linda* lua_toLinda( lua_State* L, int idx_) |
428 | { | 428 | { |
429 | struct s_Linda* linda = luaG_todeep( L, linda_id, idx_); | 429 | struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_); |
430 | luaL_argcheck( L, linda != NULL, idx_, "expecting a linda object"); | 430 | luaL_argcheck( L, linda != NULL, idx_, "expecting a linda object"); |
431 | return linda; | 431 | return linda; |
432 | } | 432 | } |
@@ -996,7 +996,7 @@ LUAG_FUNC( linda_deep) | |||
996 | 996 | ||
997 | static int linda_tostring( lua_State* L, int idx_, bool_t opt_) | 997 | static int linda_tostring( lua_State* L, int idx_, bool_t opt_) |
998 | { | 998 | { |
999 | struct s_Linda* linda = luaG_todeep( L, linda_id, idx_); | 999 | struct s_Linda* linda = (struct s_Linda*) luaG_todeep( L, linda_id, idx_); |
1000 | if( !opt_) | 1000 | if( !opt_) |
1001 | { | 1001 | { |
1002 | luaL_argcheck( L, linda, idx_, "expecting a linda object"); | 1002 | luaL_argcheck( L, linda, idx_, "expecting a linda object"); |
@@ -1084,122 +1084,127 @@ LUAG_FUNC( linda_dump) | |||
1084 | * For any other strings, the ID function must not react at all. This allows | 1084 | * For any other strings, the ID function must not react at all. This allows |
1085 | * future extensions of the system. | 1085 | * future extensions of the system. |
1086 | */ | 1086 | */ |
1087 | static void linda_id( lua_State* L, char const* const which) | 1087 | static void* linda_id( lua_State* L, enum eDeepOp op_) |
1088 | { | 1088 | { |
1089 | if( strcmp( which, "new" ) == 0) | 1089 | switch( op_) |
1090 | { | 1090 | { |
1091 | struct s_Linda* s; | 1091 | case eDO_new: |
1092 | size_t name_len = 0; | ||
1093 | char const* linda_name = NULL; | ||
1094 | int const top = lua_gettop( L); | ||
1095 | |||
1096 | if( top > 0 && lua_type( L, top) == LUA_TSTRING) | ||
1097 | { | 1092 | { |
1098 | linda_name = lua_tostring( L, top); | 1093 | struct s_Linda* s; |
1099 | name_len = strlen( linda_name); | 1094 | size_t name_len = 0; |
1100 | } | 1095 | char const* linda_name = NULL; |
1096 | int const top = lua_gettop( L); | ||
1101 | 1097 | ||
1102 | /* The deep data is allocated separately of Lua stack; we might no | 1098 | if( top > 0 && lua_type( L, top) == LUA_TSTRING) |
1103 | * longer be around when last reference to it is being released. | 1099 | { |
1104 | * One can use any memory allocation scheme. | 1100 | linda_name = lua_tolstring( L, top, &name_len); |
1105 | */ | 1101 | } |
1106 | s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included | ||
1107 | ASSERT_L( s); | ||
1108 | |||
1109 | SIGNAL_INIT( &s->read_happened); | ||
1110 | SIGNAL_INIT( &s->write_happened); | ||
1111 | s->simulate_cancel = CANCEL_NONE; | ||
1112 | s->name[0] = 0; | ||
1113 | memcpy( s->name, linda_name, name_len ? name_len + 1 : 0); | ||
1114 | 1102 | ||
1115 | lua_pushlightuserdata( L, s); | 1103 | /* The deep data is allocated separately of Lua stack; we might no |
1116 | } | 1104 | * longer be around when last reference to it is being released. |
1117 | else if( strcmp( which, "delete") == 0) | 1105 | * One can use any memory allocation scheme. |
1118 | { | 1106 | */ |
1119 | struct s_Keeper* K; | 1107 | s = (struct s_Linda*) malloc( sizeof(struct s_Linda) + name_len); // terminating 0 is already included |
1120 | struct s_Linda* l = lua_touserdata( L, 1); | 1108 | ASSERT_L( s); |
1121 | ASSERT_L( l); | 1109 | |
1110 | SIGNAL_INIT( &s->read_happened); | ||
1111 | SIGNAL_INIT( &s->write_happened); | ||
1112 | s->simulate_cancel = CANCEL_NONE; | ||
1113 | s->name[0] = 0; | ||
1114 | memcpy( s->name, linda_name, name_len ? name_len + 1 : 0); | ||
1115 | return s; | ||
1116 | } | ||
1122 | 1117 | ||
1123 | /* Clean associated structures in the keeper state. | 1118 | case eDO_delete: |
1124 | */ | ||
1125 | K = keeper_acquire( l); | ||
1126 | if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) | ||
1127 | { | 1119 | { |
1128 | keeper_call( K->L, KEEPER_API( clear), L, l, 0); | 1120 | struct s_Keeper* K; |
1121 | struct s_Linda* l = lua_touserdata( L, 1); | ||
1122 | ASSERT_L( l); | ||
1123 | |||
1124 | /* Clean associated structures in the keeper state. | ||
1125 | */ | ||
1126 | K = keeper_acquire( l); | ||
1127 | if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) | ||
1128 | { | ||
1129 | keeper_call( K->L, KEEPER_API( clear), L, l, 0); | ||
1130 | } | ||
1131 | keeper_release( K); | ||
1132 | |||
1133 | /* There aren't any lanes waiting on these lindas, since all proxies | ||
1134 | * have been gc'ed. Right? | ||
1135 | */ | ||
1136 | SIGNAL_FREE( &l->read_happened); | ||
1137 | SIGNAL_FREE( &l->write_happened); | ||
1138 | free( l); | ||
1139 | return NULL; | ||
1129 | } | 1140 | } |
1130 | keeper_release( K); | ||
1131 | 1141 | ||
1132 | /* There aren't any lanes waiting on these lindas, since all proxies | 1142 | case eDO_metatable: |
1133 | * have been gc'ed. Right? | 1143 | { |
1134 | */ | ||
1135 | SIGNAL_FREE( &l->read_happened); | ||
1136 | SIGNAL_FREE( &l->write_happened); | ||
1137 | free( l); | ||
1138 | } | ||
1139 | else if( strcmp( which, "metatable" ) == 0) | ||
1140 | { | ||
1141 | 1144 | ||
1142 | STACK_CHECK( L); | 1145 | STACK_CHECK( L); |
1143 | lua_newtable( L); | 1146 | lua_newtable( L); |
1144 | // metatable is its own index | 1147 | // metatable is its own index |
1145 | lua_pushvalue( L, -1); | 1148 | lua_pushvalue( L, -1); |
1146 | lua_setfield( L, -2, "__index"); | 1149 | lua_setfield( L, -2, "__index"); |
1147 | 1150 | ||
1148 | // protect metatable from external access | 1151 | // protect metatable from external access |
1149 | lua_pushliteral( L, "Linda"); | 1152 | lua_pushliteral( L, "Linda"); |
1150 | lua_setfield( L, -2, "__metatable"); | 1153 | lua_setfield( L, -2, "__metatable"); |
1151 | 1154 | ||
1152 | lua_pushcfunction( L, LG_linda_tostring); | 1155 | lua_pushcfunction( L, LG_linda_tostring); |
1153 | lua_setfield( L, -2, "__tostring"); | 1156 | lua_setfield( L, -2, "__tostring"); |
1154 | 1157 | ||
1155 | // Decoda __towatch support | 1158 | // Decoda __towatch support |
1156 | lua_pushcfunction( L, LG_linda_dump); | 1159 | lua_pushcfunction( L, LG_linda_dump); |
1157 | lua_setfield( L, -2, "__towatch"); | 1160 | lua_setfield( L, -2, "__towatch"); |
1158 | 1161 | ||
1159 | lua_pushcfunction( L, LG_linda_concat); | 1162 | lua_pushcfunction( L, LG_linda_concat); |
1160 | lua_setfield( L, -2, "__concat"); | 1163 | lua_setfield( L, -2, "__concat"); |
1161 | 1164 | ||
1162 | // [-1]: linda metatable | 1165 | // [-1]: linda metatable |
1163 | lua_pushcfunction( L, LG_linda_send); | 1166 | lua_pushcfunction( L, LG_linda_send); |
1164 | lua_setfield( L, -2, "send"); | 1167 | lua_setfield( L, -2, "send"); |
1165 | 1168 | ||
1166 | lua_pushcfunction( L, LG_linda_receive); | 1169 | lua_pushcfunction( L, LG_linda_receive); |
1167 | lua_setfield( L, -2, "receive"); | 1170 | lua_setfield( L, -2, "receive"); |
1168 | 1171 | ||
1169 | lua_pushcfunction( L, LG_linda_limit); | 1172 | lua_pushcfunction( L, LG_linda_limit); |
1170 | lua_setfield( L, -2, "limit"); | 1173 | lua_setfield( L, -2, "limit"); |
1171 | 1174 | ||
1172 | lua_pushcfunction( L, LG_linda_set); | 1175 | lua_pushcfunction( L, LG_linda_set); |
1173 | lua_setfield( L, -2, "set"); | 1176 | lua_setfield( L, -2, "set"); |
1174 | 1177 | ||
1175 | lua_pushcfunction( L, LG_linda_count); | 1178 | lua_pushcfunction( L, LG_linda_count); |
1176 | lua_setfield( L, -2, "count"); | 1179 | lua_setfield( L, -2, "count"); |
1177 | 1180 | ||
1178 | lua_pushcfunction( L, LG_linda_get); | 1181 | lua_pushcfunction( L, LG_linda_get); |
1179 | lua_setfield( L, -2, "get"); | 1182 | lua_setfield( L, -2, "get"); |
1180 | 1183 | ||
1181 | lua_pushcfunction( L, LG_linda_cancel); | 1184 | lua_pushcfunction( L, LG_linda_cancel); |
1182 | lua_setfield( L, -2, "cancel"); | 1185 | lua_setfield( L, -2, "cancel"); |
1183 | 1186 | ||
1184 | lua_pushcfunction( L, LG_linda_deep); | 1187 | lua_pushcfunction( L, LG_linda_deep); |
1185 | lua_setfield( L, -2, "deep"); | 1188 | lua_setfield( L, -2, "deep"); |
1186 | 1189 | ||
1187 | lua_pushcfunction( L, LG_linda_dump); | 1190 | lua_pushcfunction( L, LG_linda_dump); |
1188 | lua_setfield( L, -2, "dump"); | 1191 | lua_setfield( L, -2, "dump"); |
1189 | 1192 | ||
1190 | lua_pushliteral( L, BATCH_SENTINEL); | 1193 | lua_pushliteral( L, BATCH_SENTINEL); |
1191 | lua_setfield(L, -2, "batched"); | 1194 | lua_setfield(L, -2, "batched"); |
1192 | 1195 | ||
1193 | STACK_END( L, 1); | 1196 | STACK_END( L, 1); |
1194 | } | 1197 | return NULL; |
1195 | else if( strcmp( which, "module") == 0) | 1198 | } |
1196 | { | 1199 | |
1200 | case eDO_module: | ||
1197 | // linda is a special case because we know lanes must be loaded from the main lua state | 1201 | // linda is a special case because we know lanes must be loaded from the main lua state |
1198 | // to be able to ever get here, so we know it will remain loaded as long a the main state is around | 1202 | // to be able to ever get here, so we know it will remain loaded as long a the main state is around |
1199 | // in other words, forever. | 1203 | // in other words, forever. |
1200 | lua_pushnil( L); | 1204 | default: |
1201 | // other idfuncs must push a string naming the module they come from | 1205 | { |
1202 | //lua_pushliteral( L, "lanes.core"); | 1206 | return NULL; |
1207 | } | ||
1203 | } | 1208 | } |
1204 | } | 1209 | } |
1205 | 1210 | ||
@@ -1214,7 +1219,7 @@ LUAG_FUNC( linda) | |||
1214 | luaL_argcheck( L, top <= 1, top, "too many arguments"); | 1219 | luaL_argcheck( L, top <= 1, top, "too many arguments"); |
1215 | if( top == 1) | 1220 | if( top == 1) |
1216 | luaL_checktype( L, 1, LUA_TSTRING); | 1221 | luaL_checktype( L, 1, LUA_TSTRING); |
1217 | return luaG_deep_userdata( L, linda_id); | 1222 | return luaG_newdeepuserdata( L, linda_id); |
1218 | } | 1223 | } |
1219 | 1224 | ||
1220 | /* | 1225 | /* |
@@ -2199,7 +2204,7 @@ LUAG_FUNC( thread_new) | |||
2199 | // which might not be the case if the libs list didn't include lanes.core or "*" | 2204 | // which might not be the case if the libs list didn't include lanes.core or "*" |
2200 | if( strncmp( name, "lanes.core", len) == 0) // this works both both "lanes" and "lanes.core" because of len | 2205 | if( strncmp( name, "lanes.core", len) == 0) // this works both both "lanes" and "lanes.core" because of len |
2201 | { | 2206 | { |
2202 | luaG_copy_one_time_settings( L, L2, name); | 2207 | luaG_copy_one_time_settings( L, L2); |
2203 | } | 2208 | } |
2204 | lua_pushlstring( L2, name, len); // require() name | 2209 | lua_pushlstring( L2, name, len); // require() name |
2205 | if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode | 2210 | if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode |
@@ -2324,8 +2329,8 @@ LUAG_FUNC( thread_new) | |||
2324 | MUTEX_INIT( &s->done_lock); | 2329 | MUTEX_INIT( &s->done_lock); |
2325 | SIGNAL_INIT( &s->done_signal); | 2330 | SIGNAL_INIT( &s->done_signal); |
2326 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR | 2331 | #endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR |
2327 | s->mstatus= NORMAL; | 2332 | s->mstatus = NORMAL; |
2328 | s->selfdestruct_next= NULL; | 2333 | s->selfdestruct_next = NULL; |
2329 | #if HAVE_LANE_TRACKING | 2334 | #if HAVE_LANE_TRACKING |
2330 | s->tracking_next = NULL; | 2335 | s->tracking_next = NULL; |
2331 | #endif // HAVE_LANE_TRACKING | 2336 | #endif // HAVE_LANE_TRACKING |
@@ -2969,7 +2974,7 @@ static void init_once_LOCKED( lua_State* L) | |||
2969 | // proxy_ud= deep_userdata( idfunc ) | 2974 | // proxy_ud= deep_userdata( idfunc ) |
2970 | // | 2975 | // |
2971 | lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes | 2976 | lua_pushliteral( L, "lanes-timer"); // push a name for debug purposes |
2972 | luaG_deep_userdata( L, linda_id); | 2977 | luaG_newdeepuserdata( L, linda_id); |
2973 | STACK_MID( L, 2); | 2978 | STACK_MID( L, 2); |
2974 | lua_remove( L, -2); // remove the name as we no longer need it | 2979 | lua_remove( L, -2); // remove the name as we no longer need it |
2975 | 2980 | ||
@@ -2978,7 +2983,7 @@ static void init_once_LOCKED( lua_State* L) | |||
2978 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer | 2983 | // Proxy userdata contents is only a 'DEEP_PRELUDE*' pointer |
2979 | // | 2984 | // |
2980 | timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1); | 2985 | timer_deep = * (DEEP_PRELUDE**) lua_touserdata( L, -1); |
2981 | ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep); | 2986 | ASSERT_L( timer_deep && (timer_deep->refcount == 1) && timer_deep->deep && timer_deep->idfunc == linda_id); |
2982 | 2987 | ||
2983 | // The host Lua state must always have a reference to this Linda object in order for the timer_deep pointer to be valid. | 2988 | // The host Lua state must always have a reference to this Linda object in order for the timer_deep pointer to be valid. |
2984 | // So store a reference that we will never actually use. | 2989 | // So store a reference that we will never actually use. |
@@ -3019,7 +3024,7 @@ LUAG_FUNC( configure) | |||
3019 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | 3024 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
3020 | 3025 | ||
3021 | // not in init_once_LOCKED because we can have several hosted "master" Lua states where Lanes is require()d. | 3026 | // not in init_once_LOCKED because we can have several hosted "master" Lua states where Lanes is require()d. |
3022 | lua_getfield( L, 1, "protect_allocator"); // settings protect_allocator | 3027 | lua_getfield( L, 1, "protect_allocator"); // settings protect_allocator |
3023 | if( lua_toboolean( L, -1)) | 3028 | if( lua_toboolean( L, -1)) |
3024 | { | 3029 | { |
3025 | void* ud; | 3030 | void* ud; |
@@ -3033,7 +3038,7 @@ LUAG_FUNC( configure) | |||
3033 | lua_setallocf( L, protected_lua_Alloc, s); | 3038 | lua_setallocf( L, protected_lua_Alloc, s); |
3034 | } | 3039 | } |
3035 | } | 3040 | } |
3036 | lua_pop( L, 1); // settings | 3041 | lua_pop( L, 1); // settings |
3037 | STACK_MID( L, 0); | 3042 | STACK_MID( L, 0); |
3038 | 3043 | ||
3039 | /* | 3044 | /* |
@@ -3075,68 +3080,75 @@ LUAG_FUNC( configure) | |||
3075 | #endif // THREADAPI == THREADAPI_PTHREAD | 3080 | #endif // THREADAPI == THREADAPI_PTHREAD |
3076 | 3081 | ||
3077 | // Retrieve main module interface table | 3082 | // Retrieve main module interface table |
3078 | lua_pushvalue( L, lua_upvalueindex( 2)); // settings M | 3083 | lua_pushvalue( L, lua_upvalueindex( 2)); // settings M |
3079 | // remove configure() (this function) from the module interface | 3084 | // remove configure() (this function) from the module interface |
3080 | lua_pushnil( L); // settings M nil | 3085 | lua_pushnil( L); // settings M nil |
3081 | lua_setfield( L, -2, "configure"); // settings M | 3086 | lua_setfield( L, -2, "configure"); // settings M |
3082 | // add functions to the module's table | 3087 | // add functions to the module's table |
3083 | luaG_registerlibfuncs( L, lanes_functions); | 3088 | luaG_registerlibfuncs( L, lanes_functions); |
3084 | #if HAVE_LANE_TRACKING | 3089 | #if HAVE_LANE_TRACKING |
3085 | // register core.threads() only if settings say it should be available | 3090 | // register core.threads() only if settings say it should be available |
3086 | if( tracking_first != NULL) | 3091 | if( tracking_first != NULL) |
3087 | { | 3092 | { |
3088 | lua_pushcfunction( L, LG_threads); // settings M LG_threads() | 3093 | lua_pushcfunction( L, LG_threads); // settings M LG_threads() |
3089 | lua_setfield( L, -2, "threads"); | 3094 | lua_setfield( L, -2, "threads"); // settings M |
3090 | } | 3095 | } |
3091 | #endif // HAVE_LANE_TRACKING | 3096 | #endif // HAVE_LANE_TRACKING |
3092 | STACK_MID( L, 1); | 3097 | STACK_MID( L, 1); |
3093 | 3098 | ||
3094 | ASSERT_L( timer_deep != NULL); // initialized by init_once_LOCKED | 3099 | { |
3095 | luaG_push_proxy( L, linda_id, (DEEP_PRELUDE*) timer_deep); // settings M timer_deep | 3100 | char const* errmsg; |
3096 | lua_setfield( L, -2, "timer_gateway"); // settings M | 3101 | ASSERT_L( timer_deep != NULL); // initialized by init_once_LOCKED |
3102 | errmsg = push_deep_proxy( L, (DEEP_PRELUDE*) timer_deep, eLM_LaneBody); // settings M timer_deep | ||
3103 | if( errmsg != NULL) | ||
3104 | { | ||
3105 | luaL_error( L, errmsg); | ||
3106 | } | ||
3107 | lua_setfield( L, -2, "timer_gateway"); // settings M | ||
3108 | } | ||
3097 | STACK_MID( L, 1); | 3109 | STACK_MID( L, 1); |
3098 | 3110 | ||
3099 | // prepare the metatable for threads | 3111 | // prepare the metatable for threads |
3100 | // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname } | 3112 | // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join, get_debug_threadname } |
3101 | // | 3113 | // |
3102 | if( luaL_newmetatable( L, "Lane")) // settings M mt | 3114 | if( luaL_newmetatable( L, "Lane")) // settings M mt |
3103 | { | 3115 | { |
3104 | lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc | 3116 | lua_pushcfunction( L, LG_thread_gc); // settings M mt LG_thread_gc |
3105 | lua_setfield( L, -2, "__gc"); // settings M mt | 3117 | lua_setfield( L, -2, "__gc"); // settings M mt |
3106 | lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index | 3118 | lua_pushcfunction( L, LG_thread_index); // settings M mt LG_thread_index |
3107 | lua_setfield( L, -2, "__index"); // settings M mt | 3119 | lua_setfield( L, -2, "__index"); // settings M mt |
3108 | lua_getglobal( L, "error"); // settings M mt error | 3120 | lua_getglobal( L, "error"); // settings M mt error |
3109 | ASSERT_L( lua_isfunction( L, -1)); | 3121 | ASSERT_L( lua_isfunction( L, -1)); |
3110 | lua_setfield( L, -2, "cached_error"); // settings M mt | 3122 | lua_setfield( L, -2, "cached_error"); // settings M mt |
3111 | lua_getglobal( L, "tostring"); // settings M mt tostring | 3123 | lua_getglobal( L, "tostring"); // settings M mt tostring |
3112 | ASSERT_L( lua_isfunction( L, -1)); | 3124 | ASSERT_L( lua_isfunction( L, -1)); |
3113 | lua_setfield( L, -2, "cached_tostring"); // settings M mt | 3125 | lua_setfield( L, -2, "cached_tostring"); // settings M mt |
3114 | lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join | 3126 | lua_pushcfunction( L, LG_thread_join); // settings M mt LG_thread_join |
3115 | lua_setfield( L, -2, "join"); // settings M mt | 3127 | lua_setfield( L, -2, "join"); // settings M mt |
3116 | lua_pushcfunction( L, LG_get_debug_threadname); // settings M mt LG_get_debug_threadname | 3128 | lua_pushcfunction( L, LG_get_debug_threadname); // settings M mt LG_get_debug_threadname |
3117 | lua_setfield( L, -2, "get_debug_threadname"); // settings M mt | 3129 | lua_setfield( L, -2, "get_debug_threadname"); // settings M mt |
3118 | lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel | 3130 | lua_pushcfunction( L, LG_thread_cancel); // settings M mt LG_thread_cancel |
3119 | lua_setfield( L, -2, "cancel"); // settings M mt | 3131 | lua_setfield( L, -2, "cancel"); // settings M mt |
3120 | lua_pushliteral( L, "Lane"); // settings M mt "Lane" | 3132 | lua_pushliteral( L, "Lane"); // settings M mt "Lane" |
3121 | lua_setfield( L, -2, "__metatable"); // settings M mt | 3133 | lua_setfield( L, -2, "__metatable"); // settings M mt |
3122 | } | 3134 | } |
3123 | 3135 | ||
3124 | lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new | 3136 | lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new |
3125 | lua_setfield( L, -2, "thread_new"); // settings M | 3137 | lua_setfield( L, -2, "thread_new"); // settings M |
3126 | 3138 | ||
3127 | // we can't register 'lanes.require' normally because we want to create an upvalued closure | 3139 | // we can't register 'lanes.require' normally because we want to create an upvalued closure |
3128 | lua_getglobal( L, "require"); // settings M require | 3140 | lua_getglobal( L, "require"); // settings M require |
3129 | lua_pushcclosure( L, LG_require, 1); // settings M lanes.require | 3141 | lua_pushcclosure( L, LG_require, 1); // settings M lanes.require |
3130 | lua_setfield( L, -2, "require"); // settings M | 3142 | lua_setfield( L, -2, "require"); // settings M |
3131 | 3143 | ||
3132 | lua_pushstring(L, VERSION); // settings M VERSION | 3144 | lua_pushstring(L, VERSION); // settings M VERSION |
3133 | lua_setfield(L, -2, "version"); // settings M | 3145 | lua_setfield(L, -2, "version"); // settings M |
3134 | 3146 | ||
3135 | lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX | 3147 | lua_pushinteger(L, THREAD_PRIO_MAX); // settings M THREAD_PRIO_MAX |
3136 | lua_setfield(L, -2, "max_prio"); // settings M | 3148 | lua_setfield(L, -2, "max_prio"); // settings M |
3137 | 3149 | ||
3138 | lua_pushlightuserdata( L, CANCEL_ERROR); // settings M CANCEL_ERROR | 3150 | lua_pushlightuserdata( L, CANCEL_ERROR); // settings M CANCEL_ERROR |
3139 | lua_setfield(L, -2, "cancel_error"); // settings M | 3151 | lua_setfield(L, -2, "cancel_error"); // settings M |
3140 | 3152 | ||
3141 | // register all native functions found in that module in the transferable functions database | 3153 | // register all native functions found in that module in the transferable functions database |
3142 | // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) | 3154 | // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) |
@@ -3151,7 +3163,7 @@ LUAG_FUNC( configure) | |||
3151 | // set _R[CONFIG_REGKEY] = settings | 3163 | // set _R[CONFIG_REGKEY] = settings |
3152 | lua_pushvalue( L, -2); // settings M settings | 3164 | lua_pushvalue( L, -2); // settings M settings |
3153 | lua_setfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // settings M | 3165 | lua_setfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); // settings M |
3154 | lua_pop( L, 1); // settings | 3166 | lua_pop( L, 1); // settings |
3155 | STACK_END( L, 0); | 3167 | STACK_END( L, 0); |
3156 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); | 3168 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END, L)); |
3157 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 3169 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
diff --git a/src/tools.c b/src/tools.c index fc3e7e0..2aa9b82 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -195,14 +195,14 @@ int initialize_on_state_create( lua_State* L) | |||
195 | } | 195 | } |
196 | 196 | ||
197 | // just like lua_xmove, args are (from, to) | 197 | // just like lua_xmove, args are (from, to) |
198 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_) | 198 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2) |
199 | { | 199 | { |
200 | STACK_GROW( L, 1); | 200 | STACK_GROW( L, 1); |
201 | // copy settings from from source to destination registry | 201 | // copy settings from from source to destination registry |
202 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); | 202 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); |
203 | if( luaG_inter_move( L, L2, 1, eLM_LaneBody) < 0) // error? | 203 | if( luaG_inter_move( L, L2, 1, eLM_LaneBody) < 0) // error? |
204 | { | 204 | { |
205 | (void) luaL_error( L, "failed to copy settings when loading %s", name_); | 205 | (void) luaL_error( L, "failed to copy settings when loading lanes.core"); |
206 | } | 206 | } |
207 | lua_setfield( L2, LUA_REGISTRYINDEX, CONFIG_REGKEY); | 207 | lua_setfield( L2, LUA_REGISTRYINDEX, CONFIG_REGKEY); |
208 | } | 208 | } |
@@ -258,7 +258,7 @@ static void open1lib( lua_State* L, char const* name_, size_t len_, lua_State* f | |||
258 | if( isLanesCore == TRUE) | 258 | if( isLanesCore == TRUE) |
259 | { | 259 | { |
260 | // copy settings from from source to destination registry | 260 | // copy settings from from source to destination registry |
261 | luaG_copy_one_time_settings( from_, L, name_); | 261 | luaG_copy_one_time_settings( from_, L); |
262 | } | 262 | } |
263 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) | 263 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) |
264 | luaL_requiref( L, name_, libfunc, !isLanesCore); | 264 | luaL_requiref( L, name_, libfunc, !isLanesCore); |
@@ -591,28 +591,61 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
591 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | 591 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
592 | } | 592 | } |
593 | 593 | ||
594 | void call_on_state_create( lua_State* L, lua_State* from_, enum eLookupMode mode_) | ||
595 | { | ||
596 | if( s_on_state_create_func != NULL) | ||
597 | { | ||
598 | STACK_CHECK( L); | ||
599 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | ||
600 | if( s_on_state_create_func != initialize_on_state_create) | ||
601 | { | ||
602 | // C function: recreate a closure in the new state, bypassing the lookup scheme | ||
603 | lua_pushcfunction( L, s_on_state_create_func); | ||
604 | } | ||
605 | else // Lua function located in the config table, copied when we opened "lanes.core" | ||
606 | { | ||
607 | if( mode_ != eLM_LaneBody) | ||
608 | { | ||
609 | // if attempting to call in a keeper state, do nothing because the function doesn't exist there | ||
610 | return; | ||
611 | } | ||
612 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); | ||
613 | lua_getfield( L, -1, "on_state_create"); | ||
614 | lua_remove( L, -2); | ||
615 | } | ||
616 | // capture error and forward it to main state | ||
617 | if( lua_pcall( L, 0, 0, 0) != LUA_OK) | ||
618 | { | ||
619 | (void) luaL_error( from_, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1))); | ||
620 | } | ||
621 | STACK_END( L, 0); | ||
622 | } | ||
623 | } | ||
624 | |||
594 | /* | 625 | /* |
595 | * Like 'luaL_openlibs()' but allows the set of libraries be selected | 626 | * Like 'luaL_openlibs()' but allows the set of libraries be selected |
596 | * | 627 | * |
597 | * NULL no libraries, not even base | 628 | * NULL no libraries, not even base |
598 | * "" base library only | 629 | * "" base library only |
599 | * "io,string" named libraries | 630 | * "io,string" named libraries |
600 | * "*" all libraries | 631 | * "*" all libraries |
601 | * | 632 | * |
602 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. | 633 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. |
603 | * | 634 | * |
604 | */ | 635 | * *NOT* called for keeper states! |
605 | lua_State* luaG_newstate( lua_State* _from, char const* libs) | 636 | * |
637 | */ | ||
638 | lua_State* luaG_newstate( lua_State* from_, char const* libs_) | ||
606 | { | 639 | { |
607 | // reuse alloc function from the originating state | 640 | // reuse alloc function from the originating state |
608 | #if PROPAGATE_ALLOCF | 641 | #if PROPAGATE_ALLOCF |
609 | PROPAGATE_ALLOCF_PREP( _from); | 642 | PROPAGATE_ALLOCF_PREP( from_); |
610 | #endif // PROPAGATE_ALLOCF | 643 | #endif // PROPAGATE_ALLOCF |
611 | lua_State* L = PROPAGATE_ALLOCF_ALLOC(); | 644 | lua_State* L = PROPAGATE_ALLOCF_ALLOC(); |
612 | 645 | ||
613 | if( L == NULL) | 646 | if( L == NULL) |
614 | { | 647 | { |
615 | (void) luaL_error( _from, "luaG_newstate() failed while creating state; out of memory"); | 648 | (void) luaL_error( from_, "luaG_newstate() failed while creating state; out of memory"); |
616 | } | 649 | } |
617 | 650 | ||
618 | // we'll need this everytime we transfer some C function from/to this state | 651 | // we'll need this everytime we transfer some C function from/to this state |
@@ -620,7 +653,7 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
620 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); | 653 | lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); |
621 | 654 | ||
622 | // neither libs (not even 'base') nor special init func: we are done | 655 | // neither libs (not even 'base') nor special init func: we are done |
623 | if( libs == NULL && s_on_state_create_func == NULL) | 656 | if( libs_ == NULL && s_on_state_create_func == NULL) |
624 | { | 657 | { |
625 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END)); | 658 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END)); |
626 | return L; | 659 | return L; |
@@ -636,17 +669,17 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
636 | 669 | ||
637 | // Anything causes 'base' to be taken in | 670 | // Anything causes 'base' to be taken in |
638 | // | 671 | // |
639 | if( libs != NULL) | 672 | if( libs_ != NULL) |
640 | { | 673 | { |
641 | // special "*" case (mainly to help with LuaJIT compatibility) | 674 | // special "*" case (mainly to help with LuaJIT compatibility) |
642 | // as we are called from luaopen_lanes_core() already, and that would deadlock | 675 | // as we are called from luaopen_lanes_core() already, and that would deadlock |
643 | if( libs[0] == '*' && libs[1] == 0) | 676 | if( libs_[0] == '*' && libs_[1] == 0) |
644 | { | 677 | { |
645 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); | 678 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); |
646 | luaL_openlibs( L); | 679 | luaL_openlibs( L); |
647 | // don't forget lanes.core for regular lane states | 680 | // don't forget lanes.core for regular lane states |
648 | open1lib( L, "lanes.core", 10, _from); | 681 | open1lib( L, "lanes.core", 10, from_); |
649 | libs = NULL; // done with libs | 682 | libs_ = NULL; // done with libs |
650 | } | 683 | } |
651 | else | 684 | else |
652 | { | 685 | { |
@@ -665,11 +698,11 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
665 | STACK_END( L, 0); | 698 | STACK_END( L, 0); |
666 | 699 | ||
667 | // scan all libraries, open them one by one | 700 | // scan all libraries, open them one by one |
668 | if( libs) | 701 | if( libs_) |
669 | { | 702 | { |
670 | char const* p; | 703 | char const* p; |
671 | unsigned int len = 0; | 704 | unsigned int len = 0; |
672 | for( p = libs; *p; p += len) | 705 | for( p = libs_; *p; p += len) |
673 | { | 706 | { |
674 | // skip delimiters ('.' can be part of name for "lanes.core") | 707 | // skip delimiters ('.' can be part of name for "lanes.core") |
675 | while( *p && !isalnum( *p) && *p != '.') | 708 | while( *p && !isalnum( *p) && *p != '.') |
@@ -679,37 +712,17 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
679 | while( isalnum( p[len]) || p[len] == '.') | 712 | while( isalnum( p[len]) || p[len] == '.') |
680 | ++ len; | 713 | ++ len; |
681 | // open library | 714 | // open library |
682 | open1lib( L, p, len, _from); | 715 | open1lib( L, p, len, from_); |
683 | } | 716 | } |
684 | serialize_require( L); | 717 | serialize_require( L); |
685 | } | 718 | } |
686 | 719 | ||
687 | lua_gc( L, LUA_GCRESTART, 0); | 720 | lua_gc( L, LUA_GCRESTART, 0); |
688 | 721 | ||
689 | STACK_CHECK( L); | ||
690 | // call this after the base libraries are loaded and GC is restarted | 722 | // call this after the base libraries are loaded and GC is restarted |
691 | if( s_on_state_create_func != NULL) | 723 | call_on_state_create( L, from_, eLM_LaneBody); |
692 | { | ||
693 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | ||
694 | if( s_on_state_create_func != initialize_on_state_create) | ||
695 | { | ||
696 | // C function: recreate a closure in the new state, bypassing the lookup scheme | ||
697 | lua_pushcfunction( L, s_on_state_create_func); | ||
698 | } | ||
699 | else // Lua function located in the config table | ||
700 | { | ||
701 | lua_getfield( L, LUA_REGISTRYINDEX, CONFIG_REGKEY); | ||
702 | lua_getfield( L, -1, "on_state_create"); | ||
703 | lua_remove( L, -2); | ||
704 | } | ||
705 | // capture error and forward it to main state | ||
706 | if( lua_pcall( L, 0, 0, 0) != LUA_OK) | ||
707 | { | ||
708 | (void) luaL_error( _from, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1))); | ||
709 | } | ||
710 | STACK_MID( L, 0); | ||
711 | } | ||
712 | 724 | ||
725 | STACK_CHECK( L); | ||
713 | // after all this, register everything we find in our name<->function database | 726 | // after all this, register everything we find in our name<->function database |
714 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack | 727 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack |
715 | populate_func_lookup_table( L, -1, NULL); | 728 | populate_func_lookup_table( L, -1, NULL); |
@@ -743,7 +756,7 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs) | |||
743 | /* | 756 | /* |
744 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying | 757 | * The deep proxy cache is a weak valued table listing all deep UD proxies indexed by the deep UD that they are proxying |
745 | */ | 758 | */ |
746 | #define DEEP_PROXY_CACHE_KEY ((void*)luaG_push_proxy) | 759 | #define DEEP_PROXY_CACHE_KEY ((void*)push_deep_proxy) |
747 | 760 | ||
748 | static void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ); | 761 | static void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ); |
749 | static void push_registry_subtable( lua_State *L, void *token ); | 762 | static void push_registry_subtable( lua_State *L, void *token ); |
@@ -752,107 +765,76 @@ static void push_registry_subtable( lua_State *L, void *token ); | |||
752 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. | 765 | * Sets up [-1]<->[-2] two-way lookups, and ensures the lookup table exists. |
753 | * Pops the both values off the stack. | 766 | * Pops the both values off the stack. |
754 | */ | 767 | */ |
755 | void set_deep_lookup( lua_State *L ) { | 768 | static void set_deep_lookup( lua_State* L) |
756 | 769 | { | |
757 | STACK_GROW(L,3); | 770 | STACK_GROW( L, 3); |
758 | 771 | STACK_CHECK( L); // a b | |
759 | STACK_CHECK( L); | 772 | push_registry_subtable( L, DEEP_LOOKUP_KEY); // a b {} |
760 | #if 1 | 773 | STACK_MID( L, 1); |
761 | push_registry_subtable( L, DEEP_LOOKUP_KEY ); | 774 | lua_insert( L, -3); // {} a b |
762 | #else | 775 | lua_pushvalue( L, -1); // {} a b b |
763 | /* ..to be removed.. */ | 776 | lua_pushvalue( L,-3); // {} a b b a |
764 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); | 777 | lua_rawset( L, -5); // {} a b |
765 | lua_rawget( L, LUA_REGISTRYINDEX ); | 778 | lua_rawset( L, -3); // {} |
766 | 779 | lua_pop( L, 1); // | |
767 | if (lua_isnil(L,-1)) { | 780 | STACK_END( L, -2); |
768 | // First time here; let's make the lookup | ||
769 | // | ||
770 | lua_pop(L,1); | ||
771 | |||
772 | lua_newtable(L); | ||
773 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); | ||
774 | lua_pushvalue(L,-2); | ||
775 | // | ||
776 | // [-3]: {} (2nd ref) | ||
777 | // [-2]: DEEP_LOOKUP_KEY | ||
778 | // [-1]: {} | ||
779 | |||
780 | lua_rawset( L, LUA_REGISTRYINDEX ); | ||
781 | // | ||
782 | // [-1]: lookup table (empty) | ||
783 | } | ||
784 | #endif | ||
785 | STACK_MID( L, 1); | ||
786 | |||
787 | lua_insert(L,-3); | ||
788 | |||
789 | // [-3]: lookup table | ||
790 | // [-2]: A | ||
791 | // [-1]: B | ||
792 | |||
793 | lua_pushvalue( L,-1 ); // B | ||
794 | lua_pushvalue( L,-3 ); // A | ||
795 | lua_rawset( L, -5 ); // B->A | ||
796 | lua_rawset( L, -3 ); // A->B | ||
797 | lua_pop( L,1 ); | ||
798 | |||
799 | STACK_END( L, -2); | ||
800 | } | 781 | } |
801 | 782 | ||
802 | /* | 783 | /* |
803 | * Pops the key (metatable or idfunc) off the stack, and replaces with the | 784 | * Pops the key (metatable or idfunc) off the stack, and replaces with the |
804 | * deep lookup value (idfunc/metatable/nil). | 785 | * deep lookup value (idfunc/metatable/nil). |
805 | */ | 786 | */ |
806 | void get_deep_lookup( lua_State *L ) { | 787 | static void get_deep_lookup( lua_State* L) |
807 | 788 | { | |
808 | STACK_GROW(L,1); | 789 | STACK_GROW( L, 1); |
790 | STACK_CHECK( L); // a | ||
791 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY); // a DLK | ||
792 | lua_rawget( L, LUA_REGISTRYINDEX); // a {} | ||
809 | 793 | ||
810 | STACK_CHECK( L); | 794 | if( !lua_isnil( L, -1)) |
811 | lua_pushlightuserdata( L, DEEP_LOOKUP_KEY ); | 795 | { |
812 | lua_rawget( L, LUA_REGISTRYINDEX ); | 796 | lua_insert( L, -2); // {} a |
813 | 797 | lua_rawget( L, -2); // {} b | |
814 | if (!lua_isnil(L,-1)) { | 798 | } |
815 | // [-2]: key (metatable or idfunc) | 799 | lua_remove( L, -2); // a|b |
816 | // [-1]: lookup table | 800 | STACK_END( L, 0); |
817 | |||
818 | lua_insert( L, -2 ); | ||
819 | lua_rawget( L, -2 ); | ||
820 | |||
821 | // [-2]: lookup table | ||
822 | // [-1]: value (metatable / idfunc / nil) | ||
823 | } | ||
824 | lua_remove(L,-2); | ||
825 | // remove lookup, or unused key | ||
826 | STACK_END( L, 0); | ||
827 | } | 801 | } |
828 | 802 | ||
829 | /* | 803 | /* |
830 | * Return the registered ID function for 'index' (deep userdata proxy), | 804 | * Return the registered ID function for 'index' (deep userdata proxy), |
831 | * or NULL if 'index' is not a deep userdata proxy. | 805 | * or NULL if 'index' is not a deep userdata proxy. |
832 | */ | 806 | */ |
833 | static | 807 | static inline luaG_IdFunction get_idfunc( lua_State* L, int index, enum eLookupMode mode_) |
834 | luaG_IdFunction get_idfunc( lua_State *L, int index ) | ||
835 | { | 808 | { |
836 | luaG_IdFunction ret; | 809 | // when looking inside a keeper, we are 100% sure the object is a deep userdata |
837 | 810 | if( mode_ == eLM_FromKeeper) | |
838 | index = lua_absindex( L, index); | 811 | { |
839 | 812 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); | |
840 | STACK_GROW(L,1); | 813 | // we can (and must) cast and fetch the internally stored idfunc |
841 | 814 | return (*proxy)->idfunc; | |
842 | STACK_CHECK( L); | 815 | } |
843 | if (!lua_getmetatable( L, index )) | 816 | else |
844 | return NULL; // no metatable | 817 | { |
845 | 818 | // essentially we are making sure that the metatable of the object we want to copy is stored in our metatable/idfunc database | |
846 | // [-1]: metatable of [index] | 819 | // it is the only way to ensure that the userdata is indeed a deep userdata! |
820 | // of course, we could just trust the caller, but we won't | ||
821 | luaG_IdFunction ret; | ||
822 | STACK_GROW( L, 1); | ||
823 | STACK_CHECK( L); | ||
824 | |||
825 | if( !lua_getmetatable( L, index)) // deep ... metatable? | ||
826 | { | ||
827 | return NULL; // no metatable: can't be a deep userdata object! | ||
828 | } | ||
847 | 829 | ||
848 | get_deep_lookup(L); | 830 | // replace metatable with the idfunc pointer, if it is actually a deep userdata |
849 | // | 831 | get_deep_lookup( L); // deep ... idfunc|nil |
850 | // [-1]: idfunc/nil | ||
851 | 832 | ||
852 | ret= (luaG_IdFunction)lua_touserdata(L,-1); | 833 | ret = (luaG_IdFunction) lua_touserdata( L, -1); // NULL if not a userdata |
853 | lua_pop(L,1); | 834 | lua_pop( L, 1); |
854 | STACK_END( L, 0); | 835 | STACK_END( L, 0); |
855 | return ret; | 836 | return ret; |
837 | } | ||
856 | } | 838 | } |
857 | 839 | ||
858 | 840 | ||
@@ -862,205 +844,190 @@ luaG_IdFunction get_idfunc( lua_State *L, int index ) | |||
862 | * End of life for a proxy object; reduce the deep reference count and clean | 844 | * End of life for a proxy object; reduce the deep reference count and clean |
863 | * it up if reaches 0. | 845 | * it up if reaches 0. |
864 | */ | 846 | */ |
865 | static | 847 | static int deep_userdata_gc( lua_State* L) |
866 | int deep_userdata_gc( lua_State *L ) | ||
867 | { | 848 | { |
868 | DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 ); | 849 | DEEP_PRELUDE** proxy = (DEEP_PRELUDE**) lua_touserdata( L, 1); |
869 | DEEP_PRELUDE *p= *proxy; | 850 | DEEP_PRELUDE* p = *proxy; |
870 | int v; | 851 | int v; |
871 | 852 | ||
872 | *proxy= 0; // make sure we don't use it any more | 853 | *proxy = 0; // make sure we don't use it any more |
873 | 854 | ||
874 | MUTEX_LOCK( &deep_lock ); | 855 | MUTEX_LOCK( &deep_lock); |
875 | v= --(p->refcount); | 856 | v = -- (p->refcount); |
876 | MUTEX_UNLOCK( &deep_lock ); | 857 | MUTEX_UNLOCK( &deep_lock); |
877 | |||
878 | if (v==0) | ||
879 | { | ||
880 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | ||
881 | // | ||
882 | luaG_IdFunction idfunc = get_idfunc(L,1); | ||
883 | ASSERT_L(idfunc); | ||
884 | |||
885 | lua_settop( L, 0); // clean stack so we can call 'idfunc' directly | ||
886 | 858 | ||
887 | // void= idfunc( "delete", lightuserdata ) | 859 | if( v == 0) |
888 | // | 860 | { |
889 | lua_pushlightuserdata( L, p->deep ); | 861 | // clean stack so we can call 'idfunc' directly |
890 | idfunc( L, "delete"); | 862 | lua_settop( L, 0); |
891 | 863 | // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup | |
892 | // 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! | 864 | lua_pushlightuserdata( L, p->deep); |
893 | if ( lua_gettop( L) > 1) | 865 | ASSERT_L( p->idfunc); |
894 | luaL_error( L, "Bad idfunc on \"delete\": returned something"); | 866 | p->idfunc( L, eDO_delete); |
895 | 867 | DEEP_FREE( (void*) p); | |
896 | DEEP_FREE( (void*)p ); | 868 | |
897 | } | 869 | // 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! |
898 | return 0; | 870 | if ( lua_gettop( L) > 1) |
871 | { | ||
872 | luaL_error( L, "Bad idfunc(eDO_delete): should not push anything"); | ||
873 | } | ||
874 | } | ||
875 | return 0; | ||
899 | } | 876 | } |
900 | 877 | ||
901 | 878 | ||
902 | /* | 879 | /* |
903 | * Push a proxy userdata on the stack. | 880 | * Push a proxy userdata on the stack. |
904 | * | 881 | * returns NULL if ok, else some error string related to bad idfunc behavior or module require problem |
905 | * Initializes necessary structures if it's the first time 'idfunc' is being | 882 | * (error cannot happen with mode_ == eLM_ToKeeper) |
906 | * used in this Lua state (metatable, registring it). Otherwise, increments the | 883 | * |
907 | * reference count. | 884 | * Initializes necessary structures if it's the first time 'idfunc' is being |
908 | */ | 885 | * used in this Lua state (metatable, registring it). Otherwise, increments the |
909 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelude ) | 886 | * reference count. |
887 | */ | ||
888 | char const* push_deep_proxy( lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_) | ||
910 | { | 889 | { |
911 | DEEP_PRELUDE **proxy; | 890 | DEEP_PRELUDE** proxy; |
912 | |||
913 | // Check if a proxy already exists | ||
914 | push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); | ||
915 | lua_pushlightuserdata(L, prelude->deep); | ||
916 | lua_rawget(L, -2); | ||
917 | if (!lua_isnil(L, -1)) | ||
918 | { | ||
919 | lua_remove(L, -2); // deep proxy cache table | ||
920 | return; | ||
921 | } | ||
922 | else | ||
923 | { | ||
924 | lua_pop(L, 2); // Pop the nil and proxy cache table | ||
925 | } | ||
926 | |||
927 | MUTEX_LOCK( &deep_lock ); | ||
928 | ++(prelude->refcount); // one more proxy pointing to this deep data | ||
929 | MUTEX_UNLOCK( &deep_lock ); | ||
930 | |||
931 | STACK_GROW(L,4); | ||
932 | |||
933 | STACK_CHECK( L); | ||
934 | |||
935 | proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) ); | ||
936 | ASSERT_L(proxy); | ||
937 | *proxy= prelude; | ||
938 | 891 | ||
939 | // Get/create metatable for 'idfunc' (in this state) | 892 | // Check if a proxy already exists |
940 | // | 893 | push_registry_subtable_mode( L, DEEP_PROXY_CACHE_KEY, "v"); // DPC |
941 | lua_pushlightuserdata( L, idfunc ); // key | 894 | lua_pushlightuserdata( L, prelude->deep); // DPC deep |
942 | get_deep_lookup(L); | 895 | lua_rawget( L, -2); // DPC proxy |
943 | // | 896 | if ( !lua_isnil( L, -1)) |
944 | // [-2]: proxy | 897 | { |
945 | // [-1]: metatable / nil | 898 | lua_remove( L, -2); // proxy |
946 | 899 | return NULL; | |
947 | if (lua_isnil(L,-1)) | 900 | } |
948 | { | 901 | else |
949 | // No metatable yet. We have two things to do: | 902 | { |
950 | // 1 - make one and register it | 903 | lua_pop( L, 1); // DPC |
951 | { | 904 | } |
952 | int oldtop; | ||
953 | 905 | ||
954 | lua_pop( L, 1); | 906 | MUTEX_LOCK( &deep_lock); |
907 | ++ (prelude->refcount); // one more proxy pointing to this deep data | ||
908 | MUTEX_UNLOCK( &deep_lock); | ||
955 | 909 | ||
956 | // tbl= idfunc( "metatable" ) | 910 | STACK_GROW( L, 7); |
957 | // | 911 | STACK_CHECK( L); |
958 | oldtop = lua_gettop( L); | ||
959 | idfunc( L, "metatable"); | ||
960 | // | ||
961 | // [-2]: proxy | ||
962 | // [-1]: metatable (returned by 'idfunc') | ||
963 | 912 | ||
964 | if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1)) | 913 | proxy = lua_newuserdata( L, sizeof( DEEP_PRELUDE*)); // DPC proxy |
965 | { | 914 | ASSERT_L( proxy); |
966 | luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); | 915 | *proxy = prelude; |
967 | } | ||
968 | 916 | ||
969 | // Add '__gc' method | 917 | // Get/create metatable for 'idfunc' (in this state) |
970 | // | 918 | lua_pushlightuserdata( L, prelude->idfunc); // DPC proxy idfunc |
971 | lua_pushcfunction( L, deep_userdata_gc ); | 919 | get_deep_lookup( L); // DPC proxy metatable? |
972 | lua_setfield( L, -2, "__gc" ); | ||
973 | 920 | ||
974 | // Memorize for later rounds | 921 | if( lua_isnil( L, -1)) // // No metatable yet. |
975 | // | 922 | { |
976 | lua_pushvalue( L,-1 ); | 923 | char const* modname; |
977 | lua_pushlightuserdata( L, idfunc ); | 924 | int oldtop = lua_gettop( L); // DPC proxy nil |
978 | // | 925 | lua_pop( L, 1); // DPC proxy |
979 | // [-4]: proxy | 926 | // 1 - make one and register it |
980 | // [-3]: metatable (2nd ref) | 927 | if( mode_ != eLM_ToKeeper) |
981 | // [-2]: metatable | 928 | { |
982 | // [-1]: idfunc | 929 | prelude->idfunc( L, eDO_metatable); // DPC proxy metatable |
983 | 930 | if( lua_gettop( L) - oldtop != 0 || !lua_istable( L, -1)) | |
984 | set_deep_lookup(L); | 931 | { |
985 | } | 932 | lua_pop( L, 3); // |
986 | 933 | return "Bad idfunc(eOP_metatable): unexpected pushed value"; | |
987 | // 2 - cause the target state to require the module that exported the idfunc | 934 | } |
988 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | 935 | // make sure the idfunc didn't export __gc, as we will store our own |
989 | STACK_CHECK( L); | 936 | lua_getfield( L, -1, "__gc"); // DPC proxy metatable __gc |
990 | { | 937 | if( !lua_isnil( L, -1)) |
991 | char const * modname; | 938 | { |
992 | // make sure the function pushed a single value on the stack! | 939 | lua_pop( L, 4); // |
993 | { | 940 | return "idfunc-created metatable shouldn't contain __gc"; |
994 | int oldtop = lua_gettop( L); | 941 | } |
995 | idfunc( L, "module"); // ... "module"/nil | 942 | lua_pop( L, 1); // DPC proxy metatable |
996 | if( lua_gettop( L) - oldtop != 1) | 943 | } |
997 | { | 944 | else |
998 | luaL_error( L, "Bad idfunc on \"module\": should return a single value"); | 945 | { |
999 | } | 946 | // keepers need a minimal metatable that only contains __gc |
1000 | } | 947 | lua_newtable( L); // DPC proxy metatable |
1001 | modname = luaL_optstring( L, -1, NULL); // raises an error if not a string or nil | 948 | } |
1002 | if( modname) // we actually got a module name | 949 | // Add our own '__gc' method |
1003 | { | 950 | lua_pushcfunction( L, deep_userdata_gc); // DPC proxy metatable __gc |
1004 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. | 951 | lua_setfield( L, -2, "__gc"); // DPC proxy metatable |
1005 | lua_getglobal( L, "require"); // ... "module" require() | ||
1006 | // check that the module is already loaded (or being loaded, we are happy either way) | ||
1007 | if( lua_isfunction( L, -1)) | ||
1008 | { | ||
1009 | lua_insert( L, -2); // ... require() "module" | ||
1010 | lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED"); // ... require() "module" L.registry._LOADED | ||
1011 | if( lua_istable( L, -1)) | ||
1012 | { | ||
1013 | bool_t alreadyloaded; | ||
1014 | lua_pushvalue( L, -2); // ... require() "module" L.registry._LOADED "module" | ||
1015 | lua_rawget( L, -2); // ... require() "module" L.registry._LOADED module | ||
1016 | alreadyloaded = lua_toboolean( L, -1); | ||
1017 | if( !alreadyloaded) // not loaded | ||
1018 | { | ||
1019 | lua_pop( L, 2); // ... require() "module" | ||
1020 | lua_call( L, 1, 0); // call require "modname" // ... | ||
1021 | } | ||
1022 | else // already loaded, we are happy | ||
1023 | { | ||
1024 | lua_pop( L, 4); // ... | ||
1025 | } | ||
1026 | } | ||
1027 | else // no L.registry._LOADED; can this ever happen? | ||
1028 | { | ||
1029 | luaL_error( L, "unexpected error while requiring a module"); | ||
1030 | lua_pop( L, 3); // ... | ||
1031 | } | ||
1032 | } | ||
1033 | else // a module name, but no require() function :-( | ||
1034 | { | ||
1035 | luaL_error( L, "lanes receiving deep userdata should register the 'package' library"); | ||
1036 | lua_pop( L, 2); // ... | ||
1037 | } | ||
1038 | } | ||
1039 | else // no module name | ||
1040 | { | ||
1041 | lua_pop( L, 1); // ... | ||
1042 | } | ||
1043 | } | ||
1044 | STACK_END( L, 0); | ||
1045 | } | ||
1046 | STACK_MID( L, 2); | ||
1047 | ASSERT_L( lua_isuserdata(L,-2) ); | ||
1048 | ASSERT_L( lua_istable(L,-1) ); | ||
1049 | 952 | ||
1050 | // [-2]: proxy userdata | 953 | // Memorize for later rounds |
1051 | // [-1]: metatable to use | 954 | lua_pushvalue( L, -1); // DPC proxy metatable metatable |
955 | lua_pushlightuserdata( L, prelude->idfunc); // DPC proxy metatable metatable idfunc | ||
956 | set_deep_lookup( L); // DPC proxy metatable | ||
1052 | 957 | ||
1053 | lua_setmetatable( L, -2 ); | 958 | // 2 - cause the target state to require the module that exported the idfunc |
1054 | 959 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | |
1055 | // If we're here, we obviously had to create a new proxy, so cache it. | 960 | { |
1056 | push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); | 961 | int oldtop = lua_gettop( L); |
1057 | lua_pushlightuserdata(L, (*proxy)->deep); | 962 | modname = (char const*) prelude->idfunc( L, eDO_module); // DPC proxy metatable |
1058 | lua_pushvalue(L, -3); // Copy of the proxy | 963 | // make sure the function pushed nothing on the stack! |
1059 | lua_rawset(L, -3); | 964 | if( lua_gettop( L) - oldtop != 0) |
1060 | lua_pop(L, 1); // Remove the cache proxy table | 965 | { |
1061 | 966 | lua_pop( L, 3); // | |
1062 | STACK_END( L, 1); | 967 | return "Bad idfunc(eOP_module): should not push anything"; |
1063 | // [-1]: proxy userdata | 968 | } |
969 | } | ||
970 | if( modname) // we actually got a module name | ||
971 | { | ||
972 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. | ||
973 | lua_getglobal( L, "require"); // DPC proxy metatable require() | ||
974 | // check that the module is already loaded (or being loaded, we are happy either way) | ||
975 | if( lua_isfunction( L, -1)) | ||
976 | { | ||
977 | lua_pushstring( L, modname); // DPC proxy metatable require() "module" | ||
978 | lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED"); // DPC proxy metatable require() "module" _R._LOADED | ||
979 | if( lua_istable( L, -1)) | ||
980 | { | ||
981 | bool_t alreadyloaded; | ||
982 | lua_pushvalue( L, -2); // DPC proxy metatable require() "module" _R._LOADED "module" | ||
983 | lua_rawget( L, -2); // DPC proxy metatable require() "module" _R._LOADED module | ||
984 | alreadyloaded = lua_toboolean( L, -1); | ||
985 | if( !alreadyloaded) // not loaded | ||
986 | { | ||
987 | int require_result; | ||
988 | lua_pop( L, 2); // DPC proxy metatable require() "module" | ||
989 | // require "modname" | ||
990 | require_result = lua_pcall( L, 1, 0, 0); // DPC proxy metatable error? | ||
991 | if( require_result != LUA_OK) | ||
992 | { | ||
993 | // failed, return the error message | ||
994 | lua_pushfstring( L, "error while requiring '%s' identified by idfunc(eOP_module): ", modname); | ||
995 | lua_insert( L, -2); // DPC proxy metatable prefix error | ||
996 | lua_concat( L, 2); // DPC proxy metatable error | ||
997 | return lua_tostring( L, -1); | ||
998 | } | ||
999 | } | ||
1000 | else // already loaded, we are happy | ||
1001 | { | ||
1002 | lua_pop( L, 4); // DPC proxy metatable | ||
1003 | } | ||
1004 | } | ||
1005 | else // no L.registry._LOADED; can this ever happen? | ||
1006 | { | ||
1007 | lua_pop( L, 6); // | ||
1008 | return "unexpected error while requiring a module identified by idfunc(eOP_module)"; | ||
1009 | } | ||
1010 | } | ||
1011 | else // a module name, but no require() function :-( | ||
1012 | { | ||
1013 | lua_pop( L, 4); // | ||
1014 | return "lanes receiving deep userdata should register the 'package' library"; | ||
1015 | } | ||
1016 | } | ||
1017 | } | ||
1018 | STACK_MID( L, 2); // DPC proxy metatable | ||
1019 | ASSERT_L( lua_isuserdata( L, -2)); | ||
1020 | ASSERT_L( lua_istable( L, -1)); | ||
1021 | lua_setmetatable( L, -2); // DPC proxy | ||
1022 | |||
1023 | // If we're here, we obviously had to create a new proxy, so cache it. | ||
1024 | lua_pushlightuserdata( L, (*proxy)->deep); // DPC proxy deep | ||
1025 | lua_pushvalue( L, -2); // DPC proxy deep proxy | ||
1026 | lua_rawset( L, -4); // DPC proxy | ||
1027 | lua_remove( L, -2); // proxy | ||
1028 | ASSERT_L( lua_isuserdata( L, -1)); | ||
1029 | STACK_END( L, 0); | ||
1030 | return NULL; | ||
1064 | } | 1031 | } |
1065 | 1032 | ||
1066 | 1033 | ||
@@ -1086,39 +1053,34 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelud | |||
1086 | * | 1053 | * |
1087 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' | 1054 | * Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' |
1088 | */ | 1055 | */ |
1089 | int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc) | 1056 | int luaG_newdeepuserdata( lua_State* L, luaG_IdFunction idfunc) |
1090 | { | 1057 | { |
1091 | int oldtop; | 1058 | char const* errmsg; |
1092 | 1059 | DEEP_PRELUDE* prelude = DEEP_MALLOC( sizeof(DEEP_PRELUDE)); | |
1093 | DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) ); | 1060 | ASSERT_L( prelude); |
1094 | ASSERT_L(prelude); | ||
1095 | |||
1096 | prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1 | ||
1097 | |||
1098 | STACK_GROW(L,1); | ||
1099 | STACK_CHECK( L); | ||
1100 | |||
1101 | // lightuserdata= idfunc( "new" [, ...] ) | ||
1102 | // | ||
1103 | oldtop = lua_gettop( L); | ||
1104 | idfunc(L, "new"); | ||
1105 | |||
1106 | if( lua_gettop( L) - oldtop != 1 || lua_type( L, -1) != LUA_TLIGHTUSERDATA) | ||
1107 | { | ||
1108 | luaL_error( L, "Bad idfunc on \"new\": did not return light userdata"); | ||
1109 | } | ||
1110 | 1061 | ||
1111 | prelude->deep= lua_touserdata(L,-1); | 1062 | prelude->refcount = 0; // 'push_deep_proxy' will lift it to 1 |
1112 | ASSERT_L(prelude->deep); | 1063 | prelude->idfunc = idfunc; |
1113 | 1064 | ||
1114 | lua_pop(L,1); // pop deep data | 1065 | STACK_GROW( L, 1); |
1115 | 1066 | STACK_CHECK( L); | |
1116 | luaG_push_proxy( L, idfunc, prelude ); | 1067 | { |
1117 | // | 1068 | int oldtop = lua_gettop( L); |
1118 | // [-1]: proxy userdata | 1069 | prelude->deep = idfunc( L, eDO_new); |
1070 | ASSERT_L( prelude->deep); | ||
1119 | 1071 | ||
1120 | STACK_END( L, 1); | 1072 | if( lua_gettop( L) - oldtop != 0) |
1121 | return 1; | 1073 | { |
1074 | luaL_error( L, "Bad idfunc(eDO_new): should not push anything on the stack"); | ||
1075 | } | ||
1076 | } | ||
1077 | errmsg = push_deep_proxy( L, prelude, eLM_LaneBody); // proxy | ||
1078 | if( errmsg != NULL) | ||
1079 | { | ||
1080 | luaL_error( L, errmsg); | ||
1081 | } | ||
1082 | STACK_END( L, 1); | ||
1083 | return 1; | ||
1122 | } | 1084 | } |
1123 | 1085 | ||
1124 | 1086 | ||
@@ -1128,52 +1090,51 @@ int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc) | |||
1128 | * Reference count is not changed, and access to the deep userdata is not | 1090 | * Reference count is not changed, and access to the deep userdata is not |
1129 | * serialized. It is the module's responsibility to prevent conflicting usage. | 1091 | * serialized. It is the module's responsibility to prevent conflicting usage. |
1130 | */ | 1092 | */ |
1131 | void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index ) | 1093 | void* luaG_todeep( lua_State* L, luaG_IdFunction idfunc, int index) |
1132 | { | 1094 | { |
1133 | DEEP_PRELUDE **proxy; | 1095 | DEEP_PRELUDE** proxy; |
1134 | 1096 | ||
1135 | STACK_CHECK( L); | 1097 | STACK_CHECK( L); |
1136 | if( get_idfunc(L,index) != idfunc) | 1098 | // ensure it is actually a deep userdata |
1137 | return NULL; // no metatable, or wrong kind | 1099 | if( get_idfunc( L, index, eLM_LaneBody) != idfunc) |
1100 | { | ||
1101 | return NULL; // no metatable, or wrong kind | ||
1102 | } | ||
1138 | 1103 | ||
1139 | proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); | 1104 | proxy = (DEEP_PRELUDE**) lua_touserdata( L, index); |
1140 | STACK_END( L, 0); | 1105 | STACK_END( L, 0); |
1141 | 1106 | ||
1142 | return (*proxy)->deep; | 1107 | return (*proxy)->deep; |
1143 | } | 1108 | } |
1144 | 1109 | ||
1145 | 1110 | ||
1146 | /* | 1111 | /* |
1147 | * Copy deep userdata between two separate Lua states. | 1112 | * Copy deep userdata between two separate Lua states (from L to L2) |
1148 | * | 1113 | * |
1149 | * Returns: | 1114 | * Returns: |
1150 | * the id function of the copied value, or NULL for non-deep userdata | 1115 | * the id function of the copied value, or NULL for non-deep userdata |
1151 | * (not copied) | 1116 | * (not copied) |
1152 | */ | 1117 | */ |
1153 | static | 1118 | static luaG_IdFunction copydeep( lua_State* L, lua_State* L2, int index, enum eLookupMode mode_) |
1154 | luaG_IdFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) | ||
1155 | { | 1119 | { |
1156 | DEEP_PRELUDE **proxy; | 1120 | char const* errmsg; |
1157 | DEEP_PRELUDE *p; | 1121 | luaG_IdFunction idfunc = get_idfunc( L, index, mode_); |
1158 | 1122 | if( idfunc == NULL) | |
1159 | luaG_IdFunction idfunc = get_idfunc( L, index); | 1123 | { |
1160 | if (!idfunc) | 1124 | return NULL; // not a deep userdata |
1161 | return NULL; // not a deep userdata | 1125 | } |
1162 | |||
1163 | // Increment reference count | ||
1164 | // | ||
1165 | proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); | ||
1166 | p= *proxy; | ||
1167 | |||
1168 | luaG_push_proxy( L2, idfunc, p ); | ||
1169 | // | ||
1170 | // L2 [-1]: proxy userdata | ||
1171 | 1126 | ||
1172 | return idfunc; | 1127 | errmsg = push_deep_proxy( L2, *(DEEP_PRELUDE**) lua_touserdata( L, index), mode_); |
1128 | if( errmsg != NULL) | ||
1129 | { | ||
1130 | // raise the error in the proper state (not the keeper) | ||
1131 | lua_State* errL = (mode_ == eLM_FromKeeper) ? L2 : L; | ||
1132 | luaL_error( errL, errmsg); | ||
1133 | } | ||
1134 | return idfunc; | ||
1173 | } | 1135 | } |
1174 | 1136 | ||
1175 | 1137 | ||
1176 | |||
1177 | /*---=== Inter-state copying ===---*/ | 1138 | /*---=== Inter-state copying ===---*/ |
1178 | 1139 | ||
1179 | /*-- Metatable copying --*/ | 1140 | /*-- Metatable copying --*/ |
@@ -1190,51 +1151,45 @@ luaG_IdFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) | |||
1190 | /* | 1151 | /* |
1191 | * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it | 1152 | * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it |
1192 | */ | 1153 | */ |
1193 | static | 1154 | static void push_registry_subtable_mode( lua_State* L, void* key_, const char* mode_) |
1194 | void push_registry_subtable_mode( lua_State *L, void *token, const char* mode ) { | 1155 | { |
1156 | STACK_GROW( L, 3); | ||
1157 | STACK_CHECK( L); | ||
1195 | 1158 | ||
1196 | STACK_GROW(L,3); | 1159 | lua_pushlightuserdata( L, key_); // key |
1160 | lua_rawget( L, LUA_REGISTRYINDEX); // {}|nil | ||
1197 | 1161 | ||
1198 | STACK_CHECK( L); | 1162 | if( lua_isnil( L, -1)) |
1199 | 1163 | { | |
1200 | lua_pushlightuserdata( L, token ); | 1164 | lua_pop( L, 1); // |
1201 | lua_rawget( L, LUA_REGISTRYINDEX ); | 1165 | lua_newtable( L); // {} |
1202 | // | 1166 | lua_pushlightuserdata( L, key_); // {} key |
1203 | // [-1]: nil/subtable | 1167 | lua_pushvalue( L, -2); // {} key {} |
1204 | 1168 | ||
1205 | if (lua_isnil(L,-1)) { | 1169 | // _R[key_] = {} |
1206 | lua_pop(L,1); | 1170 | lua_rawset( L, LUA_REGISTRYINDEX); // {} |
1207 | lua_newtable(L); // value | ||
1208 | lua_pushlightuserdata( L, token ); // key | ||
1209 | lua_pushvalue(L,-2); | ||
1210 | // | ||
1211 | // [-3]: value (2nd ref) | ||
1212 | // [-2]: key | ||
1213 | // [-1]: value | ||
1214 | |||
1215 | lua_rawset( L, LUA_REGISTRYINDEX ); | ||
1216 | |||
1217 | // Set it's metatable if requested | ||
1218 | if (mode) { | ||
1219 | lua_newtable(L); | ||
1220 | lua_pushliteral(L, "__mode"); | ||
1221 | lua_pushstring(L, mode); | ||
1222 | lua_rawset(L, -3); | ||
1223 | lua_setmetatable(L, -2); | ||
1224 | } | ||
1225 | } | ||
1226 | STACK_END( L, 1); | ||
1227 | 1171 | ||
1228 | ASSERT_L( lua_istable(L,-1) ); | 1172 | // Set its metatable if requested |
1173 | if( mode_) | ||
1174 | { | ||
1175 | lua_newtable( L); // {} mt | ||
1176 | lua_pushliteral( L, "__mode"); // {} mt "__mode" | ||
1177 | lua_pushstring( L, mode_); // {} mt "__mode" mode | ||
1178 | lua_rawset( L, -3); // {} mt | ||
1179 | lua_setmetatable( L, -2); // {} | ||
1180 | } | ||
1181 | } | ||
1182 | STACK_END( L, 1); | ||
1183 | ASSERT_L( lua_istable( L, -1)); | ||
1229 | } | 1184 | } |
1230 | 1185 | ||
1231 | /* | 1186 | /* |
1232 | * Push a registry subtable (keyed by unique 'token') onto the stack. | 1187 | * Push a registry subtable (keyed by unique 'key_') onto the stack. |
1233 | * If the subtable does not exist, it is created and chained. | 1188 | * If the subtable does not exist, it is created and chained. |
1234 | */ | 1189 | */ |
1235 | static | 1190 | static inline void push_registry_subtable( lua_State* L, void* key_) |
1236 | void push_registry_subtable( lua_State *L, void *token ) { | 1191 | { |
1237 | push_registry_subtable_mode(L, token, NULL); | 1192 | push_registry_subtable_mode( L, key_, NULL); |
1238 | } | 1193 | } |
1239 | 1194 | ||
1240 | #define REG_MTID ( (void*) get_mt_id ) | 1195 | #define REG_MTID ( (void*) get_mt_id ) |
@@ -1864,12 +1819,10 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui | |||
1864 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, enum eLookupMode mode_, char const* upName_) | 1819 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt, enum eLookupMode mode_, char const* upName_) |
1865 | { | 1820 | { |
1866 | bool_t ret = TRUE; | 1821 | bool_t ret = TRUE; |
1867 | |||
1868 | STACK_GROW( L2, 1); | 1822 | STACK_GROW( L2, 1); |
1869 | |||
1870 | STACK_CHECK( L2); | 1823 | STACK_CHECK( L2); |
1871 | 1824 | ||
1872 | switch ( lua_type( L, i)) | 1825 | switch( lua_type( L, i)) |
1873 | { | 1826 | { |
1874 | /* Basic types allowed both as values, and as table keys */ | 1827 | /* Basic types allowed both as values, and as table keys */ |
1875 | 1828 | ||
@@ -1921,7 +1874,7 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
1921 | /* Allow only deep userdata entities to be copied across | 1874 | /* Allow only deep userdata entities to be copied across |
1922 | */ | 1875 | */ |
1923 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END)); | 1876 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END)); |
1924 | if( !luaG_copydeep( L, L2, i)) | 1877 | if( !copydeep( L, L2, i, mode_)) |
1925 | { | 1878 | { |
1926 | // Not a deep full userdata | 1879 | // Not a deep full userdata |
1927 | bool_t demote = FALSE; | 1880 | bool_t demote = FALSE; |
@@ -2129,7 +2082,6 @@ static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, u | |||
2129 | } | 2082 | } |
2130 | 2083 | ||
2131 | STACK_END( L2, ret ? 1 : 0); | 2084 | STACK_END( L2, ret ? 1 : 0); |
2132 | |||
2133 | return ret; | 2085 | return ret; |
2134 | } | 2086 | } |
2135 | 2087 | ||
@@ -2225,7 +2177,8 @@ void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLooku | |||
2225 | // package.loaders is renamed package.searchers in Lua 5.2 | 2177 | // package.loaders is renamed package.searchers in Lua 5.2 |
2226 | // but don't copy it anyway, as the function names change depending on the slot index! | 2178 | // but don't copy it anyway, as the function names change depending on the slot index! |
2227 | // users should provide an on_state_create function to setup custom loaders instead | 2179 | // users should provide an on_state_create function to setup custom loaders instead |
2228 | char const* entries[] = { "path", "cpath", "preload"/*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, NULL}; | 2180 | // don't copy package.preload in keeper states (they don't know how to translate functions) |
2181 | char const* entries[] = { "path", "cpath", (mode_ == eLM_LaneBody) ? "preload" : NULL/*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, NULL}; | ||
2229 | for( i = 0; entries[i]; ++ i) | 2182 | for( i = 0; entries[i]; ++ i) |
2230 | { | 2183 | { |
2231 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); | 2184 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); |
diff --git a/src/tools.h b/src/tools.h index be358db..ebe407b 100644 --- a/src/tools.h +++ b/src/tools.h | |||
@@ -99,11 +99,15 @@ extern int debugspew_indent_depth; | |||
99 | void luaG_dump( lua_State* L ); | 99 | void luaG_dump( lua_State* L ); |
100 | 100 | ||
101 | lua_State* luaG_newstate( lua_State* _from, char const* libs); | 101 | lua_State* luaG_newstate( lua_State* _from, char const* libs); |
102 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2, char const* name_); | 102 | void luaG_copy_one_time_settings( lua_State* L, lua_State* L2); |
103 | 103 | ||
104 | typedef struct { | 104 | // this is pointed to by full userdata proxies, and allocated with malloc() to survive any lua_State lifetime |
105 | volatile int refcount; | 105 | typedef struct |
106 | void *deep; | 106 | { |
107 | volatile int refcount; | ||
108 | void* deep; | ||
109 | // when stored in a keeper state, the full userdata doesn't have a metatable, so we need direct access to the idfunc | ||
110 | luaG_IdFunction idfunc; | ||
107 | } DEEP_PRELUDE; | 111 | } DEEP_PRELUDE; |
108 | 112 | ||
109 | enum eLookupMode | 113 | enum eLookupMode |
@@ -113,7 +117,7 @@ enum eLookupMode | |||
113 | eLM_FromKeeper // send a function from a keeper state to a lane | 117 | eLM_FromKeeper // send a function from a keeper state to a lane |
114 | }; | 118 | }; |
115 | 119 | ||
116 | void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata); | 120 | char const* push_deep_proxy( lua_State* L, DEEP_PRELUDE* prelude, enum eLookupMode mode_); |
117 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLookupMode mode_); | 121 | void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx, enum eLookupMode mode_); |
118 | 122 | ||
119 | int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n, enum eLookupMode mode_); | 123 | int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n, enum eLookupMode mode_); |
@@ -130,6 +134,8 @@ extern MUTEX_T mtid_lock; | |||
130 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); | 134 | void populate_func_lookup_table( lua_State* L, int _i, char const* _name); |
131 | void serialize_require( lua_State *L); | 135 | void serialize_require( lua_State *L); |
132 | int initialize_on_state_create( lua_State *L); | 136 | int initialize_on_state_create( lua_State *L); |
137 | void call_on_state_create( lua_State* L, lua_State* from_, enum eLookupMode mode_); | ||
138 | |||
133 | extern MUTEX_T require_cs; | 139 | extern MUTEX_T require_cs; |
134 | 140 | ||
135 | // for verbose errors | 141 | // for verbose errors |