diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2013-01-30 20:28:47 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2013-01-30 20:28:47 +0100 |
commit | b657f38535c3c27a848353ef853d6667d6acc917 (patch) | |
tree | 8679a62c0b6343eae4781cff10a0ea60460d9cb4 /src/tools.c | |
parent | 3377b95704e611a288791fee6a7bc59c5ecebf2d (diff) | |
download | lanes-b657f38535c3c27a848353ef853d6667d6acc917.tar.gz lanes-b657f38535c3c27a848353ef853d6667d6acc917.tar.bz2 lanes-b657f38535c3c27a848353ef853d6667d6acc917.zip |
version 3.5.0
* new: API lanes.require(), use it instead of regular require() for modules that export C functions you need to send over.
* new: lanes no longer require 'lanes.core' by default in every created state. Use {required={"lanes.core"}} if you need to transfer lanes functions.
* internal: because of the above, reworked the timer implementation to remove upvalue-dependency on lanes.core
* new: API lanes.timer_lane, to be able to operate on timer lane if need be
* improved: if a module is a full userdata, scan its metatable for function database population
* improved: on_state_create can be a Lua function
* changed: on_state_create is called after the base libraries are loaded
* package[loaders|searchers] is no longer transfered as function naming depends on slot order
* internal: changed separator from '.' to '/' in lookup databases to be able to distinguish search levels and dot coming from module names
* added some mode debug spew
* updated tests to reflect the above changes
Diffstat (limited to 'src/tools.c')
-rw-r--r-- | src/tools.c | 92 |
1 files changed, 59 insertions, 33 deletions
diff --git a/src/tools.c b/src/tools.c index 552e61e..9961c1a 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -224,7 +224,7 @@ static char const* luaG_pushFQN(lua_State *L, int t, int last) | |||
224 | { | 224 | { |
225 | lua_rawgeti( L, t, i); | 225 | lua_rawgeti( L, t, i); |
226 | luaL_addvalue( &b); | 226 | luaL_addvalue( &b); |
227 | luaL_addlstring(&b, ".", 1); | 227 | luaL_addlstring(&b, "/", 1); |
228 | } | 228 | } |
229 | if( i == last) // add last value (if interval was not empty) | 229 | if( i == last) // add last value (if interval was not empty) |
230 | { | 230 | { |
@@ -250,9 +250,16 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _ | |||
250 | int const breadth_first_cache = lua_gettop( L) + 1; | 250 | int const breadth_first_cache = lua_gettop( L) + 1; |
251 | 251 | ||
252 | STACK_GROW( L, 6); | 252 | STACK_GROW( L, 6); |
253 | // slot _i contains a table where we search for functions | 253 | // slot _i contains a table where we search for functions (or a full userdata with a metatable) |
254 | STACK_CHECK( L); // ... {_i} | 254 | STACK_CHECK( L); // ... {_i} |
255 | 255 | ||
256 | // if object is a userdata, replace it by its metatable | ||
257 | if( lua_type( L, _i) == LUA_TUSERDATA) | ||
258 | { | ||
259 | lua_getmetatable( L, _i); // ... {_i} mt | ||
260 | lua_replace( L, _i); // ... {_i} | ||
261 | } | ||
262 | |||
256 | // if table is already visited, we are done | 263 | // if table is already visited, we are done |
257 | lua_pushvalue( L, _i); // ... {_i} {} | 264 | lua_pushvalue( L, _i); // ... {_i} {} |
258 | lua_rawget( L, cache); // ... {_i} nil|n | 265 | lua_rawget( L, cache); // ... {_i} nil|n |
@@ -437,7 +444,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* _name) | |||
437 | * | 444 | * |
438 | */ | 445 | */ |
439 | 446 | ||
440 | lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_state_create) | 447 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs) |
441 | { | 448 | { |
442 | // reuse alloc function from the originating state | 449 | // reuse alloc function from the originating state |
443 | void* allocUD; | 450 | void* allocUD; |
@@ -450,7 +457,7 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_ | |||
450 | } | 457 | } |
451 | 458 | ||
452 | // neither libs (not even 'base') nor special init func: we are done | 459 | // neither libs (not even 'base') nor special init func: we are done |
453 | if( !libs && !_on_state_create) | 460 | if( libs == NULL && _on_state_create <= 0) |
454 | { | 461 | { |
455 | return L; | 462 | return L; |
456 | } | 463 | } |
@@ -460,13 +467,6 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_ | |||
460 | 467 | ||
461 | STACK_GROW( L, 2); | 468 | STACK_GROW( L, 2); |
462 | STACK_CHECK( L); | 469 | STACK_CHECK( L); |
463 | if( _on_state_create) | ||
464 | { | ||
465 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | ||
466 | lua_pushcfunction( L, _on_state_create); | ||
467 | lua_call( L, 0, 0); | ||
468 | } | ||
469 | |||
470 | // 'lua.c' stops GC during initialization so perhaps its a good idea. :) | 470 | // 'lua.c' stops GC during initialization so perhaps its a good idea. :) |
471 | // but do it after _on_state_create in case it does a lot of stuff... | 471 | // but do it after _on_state_create in case it does a lot of stuff... |
472 | lua_gc( L, LUA_GCSTOP, 0); | 472 | lua_gc( L, LUA_GCSTOP, 0); |
@@ -520,7 +520,29 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_ | |||
520 | lua_gc( L, LUA_GCRESTART, 0); | 520 | lua_gc( L, LUA_GCRESTART, 0); |
521 | 521 | ||
522 | STACK_CHECK( L); | 522 | STACK_CHECK( L); |
523 | // after opening base, register the functions it exported in our name<->function database | 523 | // call this after the base libraries are loaded! |
524 | if( _on_state_create > 0) | ||
525 | { | ||
526 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | ||
527 | if( lua_iscfunction( _from, _on_state_create)) | ||
528 | { | ||
529 | // C function: recreate a closure in the new state, bypassing the lookup scheme | ||
530 | lua_CFunction osc = lua_tocfunction( _from, _on_state_create); | ||
531 | lua_pushcfunction( L, osc); | ||
532 | } | ||
533 | else | ||
534 | { | ||
535 | STACK_CHECK( _from); | ||
536 | // Lua function: transfer as usual (should work as long as it only uses base libraries) | ||
537 | lua_pushvalue( _from, _on_state_create); | ||
538 | luaG_inter_move( _from, L, 1); | ||
539 | STACK_END( _from, 0); | ||
540 | } | ||
541 | lua_call( L, 0, 0); | ||
542 | STACK_MID( L, 0); | ||
543 | } | ||
544 | |||
545 | // after all this, register everything we find in our name<->function database | ||
524 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack | 546 | lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack |
525 | populate_func_lookup_table( L, -1, NULL); | 547 | populate_func_lookup_table( L, -1, NULL); |
526 | lua_pop( L, 1); | 548 | lua_pop( L, 1); |
@@ -1180,9 +1202,9 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin | |||
1180 | 1202 | ||
1181 | static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i) | 1203 | static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i) |
1182 | { | 1204 | { |
1183 | void * const aspointer = (void*)lua_topointer( L, i); | 1205 | void* const aspointer = (void*)lua_topointer( L, i); |
1184 | // TBD: Merge this and same code for tables | 1206 | // TBD: Merge this and same code for tables |
1185 | ASSERT_L( L2_cache_i != 0 ); | 1207 | ASSERT_L( L2_cache_i != 0); |
1186 | 1208 | ||
1187 | STACK_GROW( L2, 2); | 1209 | STACK_GROW( L2, 2); |
1188 | 1210 | ||
@@ -1199,8 +1221,8 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui | |||
1199 | 1221 | ||
1200 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); | 1222 | //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); |
1201 | 1223 | ||
1202 | lua_pushvalue( L2, -1 ); // ... {cache} ... p p | 1224 | lua_pushvalue( L2, -1); // ... {cache} ... p p |
1203 | lua_rawget( L2, L2_cache_i ); // ... {cache} ... p function|nil|true | 1225 | lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true |
1204 | 1226 | ||
1205 | if( lua_isnil(L2,-1)) // function is unknown | 1227 | if( lua_isnil(L2,-1)) // function is unknown |
1206 | { | 1228 | { |
@@ -1209,7 +1231,7 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui | |||
1209 | // Set to 'true' for the duration of creation; need to find self-references | 1231 | // Set to 'true' for the duration of creation; need to find self-references |
1210 | // via upvalues | 1232 | // via upvalues |
1211 | // | 1233 | // |
1212 | // pushes a copy of the func, a stores a reference in the cache | 1234 | // pushes a copy of the func, stores a reference in the cache |
1213 | inter_copy_func( L2, L2_cache_i, L, i); // ... {cache} ... function | 1235 | inter_copy_func( L2, L2_cache_i, L, i); // ... {cache} ... function |
1214 | } | 1236 | } |
1215 | else // found function in the cache | 1237 | else // found function in the cache |
@@ -1426,7 +1448,9 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin | |||
1426 | // if already on top of the stack, no need to push again | 1448 | // if already on top of the stack, no need to push again |
1427 | int needToPush = (i != (uint_t)lua_gettop( L)); | 1449 | int needToPush = (i != (uint_t)lua_gettop( L)); |
1428 | if( needToPush) | 1450 | if( needToPush) |
1451 | { | ||
1429 | lua_pushvalue( L, i); // ... f | 1452 | lua_pushvalue( L, i); // ... f |
1453 | } | ||
1430 | 1454 | ||
1431 | luaL_buffinit( L, &b); | 1455 | luaL_buffinit( L, &b); |
1432 | // | 1456 | // |
@@ -1568,11 +1592,11 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin | |||
1568 | * | 1592 | * |
1569 | * Returns TRUE if value was pushed, FALSE if its type is non-supported. | 1593 | * Returns TRUE if value was pushed, FALSE if its type is non-supported. |
1570 | */ | 1594 | */ |
1571 | static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i, enum e_vt vt ) | 1595 | static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt) |
1572 | { | 1596 | { |
1573 | bool_t ret= TRUE; | 1597 | bool_t ret = TRUE; |
1574 | 1598 | ||
1575 | STACK_GROW( L2, 1 ); | 1599 | STACK_GROW( L2, 1); |
1576 | 1600 | ||
1577 | STACK_CHECK( L2); | 1601 | STACK_CHECK( L2); |
1578 | 1602 | ||
@@ -1626,6 +1650,7 @@ static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, u | |||
1626 | } | 1650 | } |
1627 | /* Allow only deep userdata entities to be copied across | 1651 | /* Allow only deep userdata entities to be copied across |
1628 | */ | 1652 | */ |
1653 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END)); | ||
1629 | if( !luaG_copydeep( L, L2, i)) | 1654 | if( !luaG_copydeep( L, L2, i)) |
1630 | { | 1655 | { |
1631 | // Cannot copy it full; copy as light userdata | 1656 | // Cannot copy it full; copy as light userdata |
@@ -1669,7 +1694,6 @@ static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, u | |||
1669 | #endif | 1694 | #endif |
1670 | STACK_CHECK( L2); | 1695 | STACK_CHECK( L2); |
1671 | push_cached_func( L2, L2_cache_i, L, i); | 1696 | push_cached_func( L2, L2_cache_i, L, i); |
1672 | ASSERT_L( lua_isfunction( L2, -1)); | ||
1673 | STACK_END( L2, 1); | 1697 | STACK_END( L2, 1); |
1674 | } | 1698 | } |
1675 | break; | 1699 | break; |
@@ -1827,7 +1851,7 @@ static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, u | |||
1827 | * | 1851 | * |
1828 | * Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'. | 1852 | * Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'. |
1829 | */ | 1853 | */ |
1830 | int luaG_inter_copy( lua_State* L, lua_State *L2, uint_t n) | 1854 | int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n) |
1831 | { | 1855 | { |
1832 | uint_t top_L = lua_gettop( L); | 1856 | uint_t top_L = lua_gettop( L); |
1833 | uint_t top_L2 = lua_gettop( L2); | 1857 | uint_t top_L2 = lua_gettop( L2); |
@@ -1903,7 +1927,9 @@ void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx) | |||
1903 | { | 1927 | { |
1904 | int i; | 1928 | int i; |
1905 | // package.loaders is renamed package.searchers in Lua 5.2 | 1929 | // package.loaders is renamed package.searchers in Lua 5.2 |
1906 | char const* entries[] = { "path", "cpath", "preload", (LUA_VERSION_NUM == 501) ? "loaders" : "searchers", NULL}; | 1930 | // but don't copy it anyway, as the function names change depending on the slot index! |
1931 | // users should provide an on_state_create function to setup custom loaders instead | ||
1932 | char const* entries[] = { "path", "cpath", "preload"/*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, NULL}; | ||
1907 | for( i = 0; entries[i]; ++ i) | 1933 | for( i = 0; entries[i]; ++ i) |
1908 | { | 1934 | { |
1909 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); | 1935 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); |
@@ -1944,7 +1970,7 @@ MUTEX_T require_cs; | |||
1944 | // | 1970 | // |
1945 | // Upvalues: [1]: original 'require' function | 1971 | // Upvalues: [1]: original 'require' function |
1946 | // | 1972 | // |
1947 | static int new_require( lua_State *L) | 1973 | int luaG_new_require( lua_State* L) |
1948 | { | 1974 | { |
1949 | int rc, i; | 1975 | int rc, i; |
1950 | int args = lua_gettop( L); | 1976 | int args = lua_gettop( L); |
@@ -1955,24 +1981,24 @@ static int new_require( lua_State *L) | |||
1955 | 1981 | ||
1956 | lua_pushvalue( L, lua_upvalueindex(1)); | 1982 | lua_pushvalue( L, lua_upvalueindex(1)); |
1957 | for( i = 1; i <= args; ++ i) | 1983 | for( i = 1; i <= args; ++ i) |
1984 | { | ||
1958 | lua_pushvalue( L, i); | 1985 | lua_pushvalue( L, i); |
1986 | } | ||
1959 | 1987 | ||
1960 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would | 1988 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would |
1961 | // leave us locked, blocking any future 'require' calls from other lanes. | 1989 | // leave us locked, blocking any future 'require' calls from other lanes. |
1962 | // | 1990 | // |
1963 | MUTEX_LOCK( &require_cs); | 1991 | MUTEX_LOCK( &require_cs); |
1964 | { | 1992 | rc = lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ ); |
1965 | rc = lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ ); | ||
1966 | // | ||
1967 | // LUA_ERRRUN / LUA_ERRMEM | ||
1968 | } | ||
1969 | MUTEX_UNLOCK( &require_cs); | 1993 | MUTEX_UNLOCK( &require_cs); |
1970 | 1994 | ||
1971 | // the required module (or an error message) is left on the stack as returned value by original require function | 1995 | // the required module (or an error message) is left on the stack as returned value by original require function |
1972 | STACK_END( L, 1); | 1996 | STACK_END( L, 1); |
1973 | 1997 | ||
1974 | if (rc) | 1998 | if( rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ? |
1975 | lua_error(L); // error message already at [-1] | 1999 | { |
2000 | return lua_error( L); // error message already at [-1] | ||
2001 | } | ||
1976 | 2002 | ||
1977 | return 1; | 2003 | return 1; |
1978 | } | 2004 | } |
@@ -1980,7 +2006,7 @@ static int new_require( lua_State *L) | |||
1980 | /* | 2006 | /* |
1981 | * Serialize calls to 'require', if it exists | 2007 | * Serialize calls to 'require', if it exists |
1982 | */ | 2008 | */ |
1983 | void serialize_require( lua_State *L ) | 2009 | void serialize_require( lua_State* L) |
1984 | { | 2010 | { |
1985 | STACK_GROW( L, 1); | 2011 | STACK_GROW( L, 1); |
1986 | STACK_CHECK( L); | 2012 | STACK_CHECK( L); |
@@ -1991,7 +2017,7 @@ void serialize_require( lua_State *L ) | |||
1991 | if( lua_isfunction( L, -1)) | 2017 | if( lua_isfunction( L, -1)) |
1992 | { | 2018 | { |
1993 | // [-1]: original 'require' function | 2019 | // [-1]: original 'require' function |
1994 | lua_pushcclosure( L, new_require, 1 /*upvalues*/); | 2020 | lua_pushcclosure( L, luaG_new_require, 1 /*upvalues*/); |
1995 | lua_setglobal( L, "require"); | 2021 | lua_setglobal( L, "require"); |
1996 | } | 2022 | } |
1997 | else | 2023 | else |