'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.
diff --git a/lstate.c b/lstate.c
index 1596b51..96187c6 100644
--- a/lstate.c
+++ b/lstate.c
@@ -323,14 +323,16 @@
int lua_resetthread (lua_State *L) {
CallInfo *ci;
- int status;
+ int status = L->status;
lua_lock(L);
L->ci = ci = &L->base_ci; /* unwind CallInfo list */
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
ci->func = L->stack;
ci->callstatus = CIST_C;
- status = luaF_close(L, L->stack, CLOSEPROTECT);
- if (status != CLOSEPROTECT) /* real errors? */
+ if (status == LUA_OK || status == LUA_YIELD)
+ status = CLOSEPROTECT; /* run closing methods in protected mode */
+ status = luaF_close(L, L->stack, status);
+ if (status != CLOSEPROTECT) /* errors? */
luaD_seterrorobj(L, status, L->stack + 1);
else {
status = LUA_OK;
diff --git a/manual/manual.of b/manual/manual.of
index 771bace..164e359 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -4098,10 +4098,12 @@
Resets a thread, cleaning its call stack and closing all pending
to-be-closed variables.
Returns a status code:
-@Lid{LUA_OK} for no errors in closing methods,
+@Lid{LUA_OK} for no errors in the thread
+(either the original error that stopped the thread or
+errors in closing methods),
or an error status otherwise.
In case of error,
-leaves the error object on the top of the stack,
+leaves the error object on the top of the stack.
}
@@ -6577,7 +6579,9 @@
closes all its pending to-be-closed variables
and puts the coroutine in a dead state.
The given coroutine must be dead or suspended.
-In case of error closing some variable,
+In case of error
+(either the original error that stopped the coroutine or
+errors in closing methods),
returns @false plus the error object;
otherwise returns @true.
diff --git a/testes/coroutine.lua b/testes/coroutine.lua
index 5b92715..aaf565f 100644
--- a/testes/coroutine.lua
+++ b/testes/coroutine.lua
@@ -134,7 +134,8 @@
local co = coroutine.create(print)
assert(coroutine.resume(co, "testing 'coroutine.close'"))
assert(coroutine.status(co) == "dead")
- assert(coroutine.close(co))
+ local st, msg = coroutine.close(co)
+ assert(st and msg == nil)
-- cannot close the running coroutine
local st, msg = pcall(coroutine.close, coroutine.running())
@@ -151,6 +152,13 @@
-- to-be-closed variables in coroutines
local X
+ -- closing a coroutine after an error
+ local co = coroutine.create(error)
+ local st, msg = coroutine.resume(co, 100)
+ assert(not st and msg == 100)
+ st, msg = coroutine.close(co)
+ assert(not st and msg == 100)
+
co = coroutine.create(function ()
local x <close> = func2close(function (self, err)
assert(err == nil); X = false
diff --git a/testes/cstack.lua b/testes/cstack.lua
index 8ac48e8..7bd5506 100644
--- a/testes/cstack.lua
+++ b/testes/cstack.lua
@@ -135,14 +135,18 @@
local topB, sizeB -- top and size Before overflow
local topA, sizeA -- top and size After overflow
topB, sizeB = T.stacklevel()
+ collectgarbage("stop") -- __gc should not be called with a full stack
xpcall(f, err)
+ collectgarbage("restart")
topA, sizeA = T.stacklevel()
-- sizes should be comparable
assert(topA == topB and sizeA < sizeB * 2)
print(string.format("maximum stack size: %d", stack1))
LIM = N -- will stop recursion at maximum level
N = 0 -- to count again
+ collectgarbage("stop") -- __gc should not be called with a full stack
f()
+ collectgarbage("restart")
print"+"
end
diff --git a/testes/locals.lua b/testes/locals.lua
index df44b86..e2f6f35 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -362,7 +362,7 @@
local function checkwarn (msg)
if T then
- assert(string.find(_WARN, msg))
+ assert(_WARN and string.find(_WARN, msg))
_WARN = false -- reset variable to check next warning
end
end
@@ -670,10 +670,13 @@
-- error in a wrapped coroutine raising errors when closing a variable
local x = 0
local co = coroutine.wrap(function ()
- local xx <close> = func2close(function () x = x + 1; error("@YYY") end)
+ local xx <close> = func2close(function ()
+ x = x + 1;
+ checkwarn("@XXX"); error("@YYY")
+ end)
local xv <close> = func2close(function () x = x + 1; error("@XXX") end)
- coroutine.yield(100)
- error(200)
+ coroutine.yield(100)
+ error(200)
end)
assert(co() == 100); assert(x == 0)
local st, msg = pcall(co); assert(x == 2)
@@ -683,10 +686,14 @@
local x = 0
local y = 0
co = coroutine.wrap(function ()
- local xx <close> = func2close(function () y = y + 1; error("YYY") end)
- local xv <close> = func2close(function () x = x + 1; error("XXX") end)
- coroutine.yield(100)
- return 200
+ local xx <close> = func2close(function ()
+ y = y + 1; checkwarn("XXX"); error("YYY")
+ end)
+ local xv <close> = func2close(function ()
+ x = x + 1; error("XXX")
+ end)
+ coroutine.yield(100)
+ return 200
end)
assert(co() == 100); assert(x == 0)
local st, msg = pcall(co)