diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-18 11:22:42 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-18 11:22:42 -0300 |
commit | 409256b7849ec5ab3296cb0ab9eba3d65955d5ea (patch) | |
tree | 13d6327093e900cab0b23c4d09f344a281630c73 | |
parent | b17178b27a55bd5eeb51538bec935972fd58f1ea (diff) | |
download | lua-409256b7849ec5ab3296cb0ab9eba3d65955d5ea.tar.gz lua-409256b7849ec5ab3296cb0ab9eba3d65955d5ea.tar.bz2 lua-409256b7849ec5ab3296cb0ab9eba3d65955d5ea.zip |
'coroutine.close'/'lua_resetthread' report original errors
Besides errors in closing methods, 'coroutine.close' and
'lua_resetthread' also consider the original error that stopped the
thread, if any.
-rw-r--r-- | lstate.c | 8 | ||||
-rw-r--r-- | manual/manual.of | 10 | ||||
-rw-r--r-- | testes/coroutine.lua | 10 | ||||
-rw-r--r-- | testes/cstack.lua | 4 | ||||
-rw-r--r-- | testes/locals.lua | 23 |
5 files changed, 40 insertions, 15 deletions
@@ -323,14 +323,16 @@ void luaE_freethread (lua_State *L, lua_State *L1) { | |||
323 | 323 | ||
324 | int lua_resetthread (lua_State *L) { | 324 | int lua_resetthread (lua_State *L) { |
325 | CallInfo *ci; | 325 | CallInfo *ci; |
326 | int status; | 326 | int status = L->status; |
327 | lua_lock(L); | 327 | lua_lock(L); |
328 | L->ci = ci = &L->base_ci; /* unwind CallInfo list */ | 328 | L->ci = ci = &L->base_ci; /* unwind CallInfo list */ |
329 | setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ | 329 | setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ |
330 | ci->func = L->stack; | 330 | ci->func = L->stack; |
331 | ci->callstatus = CIST_C; | 331 | ci->callstatus = CIST_C; |
332 | status = luaF_close(L, L->stack, CLOSEPROTECT); | 332 | if (status == LUA_OK || status == LUA_YIELD) |
333 | if (status != CLOSEPROTECT) /* real errors? */ | 333 | status = CLOSEPROTECT; /* run closing methods in protected mode */ |
334 | status = luaF_close(L, L->stack, status); | ||
335 | if (status != CLOSEPROTECT) /* errors? */ | ||
334 | luaD_seterrorobj(L, status, L->stack + 1); | 336 | luaD_seterrorobj(L, status, L->stack + 1); |
335 | else { | 337 | else { |
336 | status = LUA_OK; | 338 | status = LUA_OK; |
diff --git a/manual/manual.of b/manual/manual.of index 771bace0..164e359a 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
@@ -4098,10 +4098,12 @@ and then pops the top element. | |||
4098 | Resets a thread, cleaning its call stack and closing all pending | 4098 | Resets a thread, cleaning its call stack and closing all pending |
4099 | to-be-closed variables. | 4099 | to-be-closed variables. |
4100 | Returns a status code: | 4100 | Returns a status code: |
4101 | @Lid{LUA_OK} for no errors in closing methods, | 4101 | @Lid{LUA_OK} for no errors in the thread |
4102 | (either the original error that stopped the thread or | ||
4103 | errors in closing methods), | ||
4102 | or an error status otherwise. | 4104 | or an error status otherwise. |
4103 | In case of error, | 4105 | In case of error, |
4104 | leaves the error object on the top of the stack, | 4106 | leaves the error object on the top of the stack. |
4105 | 4107 | ||
4106 | } | 4108 | } |
4107 | 4109 | ||
@@ -6577,7 +6579,9 @@ that is, | |||
6577 | closes all its pending to-be-closed variables | 6579 | closes all its pending to-be-closed variables |
6578 | and puts the coroutine in a dead state. | 6580 | and puts the coroutine in a dead state. |
6579 | The given coroutine must be dead or suspended. | 6581 | The given coroutine must be dead or suspended. |
6580 | In case of error closing some variable, | 6582 | In case of error |
6583 | (either the original error that stopped the coroutine or | ||
6584 | errors in closing methods), | ||
6581 | returns @false plus the error object; | 6585 | returns @false plus the error object; |
6582 | otherwise returns @true. | 6586 | otherwise returns @true. |
6583 | 6587 | ||
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 5b927151..aaf565fb 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
@@ -134,7 +134,8 @@ do | |||
134 | local co = coroutine.create(print) | 134 | local co = coroutine.create(print) |
135 | assert(coroutine.resume(co, "testing 'coroutine.close'")) | 135 | assert(coroutine.resume(co, "testing 'coroutine.close'")) |
136 | assert(coroutine.status(co) == "dead") | 136 | assert(coroutine.status(co) == "dead") |
137 | assert(coroutine.close(co)) | 137 | local st, msg = coroutine.close(co) |
138 | assert(st and msg == nil) | ||
138 | 139 | ||
139 | -- cannot close the running coroutine | 140 | -- cannot close the running coroutine |
140 | local st, msg = pcall(coroutine.close, coroutine.running()) | 141 | local st, msg = pcall(coroutine.close, coroutine.running()) |
@@ -151,6 +152,13 @@ do | |||
151 | -- to-be-closed variables in coroutines | 152 | -- to-be-closed variables in coroutines |
152 | local X | 153 | local X |
153 | 154 | ||
155 | -- closing a coroutine after an error | ||
156 | local co = coroutine.create(error) | ||
157 | local st, msg = coroutine.resume(co, 100) | ||
158 | assert(not st and msg == 100) | ||
159 | st, msg = coroutine.close(co) | ||
160 | assert(not st and msg == 100) | ||
161 | |||
154 | co = coroutine.create(function () | 162 | co = coroutine.create(function () |
155 | local x <close> = func2close(function (self, err) | 163 | local x <close> = func2close(function (self, err) |
156 | assert(err == nil); X = false | 164 | assert(err == nil); X = false |
diff --git a/testes/cstack.lua b/testes/cstack.lua index 8ac48e89..7bd55063 100644 --- a/testes/cstack.lua +++ b/testes/cstack.lua | |||
@@ -135,14 +135,18 @@ if T then | |||
135 | local topB, sizeB -- top and size Before overflow | 135 | local topB, sizeB -- top and size Before overflow |
136 | local topA, sizeA -- top and size After overflow | 136 | local topA, sizeA -- top and size After overflow |
137 | topB, sizeB = T.stacklevel() | 137 | topB, sizeB = T.stacklevel() |
138 | collectgarbage("stop") -- __gc should not be called with a full stack | ||
138 | xpcall(f, err) | 139 | xpcall(f, err) |
140 | collectgarbage("restart") | ||
139 | topA, sizeA = T.stacklevel() | 141 | topA, sizeA = T.stacklevel() |
140 | -- sizes should be comparable | 142 | -- sizes should be comparable |
141 | assert(topA == topB and sizeA < sizeB * 2) | 143 | assert(topA == topB and sizeA < sizeB * 2) |
142 | print(string.format("maximum stack size: %d", stack1)) | 144 | print(string.format("maximum stack size: %d", stack1)) |
143 | LIM = N -- will stop recursion at maximum level | 145 | LIM = N -- will stop recursion at maximum level |
144 | N = 0 -- to count again | 146 | N = 0 -- to count again |
147 | collectgarbage("stop") -- __gc should not be called with a full stack | ||
145 | f() | 148 | f() |
149 | collectgarbage("restart") | ||
146 | print"+" | 150 | print"+" |
147 | end | 151 | end |
148 | 152 | ||
diff --git a/testes/locals.lua b/testes/locals.lua index df44b86f..e2f6f35c 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -362,7 +362,7 @@ end | |||
362 | 362 | ||
363 | local function checkwarn (msg) | 363 | local function checkwarn (msg) |
364 | if T then | 364 | if T then |
365 | assert(string.find(_WARN, msg)) | 365 | assert(_WARN and string.find(_WARN, msg)) |
366 | _WARN = false -- reset variable to check next warning | 366 | _WARN = false -- reset variable to check next warning |
367 | end | 367 | end |
368 | end | 368 | end |
@@ -670,10 +670,13 @@ do | |||
670 | -- error in a wrapped coroutine raising errors when closing a variable | 670 | -- error in a wrapped coroutine raising errors when closing a variable |
671 | local x = 0 | 671 | local x = 0 |
672 | local co = coroutine.wrap(function () | 672 | local co = coroutine.wrap(function () |
673 | local xx <close> = func2close(function () x = x + 1; error("@YYY") end) | 673 | local xx <close> = func2close(function () |
674 | x = x + 1; | ||
675 | checkwarn("@XXX"); error("@YYY") | ||
676 | end) | ||
674 | local xv <close> = func2close(function () x = x + 1; error("@XXX") end) | 677 | local xv <close> = func2close(function () x = x + 1; error("@XXX") end) |
675 | coroutine.yield(100) | 678 | coroutine.yield(100) |
676 | error(200) | 679 | error(200) |
677 | end) | 680 | end) |
678 | assert(co() == 100); assert(x == 0) | 681 | assert(co() == 100); assert(x == 0) |
679 | local st, msg = pcall(co); assert(x == 2) | 682 | local st, msg = pcall(co); assert(x == 2) |
@@ -683,10 +686,14 @@ do | |||
683 | local x = 0 | 686 | local x = 0 |
684 | local y = 0 | 687 | local y = 0 |
685 | co = coroutine.wrap(function () | 688 | co = coroutine.wrap(function () |
686 | local xx <close> = func2close(function () y = y + 1; error("YYY") end) | 689 | local xx <close> = func2close(function () |
687 | local xv <close> = func2close(function () x = x + 1; error("XXX") end) | 690 | y = y + 1; checkwarn("XXX"); error("YYY") |
688 | coroutine.yield(100) | 691 | end) |
689 | return 200 | 692 | local xv <close> = func2close(function () |
693 | x = x + 1; error("XXX") | ||
694 | end) | ||
695 | coroutine.yield(100) | ||
696 | return 200 | ||
690 | end) | 697 | end) |
691 | assert(co() == 100); assert(x == 0) | 698 | assert(co() == 100); assert(x == 0) |
692 | local st, msg = pcall(co) | 699 | local st, msg = pcall(co) |