From 1843a0add00186eee129b0b0a2ee605866acbb61 Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Thu, 16 Jan 2014 14:17:23 +0100 Subject: Cancellation improvements and some fixes * bumped version to 3.7.8 * lane:cancel() now accepts a boolean second argument when soft cancelling (negative timeout) to wake the thread if necessary * if a blocked linda send() or receive() call is interrupted by a cancellation request, it returns CANCEL_ERROR so that this case can be differentiated from a simple timeout * fixed WIN32 THREAD_CREATE() wrong _beginthreadex() error detection * fatal WIN32 threading errors retrieve and output the error description string with FormatMessage() * fixed missing lanes.set_singlethreaded * fixed perftest.lua * added test/cancel.lua --- tests/cancel.lua | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/linda_perf.lua | 8 ++--- tests/perftest.lua | 17 +++++----- 3 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 tests/cancel.lua (limited to 'tests') diff --git a/tests/cancel.lua b/tests/cancel.lua new file mode 100644 index 0000000..0aab341 --- /dev/null +++ b/tests/cancel.lua @@ -0,0 +1,93 @@ +local lanes = require "lanes" .configure{ with_timers = false} + +local linda = lanes.linda() + +local laneBody = function( timeout_) + set_finalizer( function( err, stk) + if err == lanes.cancel_error then + -- note that we don't get the cancel_error when running wrapped inside a protected call if it doesn't rethrow it + print( " laneBody after cancel" ) + elseif err then + print( " laneBody error: "..tostring(err)) + else + print(" laneBody finalized") + end + end) + + print( " entering lane with " .. tostring( timeout_) .. " timeout") + repeat + -- block-wait to be hard-cancelled + print " lane calling receive()" + local key, val = linda:receive( timeout_, "boob") + print( " receive() -> ", lanes.cancel_error == key and "cancel_error" or tostring( key), tostring( val)) + until cancel_test() -- soft cancel self test + print " shutting down after breaking out of loop" +end + +local protectedBody = function( ...) + local ce = lanes.cancel_error + local errorHandler = function( _msg) + -- forward the message to the main thread that will display it with a popup + print( " error handler got ", ce == _msg and "cancel_error"or tostring( _msg)) + return _msg + end + -- Lua 5.1 doesn't pass additional xpcall arguments to the called function + -- therefore we need to create a closure that has no arguments but pulls everything from its upvalue + local params = {...} + local paramLessClosure = function() laneBody(table.unpack( params)) end + local status, message = xpcall( paramLessClosure, errorHandler) + if status == false then + print( " error handler rethrowing '" .. (ce == message and "cancel_error"or tostring( message)) .. "'") + -- if the error isn't rethrown, the lane's finalizer won't get it + error( message) + end +end + +--#################################################################### + +print "####################################################################\nbegin soft cancel test\n" +h = lanes.gen("*", protectedBody)( 0.666) +print "wait 3s" +linda:receive( 3, "yeah") + +-- soft cancel +print "soft cancel with awakening" +h:cancel( -1, true) + +-- wait 10s: the lane will interrupt its loop and print the exit message +print "wait 2s" +linda:receive( 2, "yeah") + +--#################################################################### + +print "\n\n####################################################################\nbegin hard cancel test\n" +h = lanes.gen("*", protectedBody)() + +-- wait 3s before cancelling the lane +print "wait 3s" +linda:receive( 3, "yeah") + +-- hard cancel and wait 10s: the lane will be interrupted from inside its current linda:receive() and won't return from it +print "hard cancel (always awakens)" +h:cancel() + +print "wait 5s" +linda:receive( 5, "yeah") + +--#################################################################### + +print "\n\n####################################################################\nbegin hard cancel test with unprotected lane body\n" +h = lanes.gen("*", laneBody)() + +-- wait 3s before cancelling the lane +print "wait 3s" +linda:receive( 3, "yeah") + +-- hard cancel and wait 10s: the lane will be interrupted from inside its current linda:receive() and won't return from it +print "hard cancel (always awakens)" +h:cancel() + +print "wait 5s" +linda:receive( 5, "yeah") + +print "\ndone" \ No newline at end of file diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua index ebe9eac..9348f71 100644 --- a/tests/linda_perf.lua +++ b/tests/linda_perf.lua @@ -34,7 +34,7 @@ local function ziva( preloop, loop, batch) -- prefill the linda a bit to increase fifo stress local top = math.max( preloop, loop) local l, lane = lanes.linda() - local t1 = os.time() + local t1 = lanes.now_secs() for i = 1, preloop do l:send( "key", i) end @@ -59,7 +59,7 @@ local function ziva( preloop, loop, batch) end l:send( "done" ,"are you happy?") lane:join() - return os.difftime(os.time(), t1) + return lanes.now_secs() - t1 end local tests = @@ -149,7 +149,7 @@ local function ziva2( preloop, loop, batch) l:receive( "key") end end - local t1 = os.time() + local t1 = lanes.now_secs() -- first, prime the linda with some data for i = 1, preloop, step do batch_send() @@ -165,7 +165,7 @@ local function ziva2( preloop, loop, batch) for i = 1, preloop, step do batch_read() end - return os.difftime(os.time(), t1) + return lanes.now_secs() - t1 end local tests2 = diff --git a/tests/perftest.lua b/tests/perftest.lua index 4df2ad8..6ffc064 100644 --- a/tests/perftest.lua +++ b/tests/perftest.lua @@ -27,8 +27,7 @@ local MSYS= os.getenv("OSTYPE")=="msys" -local lanes = require "lanes" -lanes.configure() +local lanes = require "lanes".configure{ with_timers = false} local m= require "argtable" local argtable= assert( m.argtable ) @@ -36,7 +35,7 @@ local argtable= assert( m.argtable ) local N= 1000 -- threads/loops to use local M= 1000 -- sieves from 1..M local PLAIN= false -- single threaded (true) or using Lanes (false) -local SINGLE= false -- cores to use (false / 1..n) +local SINGLE= 0 -- cores to use (0 / 1..n) local TIME= false -- use Lua for the timing local PRIO_ODD, PRIO_EVEN -- -3..+3 @@ -63,7 +62,7 @@ end for k,v in pairs( argtable(...) ) do if k==1 then N= tonumber(v) or HELP() elseif k=="plain" then PLAIN= true - elseif k=="single" then SINGLE= v -- true/number + elseif k=="single" then SINGLE= v -- number elseif k=="time" then TIME= true elseif k=="prio" then PRIO_ODD, PRIO_EVEN= prio_param(v) else HELP() @@ -104,7 +103,7 @@ local function sieve_lane(N,id) while 1 do local n = g() if n == nil then return end - if math.mod(n, p) ~= 0 then coroutine.yield(n) end + if math.fmod(n, p) ~= 0 then coroutine.yield(n) end end end) end @@ -138,7 +137,7 @@ local f_odd= lanes.gen( "base,coroutine,math,table,io", -- "*" = all io.stderr:write( "*** Counting primes 1.."..M.." "..N.." times ***\n\n" ) -local t0= TIME and os.time() +local t0= TIME and lanes.now_secs() if PLAIN then io.stderr:write( "Plain (no multithreading):\n" ) @@ -148,9 +147,9 @@ if PLAIN then assert( type(tmp)=="table" and tmp[1]==2 and tmp[168]==997 ) end else - if SINGLE then + if SINGLE > 0 then io.stderr:write( (tonumber(SINGLE) and SINGLE or 1) .. " core(s):\n" ) - lanes.single(SINGLE) -- limit to N cores (just OS X) + lanes.set_singlethreaded(SINGLE) -- limit to N cores (just OS X) else io.stderr:write( "Multi core:\n" ) end @@ -177,7 +176,7 @@ end io.stderr:write "\n" if TIME then - local t= os.time() - t0 + local t= lanes.now_secs() - t0 io.stderr:write( "*** TIMING: "..t.." seconds ***\n" ) end -- cgit v1.2.3-55-g6feb