|
@@ -156,11 +156,6 @@ do
|
|
st, msg = coroutine.close(co)
|
|
st, msg = coroutine.close(co)
|
|
assert(st and msg == nil)
|
|
assert(st and msg == nil)
|
|
|
|
|
|
-
|
|
|
|
- -- cannot close the running coroutine
|
|
|
|
- local st, msg = pcall(coroutine.close, coroutine.running())
|
|
|
|
- assert(not st and string.find(msg, "running"))
|
|
|
|
-
|
|
|
|
local main = coroutine.running()
|
|
local main = coroutine.running()
|
|
|
|
|
|
-- cannot close a "normal" coroutine
|
|
-- cannot close a "normal" coroutine
|
|
@@ -169,20 +164,19 @@ do
|
|
assert(not st and string.find(msg, "normal"))
|
|
assert(not st and string.find(msg, "normal"))
|
|
end))()
|
|
end))()
|
|
|
|
|
|
- -- cannot close a coroutine while closing it
|
|
|
|
- do
|
|
|
|
|
|
+ do -- close a coroutine while closing it
|
|
local co
|
|
local co
|
|
co = coroutine.create(
|
|
co = coroutine.create(
|
|
function()
|
|
function()
|
|
local x <close> = func2close(function()
|
|
local x <close> = func2close(function()
|
|
- coroutine.close(co) -- try to close it again
|
|
|
|
|
|
+ coroutine.close(co) -- close it again
|
|
end)
|
|
end)
|
|
coroutine.yield(20)
|
|
coroutine.yield(20)
|
|
end)
|
|
end)
|
|
local st, msg = coroutine.resume(co)
|
|
local st, msg = coroutine.resume(co)
|
|
assert(st and msg == 20)
|
|
assert(st and msg == 20)
|
|
st, msg = coroutine.close(co)
|
|
st, msg = coroutine.close(co)
|
|
- assert(not st and string.find(msg, "running coroutine"))
|
|
|
|
|
|
+ assert(st and msg == nil)
|
|
end
|
|
end
|
|
|
|
|
|
-- to-be-closed variables in coroutines
|
|
-- to-be-closed variables in coroutines
|
|
@@ -289,6 +283,56 @@ do
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
+do print("coroutines closing itself")
|
|
|
|
+ global <const> coroutine, string, os
|
|
|
|
+ global <const> assert, error, pcall
|
|
|
|
+
|
|
|
|
+ local X = nil
|
|
|
|
+
|
|
|
|
+ local function new ()
|
|
|
|
+ return coroutine.create(function (what)
|
|
|
|
+
|
|
|
|
+ local <close>var = func2close(function (t, err)
|
|
|
|
+ if what == "yield" then
|
|
|
|
+ coroutine.yield()
|
|
|
|
+ elseif what == "error" then
|
|
|
|
+ error(200)
|
|
|
|
+ else
|
|
|
|
+ X = "Ok"
|
|
|
|
+ return X
|
|
|
|
+ end
|
|
|
|
+ end)
|
|
|
|
+
|
|
|
|
+ -- do an unprotected call so that coroutine becomes non-yieldable
|
|
|
|
+ string.gsub("a", "a", function ()
|
|
|
|
+ assert(not coroutine.isyieldable())
|
|
|
|
+ -- do protected calls while non-yieldable, to add recovery
|
|
|
|
+ -- entries (setjmp) to the stack
|
|
|
|
+ assert(pcall(pcall, function ()
|
|
|
|
+ -- 'close' works even while non-yieldable
|
|
|
|
+ coroutine.close() -- close itself
|
|
|
|
+ os.exit(false) -- not reacheable
|
|
|
|
+ end))
|
|
|
|
+ end)
|
|
|
|
+ end)
|
|
|
|
+ end
|
|
|
|
+
|
|
|
|
+ local co = new()
|
|
|
|
+ local st, msg = coroutine.resume(co, "ret")
|
|
|
|
+ assert(st and msg == nil)
|
|
|
|
+ assert(X == "Ok")
|
|
|
|
+
|
|
|
|
+ local co = new()
|
|
|
|
+ local st, msg = coroutine.resume(co, "error")
|
|
|
|
+ assert(not st and msg == 200)
|
|
|
|
+
|
|
|
|
+ local co = new()
|
|
|
|
+ local st, msg = coroutine.resume(co, "yield")
|
|
|
|
+ assert(not st and string.find(msg, "attempt to yield"))
|
|
|
|
+
|
|
|
|
+end
|
|
|
|
+
|
|
|
|
+
|
|
-- yielding across C boundaries
|
|
-- yielding across C boundaries
|
|
|
|
|
|
local co = coroutine.wrap(function()
|
|
local co = coroutine.wrap(function()
|