aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2011-02-12 17:06:03 +0100
committerBenoit Germain <bnt.germain@gmail.com>2011-02-12 17:06:03 +0100
commita661736f7984292a41d71847de68590f6b8ca08a (patch)
tree43e0799c20e835f1cc2d8c5fa1324b64301763e0
parentc91a03bd956bf19848253bded8217687ccd2ad81 (diff)
downloadlanes-a661736f7984292a41d71847de68590f6b8ca08a.tar.gz
lanes-a661736f7984292a41d71847de68590f6b8ca08a.tar.bz2
lanes-a661736f7984292a41d71847de68590f6b8ca08a.zip
Changed idfunc signature and contract to clarify that fact it is not lua-callable and to be able to require the module it was exported from in the target lanes.
-rw-r--r--CHANGES4
-rw-r--r--dist.info2
-rw-r--r--docs/index.html99
-rw-r--r--src/lanes.c102
-rw-r--r--src/lanes.lua12
-rw-r--r--src/tools.c170
-rw-r--r--src/tools.h8
-rw-r--r--tests/basic.lua17
8 files changed, 226 insertions, 188 deletions
diff --git a/CHANGES b/CHANGES
index 40362fb..64de559 100644
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,10 @@ CHANGES:
3 3
4CHANGE X: 4CHANGE X:
5 5
6CHANGE 25 BGe 12-Feb-2011:
7 Changed idfunc signature and contract to clarify that fact it is not lua-callable
8 and to be able to require the module it was exported from in the target lanes
9
6CHANGE 24 DPtr 25-Jan-2011: 10CHANGE 24 DPtr 25-Jan-2011:
7 Changed lanes.c to export functions as a module rather than writing them directly to the globals table. 11 Changed lanes.c to export functions as a module rather than writing them directly to the globals table.
8 12
diff --git a/dist.info b/dist.info
index 8e59368..6f824d7 100644
--- a/dist.info
+++ b/dist.info
@@ -1,7 +1,7 @@
1--- This file is part of LuaDist project 1--- This file is part of LuaDist project
2 2
3name = "lanes" 3name = "lanes"
4version = "2.0.10" 4version = "2.0.11"
5 5
6desc = "Lanes is a lightweight, native, lazy evaluating multithreading library for Lua 5.1." 6desc = "Lanes is a lightweight, native, lazy evaluating multithreading library for Lua 5.1."
7author = "Asko Kauppi" 7author = "Asko Kauppi"
diff --git a/docs/index.html b/docs/index.html
index fec2212..9d66510 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -21,11 +21,11 @@
21 <tr> 21 <tr>
22 <td align="center"> 22 <td align="center">
23 <a href="http://www.lua.org"> 23 <a href="http://www.lua.org">
24 <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> 24 <img src="multi.png" alt="Lua" align="middle" border="0" height="120" width="128" />
25 <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> 25 <img src="multi.png" alt="Lua" align="middle" border="0" height="120" width="128" />
26 <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> 26 <img src="multi.png" alt="Lua" align="middle" border="0" height="120" width="128" />
27 <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> 27 <img src="multi.png" alt="Lua" align="middle" border="0" height="120" width="128" />
28 <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> 28 <img src="multi.png" alt="Lua" align="middle" border="0" height="120" width="128" />
29 </a></td> 29 </a></td>
30 </tr> 30 </tr>
31 <tr> 31 <tr>
@@ -56,7 +56,7 @@
56 56
57<p><br/><font size="-1"><i>Copyright &copy; 2007-11 Asko Kauppi. All rights reserved.</i> 57<p><br/><font size="-1"><i>Copyright &copy; 2007-11 Asko Kauppi. All rights reserved.</i>
58 <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1. 58 <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1.
59 </p><p>This document was revised on 3-Jan-11, and applies to version 2.0.10. 59 </p><p>This document was revised on 12-Feb-11, and applies to version 2.0.11.
60</font></p> 60</font></p>
61 61
62</center> 62</center>
@@ -124,15 +124,14 @@
124 <li>Windows 2000/XP and later <font size="-1">(MinGW or Visual C++ 2005/2008)</font></li> 124 <li>Windows 2000/XP and later <font size="-1">(MinGW or Visual C++ 2005/2008)</font></li>
125<!-- 125<!--
126 Other OS'es here once people help test them. (and the tester's name) 126 Other OS'es here once people help test them. (and the tester's name)
127 127
128 Win64, BSD, Linux x64, Linux embedded, QNX, Solaris, ... 128 Win64, BSD, Linux x64, Linux embedded, QNX, Solaris, ...
129--> 129-->
130 </ul> 130 </ul>
131 131
132 <p>The underlying threading code can be compiled either towards Win32 API 132 <p>The underlying threading code can be compiled either towards Win32 API
133 or <a TARGET="_blank" HREF="http://en.wikipedia.org/wiki/POSIX_Threads">Pthreads</a>. Unfortunately, thread prioritation under Pthreads is a JOKE, 133 or <a TARGET="_blank" HREF="http://en.wikipedia.org/wiki/POSIX_Threads">Pthreads</a>. Unfortunately, thread prioritization under Pthreads is a JOKE,
134 requiring OS specific tweaks and guessing undocumented behaviour. Other 134 requiring OS specific tweaks and guessing undocumented behaviour. Other features should be portable to any modern platform.
135 features should be portable to any modern platform.
136 </p> 135 </p>
137</p> 136</p>
138 137
@@ -147,7 +146,7 @@ details and limitations.
147</p> 146</p>
148 147
149<p>To install Lanes, all you need are the <tt>lanes.lua</tt> and <tt>lua51-lanes.so|dll</tt> 148<p>To install Lanes, all you need are the <tt>lanes.lua</tt> and <tt>lua51-lanes.so|dll</tt>
150files to be reachable by Lua (see LUA_PATH, LUA_CPATH). 149files to be reachable by Lua (see LUA_PATH, LUA_CPATH).
151 150
152Or use <A HREF="http://www.luarocks.org" TARGET="_blank">Lua Rocks</A> package management. 151Or use <A HREF="http://www.luarocks.org" TARGET="_blank">Lua Rocks</A> package management.
153</p> 152</p>
@@ -264,7 +263,7 @@ also in the new lanes.
264 by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode. 263 by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode.
265 </td></tr> 264 </td></tr>
266 </table> 265 </table>
267 266
268</p> 267</p>
269 268
270<h3>Free running lanes</h3> 269<h3>Free running lanes</h3>
@@ -383,7 +382,7 @@ for the request to be processed, or a timeout to occur.
383Returns <tt>true</tt> if the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status) 382Returns <tt>true</tt> if the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status)
384or if the cancellation was fruitful within timeout period. 383or if the cancellation was fruitful within timeout period.
385</p><p> 384</p><p>
386If the lane is still running and <tt>force_kill</tt> is <tt>true</tt>, the 385If the lane is still running and <tt>force_kill</tt> is <tt>true</tt>, the
387OS thread running the lane is forcefully killed. This means no GC, and should 386OS thread running the lane is forcefully killed. This means no GC, and should
388generally be the last resort. 387generally be the last resort.
389</p> 388</p>
@@ -404,16 +403,16 @@ or <tt>send</tt> call is currently not awakened, and may be a reason for a non-d
404</table> 403</table>
405 404
406<p>The <tt>error</tt> call is used for throwing exceptions in Lua. What Lua 405<p>The <tt>error</tt> call is used for throwing exceptions in Lua. What Lua
407does not offer, however, is scoped <a href="http://en.wikipedia.org/wiki/Finalizer">finalizers</a> 406does not offer, however, is scoped <a href="http://en.wikipedia.org/wiki/Finalizer">finalizers</a>
408that would get called when a certain block of instructions gets exited, whether 407that would get called when a certain block of instructions gets exited, whether
409through peaceful return or abrupt <tt>error</tt>. 408through peaceful return or abrupt <tt>error</tt>.
410</p> 409</p>
411<p>Since 2.0.3, Lanes prepares a function <tt>set_finalizer</tt> for doing this. 410<p>Since 2.0.3, Lanes prepares a function <tt>set_finalizer</tt> for doing this.
412Any functions given to it will be called in the lane Lua state, just prior to 411Any functions given to it will be called in the lane Lua state, just prior to
413closing it. They are not called in any particular order. 412closing it. They are not called in any particular order.
414</p> 413</p>
415<p>An error in a finalizer itself overrides the state of the regular chunk 414<p>An error in a finalizer itself overrides the state of the regular chunk
416(in practise, it would be highly preferable <i>not</i> to have errors in finalizers). 415(in practise, it would be highly preferable <i>not</i> to have errors in finalizers).
417If one finalizer errors, the others may not get called. 416If one finalizer errors, the others may not get called.
418</p> 417</p>
419 418
@@ -424,7 +423,7 @@ If one finalizer errors, the others may not get called.
424 423
425<p>Communications between lanes is completely detached from the lane handles 424<p>Communications between lanes is completely detached from the lane handles
426themselves. By itself, a lane can only provide return values once it's finished, 425themselves. By itself, a lane can only provide return values once it's finished,
427or throw an error. Needs to communicate during runtime are handled by <A HREF="http://en.wikipedia.org/wiki/Linda_%28coordination_language%29" TARGET="_blank">Linda objects</A>, which are 426or throw an error. Needs to communicate during runtime are handled by <A HREF="http://en.wikipedia.org/wiki/Linda_%28coordination_language%29" TARGET="_blank">Linda objects</A>, which are
428<A HREF="#deep_userdata">deep userdata</A> instances. They can be provided to a lane 427<A HREF="#deep_userdata">deep userdata</A> instances. They can be provided to a lane
429as startup parameters, upvalues or in some other Linda's message. 428as startup parameters, upvalues or in some other Linda's message.
430</p><p> 429</p><p>
@@ -445,7 +444,7 @@ level locking is required; each Linda operation is atomic.
445 linda:send( "x", i ) -- linda as upvalue 444 linda:send( "x", i ) -- linda as upvalue
446 end 445 end
447 end 446 end
448 447
449 a= lanes.gen("",loop)( 10000 ) 448 a= lanes.gen("",loop)( 10000 )
450 449
451 while true do 450 while true do
@@ -512,7 +511,7 @@ many producers, and many consumers. It's up to you.
512if the queue limit was met, and the queue did not empty enough during the given 511if the queue limit was met, and the queue did not empty enough during the given
513timeout. 512timeout.
514</p><p> 513</p><p>
515Equally, <tt>receive</tt> returns a value and the key that provided the value, 514Equally, <tt>receive</tt> returns a value and the key that provided the value,
516or nothing for timeout. Note that <tt>nil</tt>s can be sent and received; 515or nothing for timeout. Note that <tt>nil</tt>s can be sent and received;
517the <tt>key</tt> value will tell it apart from a timeout. 516the <tt>key</tt> value will tell it apart from a timeout.
518</p><p> 517</p><p>
@@ -537,8 +536,8 @@ be used for making priority queues.
537The table access methods are for accessing a slot without queuing or consuming. 536The table access methods are for accessing a slot without queuing or consuming.
538They can be used for making shared tables of storage among the lanes. 537They can be used for making shared tables of storage among the lanes.
539</p><p> 538</p><p>
540Writing to a slot overwrites existing value, and clears any possible queued 539Writing to a slot overwrites existing value, and clears any possible queued
541entries. Table access and <tt>send</tt>/<tt>receive</tt> can be used together; 540entries. Table access and <tt>send</tt>/<tt>receive</tt> can be used together;
542reading a slot essentially peeks the next outcoming value of a queue. 541reading a slot essentially peeks the next outcoming value of a queue.
543</p> 542</p>
544 543
@@ -554,7 +553,7 @@ discussing it is good for a preview of how deep userdata works.
554Because proxy objects (<tt>linda_h</tt>) are just pointers to the real, deep 553Because proxy objects (<tt>linda_h</tt>) are just pointers to the real, deep
555userdata, they cannot be used to identify a certain Linda from the others. 554userdata, they cannot be used to identify a certain Linda from the others.
556The internal timer system needs to do this, and the <tt>:deep()</tt> method 555The internal timer system needs to do this, and the <tt>:deep()</tt> method
557has been added for its use. It returns a light userdata pointing to the 556has been added for its use. It returns a light userdata pointing to the
558<i>actual</i> deep object, and thus can be used for seeing, which proxies actually 557<i>actual</i> deep object, and thus can be used for seeing, which proxies actually
559mean the same underlying object. You might or might not need a similar system 558mean the same underlying object. You might or might not need a similar system
560with your own deep userdata. 559with your own deep userdata.
@@ -574,13 +573,13 @@ you want to use several?
574 for the other. This keeps your code clear and readable. You can pass 573 for the other. This keeps your code clear and readable. You can pass
575 multiple Linda handles to a lane with practically no added cost. 574 multiple Linda handles to a lane with practically no added cost.
576 </li> 575 </li>
577 576
578 <li>Namespace control. Linda keys have a "flat" namespace, so collisions 577 <li>Namespace control. Linda keys have a "flat" namespace, so collisions
579 are possible if you try to use the same Linda for too many separate uses. 578 are possible if you try to use the same Linda for too many separate uses.
580 </li> 579 </li>
581 580
582 <li>Performance. Changing any slot in a Linda causes all pending threads 581 <li>Performance. Changing any slot in a Linda causes all pending threads
583 for that Linda to be momentarily awakened (at least in the C level). 582 for that Linda to be momentarily awakened (at least in the C level).
584 This can degrade performance due to unnecessary OS level context switches. 583 This can degrade performance due to unnecessary OS level context switches.
585 </li> 584 </li>
586</ul> 585</ul>
@@ -603,13 +602,13 @@ events to a common Linda, but... :).</font>
603</table> 602</table>
604 603
605<p> 604<p>
606Timers can be run once, or in a reoccurring fashion (<tt>period_secs > 0</tt>). 605Timers can be run once, or in a reoccurring fashion (<tt>period_secs > 0</tt>).
607The first occurrence can be given either as a date or as a relative delay in seconds. 606The first occurrence can be given either as a date or as a relative delay in seconds.
608The <tt>date</tt> table is like what <tt>os.date("*t")</tt> returns, in the 607The <tt>date</tt> table is like what <tt>os.date("*t")</tt> returns, in the
609local time zone. 608local time zone.
610</p><p> 609</p><p>
611Once a timer expires, the <tt>key</tt> is set with the current time 610Once a timer expires, the <tt>key</tt> is set with the current time
612(in seconds, same offset as <tt>os.time()</tt> but with millisecond accuracy). 611(in seconds, same offset as <tt>os.time()</tt> but with millisecond accuracy).
613The key can be waited upon using the regular Linda <tt>:receive()</tt> 612The key can be waited upon using the regular Linda <tt>:receive()</tt>
614method. 613method.
615</p><p> 614</p><p>
@@ -632,17 +631,17 @@ A timer can be stopped simply by <tt>first_secs=0</tt> and no period.
632 t.sec= 0 631 t.sec= 0
633 632
634 lanes.timer( linda, "min", t, 60 ) -- reoccur every minute (sharp) 633 lanes.timer( linda, "min", t, 60 ) -- reoccur every minute (sharp)
635 634
636 while true do 635 while true do
637 local v,key= linda:receive( "sec", "min" ) 636 local v,key= linda:receive( "sec", "min" )
638 print( "Timer "..key..": "..v ) 637 print( "Timer "..key..": "..v )
639 end 638 end
640</pre> 639</pre>
641</table> 640</table>
642 641
643</p><p> 642</p><p>
644NOTE: Timer keys are set, not queued, so missing a beat is possible especially 643NOTE: Timer keys are set, not queued, so missing a beat is possible especially
645if the timer cycle is extremely small. The key value can be used to know the 644if the timer cycle is extremely small. The key value can be used to know the
646actual time passed. 645actual time passed.
647</p><p> 646</p><p>
648<table> 647<table>
@@ -704,7 +703,7 @@ Similar sugar exists for atomic counters:
704</table> 703</table>
705</p><p> 704</p><p>
706 705
707Each time called, the generated function will change <tt>linda[key]</tt> 706Each time called, the generated function will change <tt>linda[key]</tt>
708atomically, without other lanes being able to interfere. The new value is 707atomically, without other lanes being able to interfere. The new value is
709returned. You can use either <tt>diff 0.0</tt> or <tt>get</tt> to just read the current 708returned. You can use either <tt>diff 0.0</tt> or <tt>get</tt> to just read the current
710value. 709value.
@@ -725,7 +724,7 @@ Note that the generated functions can be passed on to other lanes.
725<p><ul> 724<p><ul>
726 <li>Booleans, numbers, strings, light userdata, Lua functions and tables of such can always be passed. 725 <li>Booleans, numbers, strings, light userdata, Lua functions and tables of such can always be passed.
727 </li> 726 </li>
728 <li>Cyclic tables and/or duplicate references are allowed and reproduced appropriately, 727 <li>Cyclic tables and/or duplicate references are allowed and reproduced appropriately,
729 but only <u>within the same transmission</u>. 728 but only <u>within the same transmission</u>.
730 <ul> 729 <ul>
731 <li>using the same source table in multiple Linda messages keeps no ties between the tables 730 <li>using the same source table in multiple Linda messages keeps no ties between the tables
@@ -777,14 +776,14 @@ should be covered into a one-time-only construct such as below.
777 int luaopen_module( lua_State *L ) 776 int luaopen_module( lua_State *L )
778 { 777 {
779 static char been_here; /* 0 by ANSI C */ 778 static char been_here; /* 0 by ANSI C */
780 779
781 /* Calls to 'require' serialized by Lanes; this is safe.&nbsp;&nbsp; 780 /* Calls to 'require' serialized by Lanes; this is safe.&nbsp;&nbsp;
782 */ 781 */
783 if (!been_here) { 782 if (!been_here) {
784 been_here= 1; 783 been_here= 1;
785 ... one time initializations ... 784 ... one time initializations ...
786 } 785 }
787 786
788 ... binding to Lua ... 787 ... binding to Lua ...
789 } 788 }
790</pre> 789</pre>
@@ -804,8 +803,9 @@ used for creation and deletion of your deep userdata (the shared resource),
804and for making metatables for the state-specific proxies for accessing it. 803and for making metatables for the state-specific proxies for accessing it.
805Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>. 804Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>.
806 </li> 805 </li>
807 <li>Create your userdata using <tt>luaG_deep_userdata()</tt>, which is 806 <li>Instanciate your userdata using <tt>luaG_deep_userdata()</tt>,
808 a Lua-callable function. Given an <tt>idfunc</tt>, it sets up the support 807 instead of the regular <tt>lua_newuserdata()</tt>.
808 Given an <tt>idfunc</tt>, it sets up the support
809 structures and returns a state-specific proxy userdata for accessing your 809 structures and returns a state-specific proxy userdata for accessing your
810 data. This proxy can also be copied over to other lanes. 810 data. This proxy can also be copied over to other lanes.
811 </li> 811 </li>
@@ -815,7 +815,7 @@ Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>.
815</ol> 815</ol>
816 816
817<p>Deep userdata management will take care of tying to <tt>__gc</tt> methods, 817<p>Deep userdata management will take care of tying to <tt>__gc</tt> methods,
818and doing reference counting to see how many proxies are still there for 818and doing reference counting to see how many proxies are still there for
819accessing the data. Once there are none, the data will be freed through a call 819accessing the data. Once there are none, the data will be freed through a call
820to the <tt>idfunc</tt> you provided. 820to the <tt>idfunc</tt> you provided.
821</p> 821</p>
@@ -850,7 +850,7 @@ something like this:
850<pre> 850<pre>
851 A: print( 1, 2, 3, 4 ) 851 A: print( 1, 2, 3, 4 )
852 B: print( 'a', 'b', 'c', 'd' ) 852 B: print( 'a', 'b', 'c', 'd' )
853 853
854 1 a b 2 3 c d 4 854 1 a b 2 3 c d 4
855</pre> 855</pre>
856 856
@@ -870,7 +870,7 @@ Here are some things one should consider, if best performance is vital:
870<ul> 870<ul>
871 <li>Data passing (parameters, upvalues, Linda messages) is generally fast, 871 <li>Data passing (parameters, upvalues, Linda messages) is generally fast,
872 doing two binary state-to-state copies (from source state to hidden state, 872 doing two binary state-to-state copies (from source state to hidden state,
873 hidden state to target state). Remember that not only the function you 873 hidden state to target state). Remember that not only the function you
874 specify but also its upvalues, their upvalues, etc. etc. will get copied. 874 specify but also its upvalues, their upvalues, etc. etc. will get copied.
875 </li> 875 </li>
876 <li>Lane startup is fast (1000's of lanes a second), depending on the 876 <li>Lane startup is fast (1000's of lanes a second), depending on the
@@ -894,7 +894,7 @@ Here are some things one should consider, if best performance is vital:
894 merged into one main timer state (see <tt>timer.lua</tt>); no OS side 894 merged into one main timer state (see <tt>timer.lua</tt>); no OS side
895 timers are utilized. 895 timers are utilized.
896 </li> 896 </li>
897 <li>Lindas are hashed to a fixed number of "keeper states", which are a locking entity. 897 <li>Lindas are hashed to a fixed number of "keeper states", which are a locking entity.
898 If you are using a lot of Linda objects, 898 If you are using a lot of Linda objects,
899 it may be useful to try having more of these keeper states. By default, 899 it may be useful to try having more of these keeper states. By default,
900 only one is used (see <tt>KEEPER_STATES_N</tt>), but this is an implementation detail. 900 only one is used (see <tt>KEEPER_STATES_N</tt>), but this is an implementation detail.
@@ -907,7 +907,7 @@ Here are some things one should consider, if best performance is vital:
907 907
908<p> 908<p>
909Cancellation of lanes uses the Lua error mechanism with a special lightuserdata 909Cancellation of lanes uses the Lua error mechanism with a special lightuserdata
910error sentinel. 910error sentinel.
911If you use <tt>pcall</tt> in code that needs to be cancellable 911If you use <tt>pcall</tt> in code that needs to be cancellable
912from the outside, the special error might not get through to Lanes, thus 912from the outside, the special error might not get through to Lanes, thus
913preventing the Lane from being cleanly cancelled. You should throw any 913preventing the Lane from being cleanly cancelled. You should throw any
@@ -929,6 +929,13 @@ its actual value.
929<h2 id="changes">Change log</h2> 929<h2 id="changes">Change log</h2>
930 930
931<p> 931<p>
932Feb-2011 (2.0.11):
933<ul>
934 <li>Fixed bug where reference to Linda object was dropped for a short time (crashing if GC was run during that time).</li>
935 <li>Changed the atexit code to trip the timer thread's write signal.</li>
936 <li>Changed lanes.c to export functions as a module rather than writing them directly to the globals table.</li>
937</ul>
938
932Jan-2011 (2.0.10): 939Jan-2011 (2.0.10):
933<ul> 940<ul>
934 <li>linda_send was waiting on the wrong signal</li> 941 <li>linda_send was waiting on the wrong signal</li>
diff --git a/src/lanes.c b/src/lanes.c
index f4bef7b..16a8edc 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -64,7 +64,7 @@
64 * ... 64 * ...
65 */ 65 */
66 66
67const char *VERSION= "2.0.10"; 67const char *VERSION= "2.0.11";
68 68
69/* 69/*
70=============================================================================== 70===============================================================================
@@ -359,7 +359,8 @@ static const char *init_keepers(void) {
359 lua_State *L= luaL_newstate(); 359 lua_State *L= luaL_newstate();
360 if (!L) return "out of memory"; 360 if (!L) return "out of memory";
361 361
362 luaG_openlibs( L, "io,table" ); // 'io' for debugging messages 362 luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs
363 serialize_require( L);
363 364
364 lua_pushlightuserdata( L, &nil_sentinel ); 365 lua_pushlightuserdata( L, &nil_sentinel );
365 lua_setglobal( L, "nil_sentinel" ); 366 lua_setglobal( L, "nil_sentinel" );
@@ -449,9 +450,9 @@ struct s_Linda {
449 SIGNAL_T write_happened; 450 SIGNAL_T write_happened;
450}; 451};
451 452
452static int LG_linda_id( lua_State* ); 453static void linda_id( lua_State*, char const * const which);
453 454
454#define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, LG_linda_id, n )) 455#define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, linda_id, n ))
455 456
456 457
457/* 458/*
@@ -462,7 +463,8 @@ static int LG_linda_id( lua_State* );
462* Returns: 'true' if the value was queued 463* Returns: 'true' if the value was queued
463* 'false' for timeout (only happens when the queue size is limited) 464* 'false' for timeout (only happens when the queue size is limited)
464*/ 465*/
465LUAG_FUNC( linda_send ) { 466LUAG_FUNC( linda_send )
467{
466 struct s_Linda *linda= lua_toLinda( L, 1 ); 468 struct s_Linda *linda= lua_toLinda( L, 1 );
467 bool_t ret; 469 bool_t ret;
468 bool_t cancel= FALSE; 470 bool_t cancel= FALSE;
@@ -750,21 +752,22 @@ LUAG_FUNC( linda_deep ) {
750* Returns a metatable for the proxy objects ('__gc' method not needed; will 752* Returns a metatable for the proxy objects ('__gc' method not needed; will
751* be added by 'luaG_...') 753* be added by 'luaG_...')
752* 754*
755* string= linda_id( "module")
756*
757* Returns the name of the module that a state should require
758* in order to keep a handle on the shared library that exported the idfunc
759*
753* = linda_id( str, ... ) 760* = linda_id( str, ... )
754* 761*
755* For any other strings, the ID function must not react at all. This allows 762* For any other strings, the ID function must not react at all. This allows
756* future extensions of the system. 763* future extensions of the system.
757*/ 764*/
758LUAG_FUNC( linda_id ) { 765static void linda_id( lua_State *L, char const * const which)
759 const char *which= lua_tostring(L,1); 766{
760 767 if (strcmp( which, "new" )==0)
761 if (strcmp( which, "new" )==0) { 768 {
762 struct s_Linda *s; 769 struct s_Linda *s;
763 770
764 /* We don't use any parameters, but one could (they're at [2..TOS])
765 */
766 ASSERT_L( lua_gettop(L)==1 );
767
768 /* The deep data is allocated separately of Lua stack; we might no 771 /* The deep data is allocated separately of Lua stack; we might no
769 * longer be around when last reference to it is being released. 772 * longer be around when last reference to it is being released.
770 * One can use any memory allocation scheme. 773 * One can use any memory allocation scheme.
@@ -776,11 +779,11 @@ LUAG_FUNC( linda_id ) {
776 SIGNAL_INIT( &s->write_happened ); 779 SIGNAL_INIT( &s->write_happened );
777 780
778 lua_pushlightuserdata( L, s ); 781 lua_pushlightuserdata( L, s );
779 return 1; 782 }
780 783 else if (strcmp( which, "delete" )==0)
781 } else if (strcmp( which, "delete" )==0) { 784 {
782 struct s_Keeper *K; 785 struct s_Keeper *K;
783 struct s_Linda *s= lua_touserdata(L,2); 786 struct s_Linda *s= lua_touserdata(L,1);
784 ASSERT_L(s); 787 ASSERT_L(s);
785 788
786 /* Clean associated structures in the keeper state. 789 /* Clean associated structures in the keeper state.
@@ -797,18 +800,20 @@ LUAG_FUNC( linda_id ) {
797 SIGNAL_FREE( &s->read_happened ); 800 SIGNAL_FREE( &s->read_happened );
798 SIGNAL_FREE( &s->write_happened ); 801 SIGNAL_FREE( &s->write_happened );
799 free(s); 802 free(s);
803 }
804 else if (strcmp( which, "metatable" )==0)
805 {
800 806
801 return 0; 807 STACK_CHECK(L)
802
803 } else if (strcmp( which, "metatable" )==0) {
804
805 STACK_CHECK(L)
806 lua_newtable(L); 808 lua_newtable(L);
807 lua_newtable(L); 809 // metatable is its own index
808 // 810 lua_pushvalue( L, -1);
809 // [-2]: linda metatable 811 lua_setfield( L, -2, "__index");
810 // [-1]: metatable's to-be .__index table 812 // protect metatable from external access
811 813 lua_pushboolean( L, 0);
814 lua_setfield( L, -2, "__metatable");
815 //
816 // [-1]: linda metatable
812 lua_pushcfunction( L, LG_linda_send ); 817 lua_pushcfunction( L, LG_linda_send );
813 lua_setfield( L, -2, "send" ); 818 lua_setfield( L, -2, "send" );
814 819
@@ -827,13 +832,17 @@ LUAG_FUNC( linda_id ) {
827 lua_pushcfunction( L, LG_linda_deep ); 832 lua_pushcfunction( L, LG_linda_deep );
828 lua_setfield( L, -2, "deep" ); 833 lua_setfield( L, -2, "deep" );
829 834
830 lua_setfield( L, -2, "__index" ); 835 STACK_END(L,1)
831 STACK_END(L,1)
832
833 return 1;
834 } 836 }
835 837 else if( strcmp( which, "module") == 0)
836 return 0; // unknown request, be quiet 838 {
839 lua_pushliteral( L, "lua51-lanes");
840 }
841}
842
843LUAG_FUNC( linda)
844{
845 return luaG_deep_userdata( L, linda_id);
837} 846}
838 847
839 848
@@ -1014,8 +1023,10 @@ static void selfdestruct_atexit( void ) {
1014 MUTEX_UNLOCK( &selfdestruct_cs ); 1023 MUTEX_UNLOCK( &selfdestruct_cs );
1015 1024
1016 // Tell the timer thread to check it's cancel request 1025 // Tell the timer thread to check it's cancel request
1017 struct s_Linda *td = timer_deep->deep; 1026 {
1018 SIGNAL_ALL( &td->write_happened); 1027 struct s_Linda *td = timer_deep->deep;
1028 SIGNAL_ALL( &td->write_happened);
1029 }
1019 1030
1020 // When noticing their cancel, the lanes will remove themselves from 1031 // When noticing their cancel, the lanes will remove themselves from
1021 // the selfdestruct chain. 1032 // the selfdestruct chain.
@@ -1855,21 +1866,21 @@ LUAG_FUNC( wakeup_conv )
1855*/ 1866*/
1856 1867
1857static const struct luaL_reg lanes_functions [] = { 1868static const struct luaL_reg lanes_functions [] = {
1858 {"linda_id", LG_linda_id}, 1869 {"linda", LG_linda},
1859 {"thread_status", LG_thread_status}, 1870 {"thread_status", LG_thread_status},
1860 {"thread_join", LG_thread_join}, 1871 {"thread_join", LG_thread_join},
1861 {"thread_cancel", LG_thread_cancel}, 1872 {"thread_cancel", LG_thread_cancel},
1862 {"now_secs", LG_now_secs}, 1873 {"now_secs", LG_now_secs},
1863 {"wakeup_conv", LG_wakeup_conv}, 1874 {"wakeup_conv", LG_wakeup_conv},
1864 {"_single", LG__single}, 1875 {"_single", LG__single},
1865 {"_deep_userdata", luaG_deep_userdata},
1866 {NULL, NULL} 1876 {NULL, NULL}
1867}; 1877};
1868 1878
1869/* 1879/*
1870* One-time initializations 1880* One-time initializations
1871*/ 1881*/
1872static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ref ) { 1882static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_ref )
1883{
1873 const char *err; 1884 const char *err;
1874 1885
1875#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 1886#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
@@ -1919,8 +1930,9 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
1919 } 1930 }
1920 #endif 1931 #endif
1921#endif 1932#endif
1922 err= init_keepers(); 1933 err= init_keepers();
1923 if (err) { 1934 if (err)
1935 {
1924 luaL_error( L, "Unable to initialize: %s", err ); 1936 luaL_error( L, "Unable to initialize: %s", err );
1925 } 1937 }
1926 1938
@@ -1928,13 +1940,11 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
1928 // 1940 //
1929 ASSERT_L( timer_deep_ref && (!(*timer_deep_ref)) ); 1941 ASSERT_L( timer_deep_ref && (!(*timer_deep_ref)) );
1930 1942
1931 STACK_CHECK(L) 1943 STACK_CHECK(L)
1932 { 1944 {
1933 // proxy_ud= deep_userdata( idfunc ) 1945 // proxy_ud= deep_userdata( idfunc )
1934 // 1946 //
1935 lua_pushcfunction( L, luaG_deep_userdata ); 1947 luaG_deep_userdata( L, linda_id);
1936 lua_pushcfunction( L, LG_linda_id );
1937 lua_call( L, 1 /*args*/, 1 /*retvals*/ );
1938 1948
1939 ASSERT_L( lua_isuserdata(L,-1) ); 1949 ASSERT_L( lua_isuserdata(L,-1) );
1940 1950
@@ -1950,7 +1960,7 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
1950 lua_rawset(L, LUA_REGISTRYINDEX); 1960 lua_rawset(L, LUA_REGISTRYINDEX);
1951 1961
1952 } 1962 }
1953 STACK_END(L,0) 1963 STACK_END(L,0)
1954} 1964}
1955 1965
1956int 1966int
@@ -2014,7 +2024,7 @@ __declspec(dllexport)
2014 lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param 2024 lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param
2015 lua_setfield(L, -2, "thread_new"); 2025 lua_setfield(L, -2, "thread_new");
2016 2026
2017 luaG_push_proxy( L, LG_linda_id, (DEEP_PRELUDE *) timer_deep ); 2027 luaG_push_proxy( L, linda_id, (DEEP_PRELUDE *) timer_deep );
2018 lua_setfield(L, -2, "timer_gateway"); 2028 lua_setfield(L, -2, "timer_gateway");
2019 2029
2020 lua_pushstring(L, VERSION); 2030 lua_pushstring(L, VERSION);
diff --git a/src/lanes.lua b/src/lanes.lua
index 42e946b..b6fbc08 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -45,8 +45,6 @@ local mm = require "lua51-lanes"
45assert( type(mm)=="table" ) 45assert( type(mm)=="table" )
46 46
47 47
48local linda_id= assert( mm.linda_id )
49
50local thread_new= assert(mm.thread_new) 48local thread_new= assert(mm.thread_new)
51local thread_status= assert(mm.thread_status) 49local thread_status= assert(mm.thread_status)
52local thread_join= assert(mm.thread_join) 50local thread_join= assert(mm.thread_join)
@@ -55,8 +53,6 @@ local thread_cancel= assert(mm.thread_cancel)
55local _single= assert(mm._single) 53local _single= assert(mm._single)
56local _version= assert(mm._version) 54local _version= assert(mm._version)
57 55
58local _deep_userdata= assert(mm._deep_userdata)
59
60local now_secs= assert( mm.now_secs ) 56local now_secs= assert( mm.now_secs )
61local wakeup_conv= assert( mm.wakeup_conv ) 57local wakeup_conv= assert( mm.wakeup_conv )
62local timer_gateway= assert( mm.timer_gateway ) 58local timer_gateway= assert( mm.timer_gateway )
@@ -336,11 +332,7 @@ end
336----- 332-----
337-- linda_ud= lanes.linda() 333-- linda_ud= lanes.linda()
338-- 334--
339function linda() 335linda = mm.linda
340 local proxy= _deep_userdata( linda_id )
341 assert( (type(proxy) == "userdata") and getmetatable(proxy) )
342 return proxy
343end
344 336
345 337
346---=== Timers ===--- 338---=== Timers ===---
@@ -505,7 +497,7 @@ if first_time then
505 -- We let the timer lane be a "free running" thread; no handle to it 497 -- We let the timer lane be a "free running" thread; no handle to it
506 -- remains. 498 -- remains.
507 -- 499 --
508 gen( "io", { priority=max_prio, globals={threadName="LanesTimer"} }, function() 500 gen( "io,package", { priority=max_prio, globals={threadName="LanesTimer"} }, function()
509 501
510 while true do 502 while true do
511 local next_wakeup= check_timers() 503 local next_wakeup= check_timers()
diff --git a/src/tools.c b/src/tools.c
index 6692890..d09b11e 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -280,26 +280,27 @@ void get_deep_lookup( lua_State *L ) {
280* or NULL if 'index' is not a deep userdata proxy. 280* or NULL if 'index' is not a deep userdata proxy.
281*/ 281*/
282static 282static
283lua_CFunction get_idfunc( lua_State *L, int index ) { 283luaG_IdFunction get_idfunc( lua_State *L, int index )
284 lua_CFunction ret; 284{
285 luaG_IdFunction ret;
285 286
286 index= STACK_ABS(L,index); 287 index= STACK_ABS(L,index);
287 288
288 STACK_GROW(L,1); 289 STACK_GROW(L,1);
289 290
290 STACK_CHECK(L) 291 STACK_CHECK(L)
291 if (!lua_getmetatable( L, index )) 292 if (!lua_getmetatable( L, index ))
292 return NULL; // no metatable 293 return NULL; // no metatable
293 294
294 // [-1]: metatable of [index] 295 // [-1]: metatable of [index]
295 296
296 get_deep_lookup(L); 297 get_deep_lookup(L);
297 // 298 //
298 // [-1]: idfunc/nil 299 // [-1]: idfunc/nil
299 300
300 ret= lua_tocfunction(L,-1); 301 ret= (luaG_IdFunction)lua_touserdata(L,-1);
301 lua_pop(L,1); 302 lua_pop(L,1);
302 STACK_END(L,0) 303 STACK_END(L,0)
303 return ret; 304 return ret;
304} 305}
305 306
@@ -311,7 +312,8 @@ lua_CFunction get_idfunc( lua_State *L, int index ) {
311* it up if reaches 0. 312* it up if reaches 0.
312*/ 313*/
313static 314static
314int deep_userdata_gc( lua_State *L ) { 315int deep_userdata_gc( lua_State *L )
316{
315 DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 ); 317 DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 );
316 DEEP_PRELUDE *p= *proxy; 318 DEEP_PRELUDE *p= *proxy;
317 int v; 319 int v;
@@ -319,27 +321,26 @@ int deep_userdata_gc( lua_State *L ) {
319 *proxy= 0; // make sure we don't use it any more 321 *proxy= 0; // make sure we don't use it any more
320 322
321 MUTEX_LOCK( &deep_lock ); 323 MUTEX_LOCK( &deep_lock );
322 v= --(p->refcount); 324 v= --(p->refcount);
323 MUTEX_UNLOCK( &deep_lock ); 325 MUTEX_UNLOCK( &deep_lock );
324 326
325 if (v==0) { 327 if (v==0)
326 int pushed; 328 {
327
328 // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup 329 // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup
329 // 330 //
330 lua_CFunction idfunc= get_idfunc(L,1); 331 luaG_IdFunction idfunc = get_idfunc(L,1);
331 ASSERT_L(idfunc); 332 ASSERT_L(idfunc);
332 333
333 lua_settop(L,0); // clean stack so we can call 'idfunc' directly 334 lua_settop( L, 0); // clean stack so we can call 'idfunc' directly
334 335
335 // void= idfunc( "delete", lightuserdata ) 336 // void= idfunc( "delete", lightuserdata )
336 // 337 //
337 lua_pushliteral( L, "delete" );
338 lua_pushlightuserdata( L, p->deep ); 338 lua_pushlightuserdata( L, p->deep );
339 pushed= idfunc(L); 339 idfunc( L, "delete");
340 340
341 if (pushed) 341 // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything!
342 luaL_error( L, "Bad idfunc on \"delete\": returned something" ); 342 if ( lua_gettop( L) > 1)
343 luaL_error( L, "Bad idfunc on \"delete\": returned something");
343 344
344 DEEP_FREE( (void*)p ); 345 DEEP_FREE( (void*)p );
345 } 346 }
@@ -354,28 +355,31 @@ int deep_userdata_gc( lua_State *L ) {
354* used in this Lua state (metatable, registring it). Otherwise, increments the 355* used in this Lua state (metatable, registring it). Otherwise, increments the
355* reference count. 356* reference count.
356*/ 357*/
357void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude ) { 358void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelude )
359{
358 DEEP_PRELUDE **proxy; 360 DEEP_PRELUDE **proxy;
359 361
360 // Check if a proxy already exists 362 // Check if a proxy already exists
361 push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); 363 push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v");
362 lua_pushlightuserdata(L, prelude->deep); 364 lua_pushlightuserdata(L, prelude->deep);
363 lua_rawget(L, -2); 365 lua_rawget(L, -2);
364 if (!lua_isnil(L, -1)) { 366 if (!lua_isnil(L, -1))
367 {
365 lua_remove(L, -2); // deep proxy cache table 368 lua_remove(L, -2); // deep proxy cache table
366 return; 369 return;
367 } else { 370 }
371 else
372 {
368 lua_pop(L, 2); // Pop the nil and proxy cache table 373 lua_pop(L, 2); // Pop the nil and proxy cache table
369 } 374 }
370 375
371
372 MUTEX_LOCK( &deep_lock ); 376 MUTEX_LOCK( &deep_lock );
373 ++(prelude->refcount); // one more proxy pointing to this deep data 377 ++(prelude->refcount); // one more proxy pointing to this deep data
374 MUTEX_UNLOCK( &deep_lock ); 378 MUTEX_UNLOCK( &deep_lock );
375 379
376 STACK_GROW(L,4); 380 STACK_GROW(L,4);
377 381
378 STACK_CHECK(L) 382 STACK_CHECK(L)
379 383
380 proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) ); 384 proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) );
381 ASSERT_L(proxy); 385 ASSERT_L(proxy);
@@ -383,28 +387,32 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude
383 387
384 // Get/create metatable for 'idfunc' (in this state) 388 // Get/create metatable for 'idfunc' (in this state)
385 // 389 //
386 lua_pushcfunction( L, idfunc ); // key 390 lua_pushlightuserdata( L, idfunc ); // key
387 get_deep_lookup(L); 391 get_deep_lookup(L);
388 // 392 //
389 // [-2]: proxy 393 // [-2]: proxy
390 // [-1]: metatable / nil 394 // [-1]: metatable / nil
391 395
392 if (lua_isnil(L,-1)) { 396 if (lua_isnil(L,-1))
393 // No metatable yet; make one and register it 397 {
394 // 398 int oldtop;
399 // No metatable yet. We have two things to do:
400
401 // 1 - make one and register it
395 lua_pop(L,1); 402 lua_pop(L,1);
396 403
397 // tbl= idfunc( "metatable" ) 404 // tbl= idfunc( "metatable" )
398 // 405 //
399 lua_pushcfunction( L, idfunc ); 406 oldtop = lua_gettop( L);
400 lua_pushliteral( L, "metatable" ); 407 idfunc( L, "metatable");
401 lua_call( L, 1 /*args*/, 1 /*results*/ ); 408 //
402 // 409 // [-2]: proxy
403 // [-2]: proxy 410 // [-1]: metatable (returned by 'idfunc')
404 // [-1]: metatable (returned by 'idfunc')
405 411
406 if (!lua_istable(L,-1)) 412 if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1))
413 {
407 luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); 414 luaL_error( L, "Bad idfunc on \"metatable\": did not return one" );
415 }
408 416
409 // Add '__gc' method 417 // Add '__gc' method
410 // 418 //
@@ -414,16 +422,40 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude
414 // Memorize for later rounds 422 // Memorize for later rounds
415 // 423 //
416 lua_pushvalue( L,-1 ); 424 lua_pushvalue( L,-1 );
417 lua_pushcfunction( L, idfunc ); 425 lua_pushlightuserdata( L, idfunc );
418 // 426 //
419 // [-4]: proxy 427 // [-4]: proxy
420 // [-3]: metatable (2nd ref) 428 // [-3]: metatable (2nd ref)
421 // [-2]: metatable 429 // [-2]: metatable
422 // [-1]: idfunc 430 // [-1]: idfunc
423 431
424 set_deep_lookup(L); 432 set_deep_lookup(L);
425 } 433
426 STACK_MID(L,2) 434 // 2 - cause the target state to require the module that exported the idfunc
435 // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc
436 lua_getglobal( L, "require");
437 if( lua_isfunction( L, -1)) // just in case...
438 {
439 // make sure the function pushed a single value on the stack!
440 int oldtop = lua_gettop( L);
441 idfunc( L, "module");
442 if( lua_gettop( L) - oldtop != 1 || !lua_isstring( L, -1))
443 {
444 luaL_error( L, "Bad idfunc on \"module\": should return a string");
445 }
446 // if we are inside a call to require, this will raise a "reentrency" error that we absorb silently (we don't care, this probably means the module is already being required, which is what we need)
447 if( lua_pcall( L, 1, 0, 0) != 0)
448 {
449 //char const * const errMsg = lua_tostring( L, -1); // just to see it in the debugger
450 lua_pop( L, 1);
451 }
452 }
453 else
454 {
455 lua_pop( L, 1);
456 }
457 }
458 STACK_MID(L,2)
427 ASSERT_L( lua_isuserdata(L,-2) ); 459 ASSERT_L( lua_isuserdata(L,-2) );
428 ASSERT_L( lua_istable(L,-1) ); 460 ASSERT_L( lua_istable(L,-1) );
429 461
@@ -439,7 +471,7 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude
439 lua_rawset(L, -3); 471 lua_rawset(L, -3);
440 lua_pop(L, 1); // Remove the cache proxy table 472 lua_pop(L, 1); // Remove the cache proxy table
441 473
442 STACK_END(L,1) 474 STACK_END(L,1)
443 // [-1]: proxy userdata 475 // [-1]: proxy userdata
444} 476}
445 477
@@ -466,9 +498,9 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude
466* 498*
467* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' 499* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()'
468*/ 500*/
469int luaG_deep_userdata( lua_State *L ) { 501int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc)
470 lua_CFunction idfunc= lua_tocfunction( L,1 ); 502{
471 int pushed; 503 int oldtop;
472 504
473 DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) ); 505 DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) );
474 ASSERT_L(prelude); 506 ASSERT_L(prelude);
@@ -476,20 +508,17 @@ int luaG_deep_userdata( lua_State *L ) {
476 prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1 508 prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1
477 509
478 STACK_GROW(L,1); 510 STACK_GROW(L,1);
479 STACK_CHECK(L) 511 STACK_CHECK(L)
480
481 // Replace 'idfunc' with "new" in the stack (keep possible other params)
482 //
483 lua_remove(L,1);
484 lua_pushliteral( L, "new" );
485 lua_insert(L,1);
486 512
487 // lightuserdata= idfunc( "new" [, ...] ) 513 // lightuserdata= idfunc( "new" [, ...] )
488 // 514 //
489 pushed= idfunc(L); 515 oldtop = lua_gettop( L);
516 idfunc(L, "new");
490 517
491 if ((pushed!=1) || lua_type(L,-1) != LUA_TLIGHTUSERDATA) 518 if( lua_gettop( L) - oldtop != 1 || lua_type( L, -1) != LUA_TLIGHTUSERDATA)
492 luaL_error( L, "Bad idfunc on \"new\": did not return light userdata" ); 519 {
520 luaL_error( L, "Bad idfunc on \"new\": did not return light userdata");
521 }
493 522
494 prelude->deep= lua_touserdata(L,-1); 523 prelude->deep= lua_touserdata(L,-1);
495 ASSERT_L(prelude->deep); 524 ASSERT_L(prelude->deep);
@@ -497,10 +526,10 @@ int luaG_deep_userdata( lua_State *L ) {
497 lua_pop(L,1); // pop deep data 526 lua_pop(L,1); // pop deep data
498 527
499 luaG_push_proxy( L, idfunc, prelude ); 528 luaG_push_proxy( L, idfunc, prelude );
500 // 529 //
501 // [-1]: proxy userdata 530 // [-1]: proxy userdata
502 531
503 STACK_END(L,1) 532 STACK_END(L,1)
504 return 1; 533 return 1;
505} 534}
506 535
@@ -511,15 +540,16 @@ int luaG_deep_userdata( lua_State *L ) {
511* Reference count is not changed, and access to the deep userdata is not 540* Reference count is not changed, and access to the deep userdata is not
512* serialized. It is the module's responsibility to prevent conflicting usage. 541* serialized. It is the module's responsibility to prevent conflicting usage.
513*/ 542*/
514void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index ) { 543void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index )
544{
515 DEEP_PRELUDE **proxy; 545 DEEP_PRELUDE **proxy;
516 546
517 STACK_CHECK(L) 547 STACK_CHECK(L)
518 if (get_idfunc(L,index) != idfunc) 548 if( get_idfunc(L,index) != idfunc)
519 return NULL; // no metatable, or wrong kind 549 return NULL; // no metatable, or wrong kind
520 550
521 proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); 551 proxy= (DEEP_PRELUDE**)lua_touserdata( L, index );
522 STACK_END(L,0) 552 STACK_END(L,0)
523 553
524 return (*proxy)->deep; 554 return (*proxy)->deep;
525} 555}
@@ -533,14 +563,14 @@ void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index ) {
533* (not copied) 563* (not copied)
534*/ 564*/
535static 565static
536lua_CFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) { 566luaG_IdFunction luaG_copydeep( lua_State *L, lua_State *L2, int index )
567{
537 DEEP_PRELUDE **proxy; 568 DEEP_PRELUDE **proxy;
538 DEEP_PRELUDE *p; 569 DEEP_PRELUDE *p;
539 570
540 lua_CFunction idfunc; 571 luaG_IdFunction idfunc = get_idfunc( L, index);
541 572 if (!idfunc)
542 idfunc= get_idfunc( L, index ); 573 return NULL; // not a deep userdata
543 if (!idfunc) return NULL; // not a deep userdata
544 574
545 // Increment reference count 575 // Increment reference count
546 // 576 //
diff --git a/src/tools.h b/src/tools.h
index aad26df..05bee59 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -48,19 +48,21 @@
48 48
49#define luaG_typename( L, index ) lua_typename( L, lua_type(L,index) ) 49#define luaG_typename( L, index ) lua_typename( L, lua_type(L,index) )
50 50
51typedef void (*luaG_IdFunction)( lua_State *L, char const * const which);
52
51void luaG_dump( lua_State* L ); 53void luaG_dump( lua_State* L );
52 54
53const char *luaG_openlibs( lua_State *L, const char *libs ); 55const char *luaG_openlibs( lua_State *L, const char *libs );
54 56
55int luaG_deep_userdata( lua_State *L ); 57int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc);
56void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index ); 58void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index );
57 59
58typedef struct { 60typedef struct {
59 volatile int refcount; 61 volatile int refcount;
60 void *deep; 62 void *deep;
61} DEEP_PRELUDE; 63} DEEP_PRELUDE;
62 64
63void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *deep_userdata ); 65void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_userdata );
64 66
65void luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n ); 67void luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n );
66void luaG_inter_move( lua_State *L, lua_State *L2, uint_t n ); 68void luaG_inter_move( lua_State *L, lua_State *L2, uint_t n );
diff --git a/tests/basic.lua b/tests/basic.lua
index b1e8fd3..352e029 100644
--- a/tests/basic.lua
+++ b/tests/basic.lua
@@ -171,7 +171,7 @@ local function PEEK() return linda:get("<-") end
171local function SEND(...) linda:send( "->", ... ) end 171local function SEND(...) linda:send( "->", ... ) end
172local function RECEIVE() return linda:receive( "<-" ) end 172local function RECEIVE() return linda:receive( "<-" ) end
173 173
174local t= lanes_gen("io",chunk)(linda) -- prepare & launch 174local t= lanes_gen("io,package",chunk)(linda) -- prepare & launch
175 175
176SEND(1); WR( "1 sent\n" ) 176SEND(1); WR( "1 sent\n" )
177SEND(2); WR( "2 sent\n" ) 177SEND(2); WR( "2 sent\n" )
@@ -230,7 +230,7 @@ local tc= lanes_gen( "io",
230 end 230 end
231 STAGE("Hello") 231 STAGE("Hello")
232 STAGE("I was here first!") 232 STAGE("I was here first!")
233 STAGE("So waht?") 233 STAGE("So what?")
234 end 234 end
235) 235)
236 236
@@ -247,7 +247,6 @@ local upvalue="123"
247 247
248local function chunk2( linda ) 248local function chunk2( linda )
249 assert( upvalue=="123" ) -- even when running as separate thread 249 assert( upvalue=="123" ) -- even when running as separate thread
250
251 -- function name & line number should be there even as separate thread 250 -- function name & line number should be there even as separate thread
252 -- 251 --
253 local info= debug.getinfo(1) -- 1 = us 252 local info= debug.getinfo(1) -- 1 = us
@@ -256,17 +255,14 @@ local function chunk2( linda )
256 255
257 assert( info.nups == 2 ) -- one upvalue + PRINT 256 assert( info.nups == 2 ) -- one upvalue + PRINT
258 assert( info.what == "Lua" ) 257 assert( info.what == "Lua" )
259
260 --assert( info.name == "chunk2" ) -- name does not seem to come through 258 --assert( info.name == "chunk2" ) -- name does not seem to come through
261 assert( string.match( info.source, "^@basic.lua$" ) ) 259 assert( string.match( info.source, "^@.*basic.lua$" ) )
262 assert( string.match( info.short_src, "^basic.lua$" ) ) 260 assert( string.match( info.short_src, "^.*basic.lua$" ) )
263
264 -- These vary so let's not be picky (they're there..) 261 -- These vary so let's not be picky (they're there..)
265 -- 262 --
266 assert( info.linedefined > 200 ) -- start of 'chunk2' 263 assert( info.linedefined > 200 ) -- start of 'chunk2'
267 assert( info.currentline > info.linedefined ) -- line of 'debug.getinfo' 264 assert( info.currentline > info.linedefined ) -- line of 'debug.getinfo'
268 assert( info.lastlinedefined > info.currentline ) -- end of 'chunk2' 265 assert( info.lastlinedefined > info.currentline ) -- end of 'chunk2'
269
270 local func,k= linda:receive( "down" ) 266 local func,k= linda:receive( "down" )
271 assert( type(func)=="function" ) 267 assert( type(func)=="function" )
272 assert( k=="down" ) 268 assert( k=="down" )
@@ -280,12 +276,9 @@ local function chunk2( linda )
280end 276end
281 277
282local linda= lanes.linda() 278local linda= lanes.linda()
283 279local t2= lanes_gen( "debug,string,io", chunk2 )(linda) -- prepare & launch
284local t2= lanes_gen( "debug,string", chunk2 )(linda) -- prepare & launch
285
286linda:send( "down", function(linda) linda:send( "up", "ready!" ) end, 280linda:send( "down", function(linda) linda:send( "up", "ready!" ) end,
287 "ok" ) 281 "ok" )
288
289-- wait to see if the tiny function gets executed 282-- wait to see if the tiny function gets executed
290-- 283--
291local s= linda:receive( "up" ) 284local s= linda:receive( "up" )