diff options
| author | Benoit Germain <bnt.germain@gmail.com> | 2011-02-17 07:52:53 +0100 |
|---|---|---|
| committer | Benoit Germain <bnt.germain@gmail.com> | 2011-02-17 07:52:53 +0100 |
| commit | ab233d0c9a1edc34836e2249c1eb6d714f1066b5 (patch) | |
| tree | a91078b0ca240f870f5f15c2930bc0719a86c9d1 /src | |
| parent | afb2da4789cdaddc5a0c3c9c2d57ccd36bcc74c7 (diff) | |
| download | lanes-ab233d0c9a1edc34836e2249c1eb6d714f1066b5.tar.gz lanes-ab233d0c9a1edc34836e2249c1eb6d714f1066b5.tar.bz2 lanes-ab233d0c9a1edc34836e2249c1eb6d714f1066b5.zip | |
Lane userdata implementation refactoring:
- Refactor lane proxy implementation: it is now a full userdata instead
of a table, and its methods are implemented in C instead of Lua.
* its metatable is no longer accessible.
* writing to the proxy raises an error.
* it is no longer possible to overwrite its join() and cancel() methods
- when a deep userdata idfunc requests a module to be required, manually
check that it is not loaded before requiring it instead of relying on
the require function's loop detection feature.
- when a module must be required, raise an error if the 'require' function
is not found in the target state.
- we know Lanes is loaded in the master state, so we don't force it
to be required in every lane too when a linda deep userdata is copied.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lanes.c | 231 | ||||
| -rw-r--r-- | src/lanes.lua | 107 | ||||
| -rw-r--r-- | src/tools.c | 121 |
3 files changed, 287 insertions, 172 deletions
diff --git a/src/lanes.c b/src/lanes.c index f650d9a..0a89959 100644 --- a/src/lanes.c +++ b/src/lanes.c | |||
| @@ -912,7 +912,12 @@ static void linda_id( lua_State *L, char const * const which) | |||
| 912 | } | 912 | } |
| 913 | else if( strcmp( which, "module") == 0) | 913 | else if( strcmp( which, "module") == 0) |
| 914 | { | 914 | { |
| 915 | lua_pushliteral( L, "lua51-lanes"); | 915 | // linda is a special case because we know lanes must be loaded from the main lua state |
| 916 | // to be able to ever get here, so we know it will remain loaded as long a the main state is around | ||
| 917 | // in other words, forever. | ||
| 918 | lua_pushnil( L); | ||
| 919 | // other idfuncs must push a string naming the module they come from | ||
| 920 | //lua_pushliteral( L, "lua51-lanes"); | ||
| 916 | } | 921 | } |
| 917 | } | 922 | } |
| 918 | 923 | ||
| @@ -1635,6 +1640,11 @@ LUAG_FUNC( thread_new ) | |||
| 1635 | lua_setmetatable( L, -2 ); | 1640 | lua_setmetatable( L, -2 ); |
| 1636 | STACK_MID(L,1) | 1641 | STACK_MID(L,1) |
| 1637 | 1642 | ||
| 1643 | // Clear environment for the userdata | ||
| 1644 | // | ||
| 1645 | lua_newtable( L); | ||
| 1646 | lua_setfenv( L, -2); | ||
| 1647 | |||
| 1638 | // Place 's' to registry, for 'cancel_test()' (even if 'cs'==0 we still | 1648 | // Place 's' to registry, for 'cancel_test()' (even if 'cs'==0 we still |
| 1639 | // do cancel tests at pending send/receive). | 1649 | // do cancel tests at pending send/receive). |
| 1640 | // | 1650 | // |
| @@ -1726,7 +1736,6 @@ LUAG_FUNC( thread_gc ) | |||
| 1726 | return 0; | 1736 | return 0; |
| 1727 | } | 1737 | } |
| 1728 | 1738 | ||
| 1729 | |||
| 1730 | //--- | 1739 | //--- |
| 1731 | // = thread_cancel( lane_ud [,timeout_secs=0.0] [,force_kill_bool=false] ) | 1740 | // = thread_cancel( lane_ud [,timeout_secs=0.0] [,force_kill_bool=false] ) |
| 1732 | // | 1741 | // |
| @@ -1794,7 +1803,7 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force ) | |||
| 1794 | 1803 | ||
| 1795 | 1804 | ||
| 1796 | //--- | 1805 | //--- |
| 1797 | // str= thread_status( lane_ud ) | 1806 | // str= thread_status( lane ) |
| 1798 | // | 1807 | // |
| 1799 | // Returns: "pending" not started yet | 1808 | // Returns: "pending" not started yet |
| 1800 | // -> "running" started, doing its work.. | 1809 | // -> "running" started, doing its work.. |
| @@ -1803,25 +1812,29 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force ) | |||
| 1803 | // / "error" finished at an error, error value is there | 1812 | // / "error" finished at an error, error value is there |
| 1804 | // / "cancelled" execution cancelled by M (state gone) | 1813 | // / "cancelled" execution cancelled by M (state gone) |
| 1805 | // | 1814 | // |
| 1806 | LUAG_FUNC( thread_status ) | 1815 | static char const * const thread_status_string( struct s_lane *s) |
| 1807 | { | 1816 | { |
| 1808 | struct s_lane *s= lua_toLane(L,1); | 1817 | enum e_status st = s->status; // read just once (volatile) |
| 1809 | enum e_status st= s->status; // read just once (volatile) | 1818 | char const * str; |
| 1810 | const char *str; | 1819 | |
| 1811 | 1820 | if (s->mstatus == KILLED) | |
| 1812 | if (s->mstatus == KILLED) | 1821 | st= CANCELLED; |
| 1813 | st= CANCELLED; | 1822 | |
| 1814 | 1823 | str= (st==PENDING) ? "pending" : | |
| 1815 | str= (st==PENDING) ? "pending" : | 1824 | (st==RUNNING) ? "running" : // like in 'co.status()' |
| 1816 | (st==RUNNING) ? "running" : // like in 'co.status()' | 1825 | (st==WAITING) ? "waiting" : |
| 1817 | (st==WAITING) ? "waiting" : | 1826 | (st==DONE) ? "done" : |
| 1818 | (st==DONE) ? "done" : | 1827 | (st==ERROR_ST) ? "error" : |
| 1819 | (st==ERROR_ST) ? "error" : | 1828 | (st==CANCELLED) ? "cancelled" : NULL; |
| 1820 | (st==CANCELLED) ? "cancelled" : NULL; | 1829 | return str; |
| 1821 | ASSERT_L(str); | 1830 | } |
| 1822 | 1831 | ||
| 1823 | lua_pushstring( L, str ); | 1832 | static void push_thread_status( lua_State *L, struct s_lane *s) |
| 1824 | return 1; | 1833 | { |
| 1834 | char const * const str = thread_status_string( s); | ||
| 1835 | ASSERT_L( str); | ||
| 1836 | |||
| 1837 | lua_pushstring( L, str ); | ||
| 1825 | } | 1838 | } |
| 1826 | 1839 | ||
| 1827 | 1840 | ||
| @@ -1887,6 +1900,157 @@ LUAG_FUNC( thread_join ) | |||
| 1887 | } | 1900 | } |
| 1888 | 1901 | ||
| 1889 | 1902 | ||
| 1903 | //--- | ||
| 1904 | // thread_index( ud, key) -> value | ||
| 1905 | // | ||
| 1906 | // If key is found in the environment, return it | ||
| 1907 | // If key is numeric, wait until the thread returns and populate the environment with the return values | ||
| 1908 | // If the return values signal an error, propagate it | ||
| 1909 | // If key is "status" return the thread status | ||
| 1910 | // Else raise an error | ||
| 1911 | LUAG_FUNC( thread_index) | ||
| 1912 | { | ||
| 1913 | int const UD = 1; | ||
| 1914 | int const KEY = 2; | ||
| 1915 | int const ENV = 3; | ||
| 1916 | struct s_lane *s = lua_toLane( L, UD); | ||
| 1917 | ASSERT_L( lua_gettop( L) == 2); | ||
| 1918 | |||
| 1919 | STACK_GROW( L, 8); // up to 8 positions are needed in case of error propagation | ||
| 1920 | |||
| 1921 | // If key is numeric, wait until the thread returns and populate the environment with the return values | ||
| 1922 | if( lua_type( L, KEY) == LUA_TNUMBER) | ||
| 1923 | { | ||
| 1924 | // first, check that we don't already have an environment that holds the requested value | ||
| 1925 | { | ||
| 1926 | // If key is found in the environment, return it | ||
| 1927 | lua_getfenv( L, UD); | ||
| 1928 | lua_pushvalue( L, KEY); | ||
| 1929 | lua_rawget( L, ENV); | ||
| 1930 | if( !lua_isnil( L, -1)) | ||
| 1931 | { | ||
| 1932 | return 1; | ||
| 1933 | } | ||
| 1934 | lua_pop( L, 1); | ||
| 1935 | } | ||
| 1936 | { | ||
| 1937 | // check if we already fetched the values from the thread or not | ||
| 1938 | bool_t fetched; | ||
| 1939 | lua_Integer key = lua_tointeger( L, KEY); | ||
| 1940 | lua_pushinteger( L, 0); | ||
| 1941 | lua_rawget( L, ENV); | ||
| 1942 | fetched = !lua_isnil( L, -1); | ||
| 1943 | lua_pop( L, 1); // back to our 2 args + env on the stack | ||
| 1944 | if( !fetched) | ||
| 1945 | { | ||
| 1946 | lua_pushinteger( L, 0); | ||
| 1947 | lua_pushboolean( L, 1); | ||
| 1948 | lua_rawset( L, ENV); | ||
| 1949 | // wait until thread has completed | ||
| 1950 | lua_pushcfunction( L, LG_thread_join); | ||
| 1951 | lua_pushvalue( L, UD); | ||
| 1952 | lua_call( L, 1, LUA_MULTRET); // all return values are on the stack, at slots 4+ | ||
| 1953 | switch( s->status) | ||
| 1954 | { | ||
| 1955 | case DONE: // got regular return values | ||
| 1956 | { | ||
| 1957 | int i, nvalues = lua_gettop( L) - 3; | ||
| 1958 | for( i = nvalues; i > 0; -- i) | ||
| 1959 | { | ||
| 1960 | // pop the last element of the stack, to store it in the environment at its proper index | ||
| 1961 | lua_rawseti( L, ENV, i); | ||
| 1962 | } | ||
| 1963 | } | ||
| 1964 | break; | ||
| 1965 | |||
| 1966 | case ERROR_ST: // got 3 values: nil, errstring, callstack table | ||
| 1967 | // me[-2] could carry the stack table, but even | ||
| 1968 | // me[-1] is rather unnecessary (and undocumented); | ||
| 1969 | // use ':join()' instead. --AKa 22-Jan-2009 | ||
| 1970 | ASSERT_L( lua_isnil( L, 4) && !lua_isnil( L, 5) && lua_istable( L, 6)); | ||
| 1971 | // store errstring at key -1 | ||
| 1972 | lua_pushnumber( L, -1); | ||
| 1973 | lua_pushvalue( L, 5); | ||
| 1974 | lua_rawset( L, ENV); | ||
| 1975 | break; | ||
| 1976 | |||
| 1977 | case CANCELLED: | ||
| 1978 | // do nothing | ||
| 1979 | break; | ||
| 1980 | |||
| 1981 | default: | ||
| 1982 | // this is an internal error, we probably never get here | ||
| 1983 | lua_settop( L, 0); | ||
| 1984 | lua_pushliteral( L, "Unexpected status: "); | ||
| 1985 | lua_pushstring( L, thread_status_string( s)); | ||
| 1986 | lua_concat( L, 2); | ||
| 1987 | lua_error( L); | ||
| 1988 | break; | ||
| 1989 | } | ||
| 1990 | } | ||
| 1991 | lua_settop( L, 3); // UD KEY ENV | ||
| 1992 | if( key != -1) | ||
| 1993 | { | ||
| 1994 | lua_pushnumber( L, -1); // UD KEY ENV -1 | ||
| 1995 | lua_rawget( L, ENV); // UD KEY ENV "error" | ||
| 1996 | if( !lua_isnil( L, -1)) // an error was stored | ||
| 1997 | { | ||
| 1998 | // Note: Lua 5.1 interpreter is not prepared to show | ||
| 1999 | // non-string errors, so we use 'tostring()' here | ||
| 2000 | // to get meaningful output. --AKa 22-Jan-2009 | ||
| 2001 | // | ||
| 2002 | // Also, the stack dump we get is no good; it only | ||
| 2003 | // lists our internal Lanes functions. There seems | ||
| 2004 | // to be no way to switch it off, though. | ||
| 2005 | // | ||
| 2006 | // Level 3 should show the line where 'h[x]' was read | ||
| 2007 | // but this only seems to work for string messages | ||
| 2008 | // (Lua 5.1.4). No idea, why. --AKa 22-Jan-2009 | ||
| 2009 | lua_getmetatable( L, UD); // UD KEY ENV "error" mt | ||
| 2010 | lua_getfield( L, -1, "cached_error"); // UD KEY ENV "error" mt error() | ||
| 2011 | lua_getfield( L, -2, "cached_tostring"); // UD KEY ENV "error" mt error() tostring() | ||
| 2012 | lua_pushvalue( L, 4); // UD KEY ENV "error" mt error() tostring() "error" | ||
| 2013 | lua_call( L, 1, 1); // tostring( errstring) -- just in case // UD KEY ENV "error" mt error() "error" | ||
| 2014 | lua_pushinteger( L, 3); // UD KEY ENV "error" mt error() "error" 3 | ||
| 2015 | lua_call( L, 2, 0); // error( tostring( errstring), 3) // UD KEY ENV "error" mt | ||
| 2016 | } | ||
| 2017 | else | ||
| 2018 | { | ||
| 2019 | lua_pop( L, 1); // back to our 3 arguments on the stack | ||
| 2020 | } | ||
| 2021 | } | ||
| 2022 | lua_rawgeti( L, ENV, (int)key); | ||
| 2023 | } | ||
| 2024 | return 1; | ||
| 2025 | } | ||
| 2026 | if( lua_type( L, KEY) == LUA_TSTRING) | ||
| 2027 | { | ||
| 2028 | char const * const keystr = lua_tostring( L, KEY); | ||
| 2029 | lua_settop( L, 2); // keep only our original arguments on the stack | ||
| 2030 | if( strcmp( keystr, "status") == 0) | ||
| 2031 | { | ||
| 2032 | push_thread_status( L, s); // push the string representing the status | ||
| 2033 | } | ||
| 2034 | else if( strcmp( keystr, "cancel") == 0 || strcmp( keystr, "join") == 0) | ||
| 2035 | { | ||
| 2036 | // return UD.metatable[key] (should be a function in both cases) | ||
| 2037 | lua_getmetatable( L, UD); // UD KEY mt | ||
| 2038 | lua_replace( L, -3); // mt KEY | ||
| 2039 | lua_rawget( L, -2); // mt value | ||
| 2040 | ASSERT_L( lua_iscfunction( L, -1)); | ||
| 2041 | } | ||
| 2042 | return 1; | ||
| 2043 | } | ||
| 2044 | // unknown key | ||
| 2045 | lua_getmetatable( L, UD); | ||
| 2046 | lua_getfield( L, -1, "cached_error"); | ||
| 2047 | lua_pushliteral( L, "Unknown key: "); | ||
| 2048 | lua_pushvalue( L, KEY); | ||
| 2049 | lua_concat( L, 2); | ||
| 2050 | lua_call( L, 1, 0); // error( "Unknown key: " .. key) -> doesn't return | ||
| 2051 | return 0; | ||
| 2052 | } | ||
| 2053 | |||
| 1890 | /*---=== Timer support ===--- | 2054 | /*---=== Timer support ===--- |
| 1891 | */ | 2055 | */ |
| 1892 | 2056 | ||
| @@ -1946,15 +2110,11 @@ LUAG_FUNC( wakeup_conv ) | |||
| 1946 | return 1; | 2110 | return 1; |
| 1947 | } | 2111 | } |
| 1948 | 2112 | ||
| 1949 | |||
| 1950 | /*---=== Module linkage ===--- | 2113 | /*---=== Module linkage ===--- |
| 1951 | */ | 2114 | */ |
| 1952 | 2115 | ||
| 1953 | static const struct luaL_reg lanes_functions [] = { | 2116 | static const struct luaL_reg lanes_functions [] = { |
| 1954 | {"linda", LG_linda}, | 2117 | {"linda", LG_linda}, |
| 1955 | {"thread_status", LG_thread_status}, | ||
| 1956 | {"thread_join", LG_thread_join}, | ||
| 1957 | {"thread_cancel", LG_thread_cancel}, | ||
| 1958 | {"now_secs", LG_now_secs}, | 2118 | {"now_secs", LG_now_secs}, |
| 1959 | {"wakeup_conv", LG_wakeup_conv}, | 2119 | {"wakeup_conv", LG_wakeup_conv}, |
| 1960 | {"_single", LG__single}, | 2120 | {"_single", LG__single}, |
| @@ -2101,10 +2261,25 @@ __declspec(dllexport) | |||
| 2101 | luaL_register(L, NULL, lanes_functions); | 2261 | luaL_register(L, NULL, lanes_functions); |
| 2102 | 2262 | ||
| 2103 | // metatable for threads | 2263 | // metatable for threads |
| 2264 | // contains keys: { __gc, __index, cached_error, cached_tostring, cancel, join } | ||
| 2104 | // | 2265 | // |
| 2105 | lua_newtable( L ); | 2266 | lua_newtable( L); |
| 2106 | lua_pushcfunction( L, LG_thread_gc ); | 2267 | lua_pushcfunction( L, LG_thread_gc); |
| 2107 | lua_setfield( L, -2, "__gc" ); | 2268 | lua_setfield( L, -2, "__gc"); |
| 2269 | lua_pushcfunction( L, LG_thread_index); | ||
| 2270 | lua_setfield( L, -2, "__index"); | ||
| 2271 | lua_getfield( L, LUA_GLOBALSINDEX, "error"); | ||
| 2272 | ASSERT_L( lua_isfunction( L, -1)); | ||
| 2273 | lua_setfield( L, -2, "cached_error"); | ||
| 2274 | lua_getfield( L, LUA_GLOBALSINDEX, "tostring"); | ||
| 2275 | ASSERT_L( lua_isfunction( L, -1)); | ||
| 2276 | lua_setfield( L, -2, "cached_tostring"); | ||
| 2277 | lua_pushcfunction( L, LG_thread_join); | ||
| 2278 | lua_setfield( L, -2, "join"); | ||
| 2279 | lua_pushcfunction( L, LG_thread_cancel); | ||
| 2280 | lua_setfield( L, -2, "cancel"); | ||
| 2281 | lua_pushboolean( L, 0); | ||
| 2282 | lua_setfield( L, -2, "__metatable"); | ||
| 2108 | 2283 | ||
| 2109 | lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param | 2284 | lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param |
| 2110 | lua_setfield(L, -2, "thread_new"); | 2285 | lua_setfield(L, -2, "thread_new"); |
diff --git a/src/lanes.lua b/src/lanes.lua index b6fbc08..95bdeeb 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
| @@ -45,10 +45,7 @@ local mm = require "lua51-lanes" | |||
| 45 | assert( type(mm)=="table" ) | 45 | assert( type(mm)=="table" ) |
| 46 | 46 | ||
| 47 | 47 | ||
| 48 | local thread_new= assert(mm.thread_new) | 48 | local thread_new = assert(mm.thread_new) |
| 49 | local thread_status= assert(mm.thread_status) | ||
| 50 | local thread_join= assert(mm.thread_join) | ||
| 51 | local thread_cancel= assert(mm.thread_cancel) | ||
| 52 | 49 | ||
| 53 | local _single= assert(mm._single) | 50 | local _single= assert(mm._single) |
| 54 | local _version= assert(mm._version) | 51 | local _version= assert(mm._version) |
| @@ -77,8 +74,6 @@ local type= assert( type ) | |||
| 77 | local pairs= assert( pairs ) | 74 | local pairs= assert( pairs ) |
| 78 | local tostring= assert( tostring ) | 75 | local tostring= assert( tostring ) |
| 79 | local error= assert( error ) | 76 | local error= assert( error ) |
| 80 | local setmetatable= assert( setmetatable ) | ||
| 81 | local rawget= assert( rawget ) | ||
| 82 | 77 | ||
| 83 | ABOUT= | 78 | ABOUT= |
| 84 | { | 79 | { |
| @@ -127,76 +122,8 @@ end | |||
| 127 | -- Or, even better, 'ipairs()' should start valuing '__index' instead | 122 | -- Or, even better, 'ipairs()' should start valuing '__index' instead |
| 128 | -- of using raw reads that bypass it. | 123 | -- of using raw reads that bypass it. |
| 129 | -- | 124 | -- |
| 130 | local lane_mt= { | ||
| 131 | __index= function( me, k ) | ||
| 132 | if type(k) == "number" then | ||
| 133 | -- 'me[0]=true' marks we've already taken in the results | ||
| 134 | -- | ||
| 135 | if not rawget( me, 0 ) then | ||
| 136 | -- Wait indefinately; either propagates an error or | ||
| 137 | -- returns the return values | ||
| 138 | -- | ||
| 139 | me[0]= true -- marker, even on errors | ||
| 140 | |||
| 141 | local t= { thread_join(me._ud) } -- wait indefinate | ||
| 142 | -- | ||
| 143 | -- { ... } "done": regular return, 0..N results | ||
| 144 | -- { } "cancelled" | ||
| 145 | -- { nil, err_str, stack_tbl } "error" | ||
| 146 | |||
| 147 | local st= thread_status(me._ud) | ||
| 148 | if st=="done" then | ||
| 149 | -- Use 'pairs' and not 'ipairs' so that nil holes in | ||
| 150 | -- the returned values are tolerated. | ||
| 151 | -- | ||
| 152 | for i,v in pairs(t) do | ||
| 153 | me[i]= v | ||
| 154 | end | ||
| 155 | elseif st=="error" then | ||
| 156 | assert( t[1]==nil and t[2] and type(t[3])=="table" ) | ||
| 157 | me[-1]= t[2] | ||
| 158 | -- me[-2] could carry the stack table, but even | ||
| 159 | -- me[-1] is rather unnecessary (and undocumented); | ||
| 160 | -- use ':join()' instead. --AKa 22-Jan-2009 | ||
| 161 | elseif st=="cancelled" then | ||
| 162 | -- do nothing | ||
| 163 | else | ||
| 164 | error( "Unexpected status: "..st ) | ||
| 165 | end | ||
| 166 | end | ||
| 167 | |||
| 168 | -- Check errors even if we'd first peeked them via [-1] | ||
| 169 | -- and then came for the actual results. | ||
| 170 | -- | ||
| 171 | local err= rawget(me, -1) | ||
| 172 | if err~=nil and k~=-1 then | ||
| 173 | -- Note: Lua 5.1 interpreter is not prepared to show | ||
| 174 | -- non-string errors, so we use 'tostring()' here | ||
| 175 | -- to get meaningful output. --AKa 22-Jan-2009 | ||
| 176 | -- | ||
| 177 | -- Also, the stack dump we get is no good; it only | ||
| 178 | -- lists our internal Lanes functions. There seems | ||
| 179 | -- to be no way to switch it off, though. | ||
| 180 | |||
| 181 | -- Level 3 should show the line where 'h[x]' was read | ||
| 182 | -- but this only seems to work for string messages | ||
| 183 | -- (Lua 5.1.4). No idea, why. --AKa 22-Jan-2009 | ||
| 184 | -- | ||
| 185 | error( tostring(err), 3 ) -- level 3 should show the line where 'h[x]' was read | ||
| 186 | end | ||
| 187 | return rawget( me, k ) | ||
| 188 | -- | ||
| 189 | elseif k=="status" then -- me.status | ||
| 190 | return thread_status(me._ud) | ||
| 191 | -- | ||
| 192 | else | ||
| 193 | error( "Unknown key: "..k ) | ||
| 194 | end | ||
| 195 | end | ||
| 196 | } | ||
| 197 | |||
| 198 | ----- | 125 | ----- |
| 199 | -- h= lanes.gen( [libs_str|opt_tbl [, ...],] lane_func ) ( [...] ) | 126 | -- lanes.gen( [libs_str|opt_tbl [, ...],] lane_func ) ( [...] ) -> h |
| 200 | -- | 127 | -- |
| 201 | -- 'libs': nil: no libraries available (default) | 128 | -- 'libs': nil: no libraries available (default) |
| 202 | -- "": only base library ('assert', 'print', 'unpack' etc.) | 129 | -- "": only base library ('assert', 'print', 'unpack' etc.) |
| @@ -220,8 +147,6 @@ local lane_mt= { | |||
| 220 | -- modifiers, and prepares a lane generator. One can either finish here, | 147 | -- modifiers, and prepares a lane generator. One can either finish here, |
| 221 | -- and call the generator later (maybe multiple times, with different parameters) | 148 | -- and call the generator later (maybe multiple times, with different parameters) |
| 222 | -- or add on actual thread arguments to also ignite the thread on the same call. | 149 | -- or add on actual thread arguments to also ignite the thread on the same call. |
| 223 | -- | ||
| 224 | local lane_proxy | ||
| 225 | 150 | ||
| 226 | local valid_libs= { | 151 | local valid_libs= { |
| 227 | ["package"]= true, | 152 | ["package"]= true, |
| @@ -298,39 +223,16 @@ function gen( ... ) | |||
| 298 | -- Lane generator | 223 | -- Lane generator |
| 299 | -- | 224 | -- |
| 300 | return function(...) | 225 | return function(...) |
| 301 | return lane_proxy( thread_new( func, libs, cs, prio, g_tbl, | 226 | return thread_new( func, libs, cs, prio, g_tbl, ...) -- args |
| 302 | ... ) ) -- args | ||
| 303 | end | 227 | end |
| 304 | end | 228 | end |
| 305 | 229 | ||
| 306 | lane_proxy= function( ud ) | ||
| 307 | local proxy= { | ||
| 308 | _ud= ud, | ||
| 309 | |||
| 310 | -- true|false= me:cancel() | ||
| 311 | -- | ||
| 312 | cancel= function(me, time, force) return thread_cancel(me._ud, time, force) end, | ||
| 313 | |||
| 314 | |||
| 315 | -- [...] | [nil,err,stack_tbl]= me:join( [wait_secs=-1] ) | ||
| 316 | -- | ||
| 317 | join= function( me, wait ) | ||
| 318 | return thread_join( me._ud, wait ) | ||
| 319 | end, | ||
| 320 | } | ||
| 321 | assert( proxy._ud ) | ||
| 322 | setmetatable( proxy, lane_mt ) | ||
| 323 | |||
| 324 | return proxy | ||
| 325 | end | ||
| 326 | |||
| 327 | |||
| 328 | ---=== Lindas ===--- | 230 | ---=== Lindas ===--- |
| 329 | 231 | ||
| 330 | -- We let the C code attach methods to userdata directly | 232 | -- We let the C code attach methods to userdata directly |
| 331 | 233 | ||
| 332 | ----- | 234 | ----- |
| 333 | -- linda_ud= lanes.linda() | 235 | -- lanes.linda() -> linda_ud |
| 334 | -- | 236 | -- |
| 335 | linda = mm.linda | 237 | linda = mm.linda |
| 336 | 238 | ||
| @@ -613,5 +515,6 @@ function genatomic( linda, key, initial_val ) | |||
| 613 | end | 515 | end |
| 614 | end | 516 | end |
| 615 | 517 | ||
| 518 | -- newuserdata = mm.newuserdata | ||
| 616 | 519 | ||
| 617 | --the end | 520 | --the end |
diff --git a/src/tools.c b/src/tools.c index 41163c4..29959a8 100644 --- a/src/tools.c +++ b/src/tools.c | |||
| @@ -395,65 +395,102 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelud | |||
| 395 | 395 | ||
| 396 | if (lua_isnil(L,-1)) | 396 | if (lua_isnil(L,-1)) |
| 397 | { | 397 | { |
| 398 | int oldtop; | ||
| 399 | // No metatable yet. We have two things to do: | 398 | // No metatable yet. We have two things to do: |
| 400 | |||
| 401 | // 1 - make one and register it | 399 | // 1 - make one and register it |
| 402 | lua_pop(L,1); | 400 | { |
| 401 | int oldtop; | ||
| 403 | 402 | ||
| 404 | // tbl= idfunc( "metatable" ) | 403 | lua_pop( L, 1); |
| 405 | // | ||
| 406 | oldtop = lua_gettop( L); | ||
| 407 | idfunc( L, "metatable"); | ||
| 408 | // | ||
| 409 | // [-2]: proxy | ||
| 410 | // [-1]: metatable (returned by 'idfunc') | ||
| 411 | 404 | ||
| 412 | if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1)) | 405 | // tbl= idfunc( "metatable" ) |
| 413 | { | 406 | // |
| 414 | luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); | 407 | oldtop = lua_gettop( L); |
| 415 | } | 408 | idfunc( L, "metatable"); |
| 409 | // | ||
| 410 | // [-2]: proxy | ||
| 411 | // [-1]: metatable (returned by 'idfunc') | ||
| 416 | 412 | ||
| 417 | // Add '__gc' method | 413 | if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1)) |
| 418 | // | 414 | { |
| 419 | lua_pushcfunction( L, deep_userdata_gc ); | 415 | luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); |
| 420 | lua_setfield( L, -2, "__gc" ); | 416 | } |
| 421 | 417 | ||
| 422 | // Memorize for later rounds | 418 | // Add '__gc' method |
| 423 | // | 419 | // |
| 424 | lua_pushvalue( L,-1 ); | 420 | lua_pushcfunction( L, deep_userdata_gc ); |
| 425 | lua_pushlightuserdata( L, idfunc ); | 421 | lua_setfield( L, -2, "__gc" ); |
| 426 | // | 422 | |
| 427 | // [-4]: proxy | 423 | // Memorize for later rounds |
| 428 | // [-3]: metatable (2nd ref) | 424 | // |
| 429 | // [-2]: metatable | 425 | lua_pushvalue( L,-1 ); |
| 430 | // [-1]: idfunc | 426 | lua_pushlightuserdata( L, idfunc ); |
| 427 | // | ||
| 428 | // [-4]: proxy | ||
| 429 | // [-3]: metatable (2nd ref) | ||
| 430 | // [-2]: metatable | ||
| 431 | // [-1]: idfunc | ||
| 431 | 432 | ||
| 432 | set_deep_lookup(L); | 433 | set_deep_lookup(L); |
| 434 | } | ||
| 433 | 435 | ||
| 434 | // 2 - cause the target state to require the module that exported the idfunc | 436 | // 2 - cause the target state to require the module that exported the idfunc |
| 435 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | 437 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc |
| 436 | lua_getglobal( L, "require"); | 438 | STACK_CHECK(L) |
| 437 | if( lua_isfunction( L, -1)) // just in case... | ||
| 438 | { | 439 | { |
| 440 | char const * modname; | ||
| 439 | // make sure the function pushed a single value on the stack! | 441 | // make sure the function pushed a single value on the stack! |
| 440 | int oldtop = lua_gettop( L); | ||
| 441 | idfunc( L, "module"); | ||
| 442 | if( lua_gettop( L) - oldtop != 1 || !lua_isstring( L, -1)) | ||
| 443 | { | 442 | { |
| 444 | luaL_error( L, "Bad idfunc on \"module\": should return a string"); | 443 | int oldtop = lua_gettop( L); |
| 444 | idfunc( L, "module"); // ... "module"/nil | ||
| 445 | if( lua_gettop( L) - oldtop != 1) | ||
| 446 | { | ||
| 447 | luaL_error( L, "Bad idfunc on \"module\": should return a single value"); | ||
| 448 | } | ||
| 445 | } | 449 | } |
| 446 | // if we are inside a call to require, this will raise a "reentrency" error that we absorb silently (we don't care, this probably means the module is already being required, which is what we need) | 450 | modname = luaL_optstring( L, -1, NULL); // raises an error if not a string or nil |
| 447 | if( lua_pcall( L, 1, 0, 0) != 0) | 451 | if( modname) // we actually got a module name |
| 448 | { | 452 | { |
| 449 | //char const * const errMsg = lua_tostring( L, -1); // just to see it in the debugger | 453 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. |
| 450 | lua_pop( L, 1); | 454 | lua_getglobal( L, "require"); // ... "module" require() |
| 455 | // check that the module is already loaded (or being loaded, we are happy either way) | ||
| 456 | if( lua_isfunction( L, -1)) | ||
| 457 | { | ||
| 458 | lua_insert( L, -2); // ... require() "module" | ||
| 459 | lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED"); // ... require() "module" L.registry._LOADED | ||
| 460 | if( lua_istable( L, -1)) | ||
| 461 | { | ||
| 462 | bool_t alreadyloaded; | ||
| 463 | lua_pushvalue( L, -2); // ... require() "module" L.registry._LOADED "module" | ||
| 464 | lua_rawget( L, -2); // ... require() "module" L.registry._LOADED module | ||
| 465 | alreadyloaded = lua_toboolean( L, -1); | ||
| 466 | if( !alreadyloaded) // not loaded | ||
| 467 | { | ||
| 468 | lua_pop( L, 2); // ... require() "module" | ||
| 469 | lua_call( L, 1, 0); // call require "modname" // ... | ||
| 470 | } | ||
| 471 | else // already loaded, we are happy | ||
| 472 | { | ||
| 473 | lua_pop( L, 4); // ... | ||
| 474 | } | ||
| 475 | } | ||
| 476 | else // no L.registry._LOADED; can this ever happen? | ||
| 477 | { | ||
| 478 | luaL_error( L, "unexpected error while requiring a module"); | ||
| 479 | lua_pop( L, 3); // ... | ||
| 480 | } | ||
| 481 | } | ||
| 482 | else // a module name, but no require() function :-( | ||
| 483 | { | ||
| 484 | luaL_error( L, "lanes receiving deep userdata should register the 'package' library"); | ||
| 485 | lua_pop( L, 2); // ... | ||
| 486 | } | ||
| 487 | } | ||
| 488 | else // no module name | ||
| 489 | { | ||
| 490 | lua_pop( L, 1); // ... | ||
| 451 | } | 491 | } |
| 452 | } | 492 | } |
| 453 | else | 493 | STACK_END(L,0) |
| 454 | { | ||
| 455 | lua_pop( L, 1); | ||
| 456 | } | ||
| 457 | } | 494 | } |
| 458 | STACK_MID(L,2) | 495 | STACK_MID(L,2) |
| 459 | ASSERT_L( lua_isuserdata(L,-2) ); | 496 | ASSERT_L( lua_isuserdata(L,-2) ); |
