aboutsummaryrefslogtreecommitdiff
path: root/src/state.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.cpp')
-rw-r--r--src/state.cpp442
1 files changed, 442 insertions, 0 deletions
diff --git a/src/state.cpp b/src/state.cpp
new file mode 100644
index 0000000..85ad31e
--- /dev/null
+++ b/src/state.cpp
@@ -0,0 +1,442 @@
1/*
2* STATE.C
3*
4* Lua tools to support Lanes.
5*/
6
7/*
8===============================================================================
9
10Copyright (C) 2002-10 Asko Kauppi <akauppi@gmail.com>
112011-21 benoit Germain <bnt.germain@gmail.com>
12
13Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal
15in the Software without restriction, including without limitation the rights
16to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the Software is
18furnished to do so, subject to the following conditions:
19
20The above copyright notice and this permission notice shall be included in
21all copies or substantial portions of the Software.
22
23THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29THE SOFTWARE.
30
31===============================================================================
32*/
33
34#include <stdio.h>
35#include <assert.h>
36#include <string.h>
37#include <ctype.h>
38#include <stdlib.h>
39#if !defined(__APPLE__)
40#include <malloc.h>
41#endif // __APPLE__
42
43#include "compat.h"
44#include "macros_and_utils.h"
45#include "universe.h"
46#include "tools.h"
47#include "lanes.h"
48
49// ################################################################################################
50
51/*---=== Serialize require ===---
52*/
53
54//---
55// [val,...]= new_require( ... )
56//
57// Call 'old_require' but only one lane at a time.
58//
59// Upvalues: [1]: original 'require' function
60//
61static int luaG_new_require( lua_State* L)
62{
63 int rc;
64 int const args = lua_gettop( L); // args
65 Universe* U = universe_get( L);
66 //char const* modname = luaL_checkstring( L, 1);
67
68 STACK_GROW( L, 1);
69
70 lua_pushvalue( L, lua_upvalueindex( 1)); // args require
71 lua_insert( L, 1); // require args
72
73 // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would
74 // leave us locked, blocking any future 'require' calls from other lanes.
75
76 MUTEX_LOCK( &U->require_cs);
77 // starting with Lua 5.4, require may return a second optional value, so we need LUA_MULTRET
78 rc = lua_pcall( L, args, LUA_MULTRET, 0 /*errfunc*/ ); // err|result(s)
79 MUTEX_UNLOCK( &U->require_cs);
80
81 // the required module (or an error message) is left on the stack as returned value by original require function
82
83 if( rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ?
84 {
85 return lua_error( L);
86 }
87 // should be 1 for Lua <= 5.3, 1 or 2 starting with Lua 5.4
88 return lua_gettop(L); // result(s)
89}
90
91/*
92* Serialize calls to 'require', if it exists
93*/
94void serialize_require( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L)
95{
96 STACK_GROW( L, 1);
97 STACK_CHECK( L, 0);
98 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "serializing require()\n" INDENT_END));
99
100 // Check 'require' is there and not already wrapped; if not, do nothing
101 //
102 lua_getglobal( L, "require");
103 if( lua_isfunction( L, -1) && lua_tocfunction( L, -1) != luaG_new_require)
104 {
105 // [-1]: original 'require' function
106 lua_pushcclosure( L, luaG_new_require, 1 /*upvalues*/);
107 lua_setglobal( L, "require");
108 }
109 else
110 {
111 // [-1]: nil
112 lua_pop( L, 1);
113 }
114
115 STACK_END( L, 0);
116}
117
118// ################################################################################################
119
120/*---=== luaG_newstate ===---*/
121
122static int require_lanes_core( lua_State* L)
123{
124 // leaves a copy of 'lanes.core' module table on the stack
125 luaL_requiref( L, "lanes.core", luaopen_lanes_core, 0);
126 return 1;
127}
128
129
130static const luaL_Reg libs[] =
131{
132 { LUA_LOADLIBNAME, luaopen_package},
133 { LUA_TABLIBNAME, luaopen_table},
134 { LUA_STRLIBNAME, luaopen_string},
135 { LUA_MATHLIBNAME, luaopen_math},
136#ifndef PLATFORM_XBOX // no os/io libs on xbox
137 { LUA_OSLIBNAME, luaopen_os},
138 { LUA_IOLIBNAME, luaopen_io},
139#endif // PLATFORM_XBOX
140#if LUA_VERSION_NUM >= 503
141 { LUA_UTF8LIBNAME, luaopen_utf8},
142#endif
143#if LUA_VERSION_NUM >= 502
144#ifdef luaopen_bit32
145 { LUA_BITLIBNAME, luaopen_bit32},
146#endif
147 { LUA_COLIBNAME, luaopen_coroutine}, // Lua 5.2: coroutine is no longer a part of base!
148#else // LUA_VERSION_NUM
149 { LUA_COLIBNAME, NULL}, // Lua 5.1: part of base package
150#endif // LUA_VERSION_NUM
151 { LUA_DBLIBNAME, luaopen_debug},
152#if LUAJIT_FLAVOR() != 0 // building against LuaJIT headers, add some LuaJIT-specific libs
153//#pragma message( "supporting JIT base libs")
154 { LUA_BITLIBNAME, luaopen_bit},
155 { LUA_JITLIBNAME, luaopen_jit},
156 { LUA_FFILIBNAME, luaopen_ffi},
157#endif // LUAJIT_FLAVOR()
158
159{ LUA_DBLIBNAME, luaopen_debug},
160{ "lanes.core", require_lanes_core}, // So that we can open it like any base library (possible since we have access to the init function)
161 //
162{ "base", NULL}, // ignore "base" (already acquired it)
163{ NULL, NULL }
164};
165
166static void open1lib( DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L, char const* name_, size_t len_)
167{
168 int i;
169 for( i = 0; libs[i].name; ++ i)
170 {
171 if( strncmp( name_, libs[i].name, len_) == 0)
172 {
173 lua_CFunction libfunc = libs[i].func;
174 name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_
175 if( libfunc != NULL)
176 {
177 bool_t const isLanesCore = (libfunc == require_lanes_core) ? TRUE : FALSE; // don't want to create a global for "lanes.core"
178 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, (int) len_, name_));
179 STACK_CHECK( L, 0);
180 // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack)
181 luaL_requiref( L, name_, libfunc, !isLanesCore);
182 // lanes.core doesn't declare a global, so scan it here and now
183 if( isLanesCore == TRUE)
184 {
185 populate_func_lookup_table( L, -1, name_);
186 }
187 lua_pop( L, 1);
188 STACK_END( L, 0);
189 }
190 break;
191 }
192 }
193}
194
195
196// just like lua_xmove, args are (from, to)
197static void copy_one_time_settings( Universe* U, lua_State* L, lua_State* L2)
198{
199 STACK_GROW( L, 2);
200 STACK_CHECK( L, 0);
201 STACK_CHECK( L2, 0);
202
203 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "copy_one_time_settings()\n" INDENT_END));
204 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
205
206 REGISTRY_GET( L, CONFIG_REGKEY); // config
207 // copy settings from from source to destination registry
208 if( luaG_inter_move( U, L, L2, 1, eLM_LaneBody) < 0) // // config
209 {
210 (void) luaL_error( L, "failed to copy settings when loading lanes.core");
211 }
212 // set L2:_R[CONFIG_REGKEY] = settings
213 REGISTRY_SET( L2, CONFIG_REGKEY, lua_insert( L2, -2)); //
214 STACK_END( L2, 0);
215 STACK_END( L, 0);
216 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
217}
218
219void initialize_on_state_create( Universe* U, lua_State* L)
220{
221 STACK_CHECK( L, 0);
222 lua_getfield( L, -1, "on_state_create"); // settings on_state_create|nil
223 if( !lua_isnil( L, -1))
224 {
225 // store C function pointer in an internal variable
226 U->on_state_create_func = lua_tocfunction( L, -1); // settings on_state_create
227 if( U->on_state_create_func != NULL)
228 {
229 // make sure the function doesn't have upvalues
230 char const* upname = lua_getupvalue( L, -1, 1); // settings on_state_create upval?
231 if( upname != NULL) // should be "" for C functions with upvalues if any
232 {
233 (void) luaL_error( L, "on_state_create shouldn't have upvalues");
234 }
235 // remove this C function from the config table so that it doesn't cause problems
236 // when we transfer the config table in newly created Lua states
237 lua_pushnil( L); // settings on_state_create nil
238 lua_setfield( L, -3, "on_state_create"); // settings on_state_create
239 }
240 else
241 {
242 // optim: store marker saying we have such a function in the config table
243 U->on_state_create_func = (lua_CFunction) initialize_on_state_create;
244 }
245 }
246 lua_pop( L, 1); // settings
247 STACK_END( L, 0);
248}
249
250lua_State* create_state( Universe* U, lua_State* from_)
251{
252 lua_State* L;
253#if LUAJIT_FLAVOR() == 64
254 // for some reason, LuaJIT 64 bits does not support creating a state with lua_newstate...
255 L = luaL_newstate();
256#else // LUAJIT_FLAVOR() == 64
257 if( U->provide_allocator != NULL) // we have a function we can call to obtain an allocator
258 {
259 lua_pushcclosure( from_, U->provide_allocator, 0);
260 lua_call( from_, 0, 1);
261 {
262 AllocatorDefinition* const def = (AllocatorDefinition*) lua_touserdata( from_, -1);
263 L = lua_newstate( def->allocF, def->allocUD);
264 }
265 lua_pop( from_, 1);
266 }
267 else
268 {
269 // reuse the allocator provided when the master state was created
270 L = lua_newstate( U->protected_allocator.definition.allocF, U->protected_allocator.definition.allocUD);
271 }
272#endif // LUAJIT_FLAVOR() == 64
273
274 if( L == NULL)
275 {
276 (void) luaL_error( from_, "luaG_newstate() failed while creating state; out of memory");
277 }
278 return L;
279}
280
281void call_on_state_create( Universe* U, lua_State* L, lua_State* from_, LookupMode mode_)
282{
283 if( U->on_state_create_func != NULL)
284 {
285 STACK_CHECK( L, 0);
286 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END));
287 if( U->on_state_create_func != (lua_CFunction) initialize_on_state_create)
288 {
289 // C function: recreate a closure in the new state, bypassing the lookup scheme
290 lua_pushcfunction( L, U->on_state_create_func); // on_state_create()
291 }
292 else // Lua function located in the config table, copied when we opened "lanes.core"
293 {
294 if( mode_ != eLM_LaneBody)
295 {
296 // if attempting to call in a keeper state, do nothing because the function doesn't exist there
297 // this doesn't count as an error though
298 return;
299 }
300 REGISTRY_GET( L, CONFIG_REGKEY); // {}
301 STACK_MID( L, 1);
302 lua_getfield( L, -1, "on_state_create"); // {} on_state_create()
303 lua_remove( L, -2); // on_state_create()
304 }
305 STACK_MID( L, 1);
306 // capture error and raise it in caller state
307 if( lua_pcall( L, 0, 0, 0) != LUA_OK)
308 {
309 luaL_error( from_, "on_state_create failed: \"%s\"", lua_isstring( L, -1) ? lua_tostring( L, -1) : lua_typename( L, lua_type( L, -1)));
310 }
311 STACK_END( L, 0);
312 }
313}
314
315/*
316* Like 'luaL_openlibs()' but allows the set of libraries be selected
317*
318* NULL no libraries, not even base
319* "" base library only
320* "io,string" named libraries
321* "*" all libraries
322*
323* Base ("unpack", "print" etc.) is always added, unless 'libs' is NULL.
324*
325* *NOT* called for keeper states!
326*
327*/
328lua_State* luaG_newstate( Universe* U, lua_State* from_, char const* libs_)
329{
330 lua_State* L = create_state( U, from_);
331
332 STACK_GROW( L, 2);
333 STACK_CHECK_ABS( L, 0);
334
335 // copy the universe as a light userdata (only the master state holds the full userdata)
336 // that way, if Lanes is required in this new state, we'll know we are part of this universe
337 universe_store( L, U);
338 STACK_MID( L, 0);
339
340 // we'll need this every time we transfer some C function from/to this state
341 REGISTRY_SET( L, LOOKUP_REGKEY, lua_newtable( L));
342 STACK_MID( L, 0);
343
344 // neither libs (not even 'base') nor special init func: we are done
345 if( libs_ == NULL && U->on_state_create_func == NULL)
346 {
347 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(NULL)\n" INDENT_END));
348 return L;
349 }
350
351 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END));
352 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
353
354 // copy settings (for example because it may contain a Lua on_state_create function)
355 copy_one_time_settings( U, from_, L);
356
357 // 'lua.c' stops GC during initialization so perhaps its a good idea. :)
358 lua_gc( L, LUA_GCSTOP, 0);
359
360
361 // Anything causes 'base' to be taken in
362 //
363 if( libs_ != NULL)
364 {
365 // special "*" case (mainly to help with LuaJIT compatibility)
366 // as we are called from luaopen_lanes_core() already, and that would deadlock
367 if( libs_[0] == '*' && libs_[1] == 0)
368 {
369 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END));
370 luaL_openlibs( L);
371 // don't forget lanes.core for regular lane states
372 open1lib( DEBUGSPEW_PARAM_COMMA( U) L, "lanes.core", 10);
373 libs_ = NULL; // done with libs
374 }
375 else
376 {
377 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening base library\n" INDENT_END));
378#if LUA_VERSION_NUM >= 502
379 // open base library the same way as in luaL_openlibs()
380 luaL_requiref( L, "_G", luaopen_base, 1);
381 lua_pop( L, 1);
382#else // LUA_VERSION_NUM
383 lua_pushcfunction( L, luaopen_base);
384 lua_pushstring( L, "");
385 lua_call( L, 1, 0);
386#endif // LUA_VERSION_NUM
387 }
388 }
389 STACK_END( L, 0);
390
391 // scan all libraries, open them one by one
392 if( libs_)
393 {
394 char const* p;
395 unsigned int len = 0;
396 for( p = libs_; *p; p += len)
397 {
398 // skip delimiters ('.' can be part of name for "lanes.core")
399 while( *p && !isalnum( *p) && *p != '.')
400 ++ p;
401 // skip name
402 len = 0;
403 while( isalnum( p[len]) || p[len] == '.')
404 ++ len;
405 // open library
406 open1lib( DEBUGSPEW_PARAM_COMMA( U) L, p, len);
407 }
408 }
409 lua_gc( L, LUA_GCRESTART, 0);
410
411 serialize_require( DEBUGSPEW_PARAM_COMMA( U) L);
412
413 // call this after the base libraries are loaded and GC is restarted
414 // will raise an error in from_ in case of problem
415 call_on_state_create( U, L, from_, eLM_LaneBody);
416
417 STACK_CHECK( L, 0);
418 // after all this, register everything we find in our name<->function database
419 lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
420 populate_func_lookup_table( L, -1, NULL);
421
422#if 0 && USE_DEBUG_SPEW()
423 // dump the lookup database contents
424 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {}
425 lua_pushnil( L); // {} nil
426 while( lua_next( L, -2)) // {} k v
427 {
428 lua_getglobal( L, "print"); // {} k v print
429 lua_pushlstring( L, debugspew_indent, U->debugspew_indent_depth); // {} k v print " "
430 lua_pushvalue( L, -4); // {} k v print " " k
431 lua_pushvalue( L, -4); // {} k v print " " k v
432 lua_call( L, 3, 0); // {} k v
433 lua_pop( L, 1); // {} k
434 }
435 lua_pop( L, 1); // {}
436#endif // USE_DEBUG_SPEW()
437
438 lua_pop( L, 1);
439 STACK_END( L, 0);
440 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
441 return L;
442}