aboutsummaryrefslogtreecommitdiff
path: root/src/tools.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools.c')
-rw-r--r--src/tools.c398
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
181void 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)
215static 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
240static 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
248static 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
284static 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
314static int dummy_writer( lua_State* L, void const* p, size_t sz, void* ud) 181static 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
671void 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
705lua_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 */
743lua_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//
2280int 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*/
2317void 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}