summaryrefslogtreecommitdiff
path: root/testes
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-02-12 13:36:30 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-02-12 13:36:30 -0300
commitbc970005ce2e258e29a5c315ea4e49f76a66586e (patch)
tree5575ca66aeddad2036df74f38fa2bed217c2801e /testes
parentf79ccdca9bbe9d486d91a44a4464b99ce38de0e2 (diff)
downloadlua-github-bc970005ce2e258e29a5c315ea4e49f76a66586e.tar.gz
'__close' methods can yield in the return of a C function
When, inside a coroutine, a C function with to-be-closed slots return, the corresponding metamethods can yield. ('__close' metamethods called through 'lua_closeslot' still cannot yield, as there is no continuation to go when resuming.)
Diffstat (limited to 'testes')
-rw-r--r--testes/locals.lua76
1 files changed, 75 insertions, 1 deletions
diff --git a/testes/locals.lua b/testes/locals.lua
index 446ec13a..a93839db 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -707,7 +707,6 @@ if rawget(_G, "T") then
-- results are correct
checktable(t, {10, 20})
end
-
end
@@ -930,6 +929,81 @@ assert(co == nil) -- eventually it will be collected
collectgarbage()
+if rawget(_G, "T") then
+ print("to-be-closed variables x coroutines in C")
+ do
+ local token = 0
+ local count = 0
+ local f = T.makeCfunc[[
+ toclose 1
+ toclose 2
+ return .
+ ]]
+
+ local obj = func2close(function (_, msg)
+ count = count + 1
+ token = coroutine.yield(count, token)
+ end)
+
+ local co = coroutine.wrap(f)
+ local ct, res = co(obj, obj, 10, 20, 30, 3) -- will return 10, 20, 30
+ -- initial token value, after closing 2nd obj
+ assert(ct == 1 and res == 0)
+ -- run until yield when closing 1st obj
+ ct, res = co(100)
+ assert(ct == 2 and res == 100)
+ res = {co(200)} -- run until end
+ assert(res[1] == 10 and res[2] == 20 and res[3] == 30 and res[4] == nil)
+ assert(token == 200)
+ end
+
+ do
+ local f = T.makeCfunc[[
+ toclose 1
+ return .
+ ]]
+
+ local obj = func2close(function ()
+ local temp
+ local x <close> = func2close(function ()
+ coroutine.yield(temp)
+ return 1,2,3 -- to be ignored
+ end)
+ temp = coroutine.yield("closing obj")
+ return 1,2,3 -- to be ignored
+ end)
+
+ local co = coroutine.wrap(f)
+ local res = co(obj, 10, 30, 1) -- will return only 30
+ assert(res == "closing obj")
+ res = co("closing x")
+ assert(res == "closing x")
+ res = {co()}
+ assert(res[1] == 30 and res[2] == nil)
+ end
+
+ do
+ -- still cannot yield inside 'closeslot'
+ local f = T.makeCfunc[[
+ toclose 1
+ closeslot 1
+ ]]
+ local obj = func2close(coroutine.yield)
+ local co = coroutine.create(f)
+ local st, msg = coroutine.resume(co, obj)
+ assert(not st and string.find(msg, "attempt to yield across"))
+
+ -- nor outside a coroutine
+ local f = T.makeCfunc[[
+ toclose 1
+ ]]
+ local st, msg = pcall(f, obj)
+ assert(not st and string.find(msg, "attempt to yield from outside"))
+ end
+end
+
+
+
-- to-be-closed variables in generic for loops
do
local numopen = 0