aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <bnt period germain arrobase gmail period com>2014-05-16 11:22:39 +0200
committerBenoit Germain <bnt period germain arrobase gmail period com>2014-05-16 11:22:39 +0200
commit55e53f8a24ce42cadfd2887e50bf0248eb10d301 (patch)
treea201d614669eff9ea5ac75db9c9e86c50e2a681e
parent555e3c26c733ce653aafec25ea77b25b6b1bed07 (diff)
downloadlanes-55e53f8a24ce42cadfd2887e50bf0248eb10d301.tar.gz
lanes-55e53f8a24ce42cadfd2887e50bf0248eb10d301.tar.bz2
lanes-55e53f8a24ce42cadfd2887e50bf0248eb10d301.zip
Minor fixes and tweaks
* bumped version to 3.9.5 * lanes.gen() error reporting improvements * fix linda.__towatch to return non-nil when the linda is empty
-rw-r--r--CHANGES14
-rw-r--r--src/lanes.c241
-rw-r--r--src/lanes.lua187
3 files changed, 241 insertions, 201 deletions
diff --git a/CHANGES b/CHANGES
index 3a7ff89..31599c4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,19 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 112 BGe 16-May-14
4 * bumped version to 3.9.5
5 * fix linda.__towatch to return non-nil when the linda is empty
6 * lanes.gen() error reporting improvements
7
8CHANGE 111 BGe 24-Apr-14
9 * fixed linda:send() possibly returning an undefined value
10
11CHANGE 110 Stepets 20-Apr-14
12 * fix LuaJIT detection issues
13
14CHANGE 109 BGe 03-Apr-14
15 * moved some Lua-version compatibility code in separate source files
16
3CHANGE 108: BGe 20-Mar-14 17CHANGE 108: BGe 20-Mar-14
4 * bumped version to 3.9.4 18 * bumped version to 3.9.4
5 * set_finalizer throws an error if provided finalizer isn't a function 19 * set_finalizer throws an error if provided finalizer isn't a function
diff --git a/src/lanes.c b/src/lanes.c
index abda889..f45dac7 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.9.4"; 55char const* VERSION = "3.9.5";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -1074,6 +1074,24 @@ LUAG_FUNC( linda_dump)
1074} 1074}
1075 1075
1076/* 1076/*
1077 * table = linda:dump()
1078 * return a table listing all pending data inside the linda
1079 */
1080LUAG_FUNC( linda_towatch)
1081{
1082 struct s_Linda* linda = lua_toLinda( L, 1);
1083 int pushed;
1084 ASSERT_L( linda->U == get_universe( L));
1085 pushed = keeper_push_linda_storage( linda->U, L, linda, LINDA_KEEPER_HASHSEED( linda));
1086 if( pushed == 0)
1087 {
1088 // if the linda is empty, don't return nil
1089 pushed = linda_tostring( L, 1, FALSE);
1090 }
1091 return pushed;
1092}
1093
1094/*
1077* Identity function of a shared userdata object. 1095* Identity function of a shared userdata object.
1078* 1096*
1079* lightuserdata= linda_id( "new" [, ...] ) 1097* lightuserdata= linda_id( "new" [, ...] )
@@ -1190,7 +1208,7 @@ static void* linda_id( lua_State* L, enum eDeepOp op_)
1190 lua_setfield( L, -2, "__tostring"); 1208 lua_setfield( L, -2, "__tostring");
1191 1209
1192 // Decoda __towatch support 1210 // Decoda __towatch support
1193 lua_pushcfunction( L, LG_linda_dump); 1211 lua_pushcfunction( L, LG_linda_towatch);
1194 lua_setfield( L, -2, "__towatch"); 1212 lua_setfield( L, -2, "__towatch");
1195 1213
1196 lua_pushcfunction( L, LG_linda_concat); 1214 lua_pushcfunction( L, LG_linda_concat);
@@ -2027,12 +2045,6 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs)
2027 // Called with the lane function and arguments on the stack 2045 // Called with the lane function and arguments on the stack
2028 int const nargs = lua_gettop( L) - 1; 2046 int const nargs = lua_gettop( L) - 1;
2029 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); 2047 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L));
2030#if HAVE_LANE_TRACKING
2031 if( s->U->tracking_first)
2032 {
2033 tracking_add( s);
2034 }
2035#endif // HAVE_LANE_TRACKING
2036 THREAD_MAKE_ASYNCH_CANCELLABLE(); 2048 THREAD_MAKE_ASYNCH_CANCELLABLE();
2037 THREAD_CLEANUP_PUSH( thread_cleanup_handler, s); 2049 THREAD_CLEANUP_PUSH( thread_cleanup_handler, s);
2038 s->status = RUNNING; // PENDING -> RUNNING 2050 s->status = RUNNING; // PENDING -> RUNNING
@@ -2147,85 +2159,86 @@ LUAG_FUNC( require)
2147LUAG_FUNC( thread_gc); 2159LUAG_FUNC( thread_gc);
2148#define GCCB_KEY (void*)LG_thread_gc 2160#define GCCB_KEY (void*)LG_thread_gc
2149//--- 2161//---
2150// lane_ud= thread_new( function, [libs_str], 2162// lane_ud = lane_new( function
2151// [cancelstep_uint=0], 2163// , [libs_str]
2152// [prio_int=0], 2164// , [cancelstep_uint=0]
2153// [globals_tbl], 2165// , [priority_int=0]
2154// [package_tbl], 2166// , [globals_tbl]
2155// [required], 2167// , [package_tbl]
2156// [gc_cb], 2168// , [required_tbl]
2157// [... args ...] ) 2169// , [gc_cb_func]
2170// [, ... args ...])
2158// 2171//
2159// Upvalues: metatable to use for 'lane_ud' 2172// Upvalues: metatable to use for 'lane_ud'
2160// 2173//
2161 2174LUAG_FUNC( lane_new)
2162LUAG_FUNC( thread_new)
2163{ 2175{
2164 lua_State* L2; 2176 lua_State* L2;
2165 struct s_lane* s; 2177 struct s_lane* s;
2166 struct s_lane** ud; 2178 struct s_lane** ud;
2167 2179
2168 char const* libs = lua_tostring( L, 2); 2180 char const* libs_str = lua_tostring( L, 2);
2169 uint_t cs = luaG_optunsigned( L, 3, 0); 2181 uint_t cancelstep_idx = luaG_optunsigned( L, 3, 0);
2170 int const prio = (int) luaL_optinteger( L, 4, 0); 2182 int const priority = (int) luaL_optinteger( L, 4, 0);
2171 uint_t glob = lua_isnoneornil( L, 5) ? 0 : 5; 2183 uint_t globals_idx = lua_isnoneornil( L, 5) ? 0 : 5;
2172 uint_t package = lua_isnoneornil( L, 6) ? 0 : 6; 2184 uint_t package_idx = lua_isnoneornil( L, 6) ? 0 : 6;
2173 uint_t required = lua_isnoneornil( L, 7) ? 0 : 7; 2185 uint_t required_idx = lua_isnoneornil( L, 7) ? 0 : 7;
2174 uint_t gc_cb = lua_isnoneornil( L, 8) ? 0 : 8; 2186 uint_t gc_cb_idx = lua_isnoneornil( L, 8) ? 0 : 8;
2175 2187
2176#define FIXED_ARGS 8 2188#define FIXED_ARGS 8
2177 uint_t args = lua_gettop(L) - FIXED_ARGS; 2189 int const nargs = lua_gettop(L) - FIXED_ARGS;
2178 struct s_Universe* U = get_universe( L); 2190 struct s_Universe* U = get_universe( L);
2191 ASSERT_L( nargs >= 0);
2179 2192
2180 // public Lanes API accepts a generic range -3/+3 2193 // public Lanes API accepts a generic range -3/+3
2181 // that will be remapped into the platform-specific scheduler priority scheme 2194 // that will be remapped into the platform-specific scheduler priority scheme
2182 // On some platforms, -3 is equivalent to -2 and +3 to +2 2195 // On some platforms, -3 is equivalent to -2 and +3 to +2
2183 if( prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) 2196 if( priority < THREAD_PRIO_MIN || priority > THREAD_PRIO_MAX)
2184 { 2197 {
2185 return luaL_error( L, "Priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio); 2198 return luaL_error( L, "Priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, priority);
2186 } 2199 }
2187 2200
2188 /* --- Create and prepare the sub state --- */ 2201 /* --- Create and prepare the sub state --- */
2189 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: setup\n" INDENT_END)); 2202 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: setup\n" INDENT_END));
2190 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 2203 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2191 2204
2192 // populate with selected libraries at the same time 2205 // populate with selected libraries at the same time
2193 L2 = luaG_newstate( U, L, libs); 2206 L2 = luaG_newstate( U, L, libs_str); // L // L2
2194 2207
2195 STACK_GROW( L, 2); 2208 STACK_GROW( L2, nargs + 3); //
2196 STACK_GROW( L2, 3); 2209 STACK_CHECK( L2);
2197 2210
2198 // give a default "Lua" name to the thread to see VM name in Decoda debugger 2211 STACK_GROW( L, 3); // func libs cancelstep priority globals package required gc_cb [... args ...]
2199 lua_pushfstring( L2, "Lane #%p", L2); 2212 STACK_CHECK( L);
2200 lua_setglobal( L2, "decoda_name");
2201 2213
2202 ASSERT_L( lua_gettop(L2) == 0); 2214 // give a default "Lua" name to the thread to see VM name in Decoda debugger
2215 lua_pushfstring( L2, "Lane #%p", L2); // "..."
2216 lua_setglobal( L2, "decoda_name"); //
2217 ASSERT_L( lua_gettop( L2) == 0);
2203 2218
2204 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: update 'package'\n" INDENT_END)); 2219 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: update 'package'\n" INDENT_END));
2205 // package 2220 // package
2206 if( package != 0) 2221 if( package_idx != 0)
2207 { 2222 {
2208 // when copying with mode eLM_LaneBody, should raise an error in case of problem, not leave it one the stack 2223 // when copying with mode eLM_LaneBody, should raise an error in case of problem, not leave it one the stack
2209 (void) luaG_inter_copy_package( U, L, L2, package, eLM_LaneBody); 2224 (void) luaG_inter_copy_package( U, L, L2, package_idx, eLM_LaneBody);
2210 } 2225 }
2211 2226
2212 // modules to require in the target lane *before* the function is transfered! 2227 // modules to require in the target lane *before* the function is transfered!
2213 2228
2214 STACK_CHECK( L); 2229 if( required_idx != 0)
2215 STACK_CHECK( L2);
2216 if( required != 0)
2217 { 2230 {
2218 int nbRequired = 1; 2231 int nbRequired = 1;
2219 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: require 'required' list\n" INDENT_END)); 2232 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: require 'required' list\n" INDENT_END));
2220 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 2233 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2221 // should not happen, was checked in lanes.lua before calling thread_new() 2234 // should not happen, was checked in lanes.lua before calling lane_new()
2222 if( lua_type( L, required) != LUA_TTABLE) 2235 if( lua_type( L, required_idx) != LUA_TTABLE)
2223 { 2236 {
2224 return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required)); 2237 return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required_idx));
2225 } 2238 }
2226 2239
2227 lua_pushnil( L); 2240 lua_pushnil( L); // func libs cancelstep priority globals package required gc_cb [... args ...] nil
2228 while( lua_next( L, required) != 0) 2241 while( lua_next( L, required_idx) != 0) // func libs cancelstep priority globals package required gc_cb [... args ...] n "modname"
2229 { 2242 {
2230 if( lua_type( L, -1) != LUA_TSTRING || lua_type( L, -2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired) 2243 if( lua_type( L, -1) != LUA_TSTRING || lua_type( L, -2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired)
2231 { 2244 {
@@ -2238,12 +2251,10 @@ LUAG_FUNC( thread_new)
2238 char const* name = lua_tolstring( L, -1, &len); 2251 char const* name = lua_tolstring( L, -1, &len);
2239 2252
2240 // require the module in the target lane 2253 // require the module in the target lane
2241 STACK_GROW( L2, 2); 2254 lua_getglobal( L2, "require"); // require()?
2242 STACK_CHECK( L2);
2243 lua_getglobal( L2, "require"); // require()?
2244 if( lua_isnil( L2, -1)) 2255 if( lua_isnil( L2, -1))
2245 { 2256 {
2246 lua_pop( L2, 1); // 2257 lua_pop( L2, 1); //
2247 luaL_error( L, "cannot pre-require modules without loading 'package' library first"); 2258 luaL_error( L, "cannot pre-require modules without loading 'package' library first");
2248 } 2259 }
2249 else 2260 else
@@ -2254,113 +2265,102 @@ LUAG_FUNC( thread_new)
2254 { 2265 {
2255 luaG_copy_one_time_settings( U, L, L2); 2266 luaG_copy_one_time_settings( U, L, L2);
2256 } 2267 }
2257 lua_pushlstring( L2, name, len); // require() name 2268 lua_pushlstring( L2, name, len); // require() name
2258 if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode 2269 if( lua_pcall( L2, 1, 1, 0) != LUA_OK) // ret/errcode
2259 { 2270 {
2260 // propagate error to main state if any 2271 // propagate error to main state if any
2261 luaG_inter_move( U, L2, L, 1, eLM_LaneBody); // 2272 luaG_inter_move( U, L2, L, 1, eLM_LaneBody); // func libs cancelstep priority globals package required gc_cb [... args ...] n "modname" error
2262 return lua_error( L); 2273 return lua_error( L);
2263 } 2274 }
2264 STACK_MID( L2, 1);
2265 // after requiring the module, register the functions it exported in our name<->function database 2275 // after requiring the module, register the functions it exported in our name<->function database
2266 populate_func_lookup_table( L2, -1, name); 2276 populate_func_lookup_table( L2, -1, name);
2267 STACK_MID( L2, 1); 2277 lua_pop( L2, 1); //
2268 lua_pop( L2, 1);
2269 } 2278 }
2270 STACK_END( L2, 0);
2271 } 2279 }
2272 lua_pop( L, 1); 2280 lua_pop( L, 1); // func libs cancelstep priority globals package required gc_cb [... args ...] n
2273 ++ nbRequired; 2281 ++ nbRequired;
2274 } 2282 } // func libs cancelstep priority globals package required gc_cb [... args ...]
2275 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 2283 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2276 } 2284 }
2277 STACK_END( L2, 0); 2285 STACK_MID( L, 0);
2278 STACK_END( L, 0); 2286 STACK_MID( L2, 0); //
2279 2287
2280 // Appending the specified globals to the global environment 2288 // Appending the specified globals to the global environment
2281 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... 2289 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed...
2282 // 2290 //
2283 if( glob != 0) 2291 if( globals_idx != 0)
2284 { 2292 {
2285 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer globals\n" INDENT_END)); 2293 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer globals\n" INDENT_END));
2286 STACK_CHECK( L); 2294 if( !lua_istable( L, globals_idx))
2287 STACK_CHECK( L2);
2288 if( !lua_istable( L, glob))
2289 { 2295 {
2290 return luaL_error( L, "Expected table, got %s", luaL_typename( L, glob)); 2296 return luaL_error( L, "Expected table, got %s", luaL_typename( L, globals_idx));
2291 } 2297 }
2292 2298
2293 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 2299 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2294 lua_pushnil( L); 2300 lua_pushnil( L); // func libs cancelstep priority globals package required gc_cb [... args ...] nil
2295 lua_pushglobaltable( L2); // Lua 5.2 wants us to push the globals table on the stack 2301 // Lua 5.2 wants us to push the globals table on the stack
2296 while( lua_next( L, glob)) 2302 lua_pushglobaltable( L2); // _G
2303 while( lua_next( L, globals_idx)) // func libs cancelstep priority globals package required gc_cb [... args ...] k v
2297 { 2304 {
2298 luaG_inter_copy( U, L, L2, 2, eLM_LaneBody); // moves the key/value pair to the L2 stack 2305 luaG_inter_copy( U, L, L2, 2, eLM_LaneBody); // _G k v
2299 // assign it in L2's globals table 2306 // assign it in L2's globals table
2300 lua_rawset( L2, -3); 2307 lua_rawset( L2, -3); // _G
2301 lua_pop( L, 1); 2308 lua_pop( L, 1); // func libs cancelstep priority globals package required gc_cb [... args ...] k
2302 } 2309 } // func libs cancelstep priority globals package required gc_cb [... args ...]
2303 lua_pop( L2, 1); 2310 lua_pop( L2, 1); //
2304 2311
2305 STACK_END( L2, 0);
2306 STACK_END( L, 0);
2307 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 2312 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2308 } 2313 }
2309 2314 STACK_MID( L, 0);
2310 2315 STACK_MID( L2, 0);
2311 STACK_CHECK( L);
2312 STACK_CHECK( L2);
2313 ASSERT_L( lua_gettop( L2) == 0);
2314 2316
2315 // Lane main function 2317 // Lane main function
2316 if( lua_type( L, 1) == LUA_TFUNCTION) 2318 if( lua_type( L, 1) == LUA_TFUNCTION)
2317 { 2319 {
2318 int res; 2320 int res;
2319 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane body\n" INDENT_END)); 2321 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END));
2320 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 2322 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2321 lua_pushvalue( L, 1); 2323 lua_pushvalue( L, 1); // func libs cancelstep priority globals package required gc_cb [... args ...] func
2322 res = luaG_inter_move( U, L, L2, 1, eLM_LaneBody); // L->L2 2324 res = luaG_inter_move( U, L, L2, 1, eLM_LaneBody); // func libs cancelstep priority globals package required gc_cb [... args ...] // func
2323 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 2325 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2324 if( res != 0) 2326 if( res != 0)
2325 { 2327 {
2326 return luaL_error( L, "tried to copy unsupported types"); 2328 return luaL_error( L, "tried to copy unsupported types");
2327 } 2329 }
2328 STACK_MID( L, 0);
2329 } 2330 }
2330 else if( lua_type( L, 1) == LUA_TSTRING) 2331 else if( lua_type( L, 1) == LUA_TSTRING)
2331 { 2332 {
2332 // compile the string 2333 // compile the string
2333 if( luaL_loadstring( L2, lua_tostring( L, 1)) != 0) 2334 if( luaL_loadstring( L2, lua_tostring( L, 1)) != 0) // func
2334 { 2335 {
2335 return luaL_error( L, "error when parsing lane function code"); 2336 return luaL_error( L, "error when parsing lane function code");
2336 } 2337 }
2337 } 2338 }
2338 2339 STACK_MID( L, 0);
2339 STACK_MID( L2, 1); 2340 STACK_MID( L2, 1);
2340 ASSERT_L( lua_isfunction( L2, 1)); 2341 ASSERT_L( lua_isfunction( L2, 1));
2341 2342
2342 // revive arguments 2343 // revive arguments
2343 // 2344 if( nargs > 0)
2344 if( args > 0)
2345 { 2345 {
2346 int res; 2346 int res;
2347 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: transfer lane arguments\n" INDENT_END)); 2347 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane arguments\n" INDENT_END));
2348 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 2348 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2349 res = luaG_inter_copy( U, L, L2, args, eLM_LaneBody); // L->L2 2349 res = luaG_inter_move( U, L, L2, nargs, eLM_LaneBody); // func libs cancelstep priority globals package required gc_cb // func [... args ...]
2350 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 2350 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2351 if( res != 0) 2351 if( res != 0)
2352 { 2352 {
2353 return luaL_error( L, "tried to copy unsupported types"); 2353 return luaL_error( L, "tried to copy unsupported types");
2354 } 2354 }
2355 } 2355 }
2356 STACK_MID( L, 0); 2356 STACK_END( L, -nargs);
2357 2357 ASSERT_L( lua_gettop( L) == FIXED_ARGS);
2358 STACK_END( L2, 1 + args); 2358 STACK_CHECK( L);
2359 STACK_MID( L2, 1 + nargs);
2359 2360
2360 // 's' is allocated from heap, not Lua, since its life span may surpass 2361 // 's' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread)
2361 // the handle's (if free running thread)
2362 // 2362 //
2363 ud = lua_newuserdata( L, sizeof( struct s_lane*)); 2363 ud = lua_newuserdata( L, sizeof( struct s_lane*)); // func libs cancelstep priority globals package required gc_cb lane
2364 s = *ud = (struct s_lane*) malloc( sizeof( struct s_lane)); 2364 s = *ud = (struct s_lane*) malloc( sizeof( struct s_lane));
2365 if( s == NULL) 2365 if( s == NULL)
2366 { 2366 {
@@ -2382,44 +2382,49 @@ LUAG_FUNC( thread_new)
2382 s->selfdestruct_next = NULL; 2382 s->selfdestruct_next = NULL;
2383#if HAVE_LANE_TRACKING 2383#if HAVE_LANE_TRACKING
2384 s->tracking_next = NULL; 2384 s->tracking_next = NULL;
2385 if( s->U->tracking_first)
2386 {
2387 tracking_add( s);
2388 }
2385#endif // HAVE_LANE_TRACKING 2389#endif // HAVE_LANE_TRACKING
2386 2390
2387 // Set metatable for the userdata 2391 // Set metatable for the userdata
2388 // 2392 //
2389 lua_pushvalue( L, lua_upvalueindex( 1)); 2393 lua_pushvalue( L, lua_upvalueindex( 1)); // func libs cancelstep priority globals package required gc_cb lane mt
2390 lua_setmetatable( L, -2); 2394 lua_setmetatable( L, -2); // func libs cancelstep priority globals package required gc_cb lane
2391 STACK_MID( L, 1); 2395 STACK_MID( L, 1);
2392 2396
2393 // Create uservalue for the userdata 2397 // Create uservalue for the userdata
2394 // (this is where lane body return values will be stored when the handle is indexed by a numeric key) 2398 // (this is where lane body return values will be stored when the handle is indexed by a numeric key)
2395 lua_newtable( L); 2399 lua_newtable( L); // func libs cancelstep priority globals package required gc_cb lane uv
2396 2400
2397 // Store the gc_cb callback in the uservalue 2401 // Store the gc_cb callback in the uservalue
2398 if( gc_cb > 0) 2402 if( gc_cb_idx > 0)
2399 { 2403 {
2400 lua_pushlightuserdata( L, GCCB_KEY); 2404 lua_pushlightuserdata( L, GCCB_KEY); // func libs cancelstep priority globals package required gc_cb lane uv k
2401 lua_pushvalue( L, gc_cb); 2405 lua_pushvalue( L, gc_cb_idx); // func libs cancelstep priority globals package required gc_cb lane uv k gc_cb
2402 lua_rawset( L, -3); 2406 lua_rawset( L, -3); // func libs cancelstep priority globals package required gc_cb lane uv
2403 } 2407 }
2404 2408
2405 lua_setuservalue( L, -2); 2409 lua_setuservalue( L, -2); // func libs cancelstep priority globals package required gc_cb lane
2406 2410
2407 // Store 's' in the lane's registry, for 'cancel_test()' (even if 'cs'==0 we still do cancel tests at pending send/receive). 2411 // Store 's' in the lane's registry, for 'cancel_test()' (even if 'cs'==0 we still do cancel tests at pending send/receive).
2408 lua_pushlightuserdata( L2, CANCEL_TEST_KEY); 2412 lua_pushlightuserdata( L2, CANCEL_TEST_KEY); // func [... args ...] k
2409 lua_pushlightuserdata( L2, s); 2413 lua_pushlightuserdata( L2, s); // func [... args ...] k s
2410 lua_rawset( L2, LUA_REGISTRYINDEX); 2414 lua_rawset( L2, LUA_REGISTRYINDEX); // func [... args ...]
2411 2415
2412 if( cs) 2416 if( cancelstep_idx)
2413 { 2417 {
2414 lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cs); 2418 lua_sethook( L2, cancel_hook, LUA_MASKCOUNT, cancelstep_idx);
2415 } 2419 }
2416 2420
2417 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: launching thread\n" INDENT_END)); 2421 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END));
2418 THREAD_CREATE( &s->thread, lane_main, s, prio); 2422 THREAD_CREATE( &s->thread, lane_main, s, priority);
2419 STACK_END( L, 1);
2420 2423
2421 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 2424 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2422 2425
2426 STACK_END( L, 1);
2427 STACK_END( L2, 1 + nargs);
2423 return 1; 2428 return 1;
2424} 2429}
2425 2430
@@ -3161,8 +3166,8 @@ LUAG_FUNC( configure)
3161 lua_setfield( L, -2, "__metatable"); // settings M mt 3166 lua_setfield( L, -2, "__metatable"); // settings M mt
3162 } 3167 }
3163 3168
3164 lua_pushcclosure( L, LG_thread_new, 1); // settings M LG_thread_new 3169 lua_pushcclosure( L, LG_lane_new, 1); // settings M lane_new
3165 lua_setfield( L, -2, "thread_new"); // settings M 3170 lua_setfield( L, -2, "lane_new"); // settings M
3166 3171
3167 // we can't register 'lanes.require' normally because we want to create an upvalued closure 3172 // we can't register 'lanes.require' normally because we want to create an upvalued closure
3168 lua_getglobal( L, "require"); // settings M require 3173 lua_getglobal( L, "require"); // settings M require
diff --git a/src/lanes.lua b/src/lanes.lua
index 5dfe41d..57aa0fe 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -56,8 +56,9 @@ lanes.configure = function( settings_)
56 -- 56 --
57 -- Cache globals for code that might run under sandboxing 57 -- Cache globals for code that might run under sandboxing
58 -- 58 --
59 local assert = assert 59 local assert = assert( assert)
60 local string_gmatch = assert( string.gmatch) 60 local string_gmatch = assert( string.gmatch)
61 local string_format = assert( string.format)
61 local select = assert( select) 62 local select = assert( select)
62 local type = assert( type) 63 local type = assert( type)
63 local pairs = assert( pairs) 64 local pairs = assert( pairs)
@@ -127,7 +128,7 @@ lanes.configure = function( settings_)
127 return settings 128 return settings
128 end 129 end
129 local settings = core.configure and core.configure( params_checker( settings_)) or core.settings 130 local settings = core.configure and core.configure( params_checker( settings_)) or core.settings
130 local thread_new = assert( core.thread_new) 131 local core_lane_new = assert( core.lane_new)
131 local max_prio = assert( core.max_prio) 132 local max_prio = assert( core.max_prio)
132 133
133lanes.ABOUT = 134lanes.ABOUT =
@@ -203,11 +204,9 @@ end
203-- ... (more options may be introduced later) ... 204-- ... (more options may be introduced later) ...
204-- 205--
205-- Calling with a function parameter ('lane_func') ends the string/table 206-- Calling with a function parameter ('lane_func') ends the string/table
206-- modifiers, and prepares a lane generator. One can either finish here, 207-- modifiers, and prepares a lane generator.
207-- and call the generator later (maybe multiple times, with different parameters)
208-- or add on actual thread arguments to also ignite the thread on the same call.
209 208
210local valid_libs= 209local valid_libs =
211{ 210{
212 ["package"] = true, 211 ["package"] = true,
213 ["table"] = true, 212 ["table"] = true,
@@ -223,88 +222,110 @@ local valid_libs=
223 ["lanes.core"] = true 222 ["lanes.core"] = true
224} 223}
225 224
225local raise_option_error = function( name_, tv_, v_)
226 error( "Bad '" .. name_ .. "' option: " .. tv_ .. " " .. string_format( "%q", tostring( v_)), 4)
227end
228
229local opt_validators =
230{
231 priority = function( v_)
232 local tv = type( v_)
233 return (tv == "number") and v_ or raise_option_error( "priority", tv, v_)
234 end,
235 cancelstep = function( v_)
236 local tv = type( v_)
237 return (tv == "number") and v_ or (v_ == true) and 100 or (v_ == false) and 0 or raise_option_error( "cancelstep", tv, v_)
238 end,
239 globals = function( v_)
240 local tv = type( v_)
241 return (tv == "table") and v_ or raise_option_error( "globals", tv, v_)
242 end,
243 package = function( v_)
244 local tv = type( v_)
245 return (tv == "table") and v_ or raise_option_error( "package", tv, v_)
246 end,
247 required = function( v_)
248 local tv = type( v_)
249 return (tv == "table") and v_ or raise_option_error( "required", tv, v_)
250 end,
251 gc_cb = function( v_)
252 local tv = type( v_)
253 return (tv == "function") and v_ or raise_option_error( "gc_cb", tv, v_)
254 end
255}
256
226-- PUBLIC LANES API 257-- PUBLIC LANES API
227local function gen( ... ) 258-- receives a sequence of strings and tables, plus a function
228 local opt= {} 259local gen = function( ...)
229 local libs= nil 260 -- aggregrate all strings together, separated by "," as well as tables
230 local lev= 2 -- level for errors 261 -- the strings are a list of libraries to open
231 262 -- the tables contain the lane options
232 local n= select('#',...) 263 local opt = {}
233 264 local libs = nil
234 if n==0 then 265
235 error( "No parameters!" ) 266 local n = select( '#', ...)
236 end 267
268 -- we need at least a function
269 if n == 0 then
270 error( "No parameters!", 2)
271 end
237 272
238 for i=1,n-1 do 273 -- all arguments but the last must be nil, strings, or tables
239 local v= select(i,...) 274 for i = 1, n - 1 do
240 if type(v)=="string" then 275 local v = select( i, ...)
241 libs= libs and libs..","..v or v 276 local tv = type( v)
242 elseif type(v)=="table" then 277 if tv == "string" then
243 for k,vv in pairs(v) do 278 libs = libs and libs .. "," .. v or v
244 opt[k]= vv 279 elseif tv == "table" then
245 end 280 for k, vv in pairs( v) do
246 elseif v==nil then 281 opt[k]= vv
247 -- skip 282 end
248 else 283 elseif v == nil then
249 error( "Bad parameter: "..tostring(v) ) 284 -- skip
250 end 285 else
251 end 286 error( "Bad parameter " .. i .. ": " .. tv .. " " .. string_format( "%q", tostring( v)), 2)
287 end
288 end
252 289
253 local func= select(n,...) 290 -- the last argument should be a function or a string
254 local functype = type(func) 291 local func = select( n, ...)
255 if functype ~= "function" and functype ~= "string" then 292 local functype = type( func)
256 error( "Last parameter not function or string: "..tostring(func)) 293 if functype ~= "function" and functype ~= "string" then
257 end 294 error( "Last parameter not function or string: " .. functype .. " " .. string_format( "%q", tostring( func)), 2)
295 end
258 296
259 -- Check 'libs' already here, so the error goes in the right place 297 -- check that the caller only provides reserved library names, and those only once
260 -- (otherwise will be noticed only once the generator is called) 298 -- "*" is a special case that doesn't require individual checking
261 -- "*" is a special case that doesn't require individual checking 299 if libs and libs ~= "*" then
262 -- 300 local found = {}
263 if libs and libs ~= "*" then 301 for s in string_gmatch(libs, "[%a%d.]+") do
264 local found = {} 302 if not valid_libs[s] then
265 -- check that the caller only provides reserved library names 303 error( "Bad library name: " .. s, 2)
266 for s in string_gmatch(libs, "[%a%d.]+") do 304 else
267 if not valid_libs[s] then 305 found[s] = (found[s] or 0) + 1
268 error( "Bad library name: " .. s) 306 if found[s] > 1 then
269 else 307 error( "libs specification contains '" .. s .. "' more than once", 2)
270 found[s] = (found[s] or 0) + 1 308 end
271 if found[s] > 1 then 309 end
272 error( "libs specification contains '" .. s .. "' more than once") 310 end
273 end 311 end
274 end
275 end
276 end
277
278 local prio, cs, g_tbl, package_tbl, required, gc_cb
279
280 for k,v in pairs(opt) do
281 if k == "priority" then
282 prio = (type( v) == "number") and v or error( "Bad 'prio' option: expecting number, got " .. type( v), lev)
283 elseif k=="cancelstep" then
284 cs = (v==true) and 100 or
285 (v==false) and 0 or
286 type(v)=="number" and v or
287 error( "Bad cancelstep: "..tostring(v), lev )
288 elseif k=="globals" then g_tbl= v
289 elseif k=="package" then
290 package_tbl = (type( v) == "table") and v or error( "Bad package: " .. tostring( v), lev)
291 elseif k=="required" then
292 required= (type( v) == "table") and v or error( "Bad 'required' option: expecting table, got " .. type( v), lev)
293 elseif k == "gc_cb" then
294 gc_cb = (type( v) == "function") and v or error( "Bad 'gc_cb' option: expecting function, got " .. type( v), lev)
295 --..
296 elseif k==1 then error( "unkeyed option: ".. tostring(v), lev )
297 else error( "Bad option: ".. tostring(k), lev )
298 end
299 end
300 312
301 if not package_tbl then package_tbl = package end 313 -- validate that each option is known and properly valued
302 -- Lane generator 314 for k, v in pairs( opt) do
303 -- 315 local validator = opt_validators[k]
304 return function(...) 316 if not validator then
305 return thread_new( func, libs, cs, prio, g_tbl, package_tbl, required, gc_cb, ...) -- args 317 error( (type( k) == "number" and "Unkeyed option: " .. type( v) .. " " .. string_format( "%q", tostring( v)) or "Bad '" .. tostring( k) .. "' option"), 2)
306 end 318 else
307end 319 opt[k] = validator( v)
320 end
321 end
322
323 local cancelstep, priority, globals, package, required, gc_cb = opt.cancelstep, opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb
324 return function( ...)
325 -- must pass functions args last else they will be truncated to the first one
326 return core_lane_new( func, libs, cancelstep, priority, globals, package, required, gc_cb, ...)
327 end
328end -- gen()
308 329
309---=== Timers ===--- 330---=== Timers ===---
310 331