diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-06-12 11:15:09 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-06-12 11:15:09 -0300 |
| commit | fd897027f19288ce2cb0249cb8c1818e2f3f1c4c (patch) | |
| tree | 7fd131ca204c4100a24157405eda4239d2155a46 /testes | |
| parent | d05fe48bfdd89956c0ebd115dca0fb115aa28dd6 (diff) | |
| download | lua-fd897027f19288ce2cb0249cb8c1818e2f3f1c4c.tar.gz lua-fd897027f19288ce2cb0249cb8c1818e2f3f1c4c.tar.bz2 lua-fd897027f19288ce2cb0249cb8c1818e2f3f1c4c.zip | |
A coroutine can close itself
A call to close itself will close all its to-be-closed variables and
return to the resume that (re)started the coroutine.
Diffstat (limited to 'testes')
| -rw-r--r-- | testes/coroutine.lua | 62 |
1 files changed, 53 insertions, 9 deletions
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 17f6ceba..02536ee5 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
| @@ -156,11 +156,6 @@ do | |||
| 156 | st, msg = coroutine.close(co) | 156 | st, msg = coroutine.close(co) |
| 157 | assert(st and msg == nil) | 157 | assert(st and msg == nil) |
| 158 | 158 | ||
| 159 | |||
| 160 | -- cannot close the running coroutine | ||
| 161 | local st, msg = pcall(coroutine.close, coroutine.running()) | ||
| 162 | assert(not st and string.find(msg, "running")) | ||
| 163 | |||
| 164 | local main = coroutine.running() | 159 | local main = coroutine.running() |
| 165 | 160 | ||
| 166 | -- cannot close a "normal" coroutine | 161 | -- cannot close a "normal" coroutine |
| @@ -169,20 +164,19 @@ do | |||
| 169 | assert(not st and string.find(msg, "normal")) | 164 | assert(not st and string.find(msg, "normal")) |
| 170 | end))() | 165 | end))() |
| 171 | 166 | ||
| 172 | -- cannot close a coroutine while closing it | 167 | do -- close a coroutine while closing it |
| 173 | do | ||
| 174 | local co | 168 | local co |
| 175 | co = coroutine.create( | 169 | co = coroutine.create( |
| 176 | function() | 170 | function() |
| 177 | local x <close> = func2close(function() | 171 | local x <close> = func2close(function() |
| 178 | coroutine.close(co) -- try to close it again | 172 | coroutine.close(co) -- close it again |
| 179 | end) | 173 | end) |
| 180 | coroutine.yield(20) | 174 | coroutine.yield(20) |
| 181 | end) | 175 | end) |
| 182 | local st, msg = coroutine.resume(co) | 176 | local st, msg = coroutine.resume(co) |
| 183 | assert(st and msg == 20) | 177 | assert(st and msg == 20) |
| 184 | st, msg = coroutine.close(co) | 178 | st, msg = coroutine.close(co) |
| 185 | assert(not st and string.find(msg, "running coroutine")) | 179 | assert(st and msg == nil) |
| 186 | end | 180 | end |
| 187 | 181 | ||
| 188 | -- to-be-closed variables in coroutines | 182 | -- to-be-closed variables in coroutines |
| @@ -289,6 +283,56 @@ do | |||
| 289 | end | 283 | end |
| 290 | 284 | ||
| 291 | 285 | ||
| 286 | do print("coroutines closing itself") | ||
| 287 | global <const> coroutine, string, os | ||
| 288 | global <const> assert, error, pcall | ||
| 289 | |||
| 290 | local X = nil | ||
| 291 | |||
| 292 | local function new () | ||
| 293 | return coroutine.create(function (what) | ||
| 294 | |||
| 295 | local <close>var = func2close(function (t, err) | ||
| 296 | if what == "yield" then | ||
| 297 | coroutine.yield() | ||
| 298 | elseif what == "error" then | ||
| 299 | error(200) | ||
| 300 | else | ||
| 301 | X = "Ok" | ||
| 302 | return X | ||
| 303 | end | ||
| 304 | end) | ||
| 305 | |||
| 306 | -- do an unprotected call so that coroutine becomes non-yieldable | ||
| 307 | string.gsub("a", "a", function () | ||
| 308 | assert(not coroutine.isyieldable()) | ||
| 309 | -- do protected calls while non-yieldable, to add recovery | ||
| 310 | -- entries (setjmp) to the stack | ||
| 311 | assert(pcall(pcall, function () | ||
| 312 | -- 'close' works even while non-yieldable | ||
| 313 | coroutine.close() -- close itself | ||
| 314 | os.exit(false) -- not reacheable | ||
| 315 | end)) | ||
| 316 | end) | ||
| 317 | end) | ||
| 318 | end | ||
| 319 | |||
| 320 | local co = new() | ||
| 321 | local st, msg = coroutine.resume(co, "ret") | ||
| 322 | assert(st and msg == nil) | ||
| 323 | assert(X == "Ok") | ||
| 324 | |||
| 325 | local co = new() | ||
| 326 | local st, msg = coroutine.resume(co, "error") | ||
| 327 | assert(not st and msg == 200) | ||
| 328 | |||
| 329 | local co = new() | ||
| 330 | local st, msg = coroutine.resume(co, "yield") | ||
| 331 | assert(not st and string.find(msg, "attempt to yield")) | ||
| 332 | |||
| 333 | end | ||
| 334 | |||
| 335 | |||
| 292 | -- yielding across C boundaries | 336 | -- yielding across C boundaries |
| 293 | 337 | ||
| 294 | local co = coroutine.wrap(function() | 338 | local co = coroutine.wrap(function() |
