diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/keeper.c | 15 | ||||
-rw-r--r-- | src/keeper.h | 2 | ||||
-rw-r--r-- | src/lanes.c | 134 | ||||
-rw-r--r-- | src/lanes.lua | 323 | ||||
-rw-r--r-- | src/tools.c | 92 | ||||
-rw-r--r-- | src/tools.h | 5 |
6 files changed, 306 insertions, 265 deletions
diff --git a/src/keeper.c b/src/keeper.c index 7485110..3511b56 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
@@ -557,7 +557,7 @@ void close_keepers( void) | |||
557 | * unclosed, because it does not really matter. In production code, this | 557 | * unclosed, because it does not really matter. In production code, this |
558 | * function never fails. | 558 | * function never fails. |
559 | */ | 559 | */ |
560 | char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_state_create) | 560 | char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers) |
561 | { | 561 | { |
562 | int i; | 562 | int i; |
563 | assert( _nbKeepers >= 1); | 563 | assert( _nbKeepers >= 1); |
@@ -572,7 +572,7 @@ char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_ | |||
572 | // | 572 | // |
573 | // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs | 573 | // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs |
574 | // the others because they export functions that we may store in a keeper for transfer between lanes | 574 | // the others because they export functions that we may store in a keeper for transfer between lanes |
575 | K = luaG_newstate( L, "*", _on_state_create); | 575 | K = luaG_newstate( L, _on_state_create, "*"); |
576 | 576 | ||
577 | STACK_CHECK( K); | 577 | STACK_CHECK( K); |
578 | 578 | ||
@@ -635,8 +635,8 @@ void populate_keepers( lua_State* L) | |||
635 | char const* name = luaL_checklstring( L, -1, &name_len); | 635 | char const* name = luaL_checklstring( L, -1, &name_len); |
636 | int i; | 636 | int i; |
637 | 637 | ||
638 | STACK_CHECK( L); | 638 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "populate_keepers %s BEGIN\n" INDENT_END, name)); |
639 | STACK_GROW( L, 3); | 639 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); |
640 | 640 | ||
641 | for( i = 0; i < GNbKeepers; ++ i) | 641 | for( i = 0; i < GNbKeepers; ++ i) |
642 | { | 642 | { |
@@ -647,16 +647,19 @@ void populate_keepers( lua_State* L) | |||
647 | STACK_GROW( K, 2); | 647 | STACK_GROW( K, 2); |
648 | lua_getglobal( K, "require"); | 648 | lua_getglobal( K, "require"); |
649 | lua_pushlstring( K, name, name_len); | 649 | lua_pushlstring( K, name, name_len); |
650 | res = lua_pcall( K, 1, 0, 0); | 650 | res = lua_pcall( K, 1, 1, 0); |
651 | if( res != LUA_OK) | 651 | if( res != LUA_OK) |
652 | { | 652 | { |
653 | char const* err = luaL_checkstring( K, -1); | 653 | char const* err = luaL_checkstring( K, -1); |
654 | luaL_error( L, "error requiring '%s' in keeper state: %s", name, err); | 654 | luaL_error( L, "error requiring '%s' in keeper state: %s", name, err); |
655 | } | 655 | } |
656 | // after requiring the module, register the functions it exported in our name<->function database | ||
657 | populate_func_lookup_table( K, -1, name); | ||
658 | lua_pop( K, 1); | ||
656 | STACK_END( K, 0); | 659 | STACK_END( K, 0); |
657 | MUTEX_UNLOCK( &GKeepers[i].lock_); | 660 | MUTEX_UNLOCK( &GKeepers[i].lock_); |
658 | } | 661 | } |
659 | STACK_END( L, 0); | 662 | DEBUGSPEW_CODE( -- debugspew_indent_depth); |
660 | } | 663 | } |
661 | 664 | ||
662 | struct s_Keeper* keeper_acquire( void const* ptr) | 665 | struct s_Keeper* keeper_acquire( void const* ptr) |
diff --git a/src/keeper.h b/src/keeper.h index 15a5a41..29a19a9 100644 --- a/src/keeper.h +++ b/src/keeper.h | |||
@@ -13,7 +13,7 @@ struct s_Keeper | |||
13 | // problem: maybe on some platforms (linux) atexit() is called after DLL/so are unloaded... | 13 | // problem: maybe on some platforms (linux) atexit() is called after DLL/so are unloaded... |
14 | #define HAVE_KEEPER_ATEXIT_DESINIT 0 | 14 | #define HAVE_KEEPER_ATEXIT_DESINIT 0 |
15 | 15 | ||
16 | char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_state_create); | 16 | char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers); |
17 | #if !HAVE_KEEPER_ATEXIT_DESINIT | 17 | #if !HAVE_KEEPER_ATEXIT_DESINIT |
18 | void close_keepers( void); | 18 | void close_keepers( void); |
19 | #endif // HAVE_KEEPER_ATEXIT_DESINIT | 19 | #endif // HAVE_KEEPER_ATEXIT_DESINIT |
diff --git a/src/lanes.c b/src/lanes.c index 80f5b15..2b3d8ac 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
@@ -52,7 +52,7 @@ | |||
52 | * ... | 52 | * ... |
53 | */ | 53 | */ |
54 | 54 | ||
55 | char const* VERSION = "3.4.4"; | 55 | char const* VERSION = "3.5.0"; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | =============================================================================== | 58 | =============================================================================== |
@@ -1529,7 +1529,6 @@ LUAG_FUNC( set_singlethreaded) | |||
1529 | # define STACK_TRACE_KEY ((void*)lane_error) // used as registry key | 1529 | # define STACK_TRACE_KEY ((void*)lane_error) // used as registry key |
1530 | # define EXTENDED_STACK_TRACE_KEY ((void*)LG_set_error_reporting) // used as registry key | 1530 | # define EXTENDED_STACK_TRACE_KEY ((void*)LG_set_error_reporting) // used as registry key |
1531 | 1531 | ||
1532 | #ifdef ERROR_FULL_STACK | ||
1533 | LUAG_FUNC( set_error_reporting) | 1532 | LUAG_FUNC( set_error_reporting) |
1534 | { | 1533 | { |
1535 | bool_t equal; | 1534 | bool_t equal; |
@@ -1554,7 +1553,6 @@ done: | |||
1554 | lua_rawset( L, LUA_REGISTRYINDEX); | 1553 | lua_rawset( L, LUA_REGISTRYINDEX); |
1555 | return 0; | 1554 | return 0; |
1556 | } | 1555 | } |
1557 | #endif // ERROR_FULL_STACK | ||
1558 | 1556 | ||
1559 | static int lane_error( lua_State* L) | 1557 | static int lane_error( lua_State* L) |
1560 | { | 1558 | { |
@@ -1735,8 +1733,8 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1735 | // [3..top]: parameters | 1733 | // [3..top]: parameters |
1736 | // | 1734 | // |
1737 | rc= lua_pcall( L, lua_gettop(L)-2, LUA_MULTRET, 1 /*error handler*/ ); | 1735 | rc= lua_pcall( L, lua_gettop(L)-2, LUA_MULTRET, 1 /*error handler*/ ); |
1738 | // 0: no error | 1736 | // 0: no error, body return values are on the stack |
1739 | // LUA_ERRRUN: a runtime error (error pushed on stack) | 1737 | // LUA_ERRRUN: cancellation or a runtime error (error pushed on stack) |
1740 | // LUA_ERRMEM: memory allocation error | 1738 | // LUA_ERRMEM: memory allocation error |
1741 | // LUA_ERRERR: error while running the error handler (if any) | 1739 | // LUA_ERRERR: error while running the error handler (if any) |
1742 | 1740 | ||
@@ -1744,14 +1742,12 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1744 | 1742 | ||
1745 | lua_remove(L,1); // remove error handler | 1743 | lua_remove(L,1); // remove error handler |
1746 | 1744 | ||
1747 | // Lua 5.1 error handler is limited to one return value; taking stack trace | 1745 | // Lua 5.1 error handler is limited to one return value; taking stack trace via registry |
1748 | // via registry | 1746 | if( rc != LUA_OK) |
1749 | // | ||
1750 | if( rc != 0) | ||
1751 | { | 1747 | { |
1752 | STACK_GROW(L,1); | 1748 | STACK_GROW(L,1); |
1753 | lua_pushlightuserdata( L, STACK_TRACE_KEY ); | 1749 | lua_pushlightuserdata( L, STACK_TRACE_KEY ); |
1754 | lua_gettable(L, LUA_REGISTRYINDEX); | 1750 | lua_gettable(L, LUA_REGISTRYINDEX); // yields nil if no stack was generated (in case of cancellation for example) |
1755 | 1751 | ||
1756 | // For cancellation, a stack trace isn't placed | 1752 | // For cancellation, a stack trace isn't placed |
1757 | // | 1753 | // |
@@ -1773,7 +1769,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1773 | // LUA_ERRMEM(4): memory allocation error | 1769 | // LUA_ERRMEM(4): memory allocation error |
1774 | #endif | 1770 | #endif |
1775 | 1771 | ||
1776 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s\n" INDENT_END, L, get_errcode_name( rc))); | 1772 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name( rc), (lua_touserdata(L,1)==CANCEL_ERROR) ? "cancelled" : lua_typename( L, lua_type( L, 1)))); |
1777 | //STACK_DUMP(L); | 1773 | //STACK_DUMP(L); |
1778 | // Call finalizers, if the script has set them up. | 1774 | // Call finalizers, if the script has set them up. |
1779 | // | 1775 | // |
@@ -1831,6 +1827,26 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1831 | return 0; // ignored | 1827 | return 0; // ignored |
1832 | } | 1828 | } |
1833 | 1829 | ||
1830 | // --- If a client wants to transfer stuff of a given module from the current state to another Lane, the module must be required | ||
1831 | // with lanes.require, that will call the regular 'require', then populate lookup databases in source and keeper states | ||
1832 | // module = lanes.require( "modname") | ||
1833 | // upvalue[1]: _G.require | ||
1834 | LUAG_FUNC( require) | ||
1835 | { | ||
1836 | char const* name = lua_tostring( L, 1); | ||
1837 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name)); | ||
1838 | DEBUGSPEW_CODE( ++ debugspew_indent_depth); | ||
1839 | lua_pushvalue( L, lua_upvalueindex(1)); // "name" require | ||
1840 | lua_pushvalue( L, 1); // "name" require "name" | ||
1841 | lua_call( L, 1, 1); // "name" module | ||
1842 | populate_func_lookup_table( L, -1, name); | ||
1843 | lua_insert( L, -2); // module "name" | ||
1844 | populate_keepers( L); | ||
1845 | lua_pop( L, 1); // module | ||
1846 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s END\n" INDENT_END, name)); | ||
1847 | DEBUGSPEW_CODE( -- debugspew_indent_depth); | ||
1848 | return 1; | ||
1849 | } | ||
1834 | 1850 | ||
1835 | //--- | 1851 | //--- |
1836 | // lane_ud= thread_new( function, [libs_str], | 1852 | // lane_ud= thread_new( function, [libs_str], |
@@ -1844,32 +1860,6 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs) | |||
1844 | // Upvalues: metatable to use for 'lane_ud' | 1860 | // Upvalues: metatable to use for 'lane_ud' |
1845 | // | 1861 | // |
1846 | 1862 | ||
1847 | // helper function to require a module in the keeper states and in the target state | ||
1848 | // source state contains module name at the top of the stack | ||
1849 | static void require_one_module( lua_State* L, lua_State* L2, bool_t _fatal) | ||
1850 | { | ||
1851 | size_t len; | ||
1852 | char const* name = lua_tolstring( L, -1, &len); | ||
1853 | // require the module in the target lane | ||
1854 | STACK_GROW( L2, 2); | ||
1855 | lua_getglobal( L2, "require"); | ||
1856 | if( lua_isnil( L2, -1)) | ||
1857 | { | ||
1858 | lua_pop( L2, 1); | ||
1859 | if( _fatal) | ||
1860 | { | ||
1861 | luaL_error( L, "cannot pre-require modules without loading 'package' library first"); | ||
1862 | } | ||
1863 | } | ||
1864 | else | ||
1865 | { | ||
1866 | lua_pushlstring( L2, name, len); | ||
1867 | lua_pcall( L2, 1, 0, 0); | ||
1868 | // we need to require this module in the keeper states as well | ||
1869 | populate_keepers( L); | ||
1870 | } | ||
1871 | } | ||
1872 | |||
1873 | LUAG_FUNC( thread_new) | 1863 | LUAG_FUNC( thread_new) |
1874 | { | 1864 | { |
1875 | lua_State* L2; | 1865 | lua_State* L2; |
@@ -1877,17 +1867,17 @@ LUAG_FUNC( thread_new) | |||
1877 | struct s_lane** ud; | 1867 | struct s_lane** ud; |
1878 | 1868 | ||
1879 | char const* libs = lua_tostring( L, 2); | 1869 | char const* libs = lua_tostring( L, 2); |
1880 | lua_CFunction on_state_create = lua_iscfunction( L, 3) ? lua_tocfunction( L, 3) : NULL; | 1870 | int const on_state_create = lua_isfunction( L, 3) ? 3 : 0; |
1881 | uint_t cs = luaG_optunsigned( L, 4, 0); | 1871 | uint_t cs = luaG_optunsigned( L, 4, 0); |
1882 | int prio = (int) luaL_optinteger( L, 5, 0); | 1872 | int prio = (int) luaL_optinteger( L, 5, 0); |
1883 | uint_t glob = luaG_isany( L, 6) ? 6 : 0; | 1873 | uint_t glob = lua_isnoneornil( L, 6) ? 0 : 6; |
1884 | uint_t package = luaG_isany( L,7) ? 7 : 0; | 1874 | uint_t package = lua_isnoneornil( L,7) ? 0 : 7; |
1885 | uint_t required = luaG_isany( L, 8) ? 8 : 0; | 1875 | uint_t required = lua_isnoneornil( L, 8) ? 0 : 8; |
1886 | 1876 | ||
1887 | #define FIXED_ARGS 8 | 1877 | #define FIXED_ARGS 8 |
1888 | uint_t args= lua_gettop(L) - FIXED_ARGS; | 1878 | uint_t args= lua_gettop(L) - FIXED_ARGS; |
1889 | 1879 | ||
1890 | if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) | 1880 | if( prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) |
1891 | { | 1881 | { |
1892 | return luaL_error( L, "Priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio); | 1882 | return luaL_error( L, "Priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio); |
1893 | } | 1883 | } |
@@ -1898,7 +1888,7 @@ LUAG_FUNC( thread_new) | |||
1898 | 1888 | ||
1899 | // populate with selected libraries at the same time | 1889 | // populate with selected libraries at the same time |
1900 | // | 1890 | // |
1901 | L2 = luaG_newstate( L, libs, on_state_create); | 1891 | L2 = luaG_newstate( L, on_state_create, libs); |
1902 | 1892 | ||
1903 | STACK_GROW( L, 2); | 1893 | STACK_GROW( L, 2); |
1904 | STACK_GROW( L2, 3); | 1894 | STACK_GROW( L2, 3); |
@@ -1918,17 +1908,6 @@ LUAG_FUNC( thread_new) | |||
1918 | 1908 | ||
1919 | // modules to require in the target lane *before* the function is transfered! | 1909 | // modules to require in the target lane *before* the function is transfered! |
1920 | 1910 | ||
1921 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: require 'lanes.core'\n" INDENT_END)); | ||
1922 | //start by requiring lanes.core, since it is a bit special | ||
1923 | // it is not fatal if 'require' isn't loaded, just ignore (may cause function transfer errors later on if the lane pulls the lanes module itself) | ||
1924 | STACK_CHECK( L); | ||
1925 | STACK_CHECK( L2); | ||
1926 | lua_pushliteral( L, "lanes.core"); | ||
1927 | require_one_module( L, L2, FALSE); | ||
1928 | lua_pop( L, 1); | ||
1929 | STACK_END( L2, 0); | ||
1930 | STACK_END (L, 0); | ||
1931 | |||
1932 | STACK_CHECK( L); | 1911 | STACK_CHECK( L); |
1933 | STACK_CHECK( L2); | 1912 | STACK_CHECK( L2); |
1934 | if( required) | 1913 | if( required) |
@@ -1941,6 +1920,7 @@ LUAG_FUNC( thread_new) | |||
1941 | { | 1920 | { |
1942 | return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required)); | 1921 | return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required)); |
1943 | } | 1922 | } |
1923 | |||
1944 | lua_pushnil( L); | 1924 | lua_pushnil( L); |
1945 | while( lua_next( L, required) != 0) | 1925 | while( lua_next( L, required) != 0) |
1946 | { | 1926 | { |
@@ -1950,7 +1930,32 @@ LUAG_FUNC( thread_new) | |||
1950 | } | 1930 | } |
1951 | else | 1931 | else |
1952 | { | 1932 | { |
1953 | require_one_module( L, L2, TRUE); | 1933 | // require the module in the target state, and populate the lookup table there too |
1934 | size_t len; | ||
1935 | char const* name = lua_tolstring( L, -1, &len); | ||
1936 | |||
1937 | // require the module in the target lane | ||
1938 | STACK_GROW( L2, 2); | ||
1939 | STACK_CHECK( L2); | ||
1940 | lua_getglobal( L2, "require"); // require()? | ||
1941 | if( lua_isnil( L2, -1)) | ||
1942 | { | ||
1943 | lua_pop( L2, 1); // | ||
1944 | luaL_error( L, "cannot pre-require modules without loading 'package' library first"); | ||
1945 | } | ||
1946 | else | ||
1947 | { | ||
1948 | lua_pushlstring( L2, name, len); // require() name | ||
1949 | lua_pcall( L2, 1, 1, 0); // ret | ||
1950 | STACK_MID( L2, 1); | ||
1951 | // after requiring the module, register the functions it exported in our name<->function database | ||
1952 | populate_func_lookup_table( L2, -1, name); | ||
1953 | STACK_MID( L2, 1); | ||
1954 | lua_pop( L2, 1); | ||
1955 | // don't require this module in the keeper states as well, use lanes.require() for that! | ||
1956 | //populate_keepers( L); | ||
1957 | } | ||
1958 | STACK_END( L2, 0); | ||
1954 | } | 1959 | } |
1955 | lua_pop( L, 1); | 1960 | lua_pop( L, 1); |
1956 | ++ nbRequired; | 1961 | ++ nbRequired; |
@@ -2578,7 +2583,7 @@ static const struct luaL_Reg lanes_functions [] = { | |||
2578 | /* | 2583 | /* |
2579 | * One-time initializations | 2584 | * One-time initializations |
2580 | */ | 2585 | */ |
2581 | static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _on_state_create, lua_Number _shutdown_timeout, bool_t _track_lanes) | 2586 | static void init_once_LOCKED( lua_State* L, int const _on_state_create, int const nbKeepers, lua_Number _shutdown_timeout, bool_t _track_lanes) |
2582 | { | 2587 | { |
2583 | char const* err; | 2588 | char const* err; |
2584 | 2589 | ||
@@ -2603,7 +2608,7 @@ static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _ | |||
2603 | // | 2608 | // |
2604 | MUTEX_RECURSIVE_INIT( &require_cs ); | 2609 | MUTEX_RECURSIVE_INIT( &require_cs ); |
2605 | 2610 | ||
2606 | serialize_require( L ); | 2611 | serialize_require( L); |
2607 | 2612 | ||
2608 | // Linked chains handling | 2613 | // Linked chains handling |
2609 | // | 2614 | // |
@@ -2635,7 +2640,7 @@ static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _ | |||
2635 | } | 2640 | } |
2636 | #endif | 2641 | #endif |
2637 | #endif | 2642 | #endif |
2638 | err = init_keepers( L, nbKeepers, _on_state_create); | 2643 | err = init_keepers( L, _on_state_create, nbKeepers); |
2639 | if (err) | 2644 | if (err) |
2640 | { | 2645 | { |
2641 | (void) luaL_error( L, "Unable to initialize: %s", err ); | 2646 | (void) luaL_error( L, "Unable to initialize: %s", err ); |
@@ -2691,7 +2696,7 @@ LUAG_FUNC( configure) | |||
2691 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); | 2696 | char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); |
2692 | // all parameter checks are done lua-side | 2697 | // all parameter checks are done lua-side |
2693 | int const nbKeepers = (int)lua_tointeger( L, 1); | 2698 | int const nbKeepers = (int)lua_tointeger( L, 1); |
2694 | lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL; | 2699 | int const on_state_create = lua_isfunction( L, 2) ? 2 : 0; |
2695 | lua_Number shutdown_timeout = lua_tonumber( L, 3); | 2700 | lua_Number shutdown_timeout = lua_tonumber( L, 3); |
2696 | bool_t track_lanes = lua_toboolean( L, 4); | 2701 | bool_t track_lanes = lua_toboolean( L, 4); |
2697 | 2702 | ||
@@ -2732,6 +2737,11 @@ LUAG_FUNC( configure) | |||
2732 | lua_pushcclosure( L, LG_thread_new, 1); // ... M LG_thread_new | 2737 | lua_pushcclosure( L, LG_thread_new, 1); // ... M LG_thread_new |
2733 | lua_setfield(L, -2, "thread_new"); // ... M | 2738 | lua_setfield(L, -2, "thread_new"); // ... M |
2734 | 2739 | ||
2740 | // we can't register 'lanes.require' normally because we want to create an upvalued closure | ||
2741 | lua_getglobal( L, "require"); // ... M require | ||
2742 | lua_pushcclosure( L, LG_require, 1); // ... M lanes.require | ||
2743 | lua_setfield( L, -2, "require"); // ... M | ||
2744 | |||
2735 | lua_pushstring(L, VERSION); // ... M VERSION | 2745 | lua_pushstring(L, VERSION); // ... M VERSION |
2736 | lua_setfield(L, -2, "version"); // ... M | 2746 | lua_setfield(L, -2, "version"); // ... M |
2737 | 2747 | ||
@@ -2743,7 +2753,7 @@ LUAG_FUNC( configure) | |||
2743 | 2753 | ||
2744 | // register all native functions found in that module in the transferable functions database | 2754 | // register all native functions found in that module in the transferable functions database |
2745 | // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) | 2755 | // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) |
2746 | // for example in package.loaded.lanes.core.* | 2756 | // for example in package.loaded["lanes.core"].* |
2747 | populate_func_lookup_table( L, -1, name); | 2757 | populate_func_lookup_table( L, -1, name); |
2748 | 2758 | ||
2749 | // record all existing C/JIT-fast functions | 2759 | // record all existing C/JIT-fast functions |
@@ -2768,7 +2778,7 @@ LUAG_FUNC( configure) | |||
2768 | static volatile int /*bool*/ go_ahead; // = 0 | 2778 | static volatile int /*bool*/ go_ahead; // = 0 |
2769 | if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) | 2779 | if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) |
2770 | { | 2780 | { |
2771 | init_once_LOCKED( L, nbKeepers, on_state_create, shutdown_timeout, track_lanes); | 2781 | init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes); |
2772 | go_ahead = 1; // let others pass | 2782 | go_ahead = 1; // let others pass |
2773 | } | 2783 | } |
2774 | else | 2784 | else |
@@ -2786,7 +2796,7 @@ LUAG_FUNC( configure) | |||
2786 | // | 2796 | // |
2787 | if( s_initCount == 0) | 2797 | if( s_initCount == 0) |
2788 | { | 2798 | { |
2789 | init_once_LOCKED( L, nbKeepers, on_state_create, shutdown_timeout, track_lanes); | 2799 | init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes); |
2790 | s_initCount = 1; | 2800 | s_initCount = 1; |
2791 | } | 2801 | } |
2792 | } | 2802 | } |
diff --git a/src/lanes.lua b/src/lanes.lua index 1d50f97..f4eef81 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
@@ -123,9 +123,6 @@ lanes.configure = function( _params) | |||
123 | 123 | ||
124 | local set_singlethreaded = assert( core.set_singlethreaded) | 124 | local set_singlethreaded = assert( core.set_singlethreaded) |
125 | 125 | ||
126 | local now_secs = assert( core.now_secs) | ||
127 | local wakeup_conv = assert( core.wakeup_conv) | ||
128 | |||
129 | local max_prio = assert( core.max_prio) | 126 | local max_prio = assert( core.max_prio) |
130 | 127 | ||
131 | lanes.ABOUT= | 128 | lanes.ABOUT= |
@@ -311,6 +308,7 @@ local linda = core.linda | |||
311 | 308 | ||
312 | -- PUBLIC LANES API | 309 | -- PUBLIC LANES API |
313 | local timer = function() error "timers are not active" end | 310 | local timer = function() error "timers are not active" end |
311 | local timer_lane = nil | ||
314 | local timers = timer | 312 | local timers = timer |
315 | 313 | ||
316 | if _params.with_timers ~= false then | 314 | if _params.with_timers ~= false then |
@@ -338,158 +336,161 @@ timer_gateway:set(first_time_key,true) | |||
338 | -- has 'table' always declared) | 336 | -- has 'table' always declared) |
339 | -- | 337 | -- |
340 | if first_time then | 338 | if first_time then |
341 | local table_remove= assert( table.remove ) | ||
342 | local table_insert= assert( table.insert ) | ||
343 | 339 | ||
344 | -- | 340 | ----- |
345 | -- { [deep_linda_lightuserdata]= { [deep_linda_lightuserdata]=linda_h, | 341 | -- Snore loop (run as a lane on the background) |
346 | -- [key]= { wakeup_secs [,period_secs] } [, ...] }, | 342 | -- |
347 | -- } | 343 | -- High priority, to get trustworthy timings. |
348 | -- | 344 | -- |
349 | -- Collection of all running timers, indexed with linda's & key. | 345 | -- We let the timer lane be a "free running" thread; no handle to it |
350 | -- | 346 | -- remains. |
351 | -- Note that we need to use the deep lightuserdata identifiers, instead | 347 | -- |
352 | -- of 'linda_h' themselves as table indices. Otherwise, we'd get multiple | 348 | local timer_body = function() |
353 | -- entries for the same timer. | 349 | -- require lanes.core inside the timer body to prevent pulling now_secs() through an uvpvalue |
354 | -- | 350 | local core = require "lanes.core" |
355 | -- The 'hidden' reference to Linda proxy is used in 'check_timers()' but | 351 | |
356 | -- also important to keep the Linda alive, even if all outside world threw | 352 | -- |
357 | -- away pointers to it (which would ruin uniqueness of the deep pointer). | 353 | -- { [deep_linda_lightuserdata]= { [deep_linda_lightuserdata]=linda_h, |
358 | -- Now we're safe. | 354 | -- [key]= { wakeup_secs [,period_secs] } [, ...] }, |
359 | -- | 355 | -- } |
360 | local collection= {} | 356 | -- |
361 | 357 | -- Collection of all running timers, indexed with linda's & key. | |
362 | local function get_timers() | 358 | -- |
363 | local r = {} | 359 | -- Note that we need to use the deep lightuserdata identifiers, instead |
364 | for deep, t in pairs( collection) do | 360 | -- of 'linda_h' themselves as table indices. Otherwise, we'd get multiple |
365 | -- WR( tostring( deep)) | 361 | -- entries for the same timer. |
366 | local l = t[deep] | 362 | -- |
367 | for key, timer_data in pairs( t) do | 363 | -- The 'hidden' reference to Linda proxy is used in 'check_timers()' but |
368 | if key ~= deep then | 364 | -- also important to keep the Linda alive, even if all outside world threw |
369 | table_insert( r, {l, key, timer_data}) | 365 | -- away pointers to it (which would ruin uniqueness of the deep pointer). |
370 | end | 366 | -- Now we're safe. |
371 | end | 367 | -- |
372 | end | 368 | local collection = {} |
373 | return r | 369 | local table_insert = assert( table.insert) |
374 | end | 370 | |
375 | -- | 371 | local get_timers = function() |
376 | -- set_timer( linda_h, key [,wakeup_at_secs [,period_secs]] ) | 372 | local r = {} |
377 | -- | 373 | for deep, t in pairs( collection) do |
378 | local function set_timer( linda, key, wakeup_at, period ) | 374 | -- WR( tostring( deep)) |
379 | assert( wakeup_at==nil or wakeup_at>0.0 ) | 375 | local l = t[deep] |
380 | assert( period==nil or period>0.0 ) | 376 | for key, timer_data in pairs( t) do |
377 | if key ~= deep then | ||
378 | table_insert( r, {l, key, timer_data}) | ||
379 | end | ||
380 | end | ||
381 | end | ||
382 | return r | ||
383 | end -- get_timers() | ||
381 | 384 | ||
382 | local linda_deep= linda:deep() | 385 | -- |
383 | assert( linda_deep ) | 386 | -- set_timer( linda_h, key [,wakeup_at_secs [,period_secs]] ) |
387 | -- | ||
388 | local set_timer = function( linda, key, wakeup_at, period) | ||
389 | assert( wakeup_at == nil or wakeup_at > 0.0) | ||
390 | assert( period == nil or period > 0.0) | ||
384 | 391 | ||
385 | -- Find or make a lookup for this timer | 392 | local linda_deep = linda:deep() |
386 | -- | 393 | assert( linda_deep) |
387 | local t1= collection[linda_deep] | 394 | |
388 | if not t1 then | 395 | -- Find or make a lookup for this timer |
389 | t1= { [linda_deep]= linda } -- proxy to use the Linda | 396 | -- |
390 | collection[linda_deep]= t1 | 397 | local t1 = collection[linda_deep] |
391 | end | 398 | if not t1 then |
392 | 399 | t1 = { [linda_deep] = linda} -- proxy to use the Linda | |
393 | if wakeup_at==nil then | 400 | collection[linda_deep] = t1 |
394 | -- Clear the timer | 401 | end |
395 | -- | 402 | |
396 | t1[key]= nil | 403 | if wakeup_at == nil then |
397 | 404 | -- Clear the timer | |
398 | -- Remove empty tables from collection; speeds timer checks and | 405 | -- |
399 | -- lets our 'safety reference' proxy be gc:ed as well. | 406 | t1[key]= nil |
400 | -- | 407 | |
401 | local empty= true | 408 | -- Remove empty tables from collection; speeds timer checks and |
402 | for k,_ in pairs(t1) do | 409 | -- lets our 'safety reference' proxy be gc:ed as well. |
403 | if k~= linda_deep then | 410 | -- |
404 | empty= false; break | 411 | local empty = true |
405 | end | 412 | for k, _ in pairs( t1) do |
406 | end | 413 | if k ~= linda_deep then |
407 | if empty then | 414 | empty = false |
408 | collection[linda_deep]= nil | 415 | break |
409 | end | 416 | end |
410 | 417 | end | |
411 | -- Note: any unread timer value is left at 'linda[key]' intensionally; | 418 | if empty then |
412 | -- clearing a timer just stops it. | 419 | collection[linda_deep] = nil |
413 | else | 420 | end |
414 | -- New timer or changing the timings | 421 | |
415 | -- | 422 | -- Note: any unread timer value is left at 'linda[key]' intensionally; |
416 | local t2= t1[key] | 423 | -- clearing a timer just stops it. |
417 | if not t2 then | 424 | else |
418 | t2= {}; t1[key]= t2 | 425 | -- New timer or changing the timings |
419 | end | 426 | -- |
420 | 427 | local t2 = t1[key] | |
421 | t2[1]= wakeup_at | 428 | if not t2 then |
422 | t2[2]= period -- can be 'nil' | 429 | t2= {} |
423 | end | 430 | t1[key]= t2 |
424 | end | 431 | end |
432 | |||
433 | t2[1] = wakeup_at | ||
434 | t2[2] = period -- can be 'nil' | ||
435 | end | ||
436 | end -- set_timer() | ||
437 | |||
438 | local now_secs = core.now_secs | ||
439 | assert( type( now_secs) == "function") | ||
440 | ----- | ||
441 | -- [next_wakeup_at]= check_timers() | ||
442 | -- Check timers, and wake up the ones expired (if any) | ||
443 | -- Returns the closest upcoming (remaining) wakeup time (or 'nil' if none). | ||
444 | local check_timers = function() | ||
445 | local now = now_secs() | ||
446 | local next_wakeup | ||
447 | |||
448 | for linda_deep,t1 in pairs(collection) do | ||
449 | for key,t2 in pairs(t1) do | ||
450 | -- | ||
451 | if key==linda_deep then | ||
452 | -- no 'continue' in Lua :/ | ||
453 | else | ||
454 | -- 't2': { wakeup_at_secs [,period_secs] } | ||
455 | -- | ||
456 | local wakeup_at= t2[1] | ||
457 | local period= t2[2] -- may be 'nil' | ||
458 | |||
459 | if wakeup_at <= now then | ||
460 | local linda= t1[linda_deep] | ||
461 | assert(linda) | ||
462 | |||
463 | linda:set( key, now ) | ||
464 | |||
465 | -- 'pairs()' allows the values to be modified (and even | ||
466 | -- removed) as far as keys are not touched | ||
467 | |||
468 | if not period then | ||
469 | -- one-time timer; gone | ||
470 | -- | ||
471 | t1[key]= nil | ||
472 | wakeup_at= nil -- no 'continue' in Lua :/ | ||
473 | else | ||
474 | -- repeating timer; find next wakeup (may jump multiple repeats) | ||
475 | -- | ||
476 | repeat | ||
477 | wakeup_at= wakeup_at+period | ||
478 | until wakeup_at > now | ||
479 | |||
480 | t2[1]= wakeup_at | ||
481 | end | ||
482 | end | ||
483 | |||
484 | if wakeup_at and ((not next_wakeup) or (wakeup_at < next_wakeup)) then | ||
485 | next_wakeup= wakeup_at | ||
486 | end | ||
487 | end | ||
488 | end -- t2 loop | ||
489 | end -- t1 loop | ||
490 | |||
491 | return next_wakeup -- may be 'nil' | ||
492 | end -- check_timers() | ||
425 | 493 | ||
426 | ----- | ||
427 | -- [next_wakeup_at]= check_timers() | ||
428 | -- | ||
429 | -- Check timers, and wake up the ones expired (if any) | ||
430 | -- | ||
431 | -- Returns the closest upcoming (remaining) wakeup time (or 'nil' if none). | ||
432 | -- | ||
433 | local function check_timers() | ||
434 | |||
435 | local now= now_secs() | ||
436 | local next_wakeup | ||
437 | |||
438 | for linda_deep,t1 in pairs(collection) do | ||
439 | for key,t2 in pairs(t1) do | ||
440 | -- | ||
441 | if key==linda_deep then | ||
442 | -- no 'continue' in Lua :/ | ||
443 | else | ||
444 | -- 't2': { wakeup_at_secs [,period_secs] } | ||
445 | -- | ||
446 | local wakeup_at= t2[1] | ||
447 | local period= t2[2] -- may be 'nil' | ||
448 | |||
449 | if wakeup_at <= now then | ||
450 | local linda= t1[linda_deep] | ||
451 | assert(linda) | ||
452 | |||
453 | linda:set( key, now ) | ||
454 | |||
455 | -- 'pairs()' allows the values to be modified (and even | ||
456 | -- removed) as far as keys are not touched | ||
457 | |||
458 | if not period then | ||
459 | -- one-time timer; gone | ||
460 | -- | ||
461 | t1[key]= nil | ||
462 | wakeup_at= nil -- no 'continue' in Lua :/ | ||
463 | else | ||
464 | -- repeating timer; find next wakeup (may jump multiple repeats) | ||
465 | -- | ||
466 | repeat | ||
467 | wakeup_at= wakeup_at+period | ||
468 | until wakeup_at > now | ||
469 | |||
470 | t2[1]= wakeup_at | ||
471 | end | ||
472 | end | ||
473 | |||
474 | if wakeup_at and ((not next_wakeup) or (wakeup_at < next_wakeup)) then | ||
475 | next_wakeup= wakeup_at | ||
476 | end | ||
477 | end | ||
478 | end -- t2 loop | ||
479 | end -- t1 loop | ||
480 | |||
481 | return next_wakeup -- may be 'nil' | ||
482 | end | ||
483 | |||
484 | ----- | ||
485 | -- Snore loop (run as a lane on the background) | ||
486 | -- | ||
487 | -- High priority, to get trustworthy timings. | ||
488 | -- | ||
489 | -- We let the timer lane be a "free running" thread; no handle to it | ||
490 | -- remains. | ||
491 | -- | ||
492 | local timer_body = function() | ||
493 | local timer_gateway_batched = timer_gateway.batched | 494 | local timer_gateway_batched = timer_gateway.batched |
494 | set_debug_threadname( "LanesTimer") | 495 | set_debug_threadname( "LanesTimer") |
495 | set_finalizer( function( err, stk) | 496 | set_finalizer( function( err, stk) |
@@ -502,7 +503,7 @@ if first_time then | |||
502 | end | 503 | end |
503 | end) | 504 | end) |
504 | while true do | 505 | while true do |
505 | local next_wakeup= check_timers() | 506 | local next_wakeup = check_timers() |
506 | 507 | ||
507 | -- Sleep until next timer to wake up, or a set/clear command | 508 | -- Sleep until next timer to wake up, or a set/clear command |
508 | -- | 509 | -- |
@@ -528,9 +529,9 @@ if first_time then | |||
528 | -- WR( "timer lane: no linda, aborted?") | 529 | -- WR( "timer lane: no linda, aborted?") |
529 | end | 530 | end |
530 | end | 531 | end |
531 | end | 532 | end -- timer_body() |
532 | gen( "*", { package= {}, priority = max_prio}, timer_body)() -- "*" instead of "io,package" for LuaJIT compatibility... | 533 | timer_lane = gen( "*", { package= {}, priority = max_prio}, timer_body)() -- "*" instead of "io,package" for LuaJIT compatibility... |
533 | end | 534 | end -- first_time |
534 | 535 | ||
535 | ----- | 536 | ----- |
536 | -- = timer( linda_h, key_val, date_tbl|first_secs [,period_secs] ) | 537 | -- = timer( linda_h, key_val, date_tbl|first_secs [,period_secs] ) |
@@ -540,13 +541,13 @@ timer = function( linda, key, a, period ) | |||
540 | if getmetatable( linda) ~= "Linda" then | 541 | if getmetatable( linda) ~= "Linda" then |
541 | error "expecting a Linda" | 542 | error "expecting a Linda" |
542 | end | 543 | end |
543 | if a==0.0 then | 544 | if a == 0.0 then |
544 | -- Caller expects to get current time stamp in Linda, on return | 545 | -- Caller expects to get current time stamp in Linda, on return |
545 | -- (like the timer had expired instantly); it would be good to set this | 546 | -- (like the timer had expired instantly); it would be good to set this |
546 | -- as late as possible (to give most current time) but also we want it | 547 | -- as late as possible (to give most current time) but also we want it |
547 | -- to precede any possible timers that might start striking. | 548 | -- to precede any possible timers that might start striking. |
548 | -- | 549 | -- |
549 | linda:set( key, now_secs() ) | 550 | linda:set( key, core.now_secs()) |
550 | 551 | ||
551 | if not period or period==0.0 then | 552 | if not period or period==0.0 then |
552 | timer_gateway:send( TGW_KEY, linda, key, nil, nil ) -- clear the timer | 553 | timer_gateway:send( TGW_KEY, linda, key, nil, nil ) -- clear the timer |
@@ -555,8 +556,8 @@ timer = function( linda, key, a, period ) | |||
555 | a= period | 556 | a= period |
556 | end | 557 | end |
557 | 558 | ||
558 | local wakeup_at= type(a)=="table" and wakeup_conv(a) -- given point of time | 559 | local wakeup_at= type(a)=="table" and core.wakeup_conv(a) -- given point of time |
559 | or (a and now_secs()+a or nil) | 560 | or (a and core.now_secs()+a or nil) |
560 | -- queue to timer | 561 | -- queue to timer |
561 | -- | 562 | -- |
562 | timer_gateway:send( TGW_KEY, linda, key, wakeup_at, period ) | 563 | timer_gateway:send( TGW_KEY, linda, key, wakeup_at, period ) |
@@ -639,15 +640,17 @@ local function genatomic( linda, key, initial_val ) | |||
639 | end | 640 | end |
640 | 641 | ||
641 | -- activate full interface | 642 | -- activate full interface |
643 | lanes.require = core.require | ||
642 | lanes.gen = gen | 644 | lanes.gen = gen |
643 | lanes.linda = core.linda | 645 | lanes.linda = core.linda |
644 | lanes.cancel_error = core.cancel_error | 646 | lanes.cancel_error = core.cancel_error |
645 | lanes.nameof = core.nameof | 647 | lanes.nameof = core.nameof |
646 | lanes.threads = (_params.track_lanes and core.threads) and core.threads or function() error "lane tracking is not available" end | 648 | lanes.threads = (_params.track_lanes and core.threads) and core.threads or function() error "lane tracking is not available" end |
647 | lanes.timer = timer | 649 | lanes.timer = timer |
650 | lanes.timer_lane = timer_lane | ||
648 | lanes.timers = timers | 651 | lanes.timers = timers |
649 | lanes.genlock = genlock | 652 | lanes.genlock = genlock |
650 | lanes.now_secs = now_secs | 653 | lanes.now_secs = core.now_secs |
651 | lanes.genatomic = genatomic | 654 | lanes.genatomic = genatomic |
652 | -- from now on, calling configure does nothing but checking that we don't call it with parameters that changed compared to the first invocation | 655 | -- from now on, calling configure does nothing but checking that we don't call it with parameters that changed compared to the first invocation |
653 | lanes.configure = function( _params2) | 656 | lanes.configure = function( _params2) |
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 |
diff --git a/src/tools.h b/src/tools.h index f79d2ad..a06e23f 100644 --- a/src/tools.h +++ b/src/tools.h | |||
@@ -78,11 +78,9 @@ extern int debugspew_indent_depth; | |||
78 | #define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) | 78 | #define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) |
79 | #define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i)) | 79 | #define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i)) |
80 | 80 | ||
81 | #define luaG_isany(L,i) (!lua_isnil(L,i)) | ||
82 | |||
83 | void luaG_dump( lua_State* L ); | 81 | void luaG_dump( lua_State* L ); |
84 | 82 | ||
85 | lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_state_create); | 83 | lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs); |
86 | 84 | ||
87 | typedef struct { | 85 | typedef struct { |
88 | volatile int refcount; | 86 | volatile int refcount; |
@@ -96,6 +94,7 @@ int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n); | |||
96 | int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n); | 94 | int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n); |
97 | 95 | ||
98 | int luaG_nameof( lua_State* L); | 96 | int luaG_nameof( lua_State* L); |
97 | int luaG_new_require( lua_State* L); | ||
99 | 98 | ||
100 | // Lock for reference counter inc/dec locks (to be initialized by outside code) | 99 | // Lock for reference counter inc/dec locks (to be initialized by outside code) |
101 | // | 100 | // |