aboutsummaryrefslogtreecommitdiff
path: root/tests/cancel.lua
blob: 64294877bccf0abc90c4f06c4d9c8abda0f8913a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
local lanes = require "lanes" .configure{ with_timers = false}

local linda = lanes.linda()

--####################################################################
print "\n\n####################################################################\nbegin genlock & genatomic cancel test\n"

-- get a lock and a atomic operator
local lock = lanes.genlock( linda, "lock", 1)
local atomic = lanes.genatomic( linda, "atomic")

-- check that cancelled lindas give cancel_error as they should
linda:cancel()
assert( linda:get( "empty") == lanes.cancel_error)
assert( lanes.genlock( linda, "any", 1) == lanes.cancel_error)
assert( lanes.genatomic( linda, "any") == lanes.cancel_error)

-- check that lock and atomic functions return cancel_error if the linda was cancelled
assert( lock( 1) == lanes.cancel_error)
assert( lock( -1) == lanes.cancel_error)
assert( atomic( 1) == lanes.cancel_error)

-- reset the linda so that the other tests work
linda:cancel( "none")
linda:limit( "lock", -1)
linda:set( "lock")
linda:limit( "atomic", -1)
linda:set( "atomic")

--####################################################################

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: 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 linda cancel test\n"
h = lanes.gen("*", laneBody)()

-- wait 3s before cancelling the lane
print "wait 3s"
linda:receive( 3, "yeah")

-- linda cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it
print "linda cancel (always awakens the lane)"
linda:cancel( "both")

print "wait 5s"
linda:receive( 5, "yeah")

--####################################################################

print "\ndone"