aboutsummaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/lanes.c231
-rw-r--r--src/lanes.lua107
-rw-r--r--src/tools.c121
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//
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) );