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/lanes.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/lanes.c')
-rw-r--r-- | src/lanes.c | 134 |
1 files changed, 72 insertions, 62 deletions
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 | } |