diff options
Diffstat (limited to 'src/tools.c')
-rw-r--r-- | src/tools.c | 398 |
1 files changed, 1 insertions, 397 deletions
diff --git a/src/tools.c b/src/tools.c index f3ac236..a0ba20e 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * TOOLS.C Copyright (c) 2002-10, Asko Kauppi | 2 | * TOOLS.C Copyright (c) 2002-10, Asko Kauppi |
3 | * | 3 | * |
4 | * Lua tools to support Lanes. | 4 | * Lua tools to support Lanes. |
5 | */ | 5 | */ |
@@ -178,139 +178,6 @@ void cleanup_allocator_function( Universe* U, lua_State* L) | |||
178 | 178 | ||
179 | // ################################################################################################ | 179 | // ################################################################################################ |
180 | 180 | ||
181 | void initialize_on_state_create( Universe* U, lua_State* L) | ||
182 | { | ||
183 | STACK_CHECK( L, 0); | ||
184 | lua_getfield( L, -1, "on_state_create"); // settings on_state_create|nil | ||
185 | if( !lua_isnil( L, -1)) | ||
186 | { | ||
187 | // store C function pointer in an internal variable | ||
188 | U->on_state_create_func = lua_tocfunction( L, -1); // settings on_state_create | ||
189 | if( U->on_state_create_func != NULL) | ||
190 | { | ||
191 | // make sure the function doesn't have upvalues | ||
192 | char const* upname = lua_getupvalue( L, -1, 1); // settings on_state_create upval? | ||
193 | if( upname != NULL) // should be "" for C functions with upvalues if any | ||
194 | { | ||
195 | (void) luaL_error( L, "on_state_create shouldn't have upvalues"); | ||
196 | } | ||
197 | // remove this C function from the config table so that it doesn't cause problems | ||
198 | // when we transfer the config table in newly created Lua states | ||
199 | lua_pushnil( L); // settings on_state_create nil | ||
200 | lua_setfield( L, -3, "on_state_create"); // settings on_state_create | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | // optim: store marker saying we have such a function in the config table | ||
205 | U->on_state_create_func = (lua_CFunction) initialize_on_state_create; | ||
206 | } | ||
207 | } | ||
208 | lua_pop( L, 1); // settings | ||
209 | STACK_END( L, 0); | ||
210 | } | ||
211 | |||
212 | // ################################################################################################ | ||
213 | |||
214 | // just like lua_xmove, args are (from, to) | ||
215 | static void copy_one_time_settings( Universe* U, lua_State* L, lua_State* L2) | ||
216 | { | ||
217 | STACK_GROW( L, 2); | ||
218 | STACK_CHECK( L, 0); | ||
219 | STACK_CHECK( L2, 0); | ||
220 | |||
221 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "copy_one_time_settings()\n" INDENT_END)); | ||
222 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | ||
223 | |||
224 | REGISTRY_GET( L, CONFIG_REGKEY); // config | ||
225 | // copy settings from from source to destination registry | ||
226 | if( luaG_inter_move( U, L, L2, 1, eLM_LaneBody) < 0) // // config | ||
227 | { | ||
228 | (void) luaL_error( L, "failed to copy settings when loading lanes.core"); | ||
229 | } | ||
230 | // set L2:_R[CONFIG_REGKEY] = settings | ||
231 | REGISTRY_SET( L2, CONFIG_REGKEY, lua_insert( L2, -2)); // | ||
232 | STACK_END( L2, 0); | ||
233 | STACK_END( L, 0); | ||
234 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | ||
235 | } | ||
236 | |||
237 | |||
238 | /*---=== luaG_newstate ===---*/ | ||
239 | |||
240 | static int require_lanes_core( lua_State* L) | ||
241 | { | ||
242 | // leaves a copy of 'lanes.core' module table on the stack | ||
243 | luaL_requiref( L, "lanes.core", luaopen_lanes_core, 0); | ||
244 | return 1; | ||
245 | } | ||
246 | |||
247 | |||
248 | static const luaL_Reg libs[] = | ||
249 | { | ||
250 | { LUA_LOADLIBNAME, luaopen_package}, | ||
251 | { LUA_TABLIBNAME, luaopen_table}, | ||
252 | { LUA_STRLIBNAME, luaopen_string}, | ||
253 | { LUA_MATHLIBNAME, luaopen_math}, | ||
254 | #ifndef PLATFORM_XBOX // no os/io libs on xbox | ||
255 | { LUA_OSLIBNAME, luaopen_os}, | ||
256 | { LUA_IOLIBNAME, luaopen_io}, | ||
257 | #endif // PLATFORM_XBOX | ||
258 | #if LUA_VERSION_NUM >= 503 | ||
259 | { LUA_UTF8LIBNAME, luaopen_utf8}, | ||
260 | #endif | ||
261 | #if LUA_VERSION_NUM >= 502 | ||
262 | #ifdef luaopen_bit32 | ||
263 | { LUA_BITLIBNAME, luaopen_bit32}, | ||
264 | #endif | ||
265 | { LUA_COLIBNAME, luaopen_coroutine}, // Lua 5.2: coroutine is no longer a part of base! | ||
266 | #else // LUA_VERSION_NUM | ||
267 | { LUA_COLIBNAME, NULL}, // Lua 5.1: part of base package | ||
268 | #endif // LUA_VERSION_NUM | ||
269 | { LUA_DBLIBNAME, luaopen_debug}, | ||
270 | #if defined LUA_JITLIBNAME // building against LuaJIT headers, add some LuaJIT-specific libs | ||
271 | //#pragma message( "supporting JIT base libs") | ||
272 | { LUA_BITLIBNAME, luaopen_bit}, | ||
273 | { LUA_JITLIBNAME, luaopen_jit}, | ||
274 | { LUA_FFILIBNAME, luaopen_ffi}, | ||
275 | #endif // LUA_JITLIBNAME | ||
276 | |||
277 | { LUA_DBLIBNAME, luaopen_debug}, | ||
278 | { "lanes.core", require_lanes_core}, // So that we can open it like any base library (possible since we have access to the init function) | ||
279 | // | ||
280 | { "base", NULL}, // ignore "base" (already acquired it) | ||
281 | { NULL, NULL } | ||
282 | }; | ||
283 | |||
284 | static void open1lib( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L, char const* name_, size_t len_) | ||
285 | { | ||
286 | int i; | ||
287 | for( i = 0; libs[i].name; ++ i) | ||
288 | { | ||
289 | if( strncmp( name_, libs[i].name, len_) == 0) | ||
290 | { | ||
291 | lua_CFunction libfunc = libs[i].func; | ||
292 | name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_ | ||
293 | if( libfunc != NULL) | ||
294 | { | ||
295 | bool_t const isLanesCore = (libfunc == require_lanes_core) ? TRUE : FALSE; // don't want to create a global for "lanes.core" | ||
296 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, (int) len_, name_)); | ||
297 | STACK_CHECK( L, 0); | ||
298 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) | ||
299 | luaL_requiref( L, name_, libfunc, !isLanesCore); | ||
300 | // lanes.core doesn't declare a global, so scan it here and now | ||
301 | if( isLanesCore == TRUE) | ||
302 | { | ||
303 | populate_func_lookup_table( L, -1, name_); | ||
304 | } | ||
305 | lua_pop( L, 1); | ||
306 | STACK_END( L, 0); | ||
307 | } | ||
308 | break; | ||
309 | } | ||
310 | } | ||
311 | } | ||
312 | |||
313 | |||
314 | static int dummy_writer( lua_State* L, void const* p, size_t sz, void* ud) | 181 | static int dummy_writer( lua_State* L, void const* p, size_t sz, void* ud) |
315 | { | 182 | { |
316 | (void)L; (void)p; (void)sz; (void) ud; // unused | 183 | (void)L; (void)p; (void)sz; (void) ud; // unused |
@@ -668,197 +535,6 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_) | |||
668 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | 535 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); |
669 | } | 536 | } |
670 | 537 | ||
671 | void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMode mode_) | ||
672 | { | ||
673 | if( U->on_state_create_func != NULL) | ||
674 | { | ||
675 | STACK_CHECK( L, 0); | ||
676 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | ||
677 | if( U->on_state_create_func != (lua_CFunction) initialize_on_state_create) | ||
678 | { | ||
679 | // C function: recreate a closure in the new state, bypassing the lookup scheme | ||
680 | lua_pushcfunction( L, U->on_state_create_func); // on_state_create() | ||
681 | } | ||
682 | else // Lua function located in the config table, copied when we opened "lanes.core" | ||
683 | { | ||
684 | if( mode_ != eLM_LaneBody) | ||
685 | { | ||
686 | // if attempting to call in a keeper state, do nothing because the function doesn't exist there | ||
687 | // this doesn't count as an error though | ||
688 | return; | ||
689 | } | ||
690 | REGISTRY_GET( L, CONFIG_REGKEY); // {} | ||
691 | STACK_MID( L, 1); | ||
692 | lua_getfield( L, -1, "on_state_create"); // {} on_state_create() | ||
693 | lua_remove( L, -2); // on_state_create() | ||
694 | } | ||
695 | STACK_MID( L, 1); | ||
696 | // capture error and raise it in caller state | ||
697 | if( lua_pcall( L, 0, 0, 0) != LUA_OK) | ||
698 | { | ||
699 | luaL_error( from_, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1))); | ||
700 | } | ||
701 | STACK_END( L, 0); | ||
702 | } | ||
703 | } | ||
704 | |||
705 | lua_State* create_state( Universe* U, lua_State* from_) | ||
706 | { | ||
707 | lua_State* L; | ||
708 | if( U->provide_allocator != NULL) | ||
709 | { | ||
710 | lua_pushcclosure( from_, U->provide_allocator, 0); | ||
711 | lua_call( from_, 0, 1); | ||
712 | { | ||
713 | AllocatorDefinition* def = lua_touserdata( from_, -1); | ||
714 | L = lua_newstate( def->allocF, def->allocUD); | ||
715 | } | ||
716 | lua_pop( from_, 1); | ||
717 | } | ||
718 | else | ||
719 | { | ||
720 | L = luaL_newstate(); | ||
721 | } | ||
722 | |||
723 | if( L == NULL) | ||
724 | { | ||
725 | (void) luaL_error( from_, "luaG_newstate() failed while creating state; out of memory"); | ||
726 | } | ||
727 | return L; | ||
728 | } | ||
729 | |||
730 | /* | ||
731 | * Like 'luaL_openlibs()' but allows the set of libraries be selected | ||
732 | * | ||
733 | * NULL no libraries, not even base | ||
734 | * "" base library only | ||
735 | * "io,string" named libraries | ||
736 | * "*" all libraries | ||
737 | * | ||
738 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL. | ||
739 | * | ||
740 | * *NOT* called for keeper states! | ||
741 | * | ||
742 | */ | ||
743 | lua_State* luaG_newstate( Universe* U, lua_State* from_, char const* libs_) | ||
744 | { | ||
745 | lua_State* L = create_state( U, from_); | ||
746 | |||
747 | STACK_GROW( L, 2); | ||
748 | STACK_CHECK_ABS( L, 0); | ||
749 | |||
750 | // copy the universe as a light userdata (only the master state holds the full userdata) | ||
751 | // that way, if Lanes is required in this new state, we'll know we are part of this universe | ||
752 | universe_store( L, U); | ||
753 | STACK_MID( L, 0); | ||
754 | |||
755 | // we'll need this every time we transfer some C function from/to this state | ||
756 | REGISTRY_SET( L, LOOKUP_REGKEY, lua_newtable( L)); | ||
757 | STACK_MID( L, 0); | ||
758 | |||
759 | // neither libs (not even 'base') nor special init func: we are done | ||
760 | if( libs_ == NULL && U->on_state_create_func == NULL) | ||
761 | { | ||
762 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END)); | ||
763 | return L; | ||
764 | } | ||
765 | |||
766 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END)); | ||
767 | DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); | ||
768 | |||
769 | // copy settings (for example because it may contain a Lua on_state_create function) | ||
770 | copy_one_time_settings( U, from_, L); | ||
771 | |||
772 | // 'lua.c' stops GC during initialization so perhaps its a good idea. :) | ||
773 | lua_gc( L, LUA_GCSTOP, 0); | ||
774 | |||
775 | |||
776 | // Anything causes 'base' to be taken in | ||
777 | // | ||
778 | if( libs_ != NULL) | ||
779 | { | ||
780 | // special "*" case (mainly to help with LuaJIT compatibility) | ||
781 | // as we are called from luaopen_lanes_core() already, and that would deadlock | ||
782 | if( libs_[0] == '*' && libs_[1] == 0) | ||
783 | { | ||
784 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); | ||
785 | luaL_openlibs( L); | ||
786 | // don't forget lanes.core for regular lane states | ||
787 | open1lib( DEBUGSPEW_PARAM_COMMA( U) L, "lanes.core", 10); | ||
788 | libs_ = NULL; // done with libs | ||
789 | } | ||
790 | else | ||
791 | { | ||
792 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening base library\n" INDENT_END)); | ||
793 | #if LUA_VERSION_NUM >= 502 | ||
794 | // open base library the same way as in luaL_openlibs() | ||
795 | luaL_requiref( L, "_G", luaopen_base, 1); | ||
796 | lua_pop( L, 1); | ||
797 | #else // LUA_VERSION_NUM | ||
798 | lua_pushcfunction( L, luaopen_base); | ||
799 | lua_pushstring( L, ""); | ||
800 | lua_call( L, 1, 0); | ||
801 | #endif // LUA_VERSION_NUM | ||
802 | } | ||
803 | } | ||
804 | STACK_END( L, 0); | ||
805 | |||
806 | // scan all libraries, open them one by one | ||
807 | if( libs_) | ||
808 | { | ||
809 | char const* p; | ||
810 | unsigned int len = 0; | ||
811 | for( p = libs_; *p; p += len) | ||
812 | { | ||
813 | // skip delimiters ('.' can be part of name for "lanes.core") | ||
814 | while( *p && !isalnum( *p) && *p != '.') | ||
815 | ++ p; | ||
816 | // skip name | ||
817 | len = 0; | ||
818 | while( isalnum( p[len]) || p[len] == '.') | ||
819 | ++ len; | ||
820 | // open library | ||
821 | open1lib( DEBUGSPEW_PARAM_COMMA( U) L, p, len); | ||
822 | } | ||
823 | } | ||
824 | lua_gc( L, LUA_GCRESTART, 0); | ||
825 | |||
826 | serialize_require( DEBUGSPEW_PARAM_COMMA( U) L); | ||
827 | |||
828 | // call this after the base libraries are loaded and GC is restarted | ||
829 | // will raise an error in from_ in case of problem | ||
830 | call_on_state_create( U, L, from_, eLM_LaneBody); | ||
831 | |||
832 | STACK_CHECK( L, 0); | ||
833 | // after all this, register everything we find in our name<->function database | ||
834 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack | ||
835 | populate_func_lookup_table( L, -1, NULL); | ||
836 | |||
837 | #if 0 && USE_DEBUG_SPEW | ||
838 | // dump the lookup database contents | ||
839 | lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {} | ||
840 | lua_pushnil( L); // {} nil | ||
841 | while( lua_next( L, -2)) // {} k v | ||
842 | { | ||
843 | lua_getglobal( L, "print"); // {} k v print | ||
844 | lua_pushlstring( L, debugspew_indent, U->debugspew_indent_depth); // {} k v print " " | ||
845 | lua_pushvalue( L, -4); // {} k v print " " k | ||
846 | lua_pushvalue( L, -4); // {} k v print " " k v | ||
847 | lua_call( L, 3, 0); // {} k v | ||
848 | lua_pop( L, 1); // {} k | ||
849 | } | ||
850 | lua_pop( L, 1); // {} | ||
851 | #endif // USE_DEBUG_SPEW | ||
852 | |||
853 | lua_pop( L, 1); | ||
854 | STACK_END( L, 0); | ||
855 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | ||
856 | return L; | ||
857 | } | ||
858 | |||
859 | |||
860 | |||
861 | |||
862 | /*---=== Inter-state copying ===---*/ | 538 | /*---=== Inter-state copying ===---*/ |
863 | 539 | ||
864 | // crc64/we of string "REG_MTID" generated at http://www.nitrxgen.net/hashgen/ | 540 | // crc64/we of string "REG_MTID" generated at http://www.nitrxgen.net/hashgen/ |
@@ -2265,75 +1941,3 @@ int luaG_inter_copy_package( Universe* U, lua_State* L, lua_State* L2, int packa | |||
2265 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); | 1941 | DEBUGSPEW_CODE( -- U->debugspew_indent_depth); |
2266 | return 0; | 1942 | return 0; |
2267 | } | 1943 | } |
2268 | |||
2269 | |||
2270 | /*---=== Serialize require ===--- | ||
2271 | */ | ||
2272 | |||
2273 | //--- | ||
2274 | // [val]= new_require( ... ) | ||
2275 | // | ||
2276 | // Call 'old_require' but only one lane at a time. | ||
2277 | // | ||
2278 | // Upvalues: [1]: original 'require' function | ||
2279 | // | ||
2280 | int luaG_new_require( lua_State* L) | ||
2281 | { | ||
2282 | int rc, i; | ||
2283 | int args = lua_gettop( L); | ||
2284 | Universe* U = universe_get( L); | ||
2285 | //char const* modname = luaL_checkstring( L, 1); | ||
2286 | |||
2287 | STACK_GROW( L, args + 1); | ||
2288 | STACK_CHECK( L, 0); | ||
2289 | |||
2290 | lua_pushvalue( L, lua_upvalueindex( 1)); | ||
2291 | for( i = 1; i <= args; ++ i) | ||
2292 | { | ||
2293 | lua_pushvalue( L, i); | ||
2294 | } | ||
2295 | |||
2296 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would | ||
2297 | // leave us locked, blocking any future 'require' calls from other lanes. | ||
2298 | // | ||
2299 | MUTEX_LOCK( &U->require_cs); | ||
2300 | rc = lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ ); | ||
2301 | MUTEX_UNLOCK( &U->require_cs); | ||
2302 | |||
2303 | // the required module (or an error message) is left on the stack as returned value by original require function | ||
2304 | STACK_END( L, 1); | ||
2305 | |||
2306 | if( rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ? | ||
2307 | { | ||
2308 | return lua_error( L); // error message already at [-1] | ||
2309 | } | ||
2310 | |||
2311 | return 1; | ||
2312 | } | ||
2313 | |||
2314 | /* | ||
2315 | * Serialize calls to 'require', if it exists | ||
2316 | */ | ||
2317 | void serialize_require( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L) | ||
2318 | { | ||
2319 | STACK_GROW( L, 1); | ||
2320 | STACK_CHECK( L, 0); | ||
2321 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "serializing require()\n" INDENT_END)); | ||
2322 | |||
2323 | // Check 'require' is there and not already wrapped; if not, do nothing | ||
2324 | // | ||
2325 | lua_getglobal( L, "require"); | ||
2326 | if( lua_isfunction( L, -1) && lua_tocfunction( L, -1) != luaG_new_require) | ||
2327 | { | ||
2328 | // [-1]: original 'require' function | ||
2329 | lua_pushcclosure( L, luaG_new_require, 1 /*upvalues*/); | ||
2330 | lua_setglobal( L, "require"); | ||
2331 | } | ||
2332 | else | ||
2333 | { | ||
2334 | // [-1]: nil | ||
2335 | lua_pop( L, 1); | ||
2336 | } | ||
2337 | |||
2338 | STACK_END( L, 0); | ||
2339 | } | ||