diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-22 14:55:51 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-22 14:55:51 -0300 |
commit | c90176f96924ee7d207501b32f216925773d3bdb (patch) | |
tree | 234f3aefb0617dd7e3d1ff5faf32f9fbdf96c2d7 | |
parent | 3c7dc52909ce0688bdb20cacaf686413a79aaf48 (diff) | |
download | lua-c90176f96924ee7d207501b32f216925773d3bdb.tar.gz lua-c90176f96924ee7d207501b32f216925773d3bdb.tar.bz2 lua-c90176f96924ee7d207501b32f216925773d3bdb.zip |
Complete implementation of to-be-closed variables
-rw-r--r-- | ldo.c | 9 | ||||
-rw-r--r-- | testes/db.lua | 9 | ||||
-rw-r--r-- | testes/locals.lua | 33 |
3 files changed, 39 insertions, 12 deletions
@@ -676,12 +676,15 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
676 | /* unroll continuation */ | 676 | /* unroll continuation */ |
677 | status = luaD_rawrunprotected(L, unroll, &status); | 677 | status = luaD_rawrunprotected(L, unroll, &status); |
678 | } | 678 | } |
679 | if (unlikely(errorstatus(status))) { /* unrecoverable error? */ | 679 | if (likely(!errorstatus(status))) |
680 | lua_assert(status == L->status); /* normal end or yield */ | ||
681 | else { /* unrecoverable error */ | ||
682 | status = luaF_close(L, L->stack, status); /* close all upvalues */ | ||
680 | L->status = cast_byte(status); /* mark thread as 'dead' */ | 683 | L->status = cast_byte(status); /* mark thread as 'dead' */ |
681 | luaD_seterrorobj(L, status, L->top); /* push error message */ | 684 | luaD_seterrorobj(L, status, L->stack + 1); /* push error message */ |
685 | L->ci = &L->base_ci; /* back to the original C level */ | ||
682 | L->ci->top = L->top; | 686 | L->ci->top = L->top; |
683 | } | 687 | } |
684 | else lua_assert(status == L->status); /* normal end or yield */ | ||
685 | } | 688 | } |
686 | *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield | 689 | *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield |
687 | : cast_int(L->top - (L->ci->func + 1)); | 690 | : cast_int(L->top - (L->ci->func + 1)); |
diff --git a/testes/db.lua b/testes/db.lua index 2feaaef1..9da68210 100644 --- a/testes/db.lua +++ b/testes/db.lua | |||
@@ -734,19 +734,18 @@ 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 (or dead with error) coroutines | 737 | -- check traceback of suspended coroutines |
738 | 738 | ||
739 | function f(i) if i==0 then error(i) else coroutine.yield(); f(i-1) end end | 739 | function f(i) coroutine.yield(i == 0); f(i - 1) end |
740 | 740 | ||
741 | co = coroutine.create(function (x) f(x) end) | 741 | co = coroutine.create(function (x) f(x) end) |
742 | a, b = coroutine.resume(co, 3) | 742 | a, b = coroutine.resume(co, 3) |
743 | t = {"'coroutine.yield'", "'f'", "in function <"} | 743 | t = {"'coroutine.yield'", "'f'", "in function <"} |
744 | while coroutine.status(co) == "suspended" do | 744 | repeat |
745 | checktraceback(co, t) | 745 | checktraceback(co, t) |
746 | a, b = coroutine.resume(co) | 746 | a, b = coroutine.resume(co) |
747 | table.insert(t, 2, "'f'") -- one more recursive call to 'f' | 747 | table.insert(t, 2, "'f'") -- one more recursive call to 'f' |
748 | end | 748 | until b |
749 | t[1] = "'error'" | ||
750 | checktraceback(co, t) | 749 | checktraceback(co, t) |
751 | 750 | ||
752 | 751 | ||
diff --git a/testes/locals.lua b/testes/locals.lua index d12c70a0..f21fa2ec 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -274,13 +274,38 @@ if rawget(_G, "T") then | |||
274 | end | 274 | end |
275 | 275 | ||
276 | 276 | ||
277 | -- to-be-closed variables in coroutines | ||
278 | do | ||
279 | -- an error in a coroutine closes variables | ||
280 | local x = false | ||
281 | local y = false | ||
282 | local co = coroutine.create(function () | ||
283 | local scoped xv = function () x = true end | ||
284 | do | ||
285 | local scoped yv = function () y = true end | ||
286 | coroutine.yield(100) -- yield doesn't close variable | ||
287 | end | ||
288 | coroutine.yield(200) -- yield doesn't close variable | ||
289 | error(23) -- error does | ||
290 | end) | ||
291 | |||
292 | local a, b = coroutine.resume(co) | ||
293 | assert(a and b == 100 and not x and not y) | ||
294 | a, b = coroutine.resume(co) | ||
295 | assert(a and b == 200 and not x and y) | ||
296 | a, b = coroutine.resume(co) | ||
297 | assert(not a and b == 23 and x and y) | ||
298 | end | ||
299 | |||
277 | -- a suspended coroutine should not close its variables when collected | 300 | -- a suspended coroutine should not close its variables when collected |
278 | local co = coroutine.wrap(function() | 301 | local co |
302 | co = coroutine.wrap(function() | ||
279 | local scoped x = function () os.exit(false) end -- should not run | 303 | local scoped x = function () os.exit(false) end -- should not run |
280 | coroutine.yield() | 304 | co = nil |
305 | coroutine.yield() | ||
281 | end) | 306 | end) |
282 | co() | 307 | co() -- start coroutine |
283 | co = nil | 308 | assert(co == nil) -- eventually it will be collected |
284 | 309 | ||
285 | print('OK') | 310 | print('OK') |
286 | 311 | ||