diff options
author | Peter Drahoš <drahosp@gmail.com> | 2010-10-01 03:22:32 +0200 |
---|---|---|
committer | Peter Drahoš <drahosp@gmail.com> | 2010-10-01 03:22:32 +0200 |
commit | 89d9c98af1ac352ba4d49d660e61b0853d6e1a86 (patch) | |
tree | 15c56d2ce66b4ab147171c0f674cdb4a435ff13f /tests | |
download | lanes-89d9c98af1ac352ba4d49d660e61b0853d6e1a86.tar.gz lanes-89d9c98af1ac352ba4d49d660e61b0853d6e1a86.tar.bz2 lanes-89d9c98af1ac352ba4d49d660e61b0853d6e1a86.zip |
Import to git
Diffstat (limited to 'tests')
-rw-r--r-- | tests/argtable.lua | 38 | ||||
-rw-r--r-- | tests/assert.lua | 318 | ||||
-rw-r--r-- | tests/atomic.lua | 18 | ||||
-rw-r--r-- | tests/basic.lua | 331 | ||||
-rw-r--r-- | tests/cyclic.lua | 64 | ||||
-rw-r--r-- | tests/ehynes.lua | 52 | ||||
-rw-r--r-- | tests/error.lua | 47 | ||||
-rw-r--r-- | tests/fibonacci.lua | 75 | ||||
-rw-r--r-- | tests/fifo.lua | 43 | ||||
-rw-r--r-- | tests/finalizer.lua | 81 | ||||
-rw-r--r-- | tests/hangtest.lua | 26 | ||||
-rw-r--r-- | tests/irayo_closure.lua | 35 | ||||
-rw-r--r-- | tests/irayo_recursive.lua | 18 | ||||
-rw-r--r-- | tests/keeper.lua | 47 | ||||
-rw-r--r-- | tests/launchtest.lua | 78 | ||||
-rw-r--r-- | tests/objects.lua | 76 | ||||
-rw-r--r-- | tests/perftest.lua | 184 | ||||
-rw-r--r-- | tests/recursive.lua | 21 | ||||
-rw-r--r-- | tests/require.lua | 30 | ||||
-rw-r--r-- | tests/timer.lua | 93 |
20 files changed, 1675 insertions, 0 deletions
diff --git a/tests/argtable.lua b/tests/argtable.lua new file mode 100644 index 0000000..5ed5d4e --- /dev/null +++ b/tests/argtable.lua | |||
@@ -0,0 +1,38 @@ | |||
1 | -- | ||
2 | -- ARGTABLE.LUA Copyright (c) 2007, Asko Kauppi <akauppi@gmail.com> | ||
3 | -- | ||
4 | -- Command line parameter parsing | ||
5 | -- | ||
6 | -- NOTE: Wouldn't hurt having such a service built-in to Lua...? :P | ||
7 | -- | ||
8 | |||
9 | local m= {} | ||
10 | |||
11 | -- tbl= argtable(...) | ||
12 | -- | ||
13 | -- Returns a table with 1..N indices being 'value' parameters, and any | ||
14 | -- "-flag[=xxx]" or "--flag[=xxx]" parameters set to { flag=xxx/true }. | ||
15 | -- | ||
16 | -- In other words, makes handling command line parameters simple. :) | ||
17 | -- | ||
18 | -- 15 --> { 15 } | ||
19 | -- -20 --> { -20 } | ||
20 | -- -a --> { ['a']=true } | ||
21 | -- --some=15 --> { ['some']=15 } | ||
22 | -- --more=big --> { ['more']='big' } | ||
23 | -- | ||
24 | function m.argtable(...) | ||
25 | local ret= {} | ||
26 | for i=1,select('#',...) do | ||
27 | local v= select(i,...) | ||
28 | local flag,val= string.match( v, "^%-+([^=]+)%=?(.*)" ) | ||
29 | if flag and not tonumber(v) then | ||
30 | ret[flag]= (val=="") and true or tonumber(val) or val | ||
31 | else | ||
32 | table.insert( ret, v ) -- 1..N | ||
33 | end | ||
34 | end | ||
35 | return ret | ||
36 | end | ||
37 | |||
38 | return m | ||
diff --git a/tests/assert.lua b/tests/assert.lua new file mode 100644 index 0000000..85febfb --- /dev/null +++ b/tests/assert.lua | |||
@@ -0,0 +1,318 @@ | |||
1 | -- | ||
2 | -- ASSERT.LUA Copyright (c) 2006-07, <akauppi@gmail.com> | ||
3 | -- | ||
4 | -- Converting the Lua 'assert' function into a namespace table (without | ||
5 | -- breaking compatibility with the basic 'assert()' calling). | ||
6 | -- | ||
7 | -- This module allows shorthand use s.a. 'assert.table()' for asserting | ||
8 | -- variable types, and is also being used by Lua-super constraints system | ||
9 | -- for testing function parameter & return types. | ||
10 | -- | ||
11 | -- All in all, a worthy module and could be part of Lua future versions. | ||
12 | -- | ||
13 | -- Note: the 'assert' table is available for your own assertions, too. Just add | ||
14 | -- more functions s.a. 'assert.myobj()' to check for custom invariants. | ||
15 | -- They will then be available for the constraints check, too. | ||
16 | -- | ||
17 | -- Author: <akauppi@gmail.com> | ||
18 | -- | ||
19 | --[[ | ||
20 | /****************************************************************************** | ||
21 | * Lua 5.1.1 support and extension functions (assert.lua) | ||
22 | * | ||
23 | * Copyright (C) 2006-07, Asko Kauppi. | ||
24 | * | ||
25 | * NOTE: This license concerns only the particular source file; not necessarily | ||
26 | * the project with which it has been delivered (the project may have a more | ||
27 | * restrictive license, s.a. [L]GPL). | ||
28 | * | ||
29 | * Permission is hereby granted, free of charge, to any person obtaining | ||
30 | * a copy of this software and associated documentation files (the | ||
31 | * "Software"), to deal in the Software without restriction, including | ||
32 | * without limitation the rights to use, copy, modify, merge, publish, | ||
33 | * distribute, sublicense, and/or sell copies of the Software, and to | ||
34 | * permit persons to whom the Software is furnished to do so, subject to | ||
35 | * the following conditions: | ||
36 | * | ||
37 | * The above copyright notice and this permission notice shall be | ||
38 | * included in all copies or substantial portions of the Software. | ||
39 | * | ||
40 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
41 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
42 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
43 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
44 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
45 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
46 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
47 | ******************************************************************************/ | ||
48 | ]]-- | ||
49 | |||
50 | local m= { _info= { MODULE= "Assert.* functions for constraints, and unit testing", | ||
51 | AUTHOR= "akauppi@gmail.com", | ||
52 | VERSION= 20070603, -- last change (yyyymmdd) | ||
53 | LICENSE= "MIT/X11" } } | ||
54 | |||
55 | -- Global changes: | ||
56 | -- 'assert' redefined, in a backwards compatible way | ||
57 | -- | ||
58 | -- Module functions: | ||
59 | -- none | ||
60 | |||
61 | assert( type(assert) == "function" ) -- system assert function | ||
62 | |||
63 | ----- | ||
64 | -- Integer range: INT_MIN..INT_MAX | ||
65 | -- | ||
66 | local function try_maxint( n ) | ||
67 | return (n > n-1) and n-1 -- false when outside the integer range | ||
68 | end | ||
69 | |||
70 | local INT_MAX= | ||
71 | try_maxint( 2^64 ) or | ||
72 | try_maxint( 2^32 ) or | ||
73 | try_maxint( 2^24 ) or -- float (24-bit mantissa) | ||
74 | assert( false ) | ||
75 | |||
76 | local INT_MIN= -(INT_MAX+1) | ||
77 | |||
78 | |||
79 | ---=== assert.*() ===--- | ||
80 | |||
81 | local at_msg= "type assertion error" -- TBD: better messages, about that exact situation | ||
82 | local av_msg= "value assertion error" | ||
83 | |||
84 | -- void= _assert( val [, msg_str [, lev_uint]] ) | ||
85 | -- | ||
86 | local function _assert( cond, msg, lev ) | ||
87 | -- original 'assert' provides no level override, so we use 'error'. | ||
88 | -- | ||
89 | if not cond then | ||
90 | error( msg or "assertion failed!", (lev or 1)+1 ) | ||
91 | end | ||
92 | end | ||
93 | |||
94 | -- Note: following code uses the _new_ 'assert()' by purpose, since it provides | ||
95 | -- a level override (original doesn't) | ||
96 | -- | ||
97 | local function assert_v( v0 ) | ||
98 | return function(v,msg) | ||
99 | _assert( v == v0, msg or av_msg, 2 ) | ||
100 | return v | ||
101 | end | ||
102 | end | ||
103 | local function assert_t( str ) | ||
104 | return function(v,msg) | ||
105 | _assert( type(v) == str, msg or at_msg, 2 ) | ||
106 | return v | ||
107 | end | ||
108 | end | ||
109 | local function assert_t2( str ) | ||
110 | return function(v,subtype,msg) | ||
111 | local t,st= type(v) | ||
112 | _assert( t==str and ((not subtype) or (st==subtype)), | ||
113 | msg or at_msg, 2 ) | ||
114 | return v | ||
115 | end | ||
116 | end | ||
117 | |||
118 | assert= | ||
119 | { | ||
120 | __call= function(_,v,msg) -- plain 'assert()' (compatibility) | ||
121 | if v then return v end | ||
122 | _assert( v, msg, 2 ) | ||
123 | end, | ||
124 | |||
125 | -- Hopefully, Lua will allow use of 'nil', 'function' and other reserved words as table | ||
126 | -- shortcuts in the future (5.1.1 does not). | ||
127 | -- | ||
128 | ["nil"]= assert_v( nil ), | ||
129 | boolean= assert_t "boolean", | ||
130 | table= assert_t2 "table", | ||
131 | ["function"]= assert_t "function", | ||
132 | userdata= assert_t2 "userdata", | ||
133 | |||
134 | string= function( v, msg ) | ||
135 | local s= tostring(v) | ||
136 | _assert( s, msg or at_msg, 2 ) | ||
137 | return v | ||
138 | end, | ||
139 | |||
140 | char= function( v, msg ) | ||
141 | -- 'char' is _not_ doing int->string conversion | ||
142 | _assert( type(v)=="string" and v:len()==1, msg or at_msg, 2 ) | ||
143 | return v | ||
144 | end, | ||
145 | |||
146 | number= function( v, msg ) | ||
147 | _assert( tonumber(v), msg or at_msg, 2 ) | ||
148 | return v | ||
149 | end, | ||
150 | |||
151 | int= function( v, msg ) | ||
152 | local n= tonumber(v) | ||
153 | _assert( n and (n >= INT_MIN) and (n <= INT_MAX) and math.floor(n) == n, | ||
154 | msg or at_msg, 2 ) | ||
155 | return v | ||
156 | end, | ||
157 | |||
158 | uint= function( v, msg ) | ||
159 | local n= tonumber(v) | ||
160 | -- unsigned integer upper range is the same as integers' (there's no | ||
161 | -- real unsigned within the Lua) | ||
162 | _assert( n and (n >= 0) and (n <= INT_MAX) and math.floor(n) == n, | ||
163 | msg or at_msg, 2 ) | ||
164 | return v | ||
165 | end, | ||
166 | |||
167 | ['true']= assert_v( true ), | ||
168 | ['false']= assert_v( false ), | ||
169 | |||
170 | string_or_table= function( v, msg ) | ||
171 | assert( tostring(v) or type(v)=="table", msg or at_msg, 2 ) | ||
172 | return v | ||
173 | end, | ||
174 | |||
175 | number_or_string= function( v, msg ) | ||
176 | assert( tonumber(v) or type(v)=="table", msg or at_msg, 2 ) | ||
177 | return v | ||
178 | end, | ||
179 | |||
180 | any= function( v, msg ) | ||
181 | assert( v ~= nil, msg or av_msg, 2 ) | ||
182 | return v | ||
183 | end, | ||
184 | |||
185 | -- Range assertion, with extra parameters per instance | ||
186 | -- | ||
187 | -- Note: values may be of _any_ type that can do >=, <= comparisons. | ||
188 | -- | ||
189 | range= function( lo, hi ) | ||
190 | _assert( lo and hi and lo <= hi, "Bad limits", 2 ) | ||
191 | -- make sure the limits make sense (just once) | ||
192 | |||
193 | return function(v,msg,lev) | ||
194 | if ( (lo and v<lo) or (hi and v>hi) ) then | ||
195 | msg= msg or "not in range: ("..(lo or "")..","..(hi or "")..")" | ||
196 | _assert( false, msg, 2 ) | ||
197 | end | ||
198 | return v | ||
199 | end | ||
200 | end, | ||
201 | |||
202 | -- Table contents assertion | ||
203 | -- - no unknown (non-numeric) keys are allowed | ||
204 | -- - numeric keys are ignored | ||
205 | -- | ||
206 | -- Constraints patch should point to this, when using the ":{ ... }" constraint. | ||
207 | -- | ||
208 | ["{}"]= function( tbl ) | ||
209 | |||
210 | -- check all keys in 't' (including numeric, if any) that they do exist, | ||
211 | -- and carry the right type | ||
212 | -- | ||
213 | local function subf1(v,t,msg,lev) | ||
214 | _assert(lev) | ||
215 | for k,f in pairs(t) do | ||
216 | -- 'f' is an assert function, or subtable | ||
217 | local ft= type(f) | ||
218 | if ft=="function" then | ||
219 | f( v[k], msg, lev+1 ) | ||
220 | elseif ft=="table" then | ||
221 | _assert( type(v[k])=="table", msg or "no subtable "..tostring(k), lev+1 ) | ||
222 | subf1( v[k], f, msg, lev+1 ) | ||
223 | else | ||
224 | error( "Bad constraints table for '"..tostring(k).."'! (not a function)", lev+1 ) | ||
225 | end | ||
226 | end | ||
227 | end | ||
228 | |||
229 | -- check there are no other (non-numeric) keys in 'v' | ||
230 | local function subf2(v,t,msg,lev) | ||
231 | _assert(lev) | ||
232 | for k,vv in pairs(v) do | ||
233 | if type(k)=="number" then | ||
234 | -- skip them | ||
235 | elseif not t[k] then | ||
236 | _assert( false, msg or "extra field: '"..tostring(k).."'", lev+1 ) | ||
237 | elseif type(vv)=="table" then | ||
238 | subf2( vv, t[k], msg, lev+1 ) | ||
239 | end | ||
240 | end | ||
241 | end | ||
242 | |||
243 | _assert( type(tbl)=="table", "Wrong parameter to assert['{}']" ) | ||
244 | |||
245 | return function( v, msg, lev ) | ||
246 | lev= (lev or 1)+1 | ||
247 | _assert( type(v)=="table" ,msg, lev ) | ||
248 | subf1( v, tbl, msg, lev ) | ||
249 | subf2( v, tbl, msg, lev ) | ||
250 | return v | ||
251 | end | ||
252 | end, | ||
253 | |||
254 | -- ... | ||
255 | } | ||
256 | setmetatable( assert, assert ) | ||
257 | |||
258 | assert.void= assert["nil"] | ||
259 | |||
260 | |||
261 | ----- | ||
262 | -- void= assert.fails( function [,err_msg_str] ) | ||
263 | -- | ||
264 | -- Special assert function, to make sure the call within it fails, and gives a | ||
265 | -- specific error message (to be used in unit testing). | ||
266 | -- | ||
267 | function assert.fails( func_block, err_msg ) | ||
268 | -- | ||
269 | local st,err= pcall( func_block ) | ||
270 | if st then | ||
271 | _assert( false, "Block expected to fail, but didn't.", 2 ) | ||
272 | elseif err_msg and err ~= err_msg then | ||
273 | _assert( false, "Failed with wrong error message: \n".. | ||
274 | "'"..err.."'\nexpected: '"..err_msg.."'", 2 ) | ||
275 | end | ||
276 | end | ||
277 | |||
278 | |||
279 | ----- | ||
280 | -- void= assert.failsnot( function [,err_msg_str] ) | ||
281 | -- | ||
282 | -- Similar to 'assert.fails' but expects the code to survive. | ||
283 | -- | ||
284 | function assert.failsnot( func_block, err_msg ) | ||
285 | -- | ||
286 | local st,err= pcall( func_block ) | ||
287 | if not st then | ||
288 | _assert( false, "Block expected NOT to fail, but did.".. | ||
289 | (err and "\n\tError: '"..err.."'" or ""), 2 ) | ||
290 | end | ||
291 | end | ||
292 | |||
293 | |||
294 | ----- | ||
295 | -- void= assert.nilerr( function [,err_msg_str] ) | ||
296 | -- | ||
297 | -- Expects the function to return with 'nil,err' failure code, with | ||
298 | -- optionally error string matching. Similar to --> 'assert.fails()' | ||
299 | -- | ||
300 | function assert.nilerr( func_block, err_msg ) | ||
301 | -- | ||
302 | local v,err= func_block() | ||
303 | _assert( v==nil, "Expected to return nil, but didn't: "..tostring(v), 2 ) | ||
304 | if err_msg and err ~= err_msg then | ||
305 | _assert( false, "Failed with wrong error message: \n".. | ||
306 | "'"..err.."'\nexpected: '"..err_msg.."'", 2 ) | ||
307 | end | ||
308 | end | ||
309 | |||
310 | |||
311 | -- Sanity check | ||
312 | -- | ||
313 | assert( true ) | ||
314 | assert.fails( function() assert( false ) end ) | ||
315 | assert.fails( function() assert( nil ) end ) | ||
316 | |||
317 | |||
318 | return m -- just info | ||
diff --git a/tests/atomic.lua b/tests/atomic.lua new file mode 100644 index 0000000..a027453 --- /dev/null +++ b/tests/atomic.lua | |||
@@ -0,0 +1,18 @@ | |||
1 | -- | ||
2 | -- ATOMIC.LUA | ||
3 | -- | ||
4 | -- Test program for Lua Lanes | ||
5 | -- | ||
6 | |||
7 | require "lanes" | ||
8 | |||
9 | local linda= lanes.linda() | ||
10 | local key= "$" | ||
11 | |||
12 | local f= lanes.genatomic( linda, key, 5 ) | ||
13 | |||
14 | local v | ||
15 | v= f(); print(v); assert(v==6) | ||
16 | v= f(-0.5); print(v); assert(v==5.5) | ||
17 | |||
18 | v= f(-10); print(v); assert(v==-4.5) | ||
diff --git a/tests/basic.lua b/tests/basic.lua new file mode 100644 index 0000000..ee31ed1 --- /dev/null +++ b/tests/basic.lua | |||
@@ -0,0 +1,331 @@ | |||
1 | -- | ||
2 | -- BASIC.LUA Copyright (c) 2007-08, Asko Kauppi <akauppi@gmail.com> | ||
3 | -- | ||
4 | -- Selftests for Lua Lanes | ||
5 | -- | ||
6 | -- To do: | ||
7 | -- - ... | ||
8 | -- | ||
9 | |||
10 | require "lanes" | ||
11 | require "assert" -- assert.fails() | ||
12 | |||
13 | local lanes_gen= assert( lanes.gen ) | ||
14 | local lanes_linda= assert( lanes.linda ) | ||
15 | |||
16 | local tostring= assert( tostring ) | ||
17 | |||
18 | local function PRINT(...) | ||
19 | local str="" | ||
20 | for i=1,select('#',...) do | ||
21 | str= str..tostring(select(i,...)).."\t" | ||
22 | end | ||
23 | if io then | ||
24 | io.stderr:write(str.."\n") | ||
25 | end | ||
26 | end | ||
27 | |||
28 | |||
29 | ---=== Local helpers ===--- | ||
30 | |||
31 | local tables_match | ||
32 | |||
33 | -- true if 'a' is a subtable of 'b' | ||
34 | -- | ||
35 | local function subtable( a, b ) | ||
36 | -- | ||
37 | assert( type(a)=="table" and type(b)=="table" ) | ||
38 | |||
39 | for k,v in pairs(b) do | ||
40 | if type(v)~=type(a[k]) then | ||
41 | return false -- not subtable (different types, or missing key) | ||
42 | elseif type(v)=="table" then | ||
43 | if not tables_match(v,a[k]) then return false end | ||
44 | else | ||
45 | if a[k] ~= v then return false end | ||
46 | end | ||
47 | end | ||
48 | return true -- is a subtable | ||
49 | end | ||
50 | |||
51 | -- true when contents of 'a' and 'b' are identific | ||
52 | -- | ||
53 | tables_match= function( a, b ) | ||
54 | return subtable( a, b ) and subtable( b, a ) | ||
55 | end | ||
56 | |||
57 | |||
58 | ---=== Tasking (basic) ===--- | ||
59 | |||
60 | local function task( a, b, c ) | ||
61 | --error "111" -- testing error messages | ||
62 | assert(hey) | ||
63 | local v=0 | ||
64 | for i=a,b,c do | ||
65 | v= v+i | ||
66 | end | ||
67 | return v, hey | ||
68 | end | ||
69 | |||
70 | local task_launch= lanes_gen( "", { globals={hey=true} }, task ) | ||
71 | -- base stdlibs, normal priority | ||
72 | |||
73 | -- 'task_launch' is a factory of multithreaded tasks, we can launch several: | ||
74 | |||
75 | local lane1= task_launch( 100,200,3 ) | ||
76 | local lane2= task_launch( 200,300,4 ) | ||
77 | |||
78 | -- At this stage, states may be "pending", "running" or "done" | ||
79 | |||
80 | local st1,st2= lane1.status, lane2.status | ||
81 | PRINT(st1,st2) | ||
82 | assert( st1=="pending" or st1=="running" or st1=="done" ) | ||
83 | assert( st2=="pending" or st2=="running" or st2=="done" ) | ||
84 | |||
85 | -- Accessing results ([1..N]) pends until they are available | ||
86 | -- | ||
87 | PRINT("waiting...") | ||
88 | local v1, v1_hey= lane1[1], lane1[2] | ||
89 | local v2, v2_hey= lane2[1], lane2[2] | ||
90 | |||
91 | PRINT( v1, v1_hey ) | ||
92 | assert( v1_hey == true ) | ||
93 | |||
94 | PRINT( v2, v2_hey ) | ||
95 | assert( v2_hey == true ) | ||
96 | |||
97 | assert( lane1.status == "done" ) | ||
98 | assert( lane1.status == "done" ) | ||
99 | |||
100 | |||
101 | ---=== Tasking (cancelling) ===--- | ||
102 | |||
103 | local task_launch2= lanes_gen( "", { cancelstep=100, globals={hey=true} }, task ) | ||
104 | |||
105 | local N=999999999 | ||
106 | local lane9= task_launch2(1,N,1) -- huuuuuuge... | ||
107 | |||
108 | -- Wait until state changes "pending"->"running" | ||
109 | -- | ||
110 | local st | ||
111 | local t0= os.time() | ||
112 | while os.time()-t0 < 5 do | ||
113 | st= lane9.status | ||
114 | io.stderr:write( (i==1) and st.." " or '.' ) | ||
115 | if st~="pending" then break end | ||
116 | end | ||
117 | PRINT(" "..st) | ||
118 | |||
119 | if st=="error" then | ||
120 | local _= lane9[0] -- propagate the error here | ||
121 | end | ||
122 | if st=="done" then | ||
123 | error( "Looping to "..N.." was not long enough (cannot test cancellation)" ) | ||
124 | end | ||
125 | assert( st=="running" ) | ||
126 | |||
127 | lane9:cancel() | ||
128 | |||
129 | local t0= os.time() | ||
130 | while os.time()-t0 < 5 do | ||
131 | st= lane9.status | ||
132 | io.stderr:write( (i==1) and st.." " or '.' ) | ||
133 | if st~="running" then break end | ||
134 | end | ||
135 | PRINT(" "..st) | ||
136 | assert( st == "cancelled" ) | ||
137 | |||
138 | |||
139 | ---=== Communications ===--- | ||
140 | |||
141 | local function WR(...) io.stderr:write(...) end | ||
142 | |||
143 | local chunk= function( linda ) | ||
144 | |||
145 | local function receive() return linda:receive( "->" ) end | ||
146 | local function send(...) linda:send( "<-", ... ) end | ||
147 | |||
148 | WR( "Lane starts!\n" ) | ||
149 | |||
150 | local v | ||
151 | v=receive(); WR( v.." received\n" ); assert( v==1 ) | ||
152 | v=receive(); WR( v.." received\n" ); assert( v==2 ) | ||
153 | v=receive(); WR( v.." received\n" ); assert( v==3 ) | ||
154 | |||
155 | send( 1,2,3 ); WR( "1,2,3 sent\n" ) | ||
156 | send 'a'; WR( "'a' sent\n" ) | ||
157 | send { 'a', 'b', 'c', d=10 }; WR( "{'a','b','c',d=10} sent\n" ) | ||
158 | |||
159 | v=receive(); WR( v.." received\n" ); assert( v==4 ) | ||
160 | |||
161 | WR( "Lane ends!\n" ) | ||
162 | end | ||
163 | |||
164 | local linda= lanes_linda() | ||
165 | assert( type(linda) == "userdata" ) | ||
166 | -- | ||
167 | -- ["->"] master -> slave | ||
168 | -- ["<-"] slave <- master | ||
169 | |||
170 | local function PEEK() return linda:get("<-") end | ||
171 | local function SEND(...) linda:send( "->", ... ) end | ||
172 | local function RECEIVE() return linda:receive( "<-" ) end | ||
173 | |||
174 | local t= lanes_gen("io",chunk)(linda) -- prepare & launch | ||
175 | |||
176 | SEND(1); WR( "1 sent\n" ) | ||
177 | SEND(2); WR( "2 sent\n" ) | ||
178 | for i=1,100 do | ||
179 | WR "." | ||
180 | assert( PEEK() == nil ) -- nothing coming in, yet | ||
181 | end | ||
182 | SEND(3); WR( "3 sent\n" ) | ||
183 | |||
184 | local a,b,c= RECEIVE(), RECEIVE(), RECEIVE() | ||
185 | WR( a..", "..b..", "..c.." received\n" ) | ||
186 | assert( a==1 and b==2 and c==3 ) | ||
187 | |||
188 | local a= RECEIVE(); WR( a.." received\n" ) | ||
189 | assert( a=='a' ) | ||
190 | |||
191 | local a= RECEIVE(); WR( type(a).." received\n" ) | ||
192 | assert( tables_match( a, {'a','b','c',d=10} ) ) | ||
193 | |||
194 | assert( PEEK() == nil ) | ||
195 | SEND(4) | ||
196 | |||
197 | |||
198 | ---=== Stdlib naming ===--- | ||
199 | |||
200 | local function io_os_f() | ||
201 | assert(io) | ||
202 | assert(os) | ||
203 | assert(print) | ||
204 | return true | ||
205 | end | ||
206 | |||
207 | local f1= lanes_gen( "io,os", io_os_f ) -- any delimiter will do | ||
208 | local f2= lanes_gen( "io+os", io_os_f ) | ||
209 | local f3= lanes_gen( "io,os,base", io_os_f ) | ||
210 | |||
211 | assert.fails( function() lanes_gen( "xxx", io_os_f ) end ) | ||
212 | |||
213 | assert( f1()[1] ) | ||
214 | assert( f2()[1] ) | ||
215 | assert( f3()[1] ) | ||
216 | |||
217 | |||
218 | ---=== Comms criss cross ===--- | ||
219 | |||
220 | -- We make two identical lanes, which are using the same Linda channel. | ||
221 | -- | ||
222 | local tc= lanes_gen( "io", | ||
223 | function( linda, ch_in, ch_out ) | ||
224 | |||
225 | local function STAGE(str) | ||
226 | io.stderr:write( ch_in..": "..str.."\n" ) | ||
227 | linda:send( nil, ch_out, str ) | ||
228 | local v= linda:receive( nil, ch_in ) | ||
229 | assert(v==str) | ||
230 | end | ||
231 | STAGE("Hello") | ||
232 | STAGE("I was here first!") | ||
233 | STAGE("So waht?") | ||
234 | end | ||
235 | ) | ||
236 | |||
237 | local linda= lanes_linda() | ||
238 | |||
239 | local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twisted comms | ||
240 | |||
241 | local _= a[1],b[1] -- waits until they are both ready | ||
242 | |||
243 | |||
244 | ---=== Receive & send of code ===--- | ||
245 | |||
246 | local upvalue="123" | ||
247 | |||
248 | local function chunk2( linda ) | ||
249 | assert( upvalue=="123" ) -- even when running as separate thread | ||
250 | |||
251 | -- function name & line number should be there even as separate thread | ||
252 | -- | ||
253 | local info= debug.getinfo(1) -- 1 = us | ||
254 | -- | ||
255 | for k,v in pairs(info) do PRINT(k,v) end | ||
256 | |||
257 | assert( info.nups == 2 ) -- one upvalue + PRINT | ||
258 | assert( info.what == "Lua" ) | ||
259 | |||
260 | --assert( info.name == "chunk2" ) -- name does not seem to come through | ||
261 | assert( string.match( info.source, "^@tests[/\\]basic.lua$" ) ) | ||
262 | assert( string.match( info.short_src, "^tests[/\\]basic.lua$" ) ) | ||
263 | |||
264 | -- These vary so let's not be picky (they're there..) | ||
265 | -- | ||
266 | assert( info.linedefined > 200 ) -- start of 'chunk2' | ||
267 | assert( info.currentline > info.linedefined ) -- line of 'debug.getinfo' | ||
268 | assert( info.lastlinedefined > info.currentline ) -- end of 'chunk2' | ||
269 | |||
270 | local func,k= linda:receive( "down" ) | ||
271 | assert( type(func)=="function" ) | ||
272 | assert( k=="down" ) | ||
273 | |||
274 | func(linda) | ||
275 | |||
276 | local str= linda:receive( "down" ) | ||
277 | assert( str=="ok" ) | ||
278 | |||
279 | linda:send( "up", function() return ":)" end, "ok2" ) | ||
280 | end | ||
281 | |||
282 | local linda= lanes.linda() | ||
283 | |||
284 | local t2= lanes_gen( "debug,string", chunk2 )(linda) -- prepare & launch | ||
285 | |||
286 | linda:send( "down", function(linda) linda:send( "up", "ready!" ) end, | ||
287 | "ok" ) | ||
288 | |||
289 | -- wait to see if the tiny function gets executed | ||
290 | -- | ||
291 | local s= linda:receive( "up" ) | ||
292 | PRINT(s) | ||
293 | assert( s=="ready!" ) | ||
294 | |||
295 | -- returns of the 'chunk2' itself | ||
296 | -- | ||
297 | local f= linda:receive( "up" ) | ||
298 | assert( type(f)=="function" ) | ||
299 | |||
300 | local s2= f() | ||
301 | assert( s2==":)" ) | ||
302 | |||
303 | local ok2= linda:receive( "up" ) | ||
304 | assert( ok2 == "ok2" ) | ||
305 | |||
306 | |||
307 | ---=== :join test ===--- | ||
308 | |||
309 | -- NOTE: 'unpack()' cannot be used on the lane handle; it will always return nil | ||
310 | -- (unless [1..n] has been read earlier, in which case it would seemingly | ||
311 | -- work). | ||
312 | |||
313 | local S= lanes_gen( "table", | ||
314 | function(arg) | ||
315 | aux= {} | ||
316 | for i, v in ipairs(arg) do | ||
317 | table.insert (aux, 1, v) | ||
318 | end | ||
319 | return unpack(aux) | ||
320 | end ) | ||
321 | |||
322 | h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values | ||
323 | |||
324 | local a,b,c,d= h:join() | ||
325 | assert(a==14) | ||
326 | assert(b==13) | ||
327 | assert(c==12) | ||
328 | assert(d==nil) | ||
329 | |||
330 | -- | ||
331 | io.stderr:write "Done! :)\n" | ||
diff --git a/tests/cyclic.lua b/tests/cyclic.lua new file mode 100644 index 0000000..06452bd --- /dev/null +++ b/tests/cyclic.lua | |||
@@ -0,0 +1,64 @@ | |||
1 | -- | ||
2 | -- CYCLIC.LUA | ||
3 | -- | ||
4 | -- Test program for Lua Lanes | ||
5 | -- | ||
6 | |||
7 | require "lanes" | ||
8 | |||
9 | local table_concat= assert(table.concat) | ||
10 | |||
11 | local function WR(str,...) | ||
12 | for i=1,select('#',...) do | ||
13 | str= str.."\t"..tostring( select(i,...) ) | ||
14 | end | ||
15 | io.stderr:write( str..'\n' ) | ||
16 | end | ||
17 | |||
18 | local function same(k,l) | ||
19 | return k==l and "same" or ("NOT SAME: "..k.." "..l) | ||
20 | end | ||
21 | |||
22 | local a= {} | ||
23 | local b= {a} | ||
24 | a[1]= b | ||
25 | |||
26 | -- Getting the tables as upvalues should still have the <-> linkage | ||
27 | -- | ||
28 | local function lane1() | ||
29 | WR( "Via upvalue: ", same(a,b[1]), same(a[1],b) ) | ||
30 | assert( a[1]==b ) | ||
31 | assert( b[1]==a ) | ||
32 | end | ||
33 | local L1= lanes.gen( "io", lane1 )() | ||
34 | -- ...running | ||
35 | |||
36 | -- Getting the tables as parameters should also keep the linkage | ||
37 | -- | ||
38 | local function lane2( aa, bb ) | ||
39 | WR( "Via parameters:", same(aa,bb[1]), same(aa[1],bb) ) | ||
40 | assert( aa[1]==bb ) | ||
41 | assert( bb[1]==aa ) | ||
42 | end | ||
43 | local L2= lanes.gen( "io", lane2 )( a, b ) | ||
44 | -- ...running | ||
45 | |||
46 | -- Really unnecessary, but let's try a directly recursive table | ||
47 | -- | ||
48 | c= {} | ||
49 | c.a= c | ||
50 | |||
51 | local function lane3( cc ) | ||
52 | WR( "Directly recursive: ", same(cc, cc.a) ) | ||
53 | assert( cc and cc.a==cc ) | ||
54 | end | ||
55 | local L3= lanes.gen("io", lane3)(c) | ||
56 | |||
57 | -- Without a wait, exit from the main lane will close the process | ||
58 | -- | ||
59 | -- Waiting for multiple lanes at once could be done using a Linda | ||
60 | -- (but we're okay waiting them in order) | ||
61 | -- | ||
62 | L1:join() | ||
63 | L2:join() | ||
64 | L3:join() | ||
diff --git a/tests/ehynes.lua b/tests/ehynes.lua new file mode 100644 index 0000000..4cc370e --- /dev/null +++ b/tests/ehynes.lua | |||
@@ -0,0 +1,52 @@ | |||
1 | -- | ||
2 | -- Test from <ehynes at dharmagaia.com> | ||
3 | -- | ||
4 | require 'lanes' | ||
5 | |||
6 | local function PRINT_FMT( fmt, ... ) | ||
7 | io.stderr:write( string.format(fmt,...).."\n" ) | ||
8 | end | ||
9 | |||
10 | -- a linda for sending messages | ||
11 | local linda = lanes.linda() | ||
12 | |||
13 | -- a linda message receiver | ||
14 | local receiver_gen = lanes.gen( 'base', 'os', 'string', 'io', | ||
15 | function (message_name) | ||
16 | PRINT_FMT( 'receiver for message %s entered', message_name ) | ||
17 | local n = 1 | ||
18 | while linda:receive(message_name) do | ||
19 | PRINT_FMT( '%s %d receieved', message_name, n ) | ||
20 | n = n + 1 | ||
21 | end | ||
22 | end | ||
23 | ) | ||
24 | |||
25 | -- create a receiver | ||
26 | local receiver1 = receiver_gen('message') | ||
27 | |||
28 | -- create a second receiver (a second receiver in the same linda | ||
29 | -- appears to be needed to trigger the delays) | ||
30 | -- | ||
31 | -- AKa 4-Aug-2008: No, with svn version it isn't. But it causes the 2nd | ||
32 | -- message to be hanging... | ||
33 | -- | ||
34 | local receiver2 = receiver_gen('another message') | ||
35 | |||
36 | -- a function to pause and log the execution for debugging | ||
37 | local function logf(s, f, ...) | ||
38 | os.execute('sleep 1') | ||
39 | PRINT_FMT( "*** %s", s ) | ||
40 | f(...) | ||
41 | end | ||
42 | |||
43 | -- first message sent is received right away | ||
44 | logf('first message sent', linda.send, linda, 'message', true) | ||
45 | |||
46 | -- second message sent is not received immediatly | ||
47 | logf('second message sent', linda.send, linda, 'message', true) | ||
48 | |||
49 | -- third message sent triggers receipt of both second and third messages | ||
50 | logf('third message sent', linda.send, linda, 'message', true) | ||
51 | |||
52 | logf('all done', function() end) | ||
diff --git a/tests/error.lua b/tests/error.lua new file mode 100644 index 0000000..673bcb5 --- /dev/null +++ b/tests/error.lua | |||
@@ -0,0 +1,47 @@ | |||
1 | -- | ||
2 | -- Error reporting | ||
3 | -- | ||
4 | -- Note: this code is supposed to end in errors; not included in 'make test' | ||
5 | -- | ||
6 | |||
7 | require "lanes" | ||
8 | |||
9 | local function lane() | ||
10 | |||
11 | local subf= function() -- this so that we can see the call stack | ||
12 | --error "aa" | ||
13 | error({}) | ||
14 | error(error) | ||
15 | end | ||
16 | local subf2= function() | ||
17 | subf() | ||
18 | end | ||
19 | subf2() | ||
20 | end | ||
21 | |||
22 | local function cleanup(err) | ||
23 | end | ||
24 | |||
25 | local lgen = lanes.gen("*", { --[[finalizer=cleanup]] }, lane) | ||
26 | |||
27 | --- | ||
28 | io.stderr:write( "\n** Error catching **\n" ) | ||
29 | -- | ||
30 | local h= lgen() | ||
31 | local _,err,stack= h:join() -- wait for the lane (no automatic error propagation) | ||
32 | |||
33 | if err then | ||
34 | assert( type(stack)=="table" ) | ||
35 | io.stderr:write( "Lane error: "..tostring(err).."\n" ) | ||
36 | |||
37 | io.stderr:write( "\t", table.concat(stack,"\n\t"), "\n" ); | ||
38 | end | ||
39 | |||
40 | --- | ||
41 | io.stderr:write( "\n** Error propagation **\n" ) | ||
42 | -- | ||
43 | local h2= lgen() | ||
44 | local _= h2[0] | ||
45 | assert(false) -- does NOT get here | ||
46 | |||
47 | --never ends | ||
diff --git a/tests/fibonacci.lua b/tests/fibonacci.lua new file mode 100644 index 0000000..8867e14 --- /dev/null +++ b/tests/fibonacci.lua | |||
@@ -0,0 +1,75 @@ | |||
1 | -- | ||
2 | -- FIBONACCI.LUA Copyright (c) 2007-08, Asko Kauppi <akauppi@gmail.com> | ||
3 | -- | ||
4 | -- Parallel calculation of Fibonacci numbers | ||
5 | -- | ||
6 | -- A sample of task splitting like Intel TBB library does. | ||
7 | -- | ||
8 | -- References: | ||
9 | -- Intel Threading Building Blocks, 'test all' | ||
10 | -- <http://shareit.intel.com/WikiHome/Articles/111111316> | ||
11 | -- | ||
12 | |||
13 | -- Need to say it's 'local' so it can be an upvalue | ||
14 | -- | ||
15 | local lanes= require "lanes" | ||
16 | |||
17 | local function WR(str) | ||
18 | io.stderr:write( str.."\n" ) | ||
19 | end | ||
20 | |||
21 | -- Threshold for serial calculation (optimal depends on multithreading fixed | ||
22 | -- cost and is system specific) | ||
23 | -- | ||
24 | local KNOWN= { [0]=0, 1,1,2,3,5,8,13,21,34,55,89,144 } | ||
25 | |||
26 | -- | ||
27 | -- uint= fib( n_uint ) | ||
28 | -- | ||
29 | local function fib( n ) | ||
30 | -- | ||
31 | local sum | ||
32 | local floor= assert(math.floor) | ||
33 | |||
34 | WR( "fib("..n..")" ) | ||
35 | |||
36 | if n <= #KNOWN then | ||
37 | sum= KNOWN[n] | ||
38 | else | ||
39 | -- Splits into two; this task remains waiting for the results | ||
40 | -- | ||
41 | local gen_f= lanes.gen( "io,math,debug", fib ) | ||
42 | |||
43 | local n1=floor(n/2) +1 | ||
44 | local n2=floor(n/2) -1 + n%2 | ||
45 | |||
46 | WR( "splitting "..n.." -> "..n1.." "..n2 ) | ||
47 | |||
48 | local a= gen_f( n1 ) | ||
49 | local b= gen_f( n2 ) | ||
50 | |||
51 | -- children running... | ||
52 | |||
53 | local a2= a[1]^2 | ||
54 | local b2= b[1]^2 | ||
55 | |||
56 | sum = (n%2==1) and a2+b2 or a2-b2 | ||
57 | end | ||
58 | |||
59 | io.stderr:write( "fib("..n..") = "..sum.."\n" ) | ||
60 | |||
61 | return sum | ||
62 | end | ||
63 | |||
64 | -- | ||
65 | -- Right answers from: <http://sonic.net/~douglasi/fibo.htm> | ||
66 | -- | ||
67 | local right= { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050, 3416454622906707, 5527939700884757, 8944394323791464, 14472334024676220, 23416728348467684, 37889062373143900, 61305790721611580, 99194853094755490, 160500643816367070, 259695496911122560, 420196140727489660, 679891637638612200, 1100087778366101900, 1779979416004714000, 2880067194370816000, 4660046610375530000, 7540113804746346000, 12200160415121877000, 19740274219868226000, 31940434634990105000, 51680708854858334000, 83621143489848440000, 135301852344706780000, 218922995834555200000 | ||
68 | } | ||
69 | assert( #right==99 ) | ||
70 | |||
71 | local N= 80 | ||
72 | local res= fib(N) | ||
73 | print( right[N] ) | ||
74 | assert( res==right[N] ) | ||
75 | |||
diff --git a/tests/fifo.lua b/tests/fifo.lua new file mode 100644 index 0000000..898b04d --- /dev/null +++ b/tests/fifo.lua | |||
@@ -0,0 +1,43 @@ | |||
1 | -- | ||
2 | -- FIFO.LUA | ||
3 | -- | ||
4 | -- Sample program for Lua Lanes | ||
5 | -- | ||
6 | |||
7 | require "lanes" | ||
8 | |||
9 | local linda= lanes.linda() | ||
10 | local atomic_inc= lanes.genatomic( linda, "FIFO_n" ) | ||
11 | |||
12 | assert( atomic_inc()==1 ) | ||
13 | assert( atomic_inc()==2 ) | ||
14 | |||
15 | local function FIFO() | ||
16 | local my_channel= "FIFO"..atomic_inc() | ||
17 | |||
18 | return { | ||
19 | -- Giving explicit 'nil' timeout allows numbers to be used as 'my_channel' | ||
20 | -- | ||
21 | send= function(...) linda:send( nil, my_channel, ... ) end, | ||
22 | receive= function(timeout) linda:receive( timeout, my_channel ) end | ||
23 | } | ||
24 | end | ||
25 | |||
26 | local A= FIFO() | ||
27 | local B= FIFO() | ||
28 | |||
29 | print "Sending to A.." | ||
30 | A:send( 1,2,3,4,5 ) | ||
31 | |||
32 | print "Sending to B.." | ||
33 | B:send( 'a','b','c' ) | ||
34 | |||
35 | print "Reading A.." | ||
36 | print( A:receive( 1.0 ) ) | ||
37 | |||
38 | print "Reading B.." | ||
39 | print( B:receive( 2.0 ) ) | ||
40 | |||
41 | -- Note: A and B can be passed between threads, or used as upvalues | ||
42 | -- by multiple threads (other parts will be copied but the 'linda' | ||
43 | -- handle is shared userdata and will thus point to the single place) | ||
diff --git a/tests/finalizer.lua b/tests/finalizer.lua new file mode 100644 index 0000000..c94b36d --- /dev/null +++ b/tests/finalizer.lua | |||
@@ -0,0 +1,81 @@ | |||
1 | -- | ||
2 | -- Test resource cleanup | ||
3 | -- | ||
4 | -- This feature was ... by discussion on the Lua list about exceptions. | ||
5 | -- The idea is to always run a certain block at exit, whether due to success | ||
6 | -- or error. Normally, 'pcall' would be used for such but as Lua already | ||
7 | -- does that, simply giving a 'cleanup=function' parameter is a logical | ||
8 | -- thing to do. -- AKa 22-Jan-2009 | ||
9 | -- | ||
10 | |||
11 | require "lanes" | ||
12 | |||
13 | local FN= "finalizer-test.tmp" | ||
14 | |||
15 | local cleanup | ||
16 | |||
17 | local which= os.time() % 2 -- 0/1 | ||
18 | |||
19 | local function lane() | ||
20 | |||
21 | set_finalizer(cleanup) | ||
22 | |||
23 | local f,err= io.open(FN,"w") | ||
24 | if not f then | ||
25 | error( "Could not create "..FN..": "..err ) | ||
26 | end | ||
27 | |||
28 | f:write( "Test file that should get removed." ) | ||
29 | |||
30 | io.stderr:write( "File "..FN.." created\n" ) | ||
31 | |||
32 | if which==0 then | ||
33 | error("aa") -- exception here; the value needs NOT be a string | ||
34 | end | ||
35 | |||
36 | -- no exception | ||
37 | end | ||
38 | |||
39 | -- | ||
40 | -- This is called at the end of the lane; whether succesful or not. | ||
41 | -- Gets the 'error()' parameter as parameter ('nil' if normal return). | ||
42 | -- | ||
43 | cleanup= function(err) | ||
44 | |||
45 | -- An error in finalizer will override an error (or success) in the main | ||
46 | -- chunk. | ||
47 | -- | ||
48 | --error( "This is important!" ) | ||
49 | |||
50 | if err then | ||
51 | io.stderr:write( "Cleanup after error: "..tostring(err).."\n" ) | ||
52 | else | ||
53 | io.stderr:write( "Cleanup after normal return\n" ) | ||
54 | end | ||
55 | |||
56 | local _,err2= os.remove(FN) | ||
57 | assert(not err2) -- if this fails, it will be shown in the calling script | ||
58 | -- as an error from the lane itself | ||
59 | |||
60 | io.stderr:write( "Removed file "..FN.."\n" ) | ||
61 | end | ||
62 | |||
63 | local lgen = lanes.gen("*", lane) | ||
64 | |||
65 | io.stderr:write "Launching the lane!\n" | ||
66 | |||
67 | local h= lgen() | ||
68 | |||
69 | local _,err,stack= h:join() -- wait for the lane (no automatic error propagation) | ||
70 | if err then | ||
71 | assert(stack) | ||
72 | io.stderr:write( "Lane error: "..tostring(err).."\n" ) | ||
73 | io.stderr:write( "\t", table.concat(stack,"\t\n"), "\n" ) | ||
74 | end | ||
75 | |||
76 | local f= io.open(FN,"r") | ||
77 | if f then | ||
78 | error( "CLEANUP DID NOT WORK: "..FN.." still exists!" ) | ||
79 | end | ||
80 | |||
81 | io.stderr:write "Finished!\n" | ||
diff --git a/tests/hangtest.lua b/tests/hangtest.lua new file mode 100644 index 0000000..d0bbea4 --- /dev/null +++ b/tests/hangtest.lua | |||
@@ -0,0 +1,26 @@ | |||
1 | -- | ||
2 | -- Test case for hang on [1]s and :join()s. | ||
3 | -- | ||
4 | |||
5 | require "lanes" | ||
6 | |||
7 | local function ret(b) | ||
8 | return b | ||
9 | end | ||
10 | local lgen = lanes.gen("*", {}, ret) | ||
11 | |||
12 | for i=1,10000 do | ||
13 | local ln = lgen(i) | ||
14 | |||
15 | print( "getting result for "..i ) | ||
16 | |||
17 | -- Hangs here forever every few hundred runs or so, | ||
18 | -- can be illustrated by putting another print() statement | ||
19 | -- after, which will never be called. | ||
20 | -- | ||
21 | local result = ln[1]; | ||
22 | |||
23 | assert (result == i); | ||
24 | end | ||
25 | |||
26 | print "Finished!" | ||
diff --git a/tests/irayo_closure.lua b/tests/irayo_closure.lua new file mode 100644 index 0000000..faf08fd --- /dev/null +++ b/tests/irayo_closure.lua | |||
@@ -0,0 +1,35 @@ | |||
1 | -- | ||
2 | -- Bugs filed by irayo Jul-2008 | ||
3 | -- | ||
4 | --[[ | ||
5 | "Another issue I've noticed is trying to pass a table with a function | ||
6 | that uses closures in it as a global variable into a new lane. This | ||
7 | causes a segmentation fault and it appears to be related to the | ||
8 | luaG_inter_move function near line 835-836 or so in lanes.c, but I | ||
9 | haven't investigated further. | ||
10 | e.g. { globals = { data = 1, func = function() useclosurehere() end } }" | ||
11 | ]] | ||
12 | |||
13 | require "lanes" | ||
14 | |||
15 | local function testrun() | ||
16 | assert( print ) | ||
17 | assert( data==1 ) | ||
18 | assert( type(func)=="function" ) | ||
19 | func() -- "using the closure" | ||
20 | return true | ||
21 | end | ||
22 | |||
23 | -- Should also work without these lines, but currently doesn't (bug in Lanes, | ||
24 | -- a function thrown over isn't connected to receiving lane's globals) | ||
25 | -- | ||
26 | --local print=print | ||
27 | --local assert=assert | ||
28 | |||
29 | local function useclosurehere() | ||
30 | assert( print ) | ||
31 | print "using the closure" | ||
32 | end | ||
33 | |||
34 | local lane= lanes.gen( "", { globals = { data=1, func=useclosurehere } }, testrun )() | ||
35 | print(lane[1]) | ||
diff --git a/tests/irayo_recursive.lua b/tests/irayo_recursive.lua new file mode 100644 index 0000000..82e5a54 --- /dev/null +++ b/tests/irayo_recursive.lua | |||
@@ -0,0 +1,18 @@ | |||
1 | -- | ||
2 | -- Bugs filed by irayo Jul-2008 | ||
3 | -- | ||
4 | --[[ | ||
5 | This code showed lack of caching 'select', 'type' etc. in 'src/lanes.lua'. | ||
6 | ]] | ||
7 | local function recurse() | ||
8 | print("level "..i); | ||
9 | if i > 10 then return "finished" end | ||
10 | |||
11 | require "lanes" | ||
12 | |||
13 | local lane = lanes.gen( "*", { globals = { ["i"]= i + 1 } }, recurse ) () | ||
14 | return lane[1] | ||
15 | end | ||
16 | |||
17 | i = 0; | ||
18 | recurse() | ||
diff --git a/tests/keeper.lua b/tests/keeper.lua new file mode 100644 index 0000000..5c8c23a --- /dev/null +++ b/tests/keeper.lua | |||
@@ -0,0 +1,47 @@ | |||
1 | -- | ||
2 | -- KEEPER.LUA | ||
3 | -- | ||
4 | -- Test program for Lua Lanes | ||
5 | -- | ||
6 | |||
7 | require "lanes" | ||
8 | |||
9 | local function keeper(linda) | ||
10 | local mt= { | ||
11 | __index= function( _, key ) | ||
12 | return linda:get( key ) | ||
13 | end, | ||
14 | __newindex= function( _, key, val ) | ||
15 | linda:set( key, val ) | ||
16 | end | ||
17 | } | ||
18 | return setmetatable( {}, mt ) | ||
19 | end | ||
20 | |||
21 | -- | ||
22 | local lindaA= lanes.linda() | ||
23 | local A= keeper( lindaA ) | ||
24 | |||
25 | local lindaB= lanes.linda() | ||
26 | local B= keeper( lindaB ) | ||
27 | |||
28 | A.some= 1 | ||
29 | print( A.some ) | ||
30 | assert( A.some==1 ) | ||
31 | |||
32 | B.some= "hoo" | ||
33 | assert( B.some=="hoo" ) | ||
34 | assert( A.some==1 ) | ||
35 | |||
36 | function lane() | ||
37 | local a= keeper(lindaA) | ||
38 | print( a.some ) | ||
39 | assert( a.some==1 ) | ||
40 | a.some= 2 | ||
41 | end | ||
42 | |||
43 | local h= lanes.gen( "io", lane )() | ||
44 | h:join() | ||
45 | |||
46 | print( A.some ) -- 2 | ||
47 | assert( A.some==2 ) | ||
diff --git a/tests/launchtest.lua b/tests/launchtest.lua new file mode 100644 index 0000000..5e3037f --- /dev/null +++ b/tests/launchtest.lua | |||
@@ -0,0 +1,78 @@ | |||
1 | -- | ||
2 | -- LAUNCHTEST.LUA Copyright (c) 2007-08, Asko Kauppi <akauppi@gmail.com> | ||
3 | -- | ||
4 | -- Tests launching speed of N threads | ||
5 | -- | ||
6 | -- Usage: | ||
7 | -- [time] lua -lstrict launchtest.lua [threads] [-libs[=io,os,math,...]] | ||
8 | -- | ||
9 | -- threads: number of threads to launch (like: 2000) :) | ||
10 | -- libs: combination of "os","io","math","package", ... | ||
11 | -- just "-libs" for all libraries | ||
12 | -- | ||
13 | -- Note: | ||
14 | -- One _can_ reach the system threading level, ie. doing 10000 on | ||
15 | -- PowerBook G4: | ||
16 | -- << | ||
17 | -- pthread_create( ref, &a, lane_main, data ) failed @ line 316: 35 | ||
18 | -- Command terminated abnormally. | ||
19 | -- << | ||
20 | -- | ||
21 | -- (Lua Lanes _can_ be made tolerable to such congestion cases. Just | ||
22 | -- currently, it is not. btw, 5000 seems to run okay - system limit | ||
23 | -- being 2040 simultaneous threads) | ||
24 | -- | ||
25 | -- To do: | ||
26 | -- - ... | ||
27 | -- | ||
28 | |||
29 | local N= 1000 -- threads/loops to use | ||
30 | local M= 1000 -- sieves from 1..M | ||
31 | local LIBS= nil -- default: load no libraries | ||
32 | |||
33 | local function HELP() | ||
34 | io.stderr:write( "Usage: lua launchtest.lua [threads] [-libs[=io,os,math,...]]\n" ) | ||
35 | exit(1) | ||
36 | end | ||
37 | |||
38 | local m= require "argtable" | ||
39 | local argtable= assert(m.argtable) | ||
40 | |||
41 | for k,v in pairs( argtable(...) ) do | ||
42 | if k==1 then N= tonumber(v) or HELP() | ||
43 | elseif k=="libs" then LIBS= (v==true) and "*" or v | ||
44 | else HELP() | ||
45 | end | ||
46 | end | ||
47 | |||
48 | require "lanes" | ||
49 | |||
50 | local g= lanes.gen( LIBS, function(i) | ||
51 | --io.stderr:write( i.."\t" ) | ||
52 | return i | ||
53 | end ) | ||
54 | |||
55 | local t= {} | ||
56 | |||
57 | for i=1,N do | ||
58 | t[i]= g(i) | ||
59 | end | ||
60 | |||
61 | if false then | ||
62 | -- just finish here, without waiting for threads to finish | ||
63 | -- | ||
64 | local st= t[N].status | ||
65 | print(st) -- if that is "done", they flew already! :) | ||
66 | else | ||
67 | -- mark that all have been launched, now wait for them to return | ||
68 | -- | ||
69 | io.stderr:write( N.." lanes launched.\n" ) | ||
70 | |||
71 | for i=1,N do | ||
72 | local rc= t[i]:join() | ||
73 | assert( rc==i ) | ||
74 | end | ||
75 | |||
76 | io.stderr:write( N.." lanes finished.\n" ) | ||
77 | end | ||
78 | |||
diff --git a/tests/objects.lua b/tests/objects.lua new file mode 100644 index 0000000..8f56a5f --- /dev/null +++ b/tests/objects.lua | |||
@@ -0,0 +1,76 @@ | |||
1 | -- | ||
2 | -- OBJECTS.LUA | ||
3 | -- | ||
4 | -- Tests that objects (metatables) can be passed between lanes. | ||
5 | -- | ||
6 | |||
7 | require "lanes" | ||
8 | |||
9 | local linda= lanes.linda() | ||
10 | |||
11 | local start_lane= lanes.gen( "io", | ||
12 | function( obj1 ) | ||
13 | |||
14 | assert( obj1.v ) | ||
15 | assert( obj1.print ) | ||
16 | |||
17 | assert( obj1 ) | ||
18 | local mt1= getmetatable(obj1) | ||
19 | assert(mt1) | ||
20 | |||
21 | local obj2= linda:receive("") | ||
22 | assert( obj2 ) | ||
23 | local mt2= getmetatable(obj2) | ||
24 | assert(mt2) | ||
25 | assert( mt1==mt2 ) | ||
26 | |||
27 | local v= obj1:print() | ||
28 | assert( v=="aaa" ) | ||
29 | |||
30 | v= obj2:print() | ||
31 | assert( v=="bbb" ) | ||
32 | |||
33 | return true | ||
34 | end | ||
35 | ) | ||
36 | |||
37 | |||
38 | local WR= function(str) | ||
39 | io.stderr:write( tostring(str).."\n") | ||
40 | end | ||
41 | |||
42 | |||
43 | -- Lanes identifies metatables and copies them only once per each lane. | ||
44 | -- | ||
45 | -- Having methods in the metatable will make passing objects lighter than | ||
46 | -- having the methods 'fixed' in the object tables themselves. | ||
47 | -- | ||
48 | local o_mt= { | ||
49 | __index= function( me, key ) | ||
50 | if key=="print" then | ||
51 | return function() WR(me.v); return me.v end | ||
52 | end | ||
53 | end | ||
54 | } | ||
55 | |||
56 | local function obj_gen(v) | ||
57 | local o= { v=v } | ||
58 | setmetatable( o, o_mt ) | ||
59 | return o | ||
60 | end | ||
61 | |||
62 | local a= obj_gen("aaa") | ||
63 | local b= obj_gen("bbb") | ||
64 | |||
65 | assert( a and b ) | ||
66 | |||
67 | local mt_a= getmetatable(a) | ||
68 | local mt_b= getmetatable(b) | ||
69 | assert( mt_a and mt_a==mt_b ) | ||
70 | |||
71 | local h= start_lane(a) -- 1st object as parameter | ||
72 | |||
73 | linda:send( "", b ) -- 2nd object via Linda | ||
74 | |||
75 | assert( h[1]==true ) -- wait for return | ||
76 | |||
diff --git a/tests/perftest.lua b/tests/perftest.lua new file mode 100644 index 0000000..8ce1b3c --- /dev/null +++ b/tests/perftest.lua | |||
@@ -0,0 +1,184 @@ | |||
1 | -- | ||
2 | -- PERFTEST.LUA Copyright (c) 2007-08, Asko Kauppi <akauppi@gmail.com> | ||
3 | -- | ||
4 | -- Performance comparison of multithreaded Lua (= how much ballast does using | ||
5 | -- Lua Lanes introduce) | ||
6 | -- | ||
7 | -- Usage: | ||
8 | -- [time] lua -lstrict perftest.lua [threads] [-plain|-single[=2..n]] [-time] [-prio[=-2..+2[,-2..+2]]] | ||
9 | -- | ||
10 | -- threads: number of threads to launch (loops in 'plain' mode) | ||
11 | -- -plain: runs in nonthreaded mode, to get a comparison baseline | ||
12 | -- -single: runs using just a single CPU core (or 'n' cores if given) | ||
13 | -- -prio: sets odd numbered threads to higher/lower priority | ||
14 | -- | ||
15 | -- History: | ||
16 | -- AKa 20-Jul-08: updated to Lanes 2008 | ||
17 | -- AK 14-Apr-07: works on Win32 | ||
18 | -- | ||
19 | -- To do: | ||
20 | -- (none?) | ||
21 | -- | ||
22 | |||
23 | -- On MSYS, stderr is buffered. In this test it matters. | ||
24 | -- Seems, even with this MSYS wants to buffer linewise, needing '\n' | ||
25 | -- before actual output. | ||
26 | -- | ||
27 | local MSYS= os.getenv("OSTYPE")=="msys" | ||
28 | |||
29 | |||
30 | require "lanes" | ||
31 | |||
32 | local m= require "argtable" | ||
33 | local argtable= assert( m.argtable ) | ||
34 | |||
35 | local N= 1000 -- threads/loops to use | ||
36 | local M= 1000 -- sieves from 1..M | ||
37 | local PLAIN= false -- single threaded (true) or using Lanes (false) | ||
38 | local SINGLE= false -- cores to use (false / 1..n) | ||
39 | local TIME= false -- use Lua for the timing | ||
40 | local PRIO_ODD, PRIO_EVEN -- -3..+3 | ||
41 | |||
42 | local function HELP() | ||
43 | io.stderr:write( "Usage: lua perftest.lua [threads]\n" ) | ||
44 | end | ||
45 | |||
46 | -- nil -> +2 | ||
47 | -- odd_prio[,even_prio] | ||
48 | -- | ||
49 | local function prio_param(v) | ||
50 | if v==true then return 2,-2 end | ||
51 | |||
52 | local a,b= string.match( v, "^([%+%-]?%d+)%,([%+%-]?%d+)$" ) | ||
53 | if a then | ||
54 | return tonumber(a), tonumber(b) | ||
55 | elseif tonumber(v) then | ||
56 | return tonumber(v) | ||
57 | else | ||
58 | error( "Bad priority: "..v ) | ||
59 | end | ||
60 | end | ||
61 | |||
62 | for k,v in pairs( argtable(...) ) do | ||
63 | if k==1 then N= tonumber(v) or HELP() | ||
64 | elseif k=="plain" then PLAIN= true | ||
65 | elseif k=="single" then SINGLE= v -- true/number | ||
66 | elseif k=="time" then TIME= true | ||
67 | elseif k=="prio" then PRIO_ODD, PRIO_EVEN= prio_param(v) | ||
68 | else HELP() | ||
69 | end | ||
70 | end | ||
71 | |||
72 | PRIO_ODD= PRIO_ODD or 0 | ||
73 | PRIO_EVEN= PRIO_EVEN or 0 | ||
74 | |||
75 | |||
76 | -- SAMPLE ADOPTED FROM Lua 5.1.1 test/sieve.lua -- | ||
77 | |||
78 | -- the sieve of of Eratosthenes programmed with coroutines | ||
79 | -- typical usage: lua -e N=1000 sieve.lua | column | ||
80 | |||
81 | -- AK: Wrapped within a surrounding function, so we can pass it to Lanes | ||
82 | -- Note that coroutines can perfectly fine be used within each Lane. :) | ||
83 | -- | ||
84 | -- AKa 20-Jul-2008: Now the wrapping to one function is no longer needed; | ||
85 | -- Lanes 2008 can take the used functions as upvalues. | ||
86 | -- | ||
87 | local function sieve_lane(N,id) | ||
88 | |||
89 | if MSYS then | ||
90 | io.stderr:setvbuf "no" | ||
91 | end | ||
92 | |||
93 | -- generate all the numbers from 2 to n | ||
94 | local function gen (n) | ||
95 | return coroutine.wrap(function () | ||
96 | for i=2,n do coroutine.yield(i) end | ||
97 | end) | ||
98 | end | ||
99 | |||
100 | -- filter the numbers generated by `g', removing multiples of `p' | ||
101 | local function filter (p, g) | ||
102 | return coroutine.wrap(function () | ||
103 | while 1 do | ||
104 | local n = g() | ||
105 | if n == nil then return end | ||
106 | if math.mod(n, p) ~= 0 then coroutine.yield(n) end | ||
107 | end | ||
108 | end) | ||
109 | end | ||
110 | |||
111 | local ret= {} -- returned values: { 2, 3, 5, 7, 11, ... } | ||
112 | N=N or 1000 -- from caller | ||
113 | local x = gen(N) -- generate primes up to N | ||
114 | while 1 do | ||
115 | local n = x() -- pick a number until done | ||
116 | if n == nil then break end | ||
117 | --print(n) -- must be a prime number | ||
118 | table.insert( ret, n ) | ||
119 | |||
120 | x = filter(n, x) -- now remove its multiples | ||
121 | end | ||
122 | |||
123 | io.stderr:write(id..(MSYS and "\n" or "\t")) -- mark we're ready | ||
124 | |||
125 | return ret | ||
126 | end | ||
127 | -- ** END OF LANE ** -- | ||
128 | |||
129 | |||
130 | -- Keep preparation code outside of the performance test | ||
131 | -- | ||
132 | local f_even= lanes.gen( "base,coroutine,math,table,io", -- "*" = all | ||
133 | { priority= PRIO_EVEN }, sieve_lane ) | ||
134 | |||
135 | local f_odd= lanes.gen( "base,coroutine,math,table,io", -- "*" = all | ||
136 | { priority= PRIO_ODD }, sieve_lane ) | ||
137 | |||
138 | io.stderr:write( "*** Counting primes 1.."..M.." "..N.." times ***\n\n" ) | ||
139 | |||
140 | local t0= TIME and os.time() | ||
141 | |||
142 | if PLAIN then | ||
143 | io.stderr:write( "Plain (no multithreading):\n" ) | ||
144 | |||
145 | for i=1,N do | ||
146 | local tmp= sieve_lane(M,i) | ||
147 | assert( type(tmp)=="table" and tmp[1]==2 and tmp[168]==997 ) | ||
148 | end | ||
149 | else | ||
150 | if SINGLE then | ||
151 | io.stderr:write( (tonumber(SINGLE) and SINGLE or 1) .. " core(s):\n" ) | ||
152 | lanes.single(SINGLE) -- limit to N cores (just OS X) | ||
153 | else | ||
154 | io.stderr:write( "Multi core:\n" ) | ||
155 | end | ||
156 | |||
157 | if PRIO_ODD ~= PRIO_EVEN then | ||
158 | io.stderr:write( ( PRIO_ODD > PRIO_EVEN and "ODD" or "EVEN" ).. | ||
159 | " LANES should come first (odd:"..PRIO_ODD..", even:"..PRIO_EVEN..")\n\n" ) | ||
160 | else | ||
161 | io.stderr:write( "EVEN AND ODD lanes should be mingled (both: "..PRIO_ODD..")\n\n" ) | ||
162 | end | ||
163 | local t= {} | ||
164 | for i=1,N do | ||
165 | t[i]= ((i%2==0) and f_even or f_odd) (M,i) | ||
166 | end | ||
167 | |||
168 | -- Make sure all lanes finished | ||
169 | -- | ||
170 | for i=1,N do | ||
171 | local tmp= t[i]:join() | ||
172 | assert( type(tmp)=="table" and tmp[1]==2 and tmp[168]==997 ) | ||
173 | end | ||
174 | end | ||
175 | |||
176 | io.stderr:write "\n" | ||
177 | |||
178 | if TIME then | ||
179 | local t= os.time() - t0 | ||
180 | io.stderr:write( "*** TIMING: "..t.." seconds ***\n" ) | ||
181 | end | ||
182 | |||
183 | -- | ||
184 | -- end | ||
diff --git a/tests/recursive.lua b/tests/recursive.lua new file mode 100644 index 0000000..49c03d3 --- /dev/null +++ b/tests/recursive.lua | |||
@@ -0,0 +1,21 @@ | |||
1 | -- | ||
2 | -- RECURSIVE.LUA | ||
3 | -- | ||
4 | -- Test program for Lua Lanes | ||
5 | -- | ||
6 | |||
7 | io.stderr:write( "depth:" ) | ||
8 | local function func( depth ) | ||
9 | io.stderr:write(" " .. depth) | ||
10 | if depth > 10 then | ||
11 | return "done!" | ||
12 | end | ||
13 | |||
14 | require "lanes" | ||
15 | local lane= lanes.gen("*", func)( depth+1 ) | ||
16 | return lane[1] | ||
17 | end | ||
18 | |||
19 | local v= func(0) | ||
20 | assert(v=="done!") | ||
21 | io.stderr:write("\n") | ||
diff --git a/tests/require.lua b/tests/require.lua new file mode 100644 index 0000000..2cfe780 --- /dev/null +++ b/tests/require.lua | |||
@@ -0,0 +1,30 @@ | |||
1 | -- | ||
2 | -- REQUIRE.LUA | ||
3 | -- | ||
4 | -- Test that 'require' works from sublanes | ||
5 | -- | ||
6 | require 'lanes' | ||
7 | |||
8 | local function a_lane() | ||
9 | -- To require 'math' we still actually need to have it initialized for | ||
10 | -- the lane. | ||
11 | -- | ||
12 | require "math" | ||
13 | assert( math and math.sqrt ) | ||
14 | assert( math.sqrt(4)==2 ) | ||
15 | |||
16 | assert( lanes==nil ) | ||
17 | require "lanes" | ||
18 | assert( lanes and lanes.gen ) | ||
19 | |||
20 | local h= lanes.gen( function() return 42 end ) () | ||
21 | local v= h[1] | ||
22 | |||
23 | return v==42 | ||
24 | end | ||
25 | |||
26 | local gen= lanes.gen( "math,package,string,table", a_lane ) | ||
27 | |||
28 | local h= gen() | ||
29 | local ret= h[1] | ||
30 | assert( ret==true ) | ||
diff --git a/tests/timer.lua b/tests/timer.lua new file mode 100644 index 0000000..e95f326 --- /dev/null +++ b/tests/timer.lua | |||
@@ -0,0 +1,93 @@ | |||
1 | -- | ||
2 | -- TIMER.LUA | ||
3 | -- | ||
4 | -- Sample program for Lua Lanes | ||
5 | -- | ||
6 | |||
7 | -- On MSYS, stderr is buffered. In this test it matters. | ||
8 | io.stderr:setvbuf "no" | ||
9 | |||
10 | |||
11 | require "lanes" | ||
12 | |||
13 | local linda= lanes.linda() | ||
14 | |||
15 | local function PRINT(str) | ||
16 | io.stderr:write(str.."\n") | ||
17 | end | ||
18 | |||
19 | local T1= "1s" -- these keys can be anything... | ||
20 | local T2= "5s" | ||
21 | |||
22 | local step= {} | ||
23 | |||
24 | lanes.timer( linda, T1, 1.0, 1.0 ) | ||
25 | step[T1]= 1.0 | ||
26 | |||
27 | PRINT( "\n*** Timers every second (not synced to wall clock) ***\n" ) | ||
28 | |||
29 | local v_first | ||
30 | local v_last= {} -- { [channel]= num } | ||
31 | local T2_first_round= true | ||
32 | |||
33 | local caught= {} -- { [T1]= bool, [T2]= bool } | ||
34 | |||
35 | while true do | ||
36 | io.stderr:write("waiting...\t") | ||
37 | local v,channel= linda:receive( 6.0, T1,T2 ) | ||
38 | assert( channel==T1 or channel==T2 ) | ||
39 | caught[channel]= true | ||
40 | |||
41 | io.stderr:write( ((channel==T1) and "" or "\t\t").. string.format("%.3f",v),"\n" ) | ||
42 | assert( type(v)=="number" ) | ||
43 | |||
44 | if v_last[channel] then | ||
45 | if channel==T2 and T2_first_round then | ||
46 | -- do not make measurements, first round is not 5secs due to wall clock adjustment | ||
47 | T2_first_round= false | ||
48 | else | ||
49 | assert( math.abs(v-v_last[channel]- step[channel]) < 0.02 ) | ||
50 | end | ||
51 | end | ||
52 | |||
53 | if not v_first then | ||
54 | v_first= v | ||
55 | elseif v-v_first > 3.0 and (not step[T2]) then | ||
56 | PRINT( "\n*** Adding timers every 5 second (synced to wall clock) ***\n" ) | ||
57 | |||
58 | -- The first event can be in the past (just cut seconds down to 5s) | ||
59 | -- | ||
60 | local date= os.date("*t") | ||
61 | date.sec = date.sec - date.sec%5 | ||
62 | |||
63 | lanes.timer( linda, T2, date, 5.0 ) | ||
64 | step[T2]= 5.0 | ||
65 | |||
66 | elseif v-v_first > 10 then -- exit condition | ||
67 | break | ||
68 | end | ||
69 | v_last[channel]= v | ||
70 | end | ||
71 | |||
72 | -- Windows version had a bug where T2 timers were not coming through, at all. | ||
73 | -- AKa 24-Jan-2009 | ||
74 | -- | ||
75 | assert( caught[T1] ) | ||
76 | assert( caught[T2] ) | ||
77 | |||
78 | PRINT( "\n*** Clearing timers ***\n" ) | ||
79 | |||
80 | lanes.timer( linda, T1, 0 ) -- reset; no reoccuring ticks | ||
81 | lanes.timer( linda, T2, 0 ) | ||
82 | |||
83 | linda:receive( 0, T1 ) -- clear out; there could be one tick left | ||
84 | linda:receive( 0, T2 ) | ||
85 | |||
86 | assert( linda:get(T1) == nil ) | ||
87 | assert( linda:get(T2) == nil ) | ||
88 | |||
89 | PRINT "...making sure no ticks are coming..." | ||
90 | |||
91 | local v= linda:receive( 1.5, T1,T2 ) -- should not get any | ||
92 | assert(v==nil) | ||
93 | |||