aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES14
-rw-r--r--docs/index.html4
-rw-r--r--src/lanes.c231
-rw-r--r--src/lanes.lua107
-rw-r--r--src/tools.c121
-rw-r--r--tests/appendud.lua20
-rw-r--r--tests/basic.lua2
-rw-r--r--tests/error.lua6
-rw-r--r--tests/fibonacci.lua2
-rw-r--r--tests/protectproxy.lua27
10 files changed, 346 insertions, 188 deletions
diff --git a/CHANGES b/CHANGES
index e9cfa25..1e84397 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,20 @@ CHANGES:
3 3
4CHANGE X: 4CHANGE X:
5 5
6CHANGE 27 BGe 17-Feb-2011
7 - we know Lanes is loaded in the master state, so we don't force it
8 to be required in every lane too when a linda deep userdata is copied
9 - Refactor lane proxy implementation: it is now a full userdata instead
10 of a table, and its methods are implemented in C instead of Lua
11 * its metatable is no longer accessible
12 * writing to the proxy raises an error
13 * it is no longer possible to overwrite its join() and cancel() methods
14 - when a deep userdata idfunc requests a module to be required, manually
15 check that it is not loaded before requiring it instead of relying on
16 the require function's loop detection feature
17 - when a module must be required, raise an error if the 'require' function
18 is not found in the target state
19
6CHANGE 26 BGe 14-Feb-2011: 20CHANGE 26 BGe 14-Feb-2011:
7 Fixed application hang-up because keeper state was not released in case of errors thrown by 21 Fixed application hang-up because keeper state was not released in case of errors thrown by
8 inter-state data copy for unsupported types 22 inter-state data copy for unsupported types
diff --git a/docs/index.html b/docs/index.html
index 9d66510..03c91f7 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -804,8 +804,8 @@ and for making metatables for the state-specific proxies for accessing it.
804Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>. 804Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>.
805 </li> 805 </li>
806 <li>Instanciate your userdata using <tt>luaG_deep_userdata()</tt>, 806 <li>Instanciate your userdata using <tt>luaG_deep_userdata()</tt>,
807 instead of the regular <tt>lua_newuserdata()</tt>. 807 instead of the regular <tt>lua_newuserdata()</tt>.
808 Given an <tt>idfunc</tt>, it sets up the support 808 Given an <tt>idfunc</tt>, it sets up the support
809 structures and returns a state-specific proxy userdata for accessing your 809 structures and returns a state-specific proxy userdata for accessing your
810 data. This proxy can also be copied over to other lanes. 810 data. This proxy can also be copied over to other lanes.
811 </li> 811 </li>
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");
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"
45assert( type(mm)=="table" ) 45assert( type(mm)=="table" )
46 46
47 47
48local thread_new= assert(mm.thread_new) 48local thread_new = assert(mm.thread_new)
49local thread_status= assert(mm.thread_status)
50local thread_join= assert(mm.thread_join)
51local thread_cancel= assert(mm.thread_cancel)
52 49
53local _single= assert(mm._single) 50local _single= assert(mm._single)
54local _version= assert(mm._version) 51local _version= assert(mm._version)
@@ -77,8 +74,6 @@ local type= assert( type )
77local pairs= assert( pairs ) 74local pairs= assert( pairs )
78local tostring= assert( tostring ) 75local tostring= assert( tostring )
79local error= assert( error ) 76local error= assert( error )
80local setmetatable= assert( setmetatable )
81local rawget= assert( rawget )
82 77
83ABOUT= 78ABOUT=
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--
130local 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--
224local lane_proxy
225 150
226local valid_libs= { 151local 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
304end 228end
305 229
306lane_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
325end
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--
335linda = mm.linda 237linda = mm.linda
336 238
@@ -613,5 +515,6 @@ function genatomic( linda, key, initial_val )
613 end 515 end
614end 516end
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) );
diff --git a/tests/appendud.lua b/tests/appendud.lua
index 65d0798..eb1f768 100644
--- a/tests/appendud.lua
+++ b/tests/appendud.lua
@@ -31,28 +31,30 @@ local _ud = {
31 31
32 32
33function appendud(tab, ud) 33function appendud(tab, ud)
34 io.stderr:write "Starting" 34 io.stderr:write "Starting "
35 tab:beginupdate() set_finalizer( function() tab:endupdate() end ) 35 tab:beginupdate() set_finalizer( function() tab:endupdate() end )
36 ud:lock() set_finalizer( function() ud:unlock() end ) 36 ud:lock() set_finalizer( function() ud:unlock() end )
37 for i = 1,#ud do 37 for i = 1,#ud do
38 tab[#tab+1] = ud[i] 38 tab[#tab+1] = ud[i]
39 end 39 end
40 io.stderr:write "Ending" 40 io.stderr:write "Ending "
41 return tab -- need to return 'tab' since we're running in a separate thread 41 return tab -- need to return 'tab' since we're running in a separate thread
42 -- ('tab' is passed over lanes by value, not by reference) 42 -- ('tab' is passed over lanes by value, not by reference)
43end 43end
44 44
45local t,err= lanes.gen( "io", appendud )( _tab, _ud ) -- create & launch a thread 45local t,err= lanes.gen( "base,io", appendud )( _tab, _ud ) -- create & launch a thread
46assert(t) 46assert(t)
47assert(not err) 47assert(not err)
48 48
49-- test 49-- test
50 50-- print("t:join()")
51t:join() -- Need to explicitly wait for the thread, since 'ipairs()' does not 51a,b,c = t[1],t[2],t[3] -- Need to explicitly wait for the thread, since 'ipairs()' does not
52--a,b,c = t:join() -- Need to explicitly wait for the thread, since 'ipairs()' does not
52 -- value the '__index' metamethod (wouldn't it be cool if it did..?) 53 -- value the '__index' metamethod (wouldn't it be cool if it did..?)
53 54
54io.stderr:write(t[1]) 55print(a,b,c)
56-- print("io.stderr:write(t[1])")
57-- io.stderr:write(t[1])
58_ = t[0]
59print(_)
55 60
56for k,v in ipairs(t) do
57 print(k,v)
58end
diff --git a/tests/basic.lua b/tests/basic.lua
index 352e029..853a8de 100644
--- a/tests/basic.lua
+++ b/tests/basic.lua
@@ -171,7 +171,7 @@ local function PEEK() return linda:get("<-") end
171local function SEND(...) linda:send( "->", ... ) end 171local function SEND(...) linda:send( "->", ... ) end
172local function RECEIVE() return linda:receive( "<-" ) end 172local function RECEIVE() return linda:receive( "<-" ) end
173 173
174local t= lanes_gen("io,package",chunk)(linda) -- prepare & launch 174local t= lanes_gen("io",chunk)(linda) -- prepare & launch
175 175
176SEND(1); WR( "1 sent\n" ) 176SEND(1); WR( "1 sent\n" )
177SEND(2); WR( "2 sent\n" ) 177SEND(2); WR( "2 sent\n" )
diff --git a/tests/error.lua b/tests/error.lua
index 673bcb5..4922846 100644
--- a/tests/error.lua
+++ b/tests/error.lua
@@ -9,9 +9,9 @@ require "lanes"
9local function lane() 9local function lane()
10 10
11 local subf= function() -- this so that we can see the call stack 11 local subf= function() -- this so that we can see the call stack
12 --error "aa" 12 error "aa"
13 error({}) 13 --error({})
14 error(error) 14 --error(error)
15 end 15 end
16 local subf2= function() 16 local subf2= function()
17 subf() 17 subf()
diff --git a/tests/fibonacci.lua b/tests/fibonacci.lua
index 8867e14..667a3e9 100644
--- a/tests/fibonacci.lua
+++ b/tests/fibonacci.lua
@@ -70,6 +70,6 @@ assert( #right==99 )
70 70
71local N= 80 71local N= 80
72local res= fib(N) 72local res= fib(N)
73print( right[N] ) 73print( right[N], res )
74assert( res==right[N] ) 74assert( res==right[N] )
75 75
diff --git a/tests/protectproxy.lua b/tests/protectproxy.lua
new file mode 100644
index 0000000..57ca831
--- /dev/null
+++ b/tests/protectproxy.lua
@@ -0,0 +1,27 @@
1require "lanes"
2
3local body = function( param)
4 print ( "lane body: " .. param)
5 return 1
6end
7
8local gen = lanes.gen( "*", body)
9
10local mylane = gen( "hello")
11
12local result = mylane[1]
13
14-- make sure we have properly protected the lane
15
16-- can't access the metatable
17print( "metatable:" .. tostring( getmetatable( mylane)))
18
19-- can't write to the userdata
20print( "lane result: " .. mylane[1])
21
22-- read nonexistent values -> nil
23print "reading nonexistent return value"
24a = mylane[2]
25
26print "writing to the lane -> error"
27mylane[4] = true