diff options
Diffstat (limited to 'tests/cancel.lua')
-rw-r--r-- | tests/cancel.lua | 162 |
1 files changed, 117 insertions, 45 deletions
diff --git a/tests/cancel.lua b/tests/cancel.lua index 6429487..0d9d143 100644 --- a/tests/cancel.lua +++ b/tests/cancel.lua | |||
@@ -27,9 +27,29 @@ linda:set( "lock") | |||
27 | linda:limit( "atomic", -1) | 27 | linda:limit( "atomic", -1) |
28 | linda:set( "atomic") | 28 | linda:set( "atomic") |
29 | 29 | ||
30 | -- a numeric value to read | ||
31 | linda:set( "val", 33.0) | ||
32 | |||
33 | print "test OK" | ||
30 | --#################################################################### | 34 | --#################################################################### |
31 | 35 | ||
32 | local laneBody = function( timeout_) | 36 | local waitCancellation = function( h, expected_status) |
37 | local l = lanes.linda() | ||
38 | if expected_status ~= "running" then | ||
39 | repeat | ||
40 | -- print( "lane status:", h.status) | ||
41 | l:receive( 0.1, "yeah") -- wait a bit | ||
42 | until h.status ~= "running" | ||
43 | end | ||
44 | print( "lane status:", h.status) | ||
45 | assert( h.status == expected_status, h.status .. " ~= " .. expected_status) | ||
46 | print "test OK" | ||
47 | end | ||
48 | |||
49 | local laneBody = function( mode_, payload_) | ||
50 | local name = "laneBody("..tostring(mode_)..","..tostring(payload_)..")" | ||
51 | set_debug_threadname( name) | ||
52 | |||
33 | set_finalizer( function( err, stk) | 53 | set_finalizer( function( err, stk) |
34 | if err == lanes.cancel_error then | 54 | if err == lanes.cancel_error then |
35 | -- note that we don't get the cancel_error when running wrapped inside a protected call if it doesn't rethrow it | 55 | -- note that we don't get the cancel_error when running wrapped inside a protected call if it doesn't rethrow it |
@@ -41,14 +61,39 @@ local laneBody = function( timeout_) | |||
41 | end | 61 | end |
42 | end) | 62 | end) |
43 | 63 | ||
44 | print( " entering lane with " .. tostring( timeout_) .. " timeout") | 64 | print( " entering " , name) |
45 | repeat | 65 | repeat |
46 | -- block-wait to be hard-cancelled | 66 | if mode_ == "receive" then |
47 | print " lane calling receive()" | 67 | -- linda mode |
48 | local key, val = linda:receive( timeout_, "boob") | 68 | io.stdout:write( " lane calling receive() ... ") |
49 | print( " receive() -> ", lanes.cancel_error == key and "cancel_error" or tostring( key), tostring( val)) | 69 | local key, val = linda:receive( payload_, "boob") |
70 | print( lanes.cancel_error == key and "cancel_error" or tostring( key), tostring( val)) | ||
71 | if key == lanes.cancel_error then | ||
72 | break -- gracefully abort loop | ||
73 | end | ||
74 | elseif mode_ == "get" then | ||
75 | -- busy wait mode getting data from the linda | ||
76 | io.stdout:write( " lane busy waiting ... ") | ||
77 | for i = 1, payload_ do | ||
78 | -- force a non-jitable call | ||
79 | local a = linda:get( "val") | ||
80 | a = a * 2 | ||
81 | end | ||
82 | print( "again?") | ||
83 | elseif mode_ == "busy" then | ||
84 | -- busy wait mode in pure Lua code | ||
85 | io.stdout:write( " lane busy waiting ... ") | ||
86 | local a = linda:get( "val") | ||
87 | for i = 1, payload_ do | ||
88 | a = a * 2 | ||
89 | a = math.sin( a) * math.sin( a) + math.cos( a) * math.cos( a) -- aka 1 | ||
90 | end | ||
91 | print( "again?") | ||
92 | else | ||
93 | error "no mode: raise an error" | ||
94 | end | ||
50 | until cancel_test() -- soft cancel self test | 95 | until cancel_test() -- soft cancel self test |
51 | print " shutting down after breaking out of loop" | 96 | print " lane shutting down after breaking out of loop" |
52 | end | 97 | end |
53 | 98 | ||
54 | local protectedBody = function( ...) | 99 | local protectedBody = function( ...) |
@@ -61,7 +106,8 @@ local protectedBody = function( ...) | |||
61 | -- Lua 5.1 doesn't pass additional xpcall arguments to the called function | 106 | -- Lua 5.1 doesn't pass additional xpcall arguments to the called function |
62 | -- therefore we need to create a closure that has no arguments but pulls everything from its upvalue | 107 | -- therefore we need to create a closure that has no arguments but pulls everything from its upvalue |
63 | local params = {...} | 108 | local params = {...} |
64 | local paramLessClosure = function() laneBody(table.unpack( params)) end | 109 | local unpack = table.unpack or unpack -- unpack for 5.1, table.unpack for 5.2+ |
110 | local paramLessClosure = function() laneBody(unpack( params)) end | ||
65 | local status, message = xpcall( paramLessClosure, errorHandler) | 111 | local status, message = xpcall( paramLessClosure, errorHandler) |
66 | if status == false then | 112 | if status == false then |
67 | print( " error handler rethrowing '" .. (ce == message and "cancel_error"or tostring( message)) .. "'") | 113 | print( " error handler rethrowing '" .. (ce == message and "cancel_error"or tostring( message)) .. "'") |
@@ -71,66 +117,92 @@ local protectedBody = function( ...) | |||
71 | end | 117 | end |
72 | 118 | ||
73 | --#################################################################### | 119 | --#################################################################### |
120 | --#################################################################### | ||
121 | |||
122 | print "\n\n####################################################################\nbegin linda cancel test\n" | ||
123 | h = lanes.gen( "*", laneBody)( "receive", nil) -- start an infinite wait on the linda | ||
124 | |||
125 | print "wait 1s" | ||
126 | linda:receive( 1, "yeah") | ||
127 | |||
128 | -- linda cancel: linda:receive() returns cancel_error immediately | ||
129 | linda:cancel( "both") | ||
130 | |||
131 | -- wait until cancellation is effective. | ||
132 | waitCancellation( h, "done") | ||
133 | |||
134 | -- reset the linda so that the other tests work | ||
135 | linda:cancel( "none") | ||
74 | 136 | ||
75 | print "####################################################################\nbegin soft cancel test\n" | 137 | print "\n\n####################################################################\nbegin soft cancel test\n" |
76 | h = lanes.gen("*", protectedBody)( 0.666) | 138 | h = lanes.gen( "*", protectedBody)( "receive") -- start an infinite wait on the linda |
77 | print "wait 3s" | ||
78 | linda:receive( 3, "yeah") | ||
79 | 139 | ||
80 | -- soft cancel | 140 | print "wait 1s" |
81 | print "soft cancel with awakening" | 141 | linda:receive( 1, "yeah") |
82 | h:cancel( -1, true) | ||
83 | 142 | ||
84 | -- wait 10s: the lane will interrupt its loop and print the exit message | 143 | -- soft cancel, no awakening of waiting linda operations, should timeout |
144 | local a, b = h:cancel( "soft", 1, false) | ||
145 | -- cancellation should fail as the lane is still waiting on its linda | ||
146 | assert( a == false and b == "timeout") | ||
147 | waitCancellation( h, "waiting") | ||
148 | |||
149 | -- soft cancel, this time awakens waiting linda operations, which returns cancel_error immediately, no timeout. | ||
150 | h:cancel( "soft", true) | ||
151 | |||
152 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message | ||
153 | waitCancellation( h, "done") | ||
154 | |||
155 | -- do return end | ||
156 | |||
157 | print "\n\n####################################################################\nbegin hook cancel test\n" | ||
158 | h = lanes.gen( "*", protectedBody)( "get", 300000) | ||
85 | print "wait 2s" | 159 | print "wait 2s" |
86 | linda:receive( 2, "yeah") | 160 | linda:receive( 2, "yeah") |
87 | 161 | ||
88 | --#################################################################### | 162 | -- count hook cancel after 3 instructions |
163 | h:cancel( "count", 300, 5.0) | ||
164 | |||
165 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message | ||
166 | waitCancellation( h, "cancelled") | ||
89 | 167 | ||
90 | print "\n\n####################################################################\nbegin hard cancel test\n" | 168 | print "\n\n####################################################################\nbegin hard cancel test\n" |
91 | h = lanes.gen("*", protectedBody)() | 169 | h = lanes.gen( "*", protectedBody)( "receive", nil) -- infinite timeout |
92 | 170 | ||
93 | -- wait 3s before cancelling the lane | 171 | -- wait 2s before cancelling the lane |
94 | print "wait 3s" | 172 | print "wait 2s" |
95 | linda:receive( 3, "yeah") | 173 | linda:receive( 2, "yeah") |
96 | 174 | ||
97 | -- hard cancel and wait 10s: the lane will be interrupted from inside its current linda:receive() and won't return from it | 175 | -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it |
98 | print "hard cancel (always awakens)" | ||
99 | h:cancel() | 176 | h:cancel() |
100 | 177 | ||
101 | print "wait 5s" | 178 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error |
102 | linda:receive( 5, "yeah") | 179 | waitCancellation( h, "cancelled") |
103 | |||
104 | --#################################################################### | ||
105 | 180 | ||
106 | print "\n\n####################################################################\nbegin hard cancel test with unprotected lane body\n" | 181 | print "\n\n####################################################################\nbegin hard cancel test with unprotected lane body\n" |
107 | h = lanes.gen("*", laneBody)() | 182 | h = lanes.gen( "*", laneBody)( "receive", nil) |
108 | 183 | ||
109 | -- wait 3s before cancelling the lane | 184 | -- wait 2s before cancelling the lane |
110 | print "wait 3s" | 185 | print "wait 2s" |
111 | linda:receive( 3, "yeah") | 186 | linda:receive( 2, "yeah") |
112 | 187 | ||
113 | -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it | 188 | -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it |
114 | print "hard cancel (always awakens)" | ||
115 | h:cancel() | 189 | h:cancel() |
116 | 190 | ||
117 | print "wait 5s" | 191 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error |
118 | linda:receive( 5, "yeah") | 192 | waitCancellation( h, "cancelled") |
119 | 193 | ||
120 | --#################################################################### | 194 | print "\n\n####################################################################\nbegin kill cancel test\n" |
121 | print "\n\n####################################################################\nbegin linda cancel test\n" | 195 | h = lanes.gen( "*", laneBody)( "busy", 50000000) -- start a pure Lua busy loop lane |
122 | h = lanes.gen("*", laneBody)() | ||
123 | 196 | ||
124 | -- wait 3s before cancelling the lane | 197 | -- wait 1/3s before cancelling the lane, before the busy loop can finish |
125 | print "wait 3s" | 198 | print "wait 0.3s" |
126 | linda:receive( 3, "yeah") | 199 | linda:receive( 0.3, "yeah") |
127 | 200 | ||
128 | -- linda cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it | 201 | -- hard cancel with kill: the lane thread will be forcefully terminated |
129 | print "linda cancel (always awakens the lane)" | 202 | h:cancel( true) |
130 | linda:cancel( "both") | ||
131 | 203 | ||
132 | print "wait 5s" | 204 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error |
133 | linda:receive( 5, "yeah") | 205 | waitCancellation( h, "killed") |
134 | 206 | ||
135 | --#################################################################### | 207 | --#################################################################### |
136 | 208 | ||