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 | |||
