diff options
Diffstat (limited to 'testes/coroutine.lua')
-rw-r--r-- | testes/coroutine.lua | 86 |
1 files changed, 77 insertions, 9 deletions
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index abc08039..4881d964 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- $Id: testes/coroutine.lua $ | 1 | -- $Id: testes/coroutine.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file lua.h |
3 | 3 | ||
4 | print "testing coroutines" | 4 | print "testing coroutines" |
5 | 5 | ||
@@ -156,12 +156,12 @@ do | |||
156 | st, msg = coroutine.close(co) | 156 | st, msg = coroutine.close(co) |
157 | assert(st and msg == nil) | 157 | assert(st and msg == nil) |
158 | 158 | ||
159 | local main = coroutine.running() | ||
159 | 160 | ||
160 | -- cannot close the running coroutine | 161 | -- cannot close 'main' |
161 | local st, msg = pcall(coroutine.close, coroutine.running()) | 162 | local st, msg = pcall(coroutine.close, main); |
162 | assert(not st and string.find(msg, "running")) | 163 | assert(not st and string.find(msg, "main")) |
163 | 164 | ||
164 | local main = coroutine.running() | ||
165 | 165 | ||
166 | -- cannot close a "normal" coroutine | 166 | -- cannot close a "normal" coroutine |
167 | ;(coroutine.wrap(function () | 167 | ;(coroutine.wrap(function () |
@@ -169,20 +169,19 @@ do | |||
169 | assert(not st and string.find(msg, "normal")) | 169 | assert(not st and string.find(msg, "normal")) |
170 | end))() | 170 | end))() |
171 | 171 | ||
172 | -- cannot close a coroutine while closing it | 172 | do -- close a coroutine while closing it |
173 | do | ||
174 | local co | 173 | local co |
175 | co = coroutine.create( | 174 | co = coroutine.create( |
176 | function() | 175 | function() |
177 | local x <close> = func2close(function() | 176 | local x <close> = func2close(function() |
178 | coroutine.close(co) -- try to close it again | 177 | coroutine.close(co) -- close it again |
179 | end) | 178 | end) |
180 | coroutine.yield(20) | 179 | coroutine.yield(20) |
181 | end) | 180 | end) |
182 | local st, msg = coroutine.resume(co) | 181 | local st, msg = coroutine.resume(co) |
183 | assert(st and msg == 20) | 182 | assert(st and msg == 20) |
184 | st, msg = coroutine.close(co) | 183 | st, msg = coroutine.close(co) |
185 | assert(not st and string.find(msg, "running coroutine")) | 184 | assert(st and msg == nil) |
186 | end | 185 | end |
187 | 186 | ||
188 | -- to-be-closed variables in coroutines | 187 | -- to-be-closed variables in coroutines |
@@ -289,6 +288,56 @@ do | |||
289 | end | 288 | end |
290 | 289 | ||
291 | 290 | ||
291 | do print("coroutines closing itself") | ||
292 | global <const> coroutine, string, os | ||
293 | global <const> assert, error, pcall | ||
294 | |||
295 | local X = nil | ||
296 | |||
297 | local function new () | ||
298 | return coroutine.create(function (what) | ||
299 | |||
300 | local <close>var = func2close(function (t, err) | ||
301 | if what == "yield" then | ||
302 | coroutine.yield() | ||
303 | elseif what == "error" then | ||
304 | error(200) | ||
305 | else | ||
306 | X = "Ok" | ||
307 | return X | ||
308 | end | ||
309 | end) | ||
310 | |||
311 | -- do an unprotected call so that coroutine becomes non-yieldable | ||
312 | string.gsub("a", "a", function () | ||
313 | assert(not coroutine.isyieldable()) | ||
314 | -- do protected calls while non-yieldable, to add recovery | ||
315 | -- entries (setjmp) to the stack | ||
316 | assert(pcall(pcall, function () | ||
317 | -- 'close' works even while non-yieldable | ||
318 | coroutine.close() -- close itself | ||
319 | os.exit(false) -- not reacheable | ||
320 | end)) | ||
321 | end) | ||
322 | end) | ||
323 | end | ||
324 | |||
325 | local co = new() | ||
326 | local st, msg = coroutine.resume(co, "ret") | ||
327 | assert(st and msg == nil) | ||
328 | assert(X == "Ok") | ||
329 | |||
330 | local co = new() | ||
331 | local st, msg = coroutine.resume(co, "error") | ||
332 | assert(not st and msg == 200) | ||
333 | |||
334 | local co = new() | ||
335 | local st, msg = coroutine.resume(co, "yield") | ||
336 | assert(not st and string.find(msg, "attempt to yield")) | ||
337 | |||
338 | end | ||
339 | |||
340 | |||
292 | -- yielding across C boundaries | 341 | -- yielding across C boundaries |
293 | 342 | ||
294 | local co = coroutine.wrap(function() | 343 | local co = coroutine.wrap(function() |
@@ -505,6 +554,25 @@ assert(not pcall(a, a)) | |||
505 | a = nil | 554 | a = nil |
506 | 555 | ||
507 | 556 | ||
557 | do | ||
558 | -- bug in 5.4: thread can use message handler higher in the stack | ||
559 | -- than the variable being closed | ||
560 | local c = coroutine.create(function() | ||
561 | local clo <close> = setmetatable({}, {__close=function() | ||
562 | local x = 134 -- will overwrite message handler | ||
563 | error(x) | ||
564 | end}) | ||
565 | -- yields coroutine but leaves a new message handler for it, | ||
566 | -- that would be used when closing the coroutine (except that it | ||
567 | -- will be overwritten) | ||
568 | xpcall(coroutine.yield, function() return "XXX" end) | ||
569 | end) | ||
570 | |||
571 | assert(coroutine.resume(c)) -- start coroutine | ||
572 | local st, msg = coroutine.close(c) | ||
573 | assert(not st and msg == 134) | ||
574 | end | ||
575 | |||
508 | -- access to locals of erroneous coroutines | 576 | -- access to locals of erroneous coroutines |
509 | local x = coroutine.create (function () | 577 | local x = coroutine.create (function () |
510 | local a = 10 | 578 | local a = 10 |