diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-05-09 11:13:45 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-05-09 11:13:45 -0300 |
commit | 389116d8abcc96db3cfe2f3cc25789c089fe12d6 (patch) | |
tree | f3d07b50c17f28ba09cf547d5a67519ffe3271a4 /testes | |
parent | 01bded3d8cd88a2d7f472b45f706565f1a9ef3b1 (diff) | |
download | lua-389116d8abcc96db3cfe2f3cc25789c089fe12d6.tar.gz lua-389116d8abcc96db3cfe2f3cc25789c089fe12d6.tar.bz2 lua-389116d8abcc96db3cfe2f3cc25789c089fe12d6.zip |
Coroutines do not unwind the stack in case of errors
Back to how it was, a coroutine does not unwind its stack in case of
errors (and therefore do not close its to-be-closed variables). This
allows the stack to be examined after the error. The program can
use 'coroutine.kill' to close the variables.
The function created by 'coroutine.wrap', however, closes the
coroutine's variables in case of errors, as it is impossible to examine
the stack any way.
Diffstat (limited to 'testes')
-rw-r--r-- | testes/coroutine.lua | 8 | ||||
-rw-r--r-- | testes/db.lua | 14 | ||||
-rw-r--r-- | testes/locals.lua | 35 |
3 files changed, 43 insertions, 14 deletions
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 35ff27fb..9dd501e7 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
@@ -346,9 +346,13 @@ do | |||
346 | local st, res = coroutine.resume(B) | 346 | local st, res = coroutine.resume(B) |
347 | assert(st == true and res == false) | 347 | assert(st == true and res == false) |
348 | 348 | ||
349 | A = coroutine.wrap(function() return pcall(A, 1) end) | 349 | local X = false |
350 | A = coroutine.wrap(function() | ||
351 | local *toclose _ = setmetatable({}, {__close = function () X = true end}) | ||
352 | return pcall(A, 1) | ||
353 | end) | ||
350 | st, res = A() | 354 | st, res = A() |
351 | assert(not st and string.find(res, "non%-suspended")) | 355 | assert(not st and string.find(res, "non%-suspended") and X == true) |
352 | end | 356 | end |
353 | 357 | ||
354 | 358 | ||
diff --git a/testes/db.lua b/testes/db.lua index 95275fb4..3d94f776 100644 --- a/testes/db.lua +++ b/testes/db.lua | |||
@@ -734,18 +734,24 @@ a, b = coroutine.resume(co, 100) | |||
734 | assert(a and b == 30) | 734 | assert(a and b == 30) |
735 | 735 | ||
736 | 736 | ||
737 | -- check traceback of suspended coroutines | 737 | -- check traceback of suspended (or dead with error) coroutines |
738 | |||
739 | function f(i) | ||
740 | if i == 0 then error(i) | ||
741 | else coroutine.yield(); f(i-1) | ||
742 | end | ||
743 | end | ||
738 | 744 | ||
739 | function f(i) coroutine.yield(i == 0); f(i - 1) end | ||
740 | 745 | ||
741 | co = coroutine.create(function (x) f(x) end) | 746 | co = coroutine.create(function (x) f(x) end) |
742 | a, b = coroutine.resume(co, 3) | 747 | a, b = coroutine.resume(co, 3) |
743 | t = {"'coroutine.yield'", "'f'", "in function <"} | 748 | t = {"'coroutine.yield'", "'f'", "in function <"} |
744 | repeat | 749 | while coroutine.status(co) == "suspended" do |
745 | checktraceback(co, t) | 750 | checktraceback(co, t) |
746 | a, b = coroutine.resume(co) | 751 | a, b = coroutine.resume(co) |
747 | table.insert(t, 2, "'f'") -- one more recursive call to 'f' | 752 | table.insert(t, 2, "'f'") -- one more recursive call to 'f' |
748 | until b | 753 | end |
754 | t[1] = "'error'" | ||
749 | checktraceback(co, t) | 755 | checktraceback(co, t) |
750 | 756 | ||
751 | 757 | ||
diff --git a/testes/locals.lua b/testes/locals.lua index de47ae31..814d1b16 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -417,12 +417,13 @@ if rawget(_G, "T") then | |||
417 | end | 417 | end |
418 | 418 | ||
419 | 419 | ||
420 | -- to-be-closed variables in coroutines | 420 | print "to-be-closed variables in coroutines" |
421 | |||
421 | do | 422 | do |
422 | -- an error in a coroutine closes variables | 423 | -- an error in a wrapped coroutine closes variables |
423 | local x = false | 424 | local x = false |
424 | local y = false | 425 | local y = false |
425 | local co = coroutine.create(function () | 426 | local co = coroutine.wrap(function () |
426 | local *toclose xv = func2close(function () x = true end) | 427 | local *toclose xv = func2close(function () x = true end) |
427 | do | 428 | do |
428 | local *toclose yv = func2close(function () y = true end) | 429 | local *toclose yv = func2close(function () y = true end) |
@@ -432,14 +433,31 @@ do | |||
432 | error(23) -- error does | 433 | error(23) -- error does |
433 | end) | 434 | end) |
434 | 435 | ||
435 | local a, b = coroutine.resume(co) | 436 | local b = co() |
436 | assert(a and b == 100 and not x and not y) | 437 | assert(b == 100 and not x and not y) |
437 | a, b = coroutine.resume(co) | 438 | b = co() |
438 | assert(a and b == 200 and not x and y) | 439 | assert(b == 200 and not x and y) |
439 | a, b = coroutine.resume(co) | 440 | local a, b = pcall(co) |
440 | assert(not a and b == 23 and x and y) | 441 | assert(not a and b == 23 and x and y) |
441 | end | 442 | end |
442 | 443 | ||
444 | |||
445 | do | ||
446 | -- error in a wrapped coroutine raising errors when closing a variable | ||
447 | local x = false | ||
448 | local co = coroutine.wrap(function () | ||
449 | local *toclose xv = func2close(function () error("XXX") end) | ||
450 | coroutine.yield(100) | ||
451 | error(200) | ||
452 | end) | ||
453 | assert(co() == 100) | ||
454 | local st, msg = pcall(co) | ||
455 | print(msg) | ||
456 | -- should get last error raised | ||
457 | assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX")) | ||
458 | end | ||
459 | |||
460 | |||
443 | -- a suspended coroutine should not close its variables when collected | 461 | -- a suspended coroutine should not close its variables when collected |
444 | local co | 462 | local co |
445 | co = coroutine.wrap(function() | 463 | co = coroutine.wrap(function() |
@@ -449,6 +467,7 @@ co = coroutine.wrap(function() | |||
449 | end) | 467 | end) |
450 | co() -- start coroutine | 468 | co() -- start coroutine |
451 | assert(co == nil) -- eventually it will be collected | 469 | assert(co == nil) -- eventually it will be collected |
470 | collectgarbage() | ||
452 | 471 | ||
453 | 472 | ||
454 | -- to-be-closed variables in generic for loops | 473 | -- to-be-closed variables in generic for loops |