summaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2011-02-17 07:52:53 +0100
committerBenoit Germain <bnt.germain@gmail.com>2011-02-17 07:52:53 +0100
commitab233d0c9a1edc34836e2249c1eb6d714f1066b5 (patch)
treea91078b0ca240f870f5f15c2930bc0719a86c9d1 /src/lanes.c
parentafb2da4789cdaddc5a0c3c9c2d57ccd36bcc74c7 (diff)
downloadlanes-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/lanes.c')
-rw-r--r--src/lanes.c231
1 files changed, 203 insertions, 28 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//
1806LUAG_FUNC( thread_status ) 1815static 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 ); 1832static 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
1911LUAG_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
1953static const struct luaL_reg lanes_functions [] = { 2116static 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");