aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2021-06-16 18:41:14 +0200
committerBenoit Germain <bnt.germain@gmail.com>2021-06-16 18:41:14 +0200
commit5875fe44ba7a240dd101f954c7dc83337a0c2cef (patch)
tree5c53b56b750c135163d462a39217fb88f8741ed6
parent21b2ac762ff8a5926872963aa2fd8feeb1bf3b39 (diff)
downloadlanes-5875fe44ba7a240dd101f954c7dc83337a0c2cef.tar.gz
lanes-5875fe44ba7a240dd101f954c7dc83337a0c2cef.tar.bz2
lanes-5875fe44ba7a240dd101f954c7dc83337a0c2cef.zip
changed lanes.threads() output so that several lanes with the same name don't clobber each other in the result table
In the original implementations, the debug name was used as key, which meant that several lanes using the same name would cause only the oldest non-collected one to be listed in the results. Now the result is an array of tuples.
-rw-r--r--CHANGES22
-rw-r--r--docs/index.html38
-rw-r--r--src/lanes.c45
-rw-r--r--src/lanes.h2
-rw-r--r--tests/track_lanes.lua72
5 files changed, 130 insertions, 49 deletions
diff --git a/CHANGES b/CHANGES
index 2b381bd..c3893d0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 147: BGe 16-Jun-21
4 * changed lanes.threads() output so that several lanes with the same name don't clobber each other in the result table
5 * bumped version to 3.15 because of the API change
6
3CHANGE 146: BGe 26-Apr-19 7CHANGE 146: BGe 26-Apr-19
4 * lane:cancel() rework (see doc). 8 * lane:cancel() rework (see doc).
5 * opt.cancelstep is gone, hook is installed by lane:cancel() if requested 9 * opt.cancelstep is gone, hook is installed by lane:cancel() if requested
@@ -662,15 +666,15 @@ CHANGE 6 (bug fix) AKa 15-Oct-2008:
662 Added local caches of the following to src/lanes.lua (was otherwise getting 666 Added local caches of the following to src/lanes.lua (was otherwise getting
663 errors at least in 'tests/irayo_recursive.lua'). 667 errors at least in 'tests/irayo_recursive.lua').
664 668
665 local assert= assert 669 local assert= assert
666 local string_gmatch= assert( string.gmatch ) 670 local string_gmatch= assert( string.gmatch )
667 local select= assert( select ) 671 local select= assert( select )
668 local type= assert( type ) 672 local type= assert( type )
669 local pairs= assert( pairs ) 673 local pairs= assert( pairs )
670 local tostring= assert( tostring ) 674 local tostring= assert( tostring )
671 local error= assert( error ) 675 local error= assert( error )
672 local setmetatable= assert( setmetatable ) 676 local setmetatable= assert( setmetatable )
673 local rawget= assert( rawget ) 677 local rawget= assert( rawget )
674 678
675 Thanks to Irayo for detecting and reporting this. 679 Thanks to Irayo for detecting and reporting this.
676 680
diff --git a/docs/index.html b/docs/index.html
index 0b19223..49b862f 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,6 +1,6 @@
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2<!-- 2<!--
3 Documentation for Lua Lanes 3 Documentation for Lua Lanes
4--> 4-->
5 5
6<html> 6<html>
@@ -85,13 +85,13 @@
85 Lua Lanes is a Lua extension library providing the possibility to run multiple Lua states in parallel. It is intended to be used for optimizing performance on multicore CPU's and to study ways to make Lua programs naturally parallel to begin with. 85 Lua Lanes is a Lua extension library providing the possibility to run multiple Lua states in parallel. It is intended to be used for optimizing performance on multicore CPU's and to study ways to make Lua programs naturally parallel to begin with.
86</p> 86</p>
87<p> 87<p>
88 Lanes is included into your software by the regular <tt>require "lanes"</tt> method. No C side programming is needed; all APIs are Lua side, and most existing extension modules should work seamlessly together with the multiple lanes. 88 Lanes is included into your software by the regular <tt>require "lanes"</tt> method. No C side programming is needed; all APIs are Lua side, and most existing extension modules should work seamlessly together with the multiple lanes.
89</p> 89</p>
90<p> 90<p>
91 Starting with version 3.1.6, Lanes should build and run identically with either Lua 5.1 or Lua 5.2. Version 3.10.0 supports Lua 5.3. 91 Starting with version 3.1.6, Lanes should build and run identically with either Lua 5.1 or Lua 5.2. Version 3.10.0 supports Lua 5.3.
92</p> 92</p>
93<p> 93<p>
94 See <A HREF="comparison.html">comparison</A> of Lua Lanes with other Lua multithreading solutions. 94 See <A HREF="comparison.html">comparison</A> of Lua Lanes with other Lua multithreading solutions.
95</p> 95</p>
96<p> 96<p>
97 <h3>Features:</h3> 97 <h3>Features:</h3>
@@ -134,11 +134,11 @@
134 <li>Openwrt (15.05 and later)</li> 134 <li>Openwrt (15.05 and later)</li>
135 <li>Windows 2000/XP and later <font size="-1">(MinGW or Visual C++ 2005/2008)</font></li> 135 <li>Windows 2000/XP and later <font size="-1">(MinGW or Visual C++ 2005/2008)</font></li>
136<!-- 136<!--
137 Other OS'es here once people help test them. (and the tester's name) 137 Other OS'es here once people help test them. (and the tester's name)
138 138
139 Win64, BSD, Linux x64, Linux embedded, QNX, Solaris, ... 139 Win64, BSD, Linux x64, Linux embedded, QNX, Solaris, ...
140--> 140-->
141 </ul> 141 </ul>
142 142
143</p> 143</p>
144<p> 144<p>
@@ -843,7 +843,7 @@
843 <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> 843 <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%">
844 <tr> 844 <tr>
845 <td> 845 <td>
846 <pre> {}|nil = lanes.threads()</pre> 846 <pre> {{name = "name", status = "status", ...}|nil = lanes.threads()</pre>
847 </td> 847 </td>
848 </tr> 848 </tr>
849 </table> 849 </table>
@@ -851,7 +851,7 @@
851<p> 851<p>
852 Only available if lane tracking feature is compiled (see <tt>HAVE_LANE_TRACKING</tt> in <tt>lanes.c</tt>) and <a href="#track_lanes"><tt>track_lanes</tt></a> is set. 852 Only available if lane tracking feature is compiled (see <tt>HAVE_LANE_TRACKING</tt> in <tt>lanes.c</tt>) and <a href="#track_lanes"><tt>track_lanes</tt></a> is set.
853 <br/> 853 <br/>
854 Returns a table where keys are a lane's name and values are the lane's status. Returns <tt>nil</tt> if no lane is running. 854 Returns an array table where each entry is a table containing a lane's name and status. Returns <tt>nil</tt> if no lane is running.
855</p> 855</p>
856 856
857 857
@@ -891,7 +891,7 @@
891</p> 891</p>
892 892
893<p> 893<p>
894 <tt>stack_tbl</tt> is a table describing where the error was thrown. 894<tt>stack_tbl</tt> is a table describing where the error was thrown.
895 <br/> 895 <br/>
896 In <tt>"extended"</tt> mode, <tt>stack_tbl</tt> is an array of tables containing info gathered with <tt>lua_getinfo()</tt> (<tt>"source"</tt>,<tt>"currentline"</tt>,<tt>"name"</tt>,<tt>"namewhat"</tt>,<tt>"what"</tt>). 896 In <tt>"extended"</tt> mode, <tt>stack_tbl</tt> is an array of tables containing info gathered with <tt>lua_getinfo()</tt> (<tt>"source"</tt>,<tt>"currentline"</tt>,<tt>"name"</tt>,<tt>"namewhat"</tt>,<tt>"what"</tt>).
897 <br/> 897 <br/>
@@ -1434,7 +1434,7 @@ events to a common Linda, but... :).</font>
1434 </ul> 1434 </ul>
1435 </li> 1435 </li>
1436 <li>Coroutines cannot be passed. A coroutine's Lua state is tied to the Lua state that created it, and there is no way the mixed C/Lua stack of a coroutine can be transfered from one Lua state to another.</li> 1436 <li>Coroutines cannot be passed. A coroutine's Lua state is tied to the Lua state that created it, and there is no way the mixed C/Lua stack of a coroutine can be transfered from one Lua state to another.</li>
1437 <li>Starting with version 3.10.1, if the metatable contains <tt>__lanesignore</tt>, the object is skipped and <tt>nil</tt> is transfered instead.</li> 1437 <li>Starting with version 3.10.1, if the metatable contains <tt>__lanesignore</tt>, the object is skipped and <tt>nil</tt> is transfered instead.</li>
1438 </ul> 1438 </ul>
1439</p> 1439</p>
1440 1440
@@ -1575,7 +1575,7 @@ static int clonable_lanesclone( lua_State* L)
1575</p> 1575</p>
1576 1576
1577<p> 1577<p>
1578 <b>NOTE</b>: In the event the source userdata has uservalues, it is not necessary to create them for the clone, Lanes will handle their cloning.<br/> 1578 <b>NOTE</b>: In the event the source userdata has uservalues, it is not necessary to create them for the clone, Lanes will handle their cloning.<br/>
1579 Of course, more complex objects may require smarter cloning behavior than a simple <tt>memcpy</tt>. Also, the module initialisation code should make each metatable accessible from the module table itself as in: 1579 Of course, more complex objects may require smarter cloning behavior than a simple <tt>memcpy</tt>. Also, the module initialisation code should make each metatable accessible from the module table itself as in:
1580<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> 1580<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre>
1581int luaopen_deep_test(lua_State* L) 1581int luaopen_deep_test(lua_State* L)
@@ -1645,13 +1645,13 @@ int luaD_new_clonable( lua_State* L)
1645</p> 1645</p>
1646 1646
1647<p> 1647<p>
1648 Deep userdata in transit inside keeper states (sent in a linda but not yet consumed) don't call <tt>idfunc(eDO_delete)</tt> and aren't considered by reference counting. The rationale is the following: 1648 Deep userdata in transit inside keeper states (sent in a linda but not yet consumed) don't call <tt>idfunc(eDO_delete)</tt> and aren't considered by reference counting. The rationale is the following:
1649 <br /> 1649 <br />
1650 If some non-keeper state holds a deep userdata for some deep object, then even if the keeper collects its own deep userdata, it shouldn't be cleaned up since the refcount is not 0. 1650 If some non-keeper state holds a deep userdata for some deep object, then even if the keeper collects its own deep userdata, it shouldn't be cleaned up since the refcount is not 0.
1651 <br /> 1651 <br />
1652 OTOH, if a keeper state holds the last deep userdata for some deep object, then no lane can do actual work with it. Deep userdata's <tt>idfunc()</tt> is never called from a keeper state. 1652 OTOH, if a keeper state holds the last deep userdata for some deep object, then no lane can do actual work with it. Deep userdata's <tt>idfunc()</tt> is never called from a keeper state.
1653 <br /> 1653 <br />
1654 Therefore, Lanes can just call <tt>idfunc(eDO_delete)</tt> when the last non-keeper-held deep userdata is collected, as long as it doesn't do the same in a keeper state after that, since any remaining deep userdata in keeper states now hold stale pointers. 1654 Therefore, Lanes can just call <tt>idfunc(eDO_delete)</tt> when the last non-keeper-held deep userdata is collected, as long as it doesn't do the same in a keeper state after that, since any remaining deep userdata in keeper states now hold stale pointers.
1655</p> 1655</p>
1656 1656
1657<p> 1657<p>
diff --git a/src/lanes.c b/src/lanes.c
index 8f159a9..f3fdc76 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -1652,26 +1652,31 @@ LUAG_FUNC( thread_index)
1652// Return a list of all known lanes 1652// Return a list of all known lanes
1653LUAG_FUNC( threads) 1653LUAG_FUNC( threads)
1654{ 1654{
1655 int const top = lua_gettop( L); 1655 int const top = lua_gettop( L);
1656 Universe* U = universe_get( L); 1656 Universe* U = universe_get( L);
1657 1657
1658 // List _all_ still running threads 1658 // List _all_ still running threads
1659 // 1659 //
1660 MUTEX_LOCK( &U->tracking_cs); 1660 MUTEX_LOCK( &U->tracking_cs);
1661 if( U->tracking_first && U->tracking_first != TRACKING_END) 1661 if( U->tracking_first && U->tracking_first != TRACKING_END)
1662 { 1662 {
1663 Lane* s = U->tracking_first; 1663 Lane* s = U->tracking_first;
1664 lua_newtable( L); // {} 1664 int index = 0;
1665 while( s != TRACKING_END) 1665 lua_newtable( L); // {}
1666 { 1666 while( s != TRACKING_END)
1667 lua_pushstring( L, s->debug_name); // {} "name" 1667 {
1668 push_thread_status( L, s); // {} "name" "status" 1668 // insert a { name, status } tuple, so that several lanes with the same name can't clobber each other
1669 lua_rawset( L, -3); // {} 1669 lua_newtable( L); // {} {}
1670 s = s->tracking_next; 1670 lua_pushstring( L, s->debug_name); // {} {} "name"
1671 } 1671 lua_setfield( L, -2, "name"); // {} {}
1672 } 1672 push_thread_status( L, s); // {} {} "status"
1673 MUTEX_UNLOCK( &U->tracking_cs); 1673 lua_setfield( L, -2, "status"); // {} {}
1674 return lua_gettop( L) - top; 1674 lua_rawseti( L, -2, ++ index); // {}
1675 s = s->tracking_next;
1676 }
1677 }
1678 MUTEX_UNLOCK( &U->tracking_cs);
1679 return lua_gettop( L) - top; // 0 or 1
1675} 1680}
1676#endif // HAVE_LANE_TRACKING 1681#endif // HAVE_LANE_TRACKING
1677 1682
diff --git a/src/lanes.h b/src/lanes.h
index da0dd26..1a38ba5 100644
--- a/src/lanes.h
+++ b/src/lanes.h
@@ -11,7 +11,7 @@
11#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 11#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
12 12
13#define LANES_VERSION_MAJOR 3 13#define LANES_VERSION_MAJOR 3
14#define LANES_VERSION_MINOR 14 14#define LANES_VERSION_MINOR 15
15#define LANES_VERSION_PATCH 0 15#define LANES_VERSION_PATCH 0
16 16
17#define LANES_MIN_VERSION_REQUIRED(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJOR>MAJOR) || (LANES_VERSION_MAJOR==MAJOR && (LANES_VERSION_MINOR>MINOR || (LANES_VERSION_MINOR==MINOR && LANES_VERSION_PATCH>=PATCH)))) 17#define LANES_MIN_VERSION_REQUIRED(MAJOR, MINOR, PATCH) ((LANES_VERSION_MAJOR>MAJOR) || (LANES_VERSION_MAJOR==MAJOR && (LANES_VERSION_MINOR>MINOR || (LANES_VERSION_MINOR==MINOR && LANES_VERSION_PATCH>=PATCH))))
diff --git a/tests/track_lanes.lua b/tests/track_lanes.lua
new file mode 100644
index 0000000..46cfdad
--- /dev/null
+++ b/tests/track_lanes.lua
@@ -0,0 +1,72 @@
1local lanes = require "lanes" .configure{ with_timers = false, track_lanes = true}
2
3local wait
4do
5 local linda = lanes.linda()
6 wait = function( seconds_)
7 linda:receive( seconds_, "dummy_key")
8 end
9end
10
11print "hello"
12
13local track = function( title_)
14 print( title_)
15 for k, v in pairs( lanes.threads())
16 do
17 print( k, v.name, v.status)
18 end
19 print( "\n")
20end
21
22local sleeper = function( name_, seconds_)
23 -- print( "entering '" .. name_ .. "'")
24 local lanes = require "lanes"
25 -- no set_debug_threadname in main thread
26 if set_debug_threadname
27 then
28 -- print( "set_debug_threadname('" .. name_ .. "')")
29 set_debug_threadname( name_)
30 end
31 -- suspend the lane for the specified duration with a failed linda read
32 wait( seconds_)
33 -- print( "exiting '" .. name_ .. "'")
34end
35
36-- sleeper( "main", 1)
37
38-- the generator
39local g = lanes.gen( "*", sleeper)
40
41-- start a forever-waiting lane (nil timeout)
42g( "forever")
43
44-- start a lane that will last 2 seconds
45g( "two_seconds", 2)
46
47-- give a bit of time to reach the linda waiting call
48wait( 0.1)
49
50-- list the known lanes
51track( "============= START")
52
53-- wait until "two_seconds has completed"
54wait(2.1)
55
56track( "============= two_seconds dead")
57
58-- this will collect the completed lane (and remove it from the tracking queue)
59-- collectgarbage()
60
61-- track( "============= two_seconds dead (after collectgarbage)")
62
63-- start another lane that will last 2 seconds, with the same name
64g( "two_seconds", 2)
65
66-- give a bit of time to reach the linda waiting call
67wait( 0.1)
68
69-- list the known lanes
70track( "============= ANOTHER")
71
72print "done" \ No newline at end of file