aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES16
-rw-r--r--Makefile8
-rw-r--r--docs/index.html39
-rw-r--r--src/keeper.c15
-rw-r--r--src/keeper.h2
-rw-r--r--src/lanes.c134
-rw-r--r--src/lanes.lua323
-rw-r--r--src/tools.c92
-rw-r--r--src/tools.h5
-rw-r--r--tests/fibonacci.lua9
-rw-r--r--tests/package.lua20
-rw-r--r--tests/pingpong.lua31
-rw-r--r--tests/timer.lua5
13 files changed, 421 insertions, 278 deletions
diff --git a/CHANGES b/CHANGES
index 66b5c23..3957956 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,19 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 58: BGe 30-Jan-13
4 * version 3.5.0
5 * new: API lanes.require(), use it instead of regular require() for modules that export C functions you need to send over.
6 * new: lanes no longer require 'lanes.core' by default in every created state. Use {required={"lanes.core"}} if you need to transfer lanes functions.
7 * internal: because of the above, reworked the timer implementation to remove upvalue-dependency on lanes.core
8 * new: API lanes.timer_lane, to be able to operate on timer lane if need be
9 * improved: if a module is a full userdata, scan its metatable for function database population
10 * improved: on_state_create can be a Lua function
11 * changed: on_state_create is called after the base libraries are loaded
12 * package[loaders|searchers] is no longer transfered as function naming depends on slot order
13 * internal: changed separator from '.' to '/' in lookup databases to be able to distinguish search levels and dot coming from module names
14 * added some mode debug spew
15 * updated tests to reflect the above changes
16
3CHANGE 57: BGe 28-Jan-13 17CHANGE 57: BGe 28-Jan-13
4 * More detailed DEBUG_SPEW logs 18 * More detailed DEBUG_SPEW logs
5 * A bit of code cosmetics 19 * A bit of code cosmetics
@@ -210,7 +224,7 @@ CHANGE 19 BGe 2-Dec-2010:
210 224
211CHANGE 18 BGe 6-Oct-2010: 225CHANGE 18 BGe 6-Oct-2010:
212 Fixed 'memory leak' in some situations where a free running lane is collected before application shutdown 226 Fixed 'memory leak' in some situations where a free running lane is collected before application shutdown
213 A bit of code cleanup 227 A bit of code cleanup
214 228
215CHANGE 17 BGe 21-Sept-2010: 229CHANGE 17 BGe 21-Sept-2010:
216 Fixed stupid compilation errors. 230 Fixed stupid compilation errors.
diff --git a/Makefile b/Makefile
index 5406dad..fc44fac 100644
--- a/Makefile
+++ b/Makefile
@@ -88,6 +88,8 @@ test:
88 $(MAKE) atexit 88 $(MAKE) atexit
89 $(MAKE) linda_perf 89 $(MAKE) linda_perf
90 $(MAKE) rupval 90 $(MAKE) rupval
91 $(MAKE) package
92 $(MAKE) pingpong
91 93
92basic: tests/basic.lua $(_TARGET_SO) 94basic: tests/basic.lua $(_TARGET_SO)
93 $(_PREFIX) $(LUA) $< 95 $(_PREFIX) $(LUA) $<
@@ -167,6 +169,12 @@ atexit: tests/atexit.lua $(_TARGET_SO)
167rupval: tests/rupval.lua $(_TARGET_SO) 169rupval: tests/rupval.lua $(_TARGET_SO)
168 $(_PREFIX) $(LUA) $< 170 $(_PREFIX) $(LUA) $<
169 171
172package: tests/package.lua $(_TARGET_SO)
173 $(_PREFIX) $(LUA) $<
174
175pingpong: tests/pingpong.lua $(_TARGET_SO)
176 $(_PREFIX) $(LUA) $<
177
170#--- 178#---
171perftest-plain: tests/perftest.lua $(_TARGET_SO) 179perftest-plain: tests/perftest.lua $(_TARGET_SO)
172 $(MAKE) _perftest ARGS="$< $(N) -plain" 180 $(MAKE) _perftest ARGS="$< $(N) -plain"
diff --git a/docs/index.html b/docs/index.html
index 4f31923..8b21a97 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -69,7 +69,7 @@
69 </p> 69 </p>
70 70
71 <p> 71 <p>
72 This document was revised on 26-Jan-13, and applies to version <tt>3.4.4</tt>. 72 This document was revised on 30-Jan-13, and applies to version <tt>3.5.0</tt>.
73 </p> 73 </p>
74 </font> 74 </font>
75 </center> 75 </center>
@@ -249,10 +249,17 @@
249 <code>.on_state_create</code> 249 <code>.on_state_create</code>
250 </td> 250 </td>
251 <td> 251 <td>
252 C function/<tt>nil</tt> 252 function/<tt>nil</tt>
253 </td> 253 </td>
254 <td> 254 <td>
255 If provided, will be called in every created Lua state (keepers and lanes) right after it is created, and *before* any library is loaded. That way, all C functions it loads in the state can be added to the function lookup database. Default is <tt>nil</tt>. 255 If provided, will be called in every created Lua state (keepers and lanes) right after initializing the base libraries.
256 <br>
257 Typical usage is twofold:
258 <ul>
259 <li>Tweak <tt>package.loaders</tt></li>
260 <li>Load some additional C functions in the global space (of course only a C function will be able to do this).</li>
261 </ul>
262 That way, all changes in the state can be properly taken into account when building the function lookup database. Default is <tt>nil</tt>.
256 </td> 263 </td>
257 </tr> 264 </tr>
258 265
@@ -270,6 +277,22 @@
270 </table> 277 </table>
271</p> 278</p>
272 279
280<p>
281 NEW (version 3.5.0)
282 <br>
283 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>.
284 <br>
285 Use <tt>lanes.require()</tt> for this purpose. This will call the original <tt>require()</tt>, then add the result to the lookup databases.
286</p>
287
288<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%">
289 <tr>
290 <td>
291 <pre> local m = lanes.require "modname"</pre>
292 </td>
293 </tr>
294</table>
295
273<hr/> 296<hr/>
274<h2 id="creation">Creation</h2> 297<h2 id="creation">Creation</h2>
275 298
@@ -468,6 +491,8 @@
468 These tables are built from the modules listed here. <tt>required</tt> must be a list of strings, each one being the name of a module to be required. Each module is required with <tt>require()</tt> before the lanes function is invoked. 491 These tables are built from the modules listed here. <tt>required</tt> must be a list of strings, each one being the name of a module to be required. Each module is required with <tt>require()</tt> before the lanes function is invoked.
469 So, from the required module's point of view, requiring it manually from inside the lane body or having it required this way doesn't change anything. From the lane body's point of view, the only difference is that a module not creating a global won't be accessible. 492 So, from the required module's point of view, requiring it manually from inside the lane body or having it required this way doesn't change anything. From the lane body's point of view, the only difference is that a module not creating a global won't be accessible.
470 Therefore, a lane body will also have to require a module manually, but this won't do anything more (see Lua's <tt>require</tt> documentation). 493 Therefore, a lane body will also have to require a module manually, but this won't do anything more (see Lua's <tt>require</tt> documentation).
494 <br>
495 ATTEMPTING TO TRANSFER A FUNCTION REGISTERED BY A MODULE NOT LISTED HERE WILL RAISE AN ERROR.
471 </td> 496 </td>
472 </tr> 497 </tr>
473 <tr valign=top> 498 <tr valign=top>
@@ -567,7 +592,7 @@
567 </td> 592 </td>
568 <td/> 593 <td/>
569 <td> 594 <td>
570 running, not suspended on a Linda call. 595 running, not suspended on a <a href="#lindas">Linda</a> call.
571 </td> 596 </td>
572 </tr> 597 </tr>
573 <tr> 598 <tr>
@@ -577,7 +602,7 @@
577 </td> 602 </td>
578 <td/> 603 <td/>
579 <td> 604 <td>
580 waiting at a Linda <tt>:receive()</tt> or <tt>:send()</tt> 605 waiting at a <a href="#lindas">Linda</a> <tt>:receive()</tt> or <tt>:send()</tt>
581 </td> 606 </td>
582 </tr> 607 </tr>
583 <tr> 608 <tr>
@@ -711,7 +736,7 @@
711</pre></td></tr></table> 736</pre></td></tr></table>
712 737
713<p> 738<p>
714 If you want to wait for multiple lanes to finish (any of a set of lanes), use a <a href="#lindas">Linda</a> object. Give each lane a specific id, and send that id over a Linda once that thread is done (as the last thing you do). 739 If you want to wait for multiple lanes to finish (any of a set of lanes), use a <a href="#lindas">Linda</a> object. Give each lane a specific id, and send that id over a <a href="#lindas">Linda</a> once that thread is done (as the last thing you do).
715</p> 740</p>
716 741
717<table border=1 bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> 742<table border=1 bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre>
@@ -750,7 +775,7 @@
750<p> 775<p>
751 Cancellation is tested <u>before</u> going to sleep in <tt>receive()</tt> or <tt>send()</tt> calls and after executing <tt>cancelstep</tt> Lua statements. Starting with version 3.0-beta, a pending <tt>receive()</tt>or <tt>send()</tt> call is awakened. 776 Cancellation is tested <u>before</u> going to sleep in <tt>receive()</tt> or <tt>send()</tt> calls and after executing <tt>cancelstep</tt> Lua statements. Starting with version 3.0-beta, a pending <tt>receive()</tt>or <tt>send()</tt> call is awakened.
752 <br> 777 <br>
753 This means the execution of the lane will resume although the operation has not completed, to give the lane a chance to detect cancellation (even in the case the code waits on a linda with infinite timeout). 778 This means the execution of the lane will resume although the operation has not completed, to give the lane a chance to detect cancellation (even in the case the code waits on a <a href="#lindas">linda</a> with infinite timeout).
754 <br> 779 <br>
755 The code should be able to handle this situation appropriately if required (in other words, it should gracefully handle the fact that it didn't receive the expected values). 780 The code should be able to handle this situation appropriately if required (in other words, it should gracefully handle the fact that it didn't receive the expected values).
756 <br> 781 <br>
diff --git a/src/keeper.c b/src/keeper.c
index 7485110..3511b56 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -557,7 +557,7 @@ void close_keepers( void)
557* unclosed, because it does not really matter. In production code, this 557* unclosed, because it does not really matter. In production code, this
558* function never fails. 558* function never fails.
559*/ 559*/
560char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_state_create) 560char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers)
561{ 561{
562 int i; 562 int i;
563 assert( _nbKeepers >= 1); 563 assert( _nbKeepers >= 1);
@@ -572,7 +572,7 @@ char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_
572 // 572 //
573 // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs 573 // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs
574 // the others because they export functions that we may store in a keeper for transfer between lanes 574 // the others because they export functions that we may store in a keeper for transfer between lanes
575 K = luaG_newstate( L, "*", _on_state_create); 575 K = luaG_newstate( L, _on_state_create, "*");
576 576
577 STACK_CHECK( K); 577 STACK_CHECK( K);
578 578
@@ -635,8 +635,8 @@ void populate_keepers( lua_State* L)
635 char const* name = luaL_checklstring( L, -1, &name_len); 635 char const* name = luaL_checklstring( L, -1, &name_len);
636 int i; 636 int i;
637 637
638 STACK_CHECK( L); 638 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "populate_keepers %s BEGIN\n" INDENT_END, name));
639 STACK_GROW( L, 3); 639 DEBUGSPEW_CODE( ++ debugspew_indent_depth);
640 640
641 for( i = 0; i < GNbKeepers; ++ i) 641 for( i = 0; i < GNbKeepers; ++ i)
642 { 642 {
@@ -647,16 +647,19 @@ void populate_keepers( lua_State* L)
647 STACK_GROW( K, 2); 647 STACK_GROW( K, 2);
648 lua_getglobal( K, "require"); 648 lua_getglobal( K, "require");
649 lua_pushlstring( K, name, name_len); 649 lua_pushlstring( K, name, name_len);
650 res = lua_pcall( K, 1, 0, 0); 650 res = lua_pcall( K, 1, 1, 0);
651 if( res != LUA_OK) 651 if( res != LUA_OK)
652 { 652 {
653 char const* err = luaL_checkstring( K, -1); 653 char const* err = luaL_checkstring( K, -1);
654 luaL_error( L, "error requiring '%s' in keeper state: %s", name, err); 654 luaL_error( L, "error requiring '%s' in keeper state: %s", name, err);
655 } 655 }
656 // after requiring the module, register the functions it exported in our name<->function database
657 populate_func_lookup_table( K, -1, name);
658 lua_pop( K, 1);
656 STACK_END( K, 0); 659 STACK_END( K, 0);
657 MUTEX_UNLOCK( &GKeepers[i].lock_); 660 MUTEX_UNLOCK( &GKeepers[i].lock_);
658 } 661 }
659 STACK_END( L, 0); 662 DEBUGSPEW_CODE( -- debugspew_indent_depth);
660} 663}
661 664
662struct s_Keeper* keeper_acquire( void const* ptr) 665struct s_Keeper* keeper_acquire( void const* ptr)
diff --git a/src/keeper.h b/src/keeper.h
index 15a5a41..29a19a9 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -13,7 +13,7 @@ struct s_Keeper
13// problem: maybe on some platforms (linux) atexit() is called after DLL/so are unloaded... 13// problem: maybe on some platforms (linux) atexit() is called after DLL/so are unloaded...
14#define HAVE_KEEPER_ATEXIT_DESINIT 0 14#define HAVE_KEEPER_ATEXIT_DESINIT 0
15 15
16char const* init_keepers( lua_State* L, int const _nbKeepers, lua_CFunction _on_state_create); 16char const* init_keepers( lua_State* L, int _on_state_create, int const _nbKeepers);
17#if !HAVE_KEEPER_ATEXIT_DESINIT 17#if !HAVE_KEEPER_ATEXIT_DESINIT
18void close_keepers( void); 18void close_keepers( void);
19#endif // HAVE_KEEPER_ATEXIT_DESINIT 19#endif // HAVE_KEEPER_ATEXIT_DESINIT
diff --git a/src/lanes.c b/src/lanes.c
index 80f5b15..2b3d8ac 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.4.4"; 55char const* VERSION = "3.5.0";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -1529,7 +1529,6 @@ LUAG_FUNC( set_singlethreaded)
1529# define STACK_TRACE_KEY ((void*)lane_error) // used as registry key 1529# define STACK_TRACE_KEY ((void*)lane_error) // used as registry key
1530# define EXTENDED_STACK_TRACE_KEY ((void*)LG_set_error_reporting) // used as registry key 1530# define EXTENDED_STACK_TRACE_KEY ((void*)LG_set_error_reporting) // used as registry key
1531 1531
1532#ifdef ERROR_FULL_STACK
1533LUAG_FUNC( set_error_reporting) 1532LUAG_FUNC( set_error_reporting)
1534{ 1533{
1535 bool_t equal; 1534 bool_t equal;
@@ -1554,7 +1553,6 @@ done:
1554 lua_rawset( L, LUA_REGISTRYINDEX); 1553 lua_rawset( L, LUA_REGISTRYINDEX);
1555 return 0; 1554 return 0;
1556} 1555}
1557#endif // ERROR_FULL_STACK
1558 1556
1559static int lane_error( lua_State* L) 1557static int lane_error( lua_State* L)
1560{ 1558{
@@ -1735,8 +1733,8 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1735 // [3..top]: parameters 1733 // [3..top]: parameters
1736 // 1734 //
1737 rc= lua_pcall( L, lua_gettop(L)-2, LUA_MULTRET, 1 /*error handler*/ ); 1735 rc= lua_pcall( L, lua_gettop(L)-2, LUA_MULTRET, 1 /*error handler*/ );
1738 // 0: no error 1736 // 0: no error, body return values are on the stack
1739 // LUA_ERRRUN: a runtime error (error pushed on stack) 1737 // LUA_ERRRUN: cancellation or a runtime error (error pushed on stack)
1740 // LUA_ERRMEM: memory allocation error 1738 // LUA_ERRMEM: memory allocation error
1741 // LUA_ERRERR: error while running the error handler (if any) 1739 // LUA_ERRERR: error while running the error handler (if any)
1742 1740
@@ -1744,14 +1742,12 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1744 1742
1745 lua_remove(L,1); // remove error handler 1743 lua_remove(L,1); // remove error handler
1746 1744
1747 // Lua 5.1 error handler is limited to one return value; taking stack trace 1745 // Lua 5.1 error handler is limited to one return value; taking stack trace via registry
1748 // via registry 1746 if( rc != LUA_OK)
1749 //
1750 if( rc != 0)
1751 { 1747 {
1752 STACK_GROW(L,1); 1748 STACK_GROW(L,1);
1753 lua_pushlightuserdata( L, STACK_TRACE_KEY ); 1749 lua_pushlightuserdata( L, STACK_TRACE_KEY );
1754 lua_gettable(L, LUA_REGISTRYINDEX); 1750 lua_gettable(L, LUA_REGISTRYINDEX); // yields nil if no stack was generated (in case of cancellation for example)
1755 1751
1756 // For cancellation, a stack trace isn't placed 1752 // For cancellation, a stack trace isn't placed
1757 // 1753 //
@@ -1773,7 +1769,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1773 // LUA_ERRMEM(4): memory allocation error 1769 // LUA_ERRMEM(4): memory allocation error
1774#endif 1770#endif
1775 1771
1776 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s\n" INDENT_END, L, get_errcode_name( rc))); 1772 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name( rc), (lua_touserdata(L,1)==CANCEL_ERROR) ? "cancelled" : lua_typename( L, lua_type( L, 1))));
1777 //STACK_DUMP(L); 1773 //STACK_DUMP(L);
1778 // Call finalizers, if the script has set them up. 1774 // Call finalizers, if the script has set them up.
1779 // 1775 //
@@ -1831,6 +1827,26 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1831 return 0; // ignored 1827 return 0; // ignored
1832} 1828}
1833 1829
1830// --- If a client wants to transfer stuff of a given module from the current state to another Lane, the module must be required
1831// with lanes.require, that will call the regular 'require', then populate lookup databases in source and keeper states
1832// module = lanes.require( "modname")
1833// upvalue[1]: _G.require
1834LUAG_FUNC( require)
1835{
1836 char const* name = lua_tostring( L, 1);
1837 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END, name));
1838 DEBUGSPEW_CODE( ++ debugspew_indent_depth);
1839 lua_pushvalue( L, lua_upvalueindex(1)); // "name" require
1840 lua_pushvalue( L, 1); // "name" require "name"
1841 lua_call( L, 1, 1); // "name" module
1842 populate_func_lookup_table( L, -1, name);
1843 lua_insert( L, -2); // module "name"
1844 populate_keepers( L);
1845 lua_pop( L, 1); // module
1846 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lanes.require %s END\n" INDENT_END, name));
1847 DEBUGSPEW_CODE( -- debugspew_indent_depth);
1848 return 1;
1849}
1834 1850
1835//--- 1851//---
1836// lane_ud= thread_new( function, [libs_str], 1852// lane_ud= thread_new( function, [libs_str],
@@ -1844,32 +1860,6 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1844// Upvalues: metatable to use for 'lane_ud' 1860// Upvalues: metatable to use for 'lane_ud'
1845// 1861//
1846 1862
1847// helper function to require a module in the keeper states and in the target state
1848// source state contains module name at the top of the stack
1849static void require_one_module( lua_State* L, lua_State* L2, bool_t _fatal)
1850{
1851 size_t len;
1852 char const* name = lua_tolstring( L, -1, &len);
1853 // require the module in the target lane
1854 STACK_GROW( L2, 2);
1855 lua_getglobal( L2, "require");
1856 if( lua_isnil( L2, -1))
1857 {
1858 lua_pop( L2, 1);
1859 if( _fatal)
1860 {
1861 luaL_error( L, "cannot pre-require modules without loading 'package' library first");
1862 }
1863 }
1864 else
1865 {
1866 lua_pushlstring( L2, name, len);
1867 lua_pcall( L2, 1, 0, 0);
1868 // we need to require this module in the keeper states as well
1869 populate_keepers( L);
1870 }
1871}
1872
1873LUAG_FUNC( thread_new) 1863LUAG_FUNC( thread_new)
1874{ 1864{
1875 lua_State* L2; 1865 lua_State* L2;
@@ -1877,17 +1867,17 @@ LUAG_FUNC( thread_new)
1877 struct s_lane** ud; 1867 struct s_lane** ud;
1878 1868
1879 char const* libs = lua_tostring( L, 2); 1869 char const* libs = lua_tostring( L, 2);
1880 lua_CFunction on_state_create = lua_iscfunction( L, 3) ? lua_tocfunction( L, 3) : NULL; 1870 int const on_state_create = lua_isfunction( L, 3) ? 3 : 0;
1881 uint_t cs = luaG_optunsigned( L, 4, 0); 1871 uint_t cs = luaG_optunsigned( L, 4, 0);
1882 int prio = (int) luaL_optinteger( L, 5, 0); 1872 int prio = (int) luaL_optinteger( L, 5, 0);
1883 uint_t glob = luaG_isany( L, 6) ? 6 : 0; 1873 uint_t glob = lua_isnoneornil( L, 6) ? 0 : 6;
1884 uint_t package = luaG_isany( L,7) ? 7 : 0; 1874 uint_t package = lua_isnoneornil( L,7) ? 0 : 7;
1885 uint_t required = luaG_isany( L, 8) ? 8 : 0; 1875 uint_t required = lua_isnoneornil( L, 8) ? 0 : 8;
1886 1876
1887#define FIXED_ARGS 8 1877#define FIXED_ARGS 8
1888 uint_t args= lua_gettop(L) - FIXED_ARGS; 1878 uint_t args= lua_gettop(L) - FIXED_ARGS;
1889 1879
1890 if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) 1880 if( prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX)
1891 { 1881 {
1892 return luaL_error( L, "Priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio); 1882 return luaL_error( L, "Priority out of range: %d..+%d (%d)", THREAD_PRIO_MIN, THREAD_PRIO_MAX, prio);
1893 } 1883 }
@@ -1898,7 +1888,7 @@ LUAG_FUNC( thread_new)
1898 1888
1899 // populate with selected libraries at the same time 1889 // populate with selected libraries at the same time
1900 // 1890 //
1901 L2 = luaG_newstate( L, libs, on_state_create); 1891 L2 = luaG_newstate( L, on_state_create, libs);
1902 1892
1903 STACK_GROW( L, 2); 1893 STACK_GROW( L, 2);
1904 STACK_GROW( L2, 3); 1894 STACK_GROW( L2, 3);
@@ -1918,17 +1908,6 @@ LUAG_FUNC( thread_new)
1918 1908
1919 // modules to require in the target lane *before* the function is transfered! 1909 // modules to require in the target lane *before* the function is transfered!
1920 1910
1921 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "thread_new: require 'lanes.core'\n" INDENT_END));
1922 //start by requiring lanes.core, since it is a bit special
1923 // it is not fatal if 'require' isn't loaded, just ignore (may cause function transfer errors later on if the lane pulls the lanes module itself)
1924 STACK_CHECK( L);
1925 STACK_CHECK( L2);
1926 lua_pushliteral( L, "lanes.core");
1927 require_one_module( L, L2, FALSE);
1928 lua_pop( L, 1);
1929 STACK_END( L2, 0);
1930 STACK_END (L, 0);
1931
1932 STACK_CHECK( L); 1911 STACK_CHECK( L);
1933 STACK_CHECK( L2); 1912 STACK_CHECK( L2);
1934 if( required) 1913 if( required)
@@ -1941,6 +1920,7 @@ LUAG_FUNC( thread_new)
1941 { 1920 {
1942 return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required)); 1921 return luaL_error( L, "expected required module list as a table, got %s", luaL_typename( L, required));
1943 } 1922 }
1923
1944 lua_pushnil( L); 1924 lua_pushnil( L);
1945 while( lua_next( L, required) != 0) 1925 while( lua_next( L, required) != 0)
1946 { 1926 {
@@ -1950,7 +1930,32 @@ LUAG_FUNC( thread_new)
1950 } 1930 }
1951 else 1931 else
1952 { 1932 {
1953 require_one_module( L, L2, TRUE); 1933 // require the module in the target state, and populate the lookup table there too
1934 size_t len;
1935 char const* name = lua_tolstring( L, -1, &len);
1936
1937 // require the module in the target lane
1938 STACK_GROW( L2, 2);
1939 STACK_CHECK( L2);
1940 lua_getglobal( L2, "require"); // require()?
1941 if( lua_isnil( L2, -1))
1942 {
1943 lua_pop( L2, 1); //
1944 luaL_error( L, "cannot pre-require modules without loading 'package' library first");
1945 }
1946 else
1947 {
1948 lua_pushlstring( L2, name, len); // require() name
1949 lua_pcall( L2, 1, 1, 0); // ret
1950 STACK_MID( L2, 1);
1951 // after requiring the module, register the functions it exported in our name<->function database
1952 populate_func_lookup_table( L2, -1, name);
1953 STACK_MID( L2, 1);
1954 lua_pop( L2, 1);
1955 // don't require this module in the keeper states as well, use lanes.require() for that!
1956 //populate_keepers( L);
1957 }
1958 STACK_END( L2, 0);
1954 } 1959 }
1955 lua_pop( L, 1); 1960 lua_pop( L, 1);
1956 ++ nbRequired; 1961 ++ nbRequired;
@@ -2578,7 +2583,7 @@ static const struct luaL_Reg lanes_functions [] = {
2578/* 2583/*
2579* One-time initializations 2584* One-time initializations
2580*/ 2585*/
2581static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _on_state_create, lua_Number _shutdown_timeout, bool_t _track_lanes) 2586static void init_once_LOCKED( lua_State* L, int const _on_state_create, int const nbKeepers, lua_Number _shutdown_timeout, bool_t _track_lanes)
2582{ 2587{
2583 char const* err; 2588 char const* err;
2584 2589
@@ -2603,7 +2608,7 @@ static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _
2603 // 2608 //
2604 MUTEX_RECURSIVE_INIT( &require_cs ); 2609 MUTEX_RECURSIVE_INIT( &require_cs );
2605 2610
2606 serialize_require( L ); 2611 serialize_require( L);
2607 2612
2608 // Linked chains handling 2613 // Linked chains handling
2609 // 2614 //
@@ -2635,7 +2640,7 @@ static void init_once_LOCKED( lua_State* L, int const nbKeepers, lua_CFunction _
2635 } 2640 }
2636 #endif 2641 #endif
2637#endif 2642#endif
2638 err = init_keepers( L, nbKeepers, _on_state_create); 2643 err = init_keepers( L, _on_state_create, nbKeepers);
2639 if (err) 2644 if (err)
2640 { 2645 {
2641 (void) luaL_error( L, "Unable to initialize: %s", err ); 2646 (void) luaL_error( L, "Unable to initialize: %s", err );
@@ -2691,7 +2696,7 @@ LUAG_FUNC( configure)
2691 char const* name = luaL_checkstring( L, lua_upvalueindex( 1)); 2696 char const* name = luaL_checkstring( L, lua_upvalueindex( 1));
2692 // all parameter checks are done lua-side 2697 // all parameter checks are done lua-side
2693 int const nbKeepers = (int)lua_tointeger( L, 1); 2698 int const nbKeepers = (int)lua_tointeger( L, 1);
2694 lua_CFunction on_state_create = lua_iscfunction( L, 2) ? lua_tocfunction( L, 2) : NULL; 2699 int const on_state_create = lua_isfunction( L, 2) ? 2 : 0;
2695 lua_Number shutdown_timeout = lua_tonumber( L, 3); 2700 lua_Number shutdown_timeout = lua_tonumber( L, 3);
2696 bool_t track_lanes = lua_toboolean( L, 4); 2701 bool_t track_lanes = lua_toboolean( L, 4);
2697 2702
@@ -2732,6 +2737,11 @@ LUAG_FUNC( configure)
2732 lua_pushcclosure( L, LG_thread_new, 1); // ... M LG_thread_new 2737 lua_pushcclosure( L, LG_thread_new, 1); // ... M LG_thread_new
2733 lua_setfield(L, -2, "thread_new"); // ... M 2738 lua_setfield(L, -2, "thread_new"); // ... M
2734 2739
2740 // we can't register 'lanes.require' normally because we want to create an upvalued closure
2741 lua_getglobal( L, "require"); // ... M require
2742 lua_pushcclosure( L, LG_require, 1); // ... M lanes.require
2743 lua_setfield( L, -2, "require"); // ... M
2744
2735 lua_pushstring(L, VERSION); // ... M VERSION 2745 lua_pushstring(L, VERSION); // ... M VERSION
2736 lua_setfield(L, -2, "version"); // ... M 2746 lua_setfield(L, -2, "version"); // ... M
2737 2747
@@ -2743,7 +2753,7 @@ LUAG_FUNC( configure)
2743 2753
2744 // register all native functions found in that module in the transferable functions database 2754 // register all native functions found in that module in the transferable functions database
2745 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) 2755 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names)
2746 // for example in package.loaded.lanes.core.* 2756 // for example in package.loaded["lanes.core"].*
2747 populate_func_lookup_table( L, -1, name); 2757 populate_func_lookup_table( L, -1, name);
2748 2758
2749 // record all existing C/JIT-fast functions 2759 // record all existing C/JIT-fast functions
@@ -2768,7 +2778,7 @@ LUAG_FUNC( configure)
2768 static volatile int /*bool*/ go_ahead; // = 0 2778 static volatile int /*bool*/ go_ahead; // = 0
2769 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0) 2779 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
2770 { 2780 {
2771 init_once_LOCKED( L, nbKeepers, on_state_create, shutdown_timeout, track_lanes); 2781 init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes);
2772 go_ahead = 1; // let others pass 2782 go_ahead = 1; // let others pass
2773 } 2783 }
2774 else 2784 else
@@ -2786,7 +2796,7 @@ LUAG_FUNC( configure)
2786 // 2796 //
2787 if( s_initCount == 0) 2797 if( s_initCount == 0)
2788 { 2798 {
2789 init_once_LOCKED( L, nbKeepers, on_state_create, shutdown_timeout, track_lanes); 2799 init_once_LOCKED( L, on_state_create, nbKeepers, shutdown_timeout, track_lanes);
2790 s_initCount = 1; 2800 s_initCount = 1;
2791 } 2801 }
2792 } 2802 }
diff --git a/src/lanes.lua b/src/lanes.lua
index 1d50f97..f4eef81 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -123,9 +123,6 @@ lanes.configure = function( _params)
123 123
124 local set_singlethreaded = assert( core.set_singlethreaded) 124 local set_singlethreaded = assert( core.set_singlethreaded)
125 125
126 local now_secs = assert( core.now_secs)
127 local wakeup_conv = assert( core.wakeup_conv)
128
129 local max_prio = assert( core.max_prio) 126 local max_prio = assert( core.max_prio)
130 127
131lanes.ABOUT= 128lanes.ABOUT=
@@ -311,6 +308,7 @@ local linda = core.linda
311 308
312-- PUBLIC LANES API 309-- PUBLIC LANES API
313local timer = function() error "timers are not active" end 310local timer = function() error "timers are not active" end
311local timer_lane = nil
314local timers = timer 312local timers = timer
315 313
316if _params.with_timers ~= false then 314if _params.with_timers ~= false then
@@ -338,158 +336,161 @@ timer_gateway:set(first_time_key,true)
338-- has 'table' always declared) 336-- has 'table' always declared)
339-- 337--
340if first_time then 338if first_time then
341 local table_remove= assert( table.remove )
342 local table_insert= assert( table.insert )
343 339
344 -- 340 -----
345 -- { [deep_linda_lightuserdata]= { [deep_linda_lightuserdata]=linda_h, 341 -- Snore loop (run as a lane on the background)
346 -- [key]= { wakeup_secs [,period_secs] } [, ...] }, 342 --
347 -- } 343 -- High priority, to get trustworthy timings.
348 -- 344 --
349 -- Collection of all running timers, indexed with linda's & key. 345 -- We let the timer lane be a "free running" thread; no handle to it
350 -- 346 -- remains.
351 -- Note that we need to use the deep lightuserdata identifiers, instead 347 --
352 -- of 'linda_h' themselves as table indices. Otherwise, we'd get multiple 348 local timer_body = function()
353 -- entries for the same timer. 349 -- require lanes.core inside the timer body to prevent pulling now_secs() through an uvpvalue
354 -- 350 local core = require "lanes.core"
355 -- The 'hidden' reference to Linda proxy is used in 'check_timers()' but 351
356 -- also important to keep the Linda alive, even if all outside world threw 352 --
357 -- away pointers to it (which would ruin uniqueness of the deep pointer). 353 -- { [deep_linda_lightuserdata]= { [deep_linda_lightuserdata]=linda_h,
358 -- Now we're safe. 354 -- [key]= { wakeup_secs [,period_secs] } [, ...] },
359 -- 355 -- }
360 local collection= {} 356 --
361 357 -- Collection of all running timers, indexed with linda's & key.
362 local function get_timers() 358 --
363 local r = {} 359 -- Note that we need to use the deep lightuserdata identifiers, instead
364 for deep, t in pairs( collection) do 360 -- of 'linda_h' themselves as table indices. Otherwise, we'd get multiple
365 -- WR( tostring( deep)) 361 -- entries for the same timer.
366 local l = t[deep] 362 --
367 for key, timer_data in pairs( t) do 363 -- The 'hidden' reference to Linda proxy is used in 'check_timers()' but
368 if key ~= deep then 364 -- also important to keep the Linda alive, even if all outside world threw
369 table_insert( r, {l, key, timer_data}) 365 -- away pointers to it (which would ruin uniqueness of the deep pointer).
370 end 366 -- Now we're safe.
371 end 367 --
372 end 368 local collection = {}
373 return r 369 local table_insert = assert( table.insert)
374 end 370
375 -- 371 local get_timers = function()
376 -- set_timer( linda_h, key [,wakeup_at_secs [,period_secs]] ) 372 local r = {}
377 -- 373 for deep, t in pairs( collection) do
378 local function set_timer( linda, key, wakeup_at, period ) 374 -- WR( tostring( deep))
379 assert( wakeup_at==nil or wakeup_at>0.0 ) 375 local l = t[deep]
380 assert( period==nil or period>0.0 ) 376 for key, timer_data in pairs( t) do
377 if key ~= deep then
378 table_insert( r, {l, key, timer_data})
379 end
380 end
381 end
382 return r
383 end -- get_timers()
381 384
382 local linda_deep= linda:deep() 385 --
383 assert( linda_deep ) 386 -- set_timer( linda_h, key [,wakeup_at_secs [,period_secs]] )
387 --
388 local set_timer = function( linda, key, wakeup_at, period)
389 assert( wakeup_at == nil or wakeup_at > 0.0)
390 assert( period == nil or period > 0.0)
384 391
385 -- Find or make a lookup for this timer 392 local linda_deep = linda:deep()
386 -- 393 assert( linda_deep)
387 local t1= collection[linda_deep] 394
388 if not t1 then 395 -- Find or make a lookup for this timer
389 t1= { [linda_deep]= linda } -- proxy to use the Linda 396 --
390 collection[linda_deep]= t1 397 local t1 = collection[linda_deep]
391 end 398 if not t1 then
392 399 t1 = { [linda_deep] = linda} -- proxy to use the Linda
393 if wakeup_at==nil then 400 collection[linda_deep] = t1
394 -- Clear the timer 401 end
395 -- 402
396 t1[key]= nil 403 if wakeup_at == nil then
397 404 -- Clear the timer
398 -- Remove empty tables from collection; speeds timer checks and 405 --
399 -- lets our 'safety reference' proxy be gc:ed as well. 406 t1[key]= nil
400 -- 407
401 local empty= true 408 -- Remove empty tables from collection; speeds timer checks and
402 for k,_ in pairs(t1) do 409 -- lets our 'safety reference' proxy be gc:ed as well.
403 if k~= linda_deep then 410 --
404 empty= false; break 411 local empty = true
405 end 412 for k, _ in pairs( t1) do
406 end 413 if k ~= linda_deep then
407 if empty then 414 empty = false
408 collection[linda_deep]= nil 415 break
409 end 416 end
410 417 end
411 -- Note: any unread timer value is left at 'linda[key]' intensionally; 418 if empty then
412 -- clearing a timer just stops it. 419 collection[linda_deep] = nil
413 else 420 end
414 -- New timer or changing the timings 421
415 -- 422 -- Note: any unread timer value is left at 'linda[key]' intensionally;
416 local t2= t1[key] 423 -- clearing a timer just stops it.
417 if not t2 then 424 else
418 t2= {}; t1[key]= t2 425 -- New timer or changing the timings
419 end 426 --
420 427 local t2 = t1[key]
421 t2[1]= wakeup_at 428 if not t2 then
422 t2[2]= period -- can be 'nil' 429 t2= {}
423 end 430 t1[key]= t2
424 end 431 end
432
433 t2[1] = wakeup_at
434 t2[2] = period -- can be 'nil'
435 end
436 end -- set_timer()
437
438 local now_secs = core.now_secs
439 assert( type( now_secs) == "function")
440 -----
441 -- [next_wakeup_at]= check_timers()
442 -- Check timers, and wake up the ones expired (if any)
443 -- Returns the closest upcoming (remaining) wakeup time (or 'nil' if none).
444 local check_timers = function()
445 local now = now_secs()
446 local next_wakeup
447
448 for linda_deep,t1 in pairs(collection) do
449 for key,t2 in pairs(t1) do
450 --
451 if key==linda_deep then
452 -- no 'continue' in Lua :/
453 else
454 -- 't2': { wakeup_at_secs [,period_secs] }
455 --
456 local wakeup_at= t2[1]
457 local period= t2[2] -- may be 'nil'
458
459 if wakeup_at <= now then
460 local linda= t1[linda_deep]
461 assert(linda)
462
463 linda:set( key, now )
464
465 -- 'pairs()' allows the values to be modified (and even
466 -- removed) as far as keys are not touched
467
468 if not period then
469 -- one-time timer; gone
470 --
471 t1[key]= nil
472 wakeup_at= nil -- no 'continue' in Lua :/
473 else
474 -- repeating timer; find next wakeup (may jump multiple repeats)
475 --
476 repeat
477 wakeup_at= wakeup_at+period
478 until wakeup_at > now
479
480 t2[1]= wakeup_at
481 end
482 end
483
484 if wakeup_at and ((not next_wakeup) or (wakeup_at < next_wakeup)) then
485 next_wakeup= wakeup_at
486 end
487 end
488 end -- t2 loop
489 end -- t1 loop
490
491 return next_wakeup -- may be 'nil'
492 end -- check_timers()
425 493
426 -----
427 -- [next_wakeup_at]= check_timers()
428 --
429 -- Check timers, and wake up the ones expired (if any)
430 --
431 -- Returns the closest upcoming (remaining) wakeup time (or 'nil' if none).
432 --
433 local function check_timers()
434
435 local now= now_secs()
436 local next_wakeup
437
438 for linda_deep,t1 in pairs(collection) do
439 for key,t2 in pairs(t1) do
440 --
441 if key==linda_deep then
442 -- no 'continue' in Lua :/
443 else
444 -- 't2': { wakeup_at_secs [,period_secs] }
445 --
446 local wakeup_at= t2[1]
447 local period= t2[2] -- may be 'nil'
448
449 if wakeup_at <= now then
450 local linda= t1[linda_deep]
451 assert(linda)
452
453 linda:set( key, now )
454
455 -- 'pairs()' allows the values to be modified (and even
456 -- removed) as far as keys are not touched
457
458 if not period then
459 -- one-time timer; gone
460 --
461 t1[key]= nil
462 wakeup_at= nil -- no 'continue' in Lua :/
463 else
464 -- repeating timer; find next wakeup (may jump multiple repeats)
465 --
466 repeat
467 wakeup_at= wakeup_at+period
468 until wakeup_at > now
469
470 t2[1]= wakeup_at
471 end
472 end
473
474 if wakeup_at and ((not next_wakeup) or (wakeup_at < next_wakeup)) then
475 next_wakeup= wakeup_at
476 end
477 end
478 end -- t2 loop
479 end -- t1 loop
480
481 return next_wakeup -- may be 'nil'
482 end
483
484 -----
485 -- Snore loop (run as a lane on the background)
486 --
487 -- High priority, to get trustworthy timings.
488 --
489 -- We let the timer lane be a "free running" thread; no handle to it
490 -- remains.
491 --
492 local timer_body = function()
493 local timer_gateway_batched = timer_gateway.batched 494 local timer_gateway_batched = timer_gateway.batched
494 set_debug_threadname( "LanesTimer") 495 set_debug_threadname( "LanesTimer")
495 set_finalizer( function( err, stk) 496 set_finalizer( function( err, stk)
@@ -502,7 +503,7 @@ if first_time then
502 end 503 end
503 end) 504 end)
504 while true do 505 while true do
505 local next_wakeup= check_timers() 506 local next_wakeup = check_timers()
506 507
507 -- Sleep until next timer to wake up, or a set/clear command 508 -- Sleep until next timer to wake up, or a set/clear command
508 -- 509 --
@@ -528,9 +529,9 @@ if first_time then
528 -- WR( "timer lane: no linda, aborted?") 529 -- WR( "timer lane: no linda, aborted?")
529 end 530 end
530 end 531 end
531 end 532 end -- timer_body()
532 gen( "*", { package= {}, priority = max_prio}, timer_body)() -- "*" instead of "io,package" for LuaJIT compatibility... 533 timer_lane = gen( "*", { package= {}, priority = max_prio}, timer_body)() -- "*" instead of "io,package" for LuaJIT compatibility...
533end 534end -- first_time
534 535
535----- 536-----
536-- = timer( linda_h, key_val, date_tbl|first_secs [,period_secs] ) 537-- = timer( linda_h, key_val, date_tbl|first_secs [,period_secs] )
@@ -540,13 +541,13 @@ timer = function( linda, key, a, period )
540 if getmetatable( linda) ~= "Linda" then 541 if getmetatable( linda) ~= "Linda" then
541 error "expecting a Linda" 542 error "expecting a Linda"
542 end 543 end
543 if a==0.0 then 544 if a == 0.0 then
544 -- Caller expects to get current time stamp in Linda, on return 545 -- Caller expects to get current time stamp in Linda, on return
545 -- (like the timer had expired instantly); it would be good to set this 546 -- (like the timer had expired instantly); it would be good to set this
546 -- as late as possible (to give most current time) but also we want it 547 -- as late as possible (to give most current time) but also we want it
547 -- to precede any possible timers that might start striking. 548 -- to precede any possible timers that might start striking.
548 -- 549 --
549 linda:set( key, now_secs() ) 550 linda:set( key, core.now_secs())
550 551
551 if not period or period==0.0 then 552 if not period or period==0.0 then
552 timer_gateway:send( TGW_KEY, linda, key, nil, nil ) -- clear the timer 553 timer_gateway:send( TGW_KEY, linda, key, nil, nil ) -- clear the timer
@@ -555,8 +556,8 @@ timer = function( linda, key, a, period )
555 a= period 556 a= period
556 end 557 end
557 558
558 local wakeup_at= type(a)=="table" and wakeup_conv(a) -- given point of time 559 local wakeup_at= type(a)=="table" and core.wakeup_conv(a) -- given point of time
559 or (a and now_secs()+a or nil) 560 or (a and core.now_secs()+a or nil)
560 -- queue to timer 561 -- queue to timer
561 -- 562 --
562 timer_gateway:send( TGW_KEY, linda, key, wakeup_at, period ) 563 timer_gateway:send( TGW_KEY, linda, key, wakeup_at, period )
@@ -639,15 +640,17 @@ local function genatomic( linda, key, initial_val )
639end 640end
640 641
641 -- activate full interface 642 -- activate full interface
643 lanes.require = core.require
642 lanes.gen = gen 644 lanes.gen = gen
643 lanes.linda = core.linda 645 lanes.linda = core.linda
644 lanes.cancel_error = core.cancel_error 646 lanes.cancel_error = core.cancel_error
645 lanes.nameof = core.nameof 647 lanes.nameof = core.nameof
646 lanes.threads = (_params.track_lanes and core.threads) and core.threads or function() error "lane tracking is not available" end 648 lanes.threads = (_params.track_lanes and core.threads) and core.threads or function() error "lane tracking is not available" end
647 lanes.timer = timer 649 lanes.timer = timer
650 lanes.timer_lane = timer_lane
648 lanes.timers = timers 651 lanes.timers = timers
649 lanes.genlock = genlock 652 lanes.genlock = genlock
650 lanes.now_secs = now_secs 653 lanes.now_secs = core.now_secs
651 lanes.genatomic = genatomic 654 lanes.genatomic = genatomic
652 -- from now on, calling configure does nothing but checking that we don't call it with parameters that changed compared to the first invocation 655 -- from now on, calling configure does nothing but checking that we don't call it with parameters that changed compared to the first invocation
653 lanes.configure = function( _params2) 656 lanes.configure = function( _params2)
diff --git a/src/tools.c b/src/tools.c
index 552e61e..9961c1a 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -224,7 +224,7 @@ static char const* luaG_pushFQN(lua_State *L, int t, int last)
224 { 224 {
225 lua_rawgeti( L, t, i); 225 lua_rawgeti( L, t, i);
226 luaL_addvalue( &b); 226 luaL_addvalue( &b);
227 luaL_addlstring(&b, ".", 1); 227 luaL_addlstring(&b, "/", 1);
228 } 228 }
229 if( i == last) // add last value (if interval was not empty) 229 if( i == last) // add last value (if interval was not empty)
230 { 230 {
@@ -250,9 +250,16 @@ static void populate_func_lookup_table_recur( lua_State* L, int _ctx_base, int _
250 int const breadth_first_cache = lua_gettop( L) + 1; 250 int const breadth_first_cache = lua_gettop( L) + 1;
251 251
252 STACK_GROW( L, 6); 252 STACK_GROW( L, 6);
253 // slot _i contains a table where we search for functions 253 // slot _i contains a table where we search for functions (or a full userdata with a metatable)
254 STACK_CHECK( L); // ... {_i} 254 STACK_CHECK( L); // ... {_i}
255 255
256 // if object is a userdata, replace it by its metatable
257 if( lua_type( L, _i) == LUA_TUSERDATA)
258 {
259 lua_getmetatable( L, _i); // ... {_i} mt
260 lua_replace( L, _i); // ... {_i}
261 }
262
256 // if table is already visited, we are done 263 // if table is already visited, we are done
257 lua_pushvalue( L, _i); // ... {_i} {} 264 lua_pushvalue( L, _i); // ... {_i} {}
258 lua_rawget( L, cache); // ... {_i} nil|n 265 lua_rawget( L, cache); // ... {_i} nil|n
@@ -437,7 +444,7 @@ void populate_func_lookup_table( lua_State* L, int _i, char const* _name)
437* 444*
438*/ 445*/
439 446
440lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_state_create) 447lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs)
441{ 448{
442 // reuse alloc function from the originating state 449 // reuse alloc function from the originating state
443 void* allocUD; 450 void* allocUD;
@@ -450,7 +457,7 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_
450 } 457 }
451 458
452 // neither libs (not even 'base') nor special init func: we are done 459 // neither libs (not even 'base') nor special init func: we are done
453 if( !libs && !_on_state_create) 460 if( libs == NULL && _on_state_create <= 0)
454 { 461 {
455 return L; 462 return L;
456 } 463 }
@@ -460,13 +467,6 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_
460 467
461 STACK_GROW( L, 2); 468 STACK_GROW( L, 2);
462 STACK_CHECK( L); 469 STACK_CHECK( L);
463 if( _on_state_create)
464 {
465 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END));
466 lua_pushcfunction( L, _on_state_create);
467 lua_call( L, 0, 0);
468 }
469
470 // 'lua.c' stops GC during initialization so perhaps its a good idea. :) 470 // 'lua.c' stops GC during initialization so perhaps its a good idea. :)
471 // but do it after _on_state_create in case it does a lot of stuff... 471 // but do it after _on_state_create in case it does a lot of stuff...
472 lua_gc( L, LUA_GCSTOP, 0); 472 lua_gc( L, LUA_GCSTOP, 0);
@@ -520,7 +520,29 @@ lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_
520 lua_gc( L, LUA_GCRESTART, 0); 520 lua_gc( L, LUA_GCRESTART, 0);
521 521
522 STACK_CHECK( L); 522 STACK_CHECK( L);
523 // after opening base, register the functions it exported in our name<->function database 523 // call this after the base libraries are loaded!
524 if( _on_state_create > 0)
525 {
526 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END));
527 if( lua_iscfunction( _from, _on_state_create))
528 {
529 // C function: recreate a closure in the new state, bypassing the lookup scheme
530 lua_CFunction osc = lua_tocfunction( _from, _on_state_create);
531 lua_pushcfunction( L, osc);
532 }
533 else
534 {
535 STACK_CHECK( _from);
536 // Lua function: transfer as usual (should work as long as it only uses base libraries)
537 lua_pushvalue( _from, _on_state_create);
538 luaG_inter_move( _from, L, 1);
539 STACK_END( _from, 0);
540 }
541 lua_call( L, 0, 0);
542 STACK_MID( L, 0);
543 }
544
545 // after all this, register everything we find in our name<->function database
524 lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack 546 lua_pushglobaltable( L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
525 populate_func_lookup_table( L, -1, NULL); 547 populate_func_lookup_table( L, -1, NULL);
526 lua_pop( L, 1); 548 lua_pop( L, 1);
@@ -1180,9 +1202,9 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1180 1202
1181static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i) 1203static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i)
1182{ 1204{
1183 void * const aspointer = (void*)lua_topointer( L, i); 1205 void* const aspointer = (void*)lua_topointer( L, i);
1184 // TBD: Merge this and same code for tables 1206 // TBD: Merge this and same code for tables
1185 ASSERT_L( L2_cache_i != 0 ); 1207 ASSERT_L( L2_cache_i != 0);
1186 1208
1187 STACK_GROW( L2, 2); 1209 STACK_GROW( L2, 2);
1188 1210
@@ -1199,8 +1221,8 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui
1199 1221
1200 //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); 1222 //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) );
1201 1223
1202 lua_pushvalue( L2, -1 ); // ... {cache} ... p p 1224 lua_pushvalue( L2, -1); // ... {cache} ... p p
1203 lua_rawget( L2, L2_cache_i ); // ... {cache} ... p function|nil|true 1225 lua_rawget( L2, L2_cache_i); // ... {cache} ... p function|nil|true
1204 1226
1205 if( lua_isnil(L2,-1)) // function is unknown 1227 if( lua_isnil(L2,-1)) // function is unknown
1206 { 1228 {
@@ -1209,7 +1231,7 @@ static void push_cached_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, ui
1209 // Set to 'true' for the duration of creation; need to find self-references 1231 // Set to 'true' for the duration of creation; need to find self-references
1210 // via upvalues 1232 // via upvalues
1211 // 1233 //
1212 // pushes a copy of the func, a stores a reference in the cache 1234 // pushes a copy of the func, stores a reference in the cache
1213 inter_copy_func( L2, L2_cache_i, L, i); // ... {cache} ... function 1235 inter_copy_func( L2, L2_cache_i, L, i); // ... {cache} ... function
1214 } 1236 }
1215 else // found function in the cache 1237 else // found function in the cache
@@ -1426,7 +1448,9 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1426 // if already on top of the stack, no need to push again 1448 // if already on top of the stack, no need to push again
1427 int needToPush = (i != (uint_t)lua_gettop( L)); 1449 int needToPush = (i != (uint_t)lua_gettop( L));
1428 if( needToPush) 1450 if( needToPush)
1451 {
1429 lua_pushvalue( L, i); // ... f 1452 lua_pushvalue( L, i); // ... f
1453 }
1430 1454
1431 luaL_buffinit( L, &b); 1455 luaL_buffinit( L, &b);
1432 // 1456 //
@@ -1568,11 +1592,11 @@ static void inter_copy_func( lua_State* L2, uint_t L2_cache_i, lua_State* L, uin
1568* 1592*
1569* Returns TRUE if value was pushed, FALSE if its type is non-supported. 1593* Returns TRUE if value was pushed, FALSE if its type is non-supported.
1570*/ 1594*/
1571static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i, enum e_vt vt ) 1595static bool_t inter_copy_one_( lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, enum e_vt vt)
1572{ 1596{
1573 bool_t ret= TRUE; 1597 bool_t ret = TRUE;
1574 1598
1575 STACK_GROW( L2, 1 ); 1599 STACK_GROW( L2, 1);
1576 1600
1577 STACK_CHECK( L2); 1601 STACK_CHECK( L2);
1578 1602
@@ -1626,6 +1650,7 @@ static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, u
1626 } 1650 }
1627 /* Allow only deep userdata entities to be copied across 1651 /* Allow only deep userdata entities to be copied across
1628 */ 1652 */
1653 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "USERDATA\n" INDENT_END));
1629 if( !luaG_copydeep( L, L2, i)) 1654 if( !luaG_copydeep( L, L2, i))
1630 { 1655 {
1631 // Cannot copy it full; copy as light userdata 1656 // Cannot copy it full; copy as light userdata
@@ -1669,7 +1694,6 @@ static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, u
1669#endif 1694#endif
1670 STACK_CHECK( L2); 1695 STACK_CHECK( L2);
1671 push_cached_func( L2, L2_cache_i, L, i); 1696 push_cached_func( L2, L2_cache_i, L, i);
1672 ASSERT_L( lua_isfunction( L2, -1));
1673 STACK_END( L2, 1); 1697 STACK_END( L2, 1);
1674 } 1698 }
1675 break; 1699 break;
@@ -1827,7 +1851,7 @@ static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, u
1827* 1851*
1828* Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'. 1852* Note: Parameters are in this order ('L' = from first) to be same as 'lua_xmove'.
1829*/ 1853*/
1830int luaG_inter_copy( lua_State* L, lua_State *L2, uint_t n) 1854int luaG_inter_copy( lua_State* L, lua_State* L2, uint_t n)
1831{ 1855{
1832 uint_t top_L = lua_gettop( L); 1856 uint_t top_L = lua_gettop( L);
1833 uint_t top_L2 = lua_gettop( L2); 1857 uint_t top_L2 = lua_gettop( L2);
@@ -1903,7 +1927,9 @@ void luaG_inter_copy_package( lua_State* L, lua_State* L2, int _idx)
1903 { 1927 {
1904 int i; 1928 int i;
1905 // package.loaders is renamed package.searchers in Lua 5.2 1929 // package.loaders is renamed package.searchers in Lua 5.2
1906 char const* entries[] = { "path", "cpath", "preload", (LUA_VERSION_NUM == 501) ? "loaders" : "searchers", NULL}; 1930 // but don't copy it anyway, as the function names change depending on the slot index!
1931 // users should provide an on_state_create function to setup custom loaders instead
1932 char const* entries[] = { "path", "cpath", "preload"/*, (LUA_VERSION_NUM == 501) ? "loaders" : "searchers"*/, NULL};
1907 for( i = 0; entries[i]; ++ i) 1933 for( i = 0; entries[i]; ++ i)
1908 { 1934 {
1909 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i])); 1935 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s\n" INDENT_END, entries[i]));
@@ -1944,7 +1970,7 @@ MUTEX_T require_cs;
1944// 1970//
1945// Upvalues: [1]: original 'require' function 1971// Upvalues: [1]: original 'require' function
1946// 1972//
1947static int new_require( lua_State *L) 1973int luaG_new_require( lua_State* L)
1948{ 1974{
1949 int rc, i; 1975 int rc, i;
1950 int args = lua_gettop( L); 1976 int args = lua_gettop( L);
@@ -1955,24 +1981,24 @@ static int new_require( lua_State *L)
1955 1981
1956 lua_pushvalue( L, lua_upvalueindex(1)); 1982 lua_pushvalue( L, lua_upvalueindex(1));
1957 for( i = 1; i <= args; ++ i) 1983 for( i = 1; i <= args; ++ i)
1984 {
1958 lua_pushvalue( L, i); 1985 lua_pushvalue( L, i);
1986 }
1959 1987
1960 // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would 1988 // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would
1961 // leave us locked, blocking any future 'require' calls from other lanes. 1989 // leave us locked, blocking any future 'require' calls from other lanes.
1962 // 1990 //
1963 MUTEX_LOCK( &require_cs); 1991 MUTEX_LOCK( &require_cs);
1964 { 1992 rc = lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ );
1965 rc = lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ );
1966 //
1967 // LUA_ERRRUN / LUA_ERRMEM
1968 }
1969 MUTEX_UNLOCK( &require_cs); 1993 MUTEX_UNLOCK( &require_cs);
1970 1994
1971 // the required module (or an error message) is left on the stack as returned value by original require function 1995 // the required module (or an error message) is left on the stack as returned value by original require function
1972 STACK_END( L, 1); 1996 STACK_END( L, 1);
1973 1997
1974 if (rc) 1998 if( rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ?
1975 lua_error(L); // error message already at [-1] 1999 {
2000 return lua_error( L); // error message already at [-1]
2001 }
1976 2002
1977 return 1; 2003 return 1;
1978} 2004}
@@ -1980,7 +2006,7 @@ static int new_require( lua_State *L)
1980/* 2006/*
1981* Serialize calls to 'require', if it exists 2007* Serialize calls to 'require', if it exists
1982*/ 2008*/
1983void serialize_require( lua_State *L ) 2009void serialize_require( lua_State* L)
1984{ 2010{
1985 STACK_GROW( L, 1); 2011 STACK_GROW( L, 1);
1986 STACK_CHECK( L); 2012 STACK_CHECK( L);
@@ -1991,7 +2017,7 @@ void serialize_require( lua_State *L )
1991 if( lua_isfunction( L, -1)) 2017 if( lua_isfunction( L, -1))
1992 { 2018 {
1993 // [-1]: original 'require' function 2019 // [-1]: original 'require' function
1994 lua_pushcclosure( L, new_require, 1 /*upvalues*/); 2020 lua_pushcclosure( L, luaG_new_require, 1 /*upvalues*/);
1995 lua_setglobal( L, "require"); 2021 lua_setglobal( L, "require");
1996 } 2022 }
1997 else 2023 else
diff --git a/src/tools.h b/src/tools.h
index f79d2ad..a06e23f 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -78,11 +78,9 @@ extern int debugspew_indent_depth;
78#define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d)) 78#define luaG_optunsigned(L,i,d) ((uint_t) luaL_optinteger(L,i,d))
79#define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i)) 79#define luaG_tounsigned(L,i) ((uint_t) lua_tointeger(L,i))
80 80
81#define luaG_isany(L,i) (!lua_isnil(L,i))
82
83void luaG_dump( lua_State* L ); 81void luaG_dump( lua_State* L );
84 82
85lua_State* luaG_newstate( lua_State* _from, char const* libs, lua_CFunction _on_state_create); 83lua_State* luaG_newstate( lua_State* _from, int const _on_state_create, char const* libs);
86 84
87typedef struct { 85typedef struct {
88 volatile int refcount; 86 volatile int refcount;
@@ -96,6 +94,7 @@ int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n);
96int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n); 94int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n);
97 95
98int luaG_nameof( lua_State* L); 96int luaG_nameof( lua_State* L);
97int luaG_new_require( lua_State* L);
99 98
100// Lock for reference counter inc/dec locks (to be initialized by outside code) 99// Lock for reference counter inc/dec locks (to be initialized by outside code)
101// 100//
diff --git a/tests/fibonacci.lua b/tests/fibonacci.lua
index 48cd8d7..a5e0b2a 100644
--- a/tests/fibonacci.lua
+++ b/tests/fibonacci.lua
@@ -28,6 +28,7 @@ local KNOWN= { [0]=0, 1,1,2,3,5,8,13,21,34,55,89,144 }
28-- uint= fib( n_uint ) 28-- uint= fib( n_uint )
29-- 29--
30local function fib( n ) 30local function fib( n )
31 --local lanes = require"lanes".configure()
31 -- 32 --
32 local sum 33 local sum
33 local floor= assert(math.floor) 34 local floor= assert(math.floor)
@@ -39,9 +40,11 @@ local function fib( n )
39 else 40 else
40 -- Splits into two; this task remains waiting for the results 41 -- Splits into two; this task remains waiting for the results
41 -- 42 --
42 -- note that lanes is pulled in as upvalue, so we need package library to require internals properly 43 -- note that lanes is pulled in by upvalue, so we need lanes.core to be available
43 -- (because lua51-lanes is always required internally if possible, which is necessary in that case) 44 -- the other solution is to require "lanes" from inside the lane body, as in:
44 local gen_f= lanes.gen( "*", fib ) 45 -- local lanes = require"lanes".configure()
46 -- local gen_f= lanes.gen( "*", fib)
47 local gen_f= lanes.gen( "*", {required={"lanes.core"}}, fib)
45 48
46 local n1=floor(n/2) +1 49 local n1=floor(n/2) +1
47 local n2=floor(n/2) -1 + n%2 50 local n2=floor(n/2) -1 + n%2
diff --git a/tests/package.lua b/tests/package.lua
new file mode 100644
index 0000000..7c72d35
--- /dev/null
+++ b/tests/package.lua
@@ -0,0 +1,20 @@
1assert(nil == package.loaders[5])
2
3local configure_loaders = function()
4 table.insert(package.loaders, 4, function() end)
5 assert(package.loaders[1])
6 assert(package.loaders[2])
7 assert(package.loaders[3])
8 assert(package.loaders[4])
9 assert(package.loaders[5])
10 print "loaders configured!"
11end
12
13configure_loaders()
14
15for k,v in pairs(package.loaders) do
16 print( k, type(v))
17end
18
19lanes = require "lanes"
20lanes.configure{with_timers=false, on_state_create = configure_loaders} \ No newline at end of file
diff --git a/tests/pingpong.lua b/tests/pingpong.lua
new file mode 100644
index 0000000..30cd360
--- /dev/null
+++ b/tests/pingpong.lua
@@ -0,0 +1,31 @@
1local lanes = require 'lanes'.configure()
2local q = lanes.linda()
3
4local pingpong = function(name, qr, qs, start)
5 print("start " .. name, qr, qs, start)
6 local count = 0
7 if start then
8 print(name .. ": sending " .. qs .. " 0")
9 q:send(qs, 0)
10 end
11 while count < 10 do
12 print(name .. ": receiving " .. qr)
13 local key, val = q:receive(qr)
14 if val == nil then
15 print(name .. ": timeout")
16 break
17 end
18 print(name .. ":" .. val)
19 val = val + 1
20 print(name .. ": sending " .. qs .. " " .. tostring(val + 1))
21 q:send(qs, val)
22 count = count + 1
23 end
24end
25
26-- pingpong("L1", '0', '1', true)
27local t1, err1 = lanes.gen("*", pingpong)("L1", 'a', 'b', true)
28local t2, err2 = lanes.gen("*", pingpong)("L2", 'b', 'a', false)
29
30t1:join()
31t2:join() \ No newline at end of file
diff --git a/tests/timer.lua b/tests/timer.lua
index 953e4ed..805d85c 100644
--- a/tests/timer.lua
+++ b/tests/timer.lua
@@ -8,8 +8,7 @@
8io.stderr:setvbuf "no" 8io.stderr:setvbuf "no"
9 9
10 10
11local lanes = require "lanes" 11local lanes = require "lanes".configure()
12lanes.configure()
13 12
14local linda= lanes.linda() 13local linda= lanes.linda()
15 14
@@ -101,3 +100,5 @@ PRINT "...making sure no ticks are coming..."
101local k,v= linda:receive( 10, T1,T2 ) -- should not get any 100local k,v= linda:receive( 10, T1,T2 ) -- should not get any
102assert(v==nil) 101assert(v==nil)
103 102
103lanes.timer_lane:cancel()
104print (lanes.timer_lane[1], lanes.timer_lane[2]) \ No newline at end of file