aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <bnt period germain arrobase gmail period com>2017-06-05 11:25:31 +0200
committerBenoit Germain <bnt period germain arrobase gmail period com>2017-06-05 11:25:31 +0200
commitc2ca1fce531e29f8209660b18ef0a493722813f1 (patch)
tree3afa59fb910b2aaee79cbccc9a58fc961b3b8868
parent0ede50e2da00f2915ceb50184425c42bda83adfd (diff)
downloadlanes-c2ca1fce531e29f8209660b18ef0a493722813f1.tar.gz
lanes-c2ca1fce531e29f8209660b18ef0a493722813f1.tar.bz2
lanes-c2ca1fce531e29f8209660b18ef0a493722813f1.zip
Table transfer improvements
* new API function lanes.register( "name", module) to manually register a module table after it was required * Transfering registered module tables will link the equivalent in the destination state instead of cloning it * bumped version to 3.11
-rw-r--r--CHANGES5
-rw-r--r--docs/index.html7
-rw-r--r--src/lanes.c42
-rw-r--r--src/lanes.lua18
-rw-r--r--src/tools.c318
-rw-r--r--tests/parallel_os_calls.lua13
6 files changed, 286 insertions, 117 deletions
diff --git a/CHANGES b/CHANGES
index df75ace..f224a5e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,10 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 120: BGe 5-Jun-17
4 * new API function lanes.register( "name", module) to manually register a module table after it was required
5 * Transfering registered module tables will link the equivalent in the destination state instead of cloning it
6 * bumped version to 3.11
7
3CHANGE 119: BGe 10-May-17 8CHANGE 119: BGe 10-May-17
4 * Fixed some compilation warnings 9 * Fixed some compilation warnings
5 * Improved LuaJIT support 10 * Improved LuaJIT support
diff --git a/docs/index.html b/docs/index.html
index 154355d..1eb1d71 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -64,13 +64,13 @@
64 <font size="-1"> 64 <font size="-1">
65 <p> 65 <p>
66 <br/> 66 <br/>
67 <i>Copyright &copy; 2007-16 Asko Kauppi, Benoit Germain. All rights reserved.</i> 67 <i>Copyright &copy; 2007-17 Asko Kauppi, Benoit Germain. All rights reserved.</i>
68 <br/> 68 <br/>
69 Lua Lanes is published under the same <a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a> as Lua 5.1, 5.2, and 5.3. 69 Lua Lanes is published under the same <a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a> as Lua 5.1, 5.2, and 5.3.
70 </p> 70 </p>
71 71
72 <p> 72 <p>
73 This document was revised on 21-Nov-16, and applies to version <tt>3.10.1</tt>. 73 This document was revised on 5-Jun-17, and applies to version <tt>3.11</tt>.
74 </p> 74 </p>
75 </font> 75 </font>
76 </center> 76 </center>
@@ -396,12 +396,15 @@
396 (Since v3.5.0) Once Lanes is configured, one should register with Lanes the modules exporting functions that will be transferred either during lane generation or through <a href="#lindas">lindas</a>. 396 (Since v3.5.0) Once Lanes is configured, one should register with Lanes the modules exporting functions that will be transferred either during lane generation or through <a href="#lindas">lindas</a>.
397 <br/> 397 <br/>
398 Use <tt>lanes.require()</tt> for this purpose. This will call the original <tt>require()</tt>, then add the result to the lookup databases. 398 Use <tt>lanes.require()</tt> for this purpose. This will call the original <tt>require()</tt>, then add the result to the lookup databases.
399 <br/>
400 (Since version 3.11) It is also possible to register a given module with <tt>lanes.register()</tt>. This function will raise an error if the registered module is not a function or table.
399</p> 401</p>
400 402
401<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"> 403<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%">
402 <tr> 404 <tr>
403 <td> 405 <td>
404 <pre> local m = lanes.require "modname"</pre> 406 <pre> local m = lanes.require "modname"</pre>
407 <pre> lanes.register( "modname", module)</pre>
405 </td> 408 </td>
406 </tr> 409 </tr>
407</table> 410</table>
diff --git a/src/lanes.c b/src/lanes.c
index d0ffee1..8410ca2 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * LANES.C Copyright (c) 2007-08, Asko Kauppi 2 * LANES.C Copyright (c) 2007-08, Asko Kauppi
3 * Copyright (C) 2009-14, Benoit Germain 3 * Copyright (C) 2009-17, Benoit Germain
4 * 4 *
5 * Multithreading in Lua. 5 * Multithreading in Lua.
6 * 6 *
@@ -52,13 +52,13 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.10.1"; 55char const* VERSION = "3.11";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
59 59
60Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com> 60Copyright (C) 2007-10 Asko Kauppi <akauppi@gmail.com>
61 2011-14 Benoit Germain <bnt.germain@gmail.com> 61 2011-17 Benoit Germain <bnt.germain@gmail.com>
62 62
63Permission is hereby granted, free of charge, to any person obtaining a copy 63Permission is hereby granted, free of charge, to any person obtaining a copy
64of this software and associated documentation files (the "Software"), to deal 64of this software and associated documentation files (the "Software"), to deal
@@ -162,7 +162,8 @@ struct s_lane
162 // lane status changes to DONE/ERROR_ST/CANCELLED. 162 // lane status changes to DONE/ERROR_ST/CANCELLED.
163#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR 163#endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
164 164
165 volatile enum { 165 volatile enum
166 {
166 NORMAL, // normal master side state 167 NORMAL, // normal master side state
167 KILLED // issued an OS kill 168 KILLED // issued an OS kill
168 } mstatus; 169 } mstatus;
@@ -307,7 +308,7 @@ static bool_t push_registry_table( lua_State* L, void* key, bool_t create)
307 return FALSE; 308 return FALSE;
308 } 309 }
309 310
310 lua_newtable(L); // t 311 lua_newtable( L); // t
311 lua_pushlightuserdata( L, key); // t key 312 lua_pushlightuserdata( L, key); // t key
312 lua_pushvalue( L, -2); // t key t 313 lua_pushvalue( L, -2); // t key t
313 lua_rawset( L, LUA_REGISTRYINDEX); // t 314 lua_rawset( L, LUA_REGISTRYINDEX); // t
@@ -351,7 +352,7 @@ static bool_t tracking_remove( struct s_lane* s)
351 // still (at process exit they will remove us from chain and then 352 // still (at process exit they will remove us from chain and then
352 // cancel/kill). 353 // cancel/kill).
353 // 354 //
354 if (s->tracking_next != NULL) 355 if( s->tracking_next != NULL)
355 { 356 {
356 struct s_lane** ref = (struct s_lane**) &s->U->tracking_first; 357 struct s_lane** ref = (struct s_lane**) &s->U->tracking_first;
357 358
@@ -539,7 +540,7 @@ LUAG_FUNC( linda_send)
539 break; 540 break;
540 } 541 }
541 542
542 // instant timout to bypass the 543 // instant timout to bypass the wait syscall
543 if( timeout == 0.0) 544 if( timeout == 0.0)
544 { 545 {
545 break; /* no wait; instant timeout */ 546 break; /* no wait; instant timeout */
@@ -2157,6 +2158,30 @@ LUAG_FUNC( require)
2157 return 1; 2158 return 1;
2158} 2159}
2159 2160
2161
2162// --- If a client wants to transfer stuff of a previously required module from the current state to another Lane, the module must be registered
2163// to populate the lookup database in the source lane (and in the destination too, of course)
2164// lanes.register( "modname", module)
2165LUAG_FUNC( register)
2166{
2167 char const* name = luaL_checkstring( L, 1);
2168 int const nargs = lua_gettop( L);
2169 int const mod_type = lua_type( L, 2);
2170 // ignore extra parameters, just in case
2171 lua_settop( L, 2);
2172 luaL_argcheck( L, (mod_type == LUA_TTABLE) || (mod_type == LUA_TFUNCTION), 2, "unexpected module type");
2173 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L));
2174 STACK_CHECK( L); // "name" mod_table
2175 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END, name));
2176 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
2177 populate_func_lookup_table( L, -1, name);
2178 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.register %s END\n" INDENT_END, name));
2179 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
2180 STACK_END( L, 0);
2181 return 0;
2182}
2183
2184
2160LUAG_FUNC( thread_gc); 2185LUAG_FUNC( thread_gc);
2161#define GCCB_KEY (void*)LG_thread_gc 2186#define GCCB_KEY (void*)LG_thread_gc
2162//--- 2187//---
@@ -2945,6 +2970,7 @@ static const struct luaL_Reg lanes_functions [] = {
2945 {"wakeup_conv", LG_wakeup_conv}, 2970 {"wakeup_conv", LG_wakeup_conv},
2946 {"set_thread_priority", LG_set_thread_priority}, 2971 {"set_thread_priority", LG_set_thread_priority},
2947 {"nameof", luaG_nameof}, 2972 {"nameof", luaG_nameof},
2973 {"register", LG_register},
2948 {"set_singlethreaded", LG_set_singlethreaded}, 2974 {"set_singlethreaded", LG_set_singlethreaded},
2949 {NULL, NULL} 2975 {NULL, NULL}
2950}; 2976};
@@ -3201,7 +3227,7 @@ LUAG_FUNC( configure)
3201 { 3227 {
3202 // don't do this when called during the initialization of a new lane, 3228 // don't do this when called during the initialization of a new lane,
3203 // because we will do it after on_state_create() is called, 3229 // because we will do it after on_state_create() is called,
3204 // and we don't want skip _G because of caching in case globals are created then 3230 // and we don't want to skip _G because of caching in case globals are created then
3205 lua_pushglobaltable( L); // settings M _G 3231 lua_pushglobaltable( L); // settings M _G
3206 populate_func_lookup_table( L, -1, NULL); 3232 populate_func_lookup_table( L, -1, NULL);
3207 lua_pop( L, 1); // settings M 3233 lua_pop( L, 1); // settings M
diff --git a/src/lanes.lua b/src/lanes.lua
index affbd7d..35071ae 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -40,9 +40,8 @@ local core = require "lanes.core"
40-- Lua 5.2: module() is gone 40-- Lua 5.2: module() is gone
41-- almost everything module() does is done by require() anyway 41-- almost everything module() does is done by require() anyway
42-- -> simply create a table, populate it, return it, and be done 42-- -> simply create a table, populate it, return it, and be done
43local lanes = {}
44local lanesMeta = {} 43local lanesMeta = {}
45setmetatable(lanes,lanesMeta) 44local lanes = setmetatable( {}, lanesMeta)
46 45
47-- this function is available in the public interface until it is called, after which it disappears 46-- this function is available in the public interface until it is called, after which it disappears
48lanes.configure = function( settings_) 47lanes.configure = function( settings_)
@@ -55,7 +54,7 @@ lanes.configure = function( settings_)
55 error( "To use 'lanes', you will also need to have 'string' available.", 2) 54 error( "To use 'lanes', you will also need to have 'string' available.", 2)
56 end 55 end
57 -- Configure called so remove metatable from lanes 56 -- Configure called so remove metatable from lanes
58 setmetatable(lanes,nil) 57 setmetatable( lanes, nil)
59 -- 58 --
60 -- Cache globals for code that might run under sandboxing 59 -- Cache globals for code that might run under sandboxing
61 -- 60 --
@@ -139,7 +138,7 @@ lanes.configure = function( settings_)
139 author= "Asko Kauppi <akauppi@gmail.com>, Benoit Germain <bnt.germain@gmail.com>", 138 author= "Asko Kauppi <akauppi@gmail.com>, Benoit Germain <bnt.germain@gmail.com>",
140 description= "Running multiple Lua states in parallel", 139 description= "Running multiple Lua states in parallel",
141 license= "MIT/X11", 140 license= "MIT/X11",
142 copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-13, Benoit Germain", 141 copyright= "Copyright (c) 2007-10, Asko Kauppi; (c) 2011-17, Benoit Germain",
143 version = assert( core.version) 142 version = assert( core.version)
144 } 143 }
145 144
@@ -716,6 +715,7 @@ lanes.configure = function( settings_)
716 715
717 -- activate full interface 716 -- activate full interface
718 lanes.require = core.require 717 lanes.require = core.require
718 lanes.register = core.register
719 lanes.gen = gen 719 lanes.gen = gen
720 lanes.linda = core.linda 720 lanes.linda = core.linda
721 lanes.cancel_error = core.cancel_error 721 lanes.cancel_error = core.cancel_error
@@ -734,20 +734,18 @@ lanes.configure = function( settings_)
734 return lanes 734 return lanes
735end -- lanes.configure 735end -- lanes.configure
736 736
737lanesMeta.__index = function(t,k) 737lanesMeta.__index = function( t, k)
738 -- This is called when some functionality is accessed without calling configure() 738 -- This is called when some functionality is accessed without calling configure()
739 lanes.configure() -- Initialize with default settings 739 lanes.configure() -- initialize with default settings
740 -- Access the required key 740 -- Access the required key
741 return lanes[k] 741 return lanes[k]
742end 742end
743 743
744-- no need to force calling configure() excepted the first time 744-- no need to force calling configure() manually excepted the first time (other times will reuse the internally stored settings of the first call)
745if core.settings then 745if core.settings then
746 return lanes.configure() 746 return lanes.configure()
747else 747else
748 return lanes 748 return lanes
749end 749end
750 750
751 751--the end
752--the end (Unreachable Code)
753--return lanes
diff --git a/src/tools.c b/src/tools.c
index d97b231..a4d781f 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -85,7 +85,7 @@ void luaG_dump( lua_State* L)
85 { 85 {
86 int type = lua_type( L, i); 86 int type = lua_type( L, i);
87 87
88 fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename(L, type)); 88 fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename( L, type));
89 89
90 // Print item contents here... 90 // Print item contents here...
91 // 91 //
@@ -99,7 +99,7 @@ void luaG_dump( lua_State* L)
99 // 99 //
100 // [-1]: tostring function, or nil 100 // [-1]: tostring function, or nil
101 101
102 if( !lua_isfunction(L, -1)) 102 if( !lua_isfunction( L, -1))
103 { 103 {
104 fprintf( stderr, "('tostring' not available)"); 104 fprintf( stderr, "('tostring' not available)");
105 } 105 }
@@ -110,7 +110,7 @@ void luaG_dump( lua_State* L)
110 110
111 // Don't trust the string contents 111 // Don't trust the string contents
112 // 112 //
113 fprintf( stderr, "%s", lua_tostring(L, -1)); 113 fprintf( stderr, "%s", lua_tostring( L, -1));
114 } 114 }
115 lua_pop( L, 1); 115 lua_pop( L, 1);
116 STACK_END( L, 0); 116 STACK_END( L, 0);
@@ -258,7 +258,8 @@ static void open1lib( struct s_Universe* U, lua_State* L, char const* name_, siz
258 } 258 }
259} 259}
260 260
261static int dummy_writer(lua_State *L, const void* p, size_t sz, void* ud) 261
262static int dummy_writer( lua_State* L, void const* p, size_t sz, void* ud)
262{ 263{
263 (void)L; (void)p; (void)sz; (void) ud; // unused 264 (void)L; (void)p; (void)sz; (void) ud; // unused
264 return 666; 265 return 666;
@@ -326,12 +327,12 @@ static lua_CFunction luaG_tocfunction( lua_State *L, int _i, FuncSubType *_out)
326 327
327 328
328// inspired from tconcat() in ltablib.c 329// inspired from tconcat() in ltablib.c
329static char const* luaG_pushFQN(lua_State *L, int t, int last, size_t* length) 330static char const* luaG_pushFQN( lua_State* L, int t, int last, size_t* length)
330{ 331{
331 int i = 1; 332 int i = 1;
332 luaL_Buffer b; 333 luaL_Buffer b;
333 STACK_CHECK( L); 334 STACK_CHECK( L);
334 luaL_buffinit(L, &b); 335 luaL_buffinit( L, &b);
335 for( ; i < last; ++ i) 336 for( ; i < last; ++ i)
336 { 337 {
337 lua_rawgeti( L, t, i); 338 lua_rawgeti( L, t, i);
@@ -349,10 +350,12 @@ static char const* luaG_pushFQN(lua_State *L, int t, int last, size_t* length)
349} 350}
350 351
351/* 352/*
353 * receives 2 arguments: a name k and an object o
352 * add two entries ["fully.qualified.name"] = o 354 * add two entries ["fully.qualified.name"] = o
353 * and [o] = "fully.qualified.name" 355 * and [o] = "fully.qualified.name"
354 * where <o> is either a table or a function 356 * where <o> is either a table or a function
355 * if we already had an entry of type [o] = ..., replace the name if the new one is shorter 357 * if we already had an entry of type [o] = ..., replace the name if the new one is shorter
358 * pops the processed object from the stack
356 */ 359 */
357static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth) 360static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth)
358{ 361{
@@ -364,12 +367,16 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth)
364 size_t prevNameLength, newNameLength; 367 size_t prevNameLength, newNameLength;
365 char const* prevName; 368 char const* prevName;
366 DEBUGSPEW_CODE( char const *newName); 369 DEBUGSPEW_CODE( char const *newName);
370 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L));
371
372 STACK_CHECK( L);
367 // first, raise an error if the function is already known 373 // first, raise an error if the function is already known
368 lua_pushvalue( L, -1); // ... {bfc} k o o 374 lua_pushvalue( L, -1); // ... {bfc} k o o
369 lua_rawget( L, dest); // ... {bfc} k o name? 375 lua_rawget( L, dest); // ... {bfc} k o name?
370 prevName = lua_tolstring( L, -1, &prevNameLength); // NULL if we got nil (first encounter of this object) 376 prevName = lua_tolstring( L, -1, &prevNameLength); // NULL if we got nil (first encounter of this object)
371 // push name in fqn stack (note that concatenation will crash if name is a not string or a number) 377 // push name in fqn stack (note that concatenation will crash if name is a not string or a number)
372 lua_pushvalue( L, -3); // ... {bfc} k o name? k 378 lua_pushvalue( L, -3); // ... {bfc} k o name? k
379 ASSERT_L( lua_type( L, -1) == LUA_TNUMBER || lua_type( L, -1) == LUA_TSTRING);
373 ++ _depth; 380 ++ _depth;
374 lua_rawseti( L, fqn, _depth); // ... {bfc} k o name? 381 lua_rawseti( L, fqn, _depth); // ... {bfc} k o name?
375 // generate name 382 // generate name
@@ -385,7 +392,7 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth)
385 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded 392 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded
386 if( prevName != NULL && (prevNameLength < newNameLength || lua_lessthan( L, -2, -1))) 393 if( prevName != NULL && (prevNameLength < newNameLength || lua_lessthan( L, -2, -1)))
387 { 394 {
388 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, -3), newName, prevName)); 395 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName));
389 // the previous name is 'smaller' than the one we just generated: keep it! 396 // the previous name is 'smaller' than the one we just generated: keep it!
390 lua_pop( L, 3); // ... {bfc} k 397 lua_pop( L, 3); // ... {bfc} k
391 } 398 }
@@ -404,7 +411,7 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth)
404 { 411 {
405 lua_remove( L, -2); // ... {bfc} k o "f.q.n" 412 lua_remove( L, -2); // ... {bfc} k o "f.q.n"
406 } 413 }
407 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename( L, -2), newName)); 414 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -2)), newName));
408 // prepare the stack for database feed 415 // prepare the stack for database feed
409 lua_pushvalue( L, -1); // ... {bfc} k o "f.q.n" "f.q.n" 416 lua_pushvalue( L, -1); // ... {bfc} k o "f.q.n" "f.q.n"
410 lua_pushvalue( L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o 417 lua_pushvalue( L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o
@@ -419,6 +426,7 @@ static void update_lookup_entry( lua_State* L, int _ctx_base, int _depth)
419 lua_rawseti( L, fqn, _depth); // ... {bfc} k 426 lua_rawseti( L, fqn, _depth); // ... {bfc} k
420 } 427 }
421 -- _depth; 428 -- _depth;
429 STACK_END( L, -1);
422} 430}
423 431
424static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _i, int _depth) 432static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _i, int _depth)
@@ -547,7 +555,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_)
547{ 555{
548 int const ctx_base = lua_gettop( L) + 1; 556 int const ctx_base = lua_gettop( L) + 1;
549 int const in_base = lua_absindex( L, _i); 557 int const in_base = lua_absindex( L, _i);
550 int const start_depth = name_ ? 1 : 0; 558 int start_depth = 0;
551 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L)); 559 DEBUGSPEW_CODE( struct s_Universe* U = get_universe( L));
552 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "NULL")); 560 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "NULL"));
553 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 561 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
@@ -571,9 +579,17 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_)
571 lua_newtable( L); // {} {fqn} 579 lua_newtable( L); // {} {fqn}
572 if( name_) 580 if( name_)
573 { 581 {
582 STACK_MID( L, 2);
574 lua_pushstring( L, name_); // {} {fqn} "name" 583 lua_pushstring( L, name_); // {} {fqn} "name"
584 // generate a name, and if we already had one name, keep whichever is the shorter
585 lua_pushvalue( L, in_base); // {} {fqn} "name" t
586 update_lookup_entry( L, ctx_base, start_depth); // {} {fqn} "name"
587 // don't forget to store the name at the bottom of the fqn stack
588 ++ start_depth;
575 lua_rawseti( L, -2, start_depth); // {} {fqn} 589 lua_rawseti( L, -2, start_depth); // {} {fqn}
590 STACK_MID( L, 2);
576 } 591 }
592 // retrieve the cache, create it if we haven't done it yet
577 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}? 593 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}?
578 if( lua_isnil( L, -1)) 594 if( lua_isnil( L, -1))
579 { 595 {
@@ -582,6 +598,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* name_)
582 lua_pushvalue( L, -1); // {} {fqn} {cache} {cache} 598 lua_pushvalue( L, -1); // {} {fqn} {cache} {cache}
583 lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache} 599 lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}
584 } 600 }
601 // process everything we find in that table, filling in lookup data for all functions and tables we see there
585 populate_func_lookup_table_recur( L, ctx_base, in_base, start_depth); // {...} {fqn} {cache} 602 populate_func_lookup_table_recur( L, ctx_base, in_base, start_depth); // {...} {fqn} {cache}
586 lua_pop( L, 3); 603 lua_pop( L, 3);
587 } 604 }
@@ -823,6 +840,158 @@ static int buf_writer( lua_State *L, const void* b, size_t n, void* B ) {
823} 840}
824 841
825 842
843// function sentinel used to transfer native functions from/to keeper states
844static int func_lookup_sentinel( lua_State* L)
845{
846 return luaL_error( L, "function lookup sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1)));
847}
848
849
850// function sentinel used to transfer native table from/to keeper states
851static int table_lookup_sentinel( lua_State* L)
852{
853 return luaL_error( L, "table lookup sentinel for %s, should never be called", lua_tostring( L, lua_upvalueindex(1)));
854}
855
856/*
857 * retrieve the name of a function/table in the lookup database
858 */
859static char const* find_lookup_name( lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_, size_t* len_)
860{
861 DEBUGSPEW_CODE( struct s_Universe* const U = get_universe( L));
862 char const* fqn;
863 ASSERT_L( lua_isfunction( L, i) || lua_istable( L, i)); // ... v ...
864 STACK_CHECK( L);
865 STACK_GROW( L, 3); // up to 3 slots are necessary on error
866 if( mode_ == eLM_FromKeeper)
867 {
868 lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel!
869 if( f == func_lookup_sentinel || f == table_lookup_sentinel)
870 {
871 lua_getupvalue( L, i, 1); // ... v ... "f.q.n"
872 }
873 else
874 {
875 // if this is not a sentinel, this is some user-created table we wanted to lookup
876 ASSERT_L( NULL == f && lua_istable( L, i));
877 // push anything that will convert to NULL string
878 lua_pushnil( L); // ... v ... nil
879 }
880 }
881 else
882 {
883 // fetch the name from the source state's lookup table
884 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // ... v ... {}
885 ASSERT_L( lua_istable( L, -1));
886 lua_pushvalue( L, i); // ... v ... {} v
887 lua_rawget( L, -2); // ... v ... {} "f.q.n"
888 }
889 fqn = lua_tolstring( L, -1, len_);
890 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn));
891 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database
892 lua_pop( L, (mode_ == eLM_FromKeeper) ? 1 : 2); // ... v ...
893 STACK_MID( L, 0);
894 if( NULL == fqn && !lua_istable( L, i)) // raise an error if we try to send an unknown function (but not for tables)
895 {
896 char const *from, *typewhat, *what, *gotchaA, *gotchaB;
897 // try to discover the name of the function we want to send
898 lua_getglobal( L, "decoda_name"); // ... v ... decoda_name
899 from = lua_tostring( L, -1);
900 lua_pushcfunction( L, luaG_nameof); // ... v ... decoda_name luaG_nameof
901 lua_pushvalue( L, i); // ... v ... decoda_name luaG_nameof t
902 lua_call( L, 1, 2); // ... v ... decoda_name "type" "name"|nil
903 typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2);
904 // second return value can be nil if the table was not found
905 // probable reason: the function was removed from the source Lua state before Lanes was required.
906 if( lua_isnil( L, -1))
907 {
908 gotchaA = " referenced by";
909 gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)";
910 what = upName_;
911 }
912 else
913 {
914 gotchaA = "";
915 gotchaB = "";
916 what = (lua_type( L, -1) == LUA_TSTRING) ? lua_tostring( L, -1) : luaL_typename( L, -1);
917 }
918 (void) luaL_error( L, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB);
919 *len_ = 0;
920 return NULL;
921 }
922 STACK_END( L, 0);
923 return fqn;
924}
925
926
927/*
928 * Push a looked-up table, or nothing if we found nothing
929 */
930static bool_t lookup_table( lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_)
931{
932 // get the name of the table we want to send
933 size_t len;
934 char const* fqn = find_lookup_name( L, i, mode_, upName_, &len);
935 if( NULL == fqn) // name not found, it is some user-created table
936 {
937 return FALSE;
938 }
939 // push the equivalent table in the destination's stack, retrieved from the lookup table
940 STACK_CHECK( L2); // L // L2
941 STACK_GROW( L2, 3); // up to 3 slots are necessary on error
942 switch( mode_)
943 {
944 default: // shouldn't happen, in theory...
945 (void) luaL_error( L, "internal error: unknown lookup mode");
946 return FALSE;
947
948 case eLM_ToKeeper:
949 // push a sentinel closure that holds the lookup name as upvalue
950 lua_pushlstring( L2, fqn, len); // "f.q.n"
951 lua_pushcclosure( L2, table_lookup_sentinel, 1); // f
952 break;
953
954 case eLM_LaneBody:
955 case eLM_FromKeeper:
956 lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // {}
957 ASSERT_L( lua_istable( L2, -1));
958 lua_pushlstring( L2, fqn, len); // {} "f.q.n"
959 lua_rawget( L2, -2); // {} t
960 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead)
961 // but not when we extract something out of a keeper, as there is nothing to clone!
962 if( lua_isnil( L2, -1) && mode_ == eLM_LaneBody)
963 {
964 lua_pop( L2, 2); //
965 STACK_MID( L2, 0);
966 return FALSE;
967 }
968 else if( !lua_istable( L2, -1))
969 {
970 char const* from, *to;
971 lua_getglobal( L, "decoda_name"); // ... t ... decoda_name
972 from = lua_tostring( L, -1);
973 lua_pop( L, 1); // ... t ...
974 lua_getglobal( L2, "decoda_name"); // {} t decoda_name
975 to = lua_tostring( L2, -1);
976 lua_pop( L2, 1); // {} t
977 // when mode_ == eLM_FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error
978 (void) luaL_error(
979 (mode_ == eLM_FromKeeper) ? L2 : L
980 , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database."
981 , from ? from : "main"
982 , fqn
983 , to ? to : "main"
984 );
985 return FALSE;
986 }
987 lua_remove( L2, -2); // t
988 break;
989 }
990 STACK_END( L2, 1);
991 return TRUE;
992}
993
994
826/* 995/*
827 * Check if we've already copied the same table from 'L', and 996 * Check if we've already copied the same table from 'L', and
828 * reuse the old copy. This allows table upvalues shared by multiple 997 * reuse the old copy. This allows table upvalues shared by multiple
@@ -847,7 +1016,7 @@ static bool_t push_cached_table( lua_State* L2, uint_t L2_cache_i, lua_State* L,
847 // push a light userdata uniquely representing the table 1016 // push a light userdata uniquely representing the table
848 lua_pushlightuserdata( L2, p); // ... p 1017 lua_pushlightuserdata( L2, p); // ... p
849 1018
850 //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); 1019 //fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1));
851 1020
852 lua_rawget( L2, L2_cache_i); // ... {cached|nil} 1021 lua_rawget( L2, L2_cache_i); // ... {cached|nil}
853 not_found_in_cache = lua_isnil( L2, -1); 1022 not_found_in_cache = lua_isnil( L2, -1);
@@ -1002,6 +1171,7 @@ static int discover_object_name_recur( lua_State* L, int shortest_, int depth_)
1002 return shortest_; 1171 return shortest_;
1003} 1172}
1004 1173
1174
1005/* 1175/*
1006 * "type", "name" = lanes.nameof( o) 1176 * "type", "name" = lanes.nameof( o)
1007 */ 1177 */
@@ -1049,72 +1219,17 @@ int luaG_nameof( lua_State* L)
1049 return 2; 1219 return 2;
1050} 1220}
1051 1221
1052// function sentinel used to transfer native functions from/to keeper states
1053static int sentinelfunc( lua_State* L)
1054{
1055 return luaL_error( L, "transfer sentinel function for %s, should never be called", lua_tostring( L, lua_upvalueindex( 1)));
1056}
1057 1222
1058/* 1223/*
1059* Push a looked-up native/LuaJIT function. 1224 * Push a looked-up native/LuaJIT function.
1060*/ 1225 */
1061static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_) 1226static void lookup_native_func( lua_State* L2, lua_State* L, uint_t i, enum eLookupMode mode_, char const* upName_)
1062{ 1227{
1063 char const* fqn; // L // L2 1228 // get the name of the function we want to send
1064 size_t len; 1229 size_t len;
1065 ASSERT_L( lua_isfunction( L, i)); // ... f ... 1230 char const* fqn = find_lookup_name( L, i, mode_, upName_, &len);
1066 STACK_CHECK( L);
1067 STACK_GROW( L, 3); // up to 3 slots are necessary on error
1068 if( mode_ == eLM_FromKeeper)
1069 {
1070 lua_CFunction f = lua_tocfunction( L, i); // should *always* be sentinelfunc!
1071 ASSERT_L( f == sentinelfunc);
1072 lua_getupvalue( L, i, 1); // ... f ... "f.q.n"
1073 fqn = lua_tolstring( L, -1, &len);
1074 }
1075 else
1076 {
1077 // fetch the name from the source state's lookup table
1078 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_REGKEY); // ... f ... {}
1079 ASSERT_L( lua_istable( L, -1));
1080 lua_pushvalue( L, i); // ... f ... {} f
1081 lua_rawget( L, -2); // ... f ... {} "f.q.n"
1082 fqn = lua_tolstring( L, -1, &len);
1083 }
1084 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END, fqn));
1085 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database
1086 lua_pop( L, (mode_ == eLM_FromKeeper) ? 1 : 2); // ... f ...
1087 STACK_MID( L, 0);
1088 if( !fqn)
1089 {
1090 char const *from, *typewhat, *what, *gotchaA, *gotchaB;
1091 // try to discover the name of the function we want to send
1092 lua_getglobal( L, "decoda_name"); // ... f ... decoda_name
1093 from = lua_tostring( L, -1);
1094 lua_pushcfunction( L, luaG_nameof); // ... f ... decoda_name luaG_nameof
1095 lua_pushvalue( L, i); // ... f ... decoda_name luaG_nameof f
1096 lua_call( L, 1, 2); // ... f ... decoda_name "type" "name"|nil
1097 typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2);
1098 // second return value can be nil if the function was not found
1099 // probable reason: the function was removed from the source Lua state before Lanes was required.
1100 if( lua_isnil( L, -1))
1101 {
1102 gotchaA = " referenced by";
1103 gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)";
1104 what = upName_;
1105 }
1106 else
1107 {
1108 gotchaA = "";
1109 gotchaB = "";
1110 what = (lua_type( L, -1) == LUA_TSTRING) ? lua_tostring( L, -1) : luaL_typename( L, -1);
1111 }
1112 (void) luaL_error( L, "%s%s '%s' not found in %s origin transfer database.%s", typewhat, gotchaA, what, from ? from : "main", gotchaB);
1113 return;
1114 }
1115 STACK_END( L, 0);
1116 // push the equivalent function in the destination's stack, retrieved from the lookup table 1231 // push the equivalent function in the destination's stack, retrieved from the lookup table
1117 STACK_CHECK( L2); 1232 STACK_CHECK( L2); // L // L2
1118 STACK_GROW( L2, 3); // up to 3 slots are necessary on error 1233 STACK_GROW( L2, 3); // up to 3 slots are necessary on error
1119 switch( mode_) 1234 switch( mode_)
1120 { 1235 {
@@ -1125,7 +1240,7 @@ static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State*
1125 case eLM_ToKeeper: 1240 case eLM_ToKeeper:
1126 // push a sentinel closure that holds the lookup name as upvalue 1241 // push a sentinel closure that holds the lookup name as upvalue
1127 lua_pushlstring( L2, fqn, len); // "f.q.n" 1242 lua_pushlstring( L2, fqn, len); // "f.q.n"
1128 lua_pushcclosure( L2, sentinelfunc, 1); // f 1243 lua_pushcclosure( L2, func_lookup_sentinel, 1); // f
1129 break; 1244 break;
1130 1245
1131 case eLM_LaneBody: 1246 case eLM_LaneBody:
@@ -1134,15 +1249,26 @@ static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State*
1134 ASSERT_L( lua_istable( L2, -1)); 1249 ASSERT_L( lua_istable( L2, -1));
1135 lua_pushlstring( L2, fqn, len); // {} "f.q.n" 1250 lua_pushlstring( L2, fqn, len); // {} "f.q.n"
1136 lua_rawget( L2, -2); // {} f 1251 lua_rawget( L2, -2); // {} f
1137 if( !lua_isfunction( L2, -1)) 1252 // nil means we don't know how to transfer stuff: user should do something
1253 // anything other than function or table should not happen!
1254 if( !lua_isfunction( L2, -1) && !lua_istable( L2, -1))
1138 { 1255 {
1139 char const* from, * to; 1256 char const* from, * to;
1140 lua_getglobal( L, "decoda_name"); // ... f ... decoda_name 1257 lua_getglobal( L, "decoda_name"); // ... f ... decoda_name
1141 from = lua_tostring( L, -1); 1258 from = lua_tostring( L, -1);
1259 lua_pop( L, 1); // ... f ...
1142 lua_getglobal( L2, "decoda_name"); // {} f decoda_name 1260 lua_getglobal( L2, "decoda_name"); // {} f decoda_name
1143 to = lua_tostring( L2, -1); 1261 to = lua_tostring( L2, -1);
1262 lua_pop( L2, 1); // {} f
1144 // when mode_ == eLM_FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error 1263 // when mode_ == eLM_FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error
1145 (void) luaL_error( (mode_ == eLM_FromKeeper) ? L2 : L, "%s: function '%s' not found in %s destination transfer database.", from ? from : "main", fqn, to ? to : "main"); 1264 (void) luaL_error(
1265 (mode_ == eLM_FromKeeper) ? L2 : L
1266 , "%s%s: function '%s' not found in %s destination transfer database."
1267 , lua_isnil( L2, -1) ? "" : "INTERNAL ERROR IN "
1268 , from ? from : "main"
1269 , fqn
1270 , to ? to : "main"
1271 );
1146 return; 1272 return;
1147 } 1273 }
1148 lua_remove( L2, -2); // f 1274 lua_remove( L2, -2); // f
@@ -1167,6 +1293,7 @@ static void lookup_native_func( struct s_Universe* U, lua_State* L2, lua_State*
1167 STACK_END( L2, 1); 1293 STACK_END( L2, 1);
1168} 1294}
1169 1295
1296
1170/* 1297/*
1171 * Copy a function over, which has not been found in the cache. 1298 * Copy a function over, which has not been found in the cache.
1172 * L2 has the cache key for this function at the top of the stack 1299 * L2 has the cache key for this function at the top of the stack
@@ -1184,7 +1311,7 @@ static void inter_copy_func( struct s_Universe* U, lua_State* L2, uint_t L2_cach
1184 int n, needToPush; 1311 int n, needToPush;
1185 luaL_Buffer b; 1312 luaL_Buffer b;
1186 ASSERT_L( L2_cache_i != 0); // ... {cache} ... p 1313 ASSERT_L( L2_cache_i != 0); // ... {cache} ... p
1187 STACK_GROW(L,2); 1314 STACK_GROW( L, 2);
1188 STACK_CHECK( L); 1315 STACK_CHECK( L);
1189 1316
1190 // 'lua_dump()' needs the function at top of stack 1317 // 'lua_dump()' needs the function at top of stack
@@ -1226,7 +1353,7 @@ static void inter_copy_func( struct s_Universe* U, lua_State* L2, uint_t L2_cach
1226 lua_Debug ar; 1353 lua_Debug ar;
1227 lua_pushvalue( L, i); // ... b f 1354 lua_pushvalue( L, i); // ... b f
1228 // fills 'name' 'namewhat' and 'linedefined', pops function 1355 // fills 'name' 'namewhat' and 'linedefined', pops function
1229 lua_getinfo(L, ">nS", &ar); // ... b 1356 lua_getinfo( L, ">nS", &ar); // ... b
1230 name = ar.namewhat; 1357 name = ar.namewhat;
1231 fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL 1358 fprintf( stderr, INDENT_BEGIN "FNAME: %s @ %d\n", i, s_indent, ar.short_src, ar.linedefined); // just gives NULL
1232 } 1359 }
@@ -1351,12 +1478,12 @@ static void push_cached_func( struct s_Universe* U, lua_State* L2, uint_t L2_cac
1351 // push a light userdata uniquely representing the function 1478 // push a light userdata uniquely representing the function
1352 lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p 1479 lua_pushlightuserdata( L2, aspointer); // ... {cache} ... p
1353 1480
1354 //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); 1481 //fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1));
1355 1482
1356 lua_pushvalue( L2, -1); // ... {cache} ... p p 1483 lua_pushvalue( L2, -1); // ... {cache} ... p p
1357 lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true 1484 lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true
1358 1485
1359 if( lua_isnil(L2,-1)) // function is unknown 1486 if( lua_isnil( L2, -1)) // function is unknown
1360 { 1487 {
1361 lua_pop( L2, 1); // ... {cache} ... p 1488 lua_pop( L2, 1); // ... {cache} ... p
1362 1489
@@ -1371,15 +1498,14 @@ static void push_cached_func( struct s_Universe* U, lua_State* L2, uint_t L2_cac
1371 lua_remove( L2, -2); // ... {cache} ... function 1498 lua_remove( L2, -2); // ... {cache} ... function
1372 } 1499 }
1373 STACK_END( L2, 1); 1500 STACK_END( L2, 1);
1501 ASSERT_L( lua_isfunction( L2, -1));
1374 } 1502 }
1375 else // function is native/LuaJIT: no need to cache 1503 else // function is native/LuaJIT: no need to cache
1376 { 1504 {
1377 lookup_native_func( U, L2, L, i, mode_, upName_); // ... {cache} ... function 1505 lookup_native_func( L2, L, i, mode_, upName_); // ... {cache} ... function
1506 // if the function was in fact a lookup sentinel, we can either get a function or a table here
1507 ASSERT_L( lua_isfunction( L2, -1) || lua_istable( L2, -1));
1378 } 1508 }
1379
1380 //
1381 // L2 [-1]: function
1382 ASSERT_L( lua_isfunction( L2, -1));
1383} 1509}
1384 1510
1385/* 1511/*
@@ -1396,12 +1522,12 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1396{ 1522{
1397 bool_t ret = TRUE; 1523 bool_t ret = TRUE;
1398 bool_t ignore = FALSE; 1524 bool_t ignore = FALSE;
1399 int val_type = lua_type(L, i); 1525 int val_type = lua_type( L, i);
1400 STACK_GROW( L2, 1); 1526 STACK_GROW( L2, 1);
1401 STACK_CHECK( L2); 1527 STACK_CHECK( L2);
1402 1528
1403 /* Skip the object if it has metatable with { __lanesignore = true } */ 1529 /* Skip the object if it has metatable with { __lanesignore = true } */
1404 if( lua_getmetatable( L, i)) // ... mt 1530 if( lua_getmetatable( L, i)) // ... mt
1405 { 1531 {
1406 lua_getfield( L, -1, "__lanesignore"); // ... mt ignore? 1532 lua_getfield( L, -1, "__lanesignore"); // ... mt ignore?
1407 if( lua_isboolean( L, -1) && lua_toboolean( L, -1)) 1533 if( lua_isboolean( L, -1) && lua_toboolean( L, -1))
@@ -1426,7 +1552,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1426 if( lua_isinteger( L, i)) 1552 if( lua_isinteger( L, i))
1427 { 1553 {
1428 lua_Integer v = lua_tointeger( L, i); 1554 lua_Integer v = lua_tointeger( L, i);
1429 DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, INDENT_BEGIN "KEY: %d\n" INDENT_END, v)); 1555 DEBUGSPEW_CODE( if( vt == VT_KEY) fprintf( stderr, INDENT_BEGIN "KEY: " LUA_INTEGER_FMT "\n" INDENT_END, v));
1430 lua_pushinteger( L2, v); 1556 lua_pushinteger( L2, v);
1431 break; 1557 break;
1432 } 1558 }
@@ -1449,7 +1575,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1449 break; 1575 break;
1450 1576
1451 case LUA_TLIGHTUSERDATA: 1577 case LUA_TLIGHTUSERDATA:
1452 lua_pushlightuserdata( L2, lua_touserdata(L, i)); 1578 lua_pushlightuserdata( L2, lua_touserdata( L, i));
1453 break; 1579 break;
1454 1580
1455 /* The following types are not allowed as table keys */ 1581 /* The following types are not allowed as table keys */
@@ -1525,6 +1651,16 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1525 STACK_CHECK( L); 1651 STACK_CHECK( L);
1526 STACK_CHECK( L2); 1652 STACK_CHECK( L2);
1527 1653
1654 /*
1655 * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?)
1656 * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism
1657 */
1658 if( lookup_table( L2, L, i, mode_, upName_))
1659 {
1660 ASSERT_L( lua_istable( L2, -1) || (lua_tocfunction( L2, -1) == table_lookup_sentinel)); // from lookup datables // can also be table_lookup_sentinel if this is a table we know
1661 break;
1662 }
1663
1528 /* Check if we've already copied the same table from 'L' (during this transmission), and 1664 /* Check if we've already copied the same table from 'L' (during this transmission), and
1529 * reuse the old copy. This allows table upvalues shared by multiple 1665 * reuse the old copy. This allows table upvalues shared by multiple
1530 * local functions to point to the same table, also in the target. 1666 * local functions to point to the same table, also in the target.
@@ -1539,7 +1675,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1539 ASSERT_L( lua_istable( L2, -1)); // from cache 1675 ASSERT_L( lua_istable( L2, -1)); // from cache
1540 break; 1676 break;
1541 } 1677 }
1542 ASSERT_L( lua_istable( L2,-1)); 1678 ASSERT_L( lua_istable( L2, -1));
1543 1679
1544 STACK_GROW( L, 2); 1680 STACK_GROW( L, 2);
1545 STACK_GROW( L2, 2); 1681 STACK_GROW( L2, 2);
@@ -1547,7 +1683,7 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1547 lua_pushnil( L); // start iteration 1683 lua_pushnil( L); // start iteration
1548 while( lua_next( L, i)) 1684 while( lua_next( L, i))
1549 { 1685 {
1550 uint_t val_i = lua_gettop(L); 1686 uint_t val_i = lua_gettop( L);
1551 uint_t key_i = val_i - 1; 1687 uint_t key_i = val_i - 1;
1552 1688
1553 // Only basic key types are copied over; others ignored 1689 // Only basic key types are copied over; others ignored
@@ -1613,8 +1749,8 @@ static bool_t inter_copy_one_( struct s_Universe* U, lua_State* L2, uint_t L2_ca
1613 { /* L2 did not know the metatable */ 1749 { /* L2 did not know the metatable */
1614 lua_pop( L2, 1); 1750 lua_pop( L2, 1);
1615 STACK_MID( L2, 2); 1751 STACK_MID( L2, 2);
1616 ASSERT_L( lua_istable(L,-1)); 1752 ASSERT_L( lua_istable( L,-1));
1617 if( inter_copy_one_( U, L2, L2_cache_i /*for function cacheing*/, L, lua_gettop(L) /*[-1]*/, VT_METATABLE, mode_, upName_)) 1753 if( inter_copy_one_( U, L2, L2_cache_i /*for function cacheing*/, L, lua_gettop( L) /*[-1]*/, VT_METATABLE, mode_, upName_))
1618 { 1754 {
1619 // 1755 //
1620 // L2 ([-3]: copied table) 1756 // L2 ([-3]: copied table)
diff --git a/tests/parallel_os_calls.lua b/tests/parallel_os_calls.lua
index b8cffa1..7119272 100644
--- a/tests/parallel_os_calls.lua
+++ b/tests/parallel_os_calls.lua
@@ -1,11 +1,12 @@
1local lanes = require "lanes".configure(1) 1local lanes = require "lanes".configure{with_timers = false, nb_keepers = 1}
2print( os.date()) 2print( os.date())
3local linda = lanes.linda() 3local linda = lanes.linda()
4lanes.gen("os,base", function() linda:receive(10, "null") print("finished_sleeping " .. os.date()) end)() 4local l1 = lanes.gen("os,base", function() print "start sleeping" linda:receive(10, "null") print("finished_sleeping " .. os.date()) end)()
5lanes.gen("os,base", function() linda:receive(10, "null") print("finished_sleeping " .. os.date()) end)() 5lanes.gen("os,base", function() print "start sleeping" linda:receive(9, "null") print("finished_sleeping " .. os.date()) end)()
6lanes.gen("os,base", function() linda:receive(10, "null") print("finished_sleeping " .. os.date()) end)() 6lanes.gen("os,base", function() print "start sleeping" linda:receive(9, "null") print("finished_sleeping " .. os.date()) end)()
7lanes.gen("os,base", function() linda:receive(10, "null") print("finished_sleeping " .. os.date()) end)() 7lanes.gen("os,base", function() print "start sleeping" linda:receive(9, "null") print("finished_sleeping " .. os.date()) end)()
8 8-- wait, else all lanes will get hard-cancelled at stat shutdown
9l1:join()
9--[[ 10--[[
10lanes.gen("os,base", function() os.execute('sleep 10 && echo finished_sleeping') print( os.date()) end)() 11lanes.gen("os,base", function() os.execute('sleep 10 && echo finished_sleeping') print( os.date()) end)()
11lanes.gen("os,base", function() os.execute('sleep 10 && echo finished_sleeping') print( os.date()) end)() 12lanes.gen("os,base", function() os.execute('sleep 10 && echo finished_sleeping') print( os.date()) end)()