diff options
| -rw-r--r-- | lcorolib.c | 12 | ||||
| -rw-r--r-- | ldo.c | 4 | ||||
| -rw-r--r-- | manual/manual.of | 33 | ||||
| -rw-r--r-- | testes/coroutine.lua | 8 | ||||
| -rw-r--r-- | testes/db.lua | 14 | ||||
| -rw-r--r-- | testes/locals.lua | 35 |
6 files changed, 80 insertions, 26 deletions
| @@ -25,6 +25,10 @@ static lua_State *getco (lua_State *L) { | |||
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | /* | ||
| 29 | ** Resumes a coroutine. Returns the number of results for non-error | ||
| 30 | ** cases or -1 for errors. | ||
| 31 | */ | ||
| 28 | static int auxresume (lua_State *L, lua_State *co, int narg) { | 32 | static int auxresume (lua_State *L, lua_State *co, int narg) { |
| 29 | int status, nres; | 33 | int status, nres; |
| 30 | if (!lua_checkstack(co, narg)) { | 34 | if (!lua_checkstack(co, narg)) { |
| @@ -74,8 +78,14 @@ static int luaB_auxwrap (lua_State *L) { | |||
| 74 | lua_State *co = lua_tothread(L, lua_upvalueindex(1)); | 78 | lua_State *co = lua_tothread(L, lua_upvalueindex(1)); |
| 75 | int r = auxresume(L, co, lua_gettop(L)); | 79 | int r = auxresume(L, co, lua_gettop(L)); |
| 76 | if (r < 0) { | 80 | if (r < 0) { |
| 81 | int stat = lua_status(co); | ||
| 82 | if (stat != LUA_OK && stat != LUA_YIELD) { | ||
| 83 | stat = lua_resetthread(co); /* close variables in case of errors */ | ||
| 84 | if (stat != LUA_OK) /* error closing variables? */ | ||
| 85 | lua_xmove(co, L, 1); /* get new error object */ | ||
| 86 | } | ||
| 77 | if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ | 87 | if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ |
| 78 | luaL_where(L, 1); /* add extra info */ | 88 | luaL_where(L, 1); /* add extra info, if available */ |
| 79 | lua_insert(L, -2); | 89 | lua_insert(L, -2); |
| 80 | lua_concat(L, 2); | 90 | lua_concat(L, 2); |
| 81 | } | 91 | } |
| @@ -686,10 +686,8 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
| 686 | if (likely(!errorstatus(status))) | 686 | if (likely(!errorstatus(status))) |
| 687 | lua_assert(status == L->status); /* normal end or yield */ | 687 | lua_assert(status == L->status); /* normal end or yield */ |
| 688 | else { /* unrecoverable error */ | 688 | else { /* unrecoverable error */ |
| 689 | status = luaF_close(L, L->stack, status); /* close all upvalues */ | ||
| 690 | L->status = cast_byte(status); /* mark thread as 'dead' */ | 689 | L->status = cast_byte(status); /* mark thread as 'dead' */ |
| 691 | luaD_seterrorobj(L, status, L->stack + 1); /* push error message */ | 690 | luaD_seterrorobj(L, status, L->top); /* push error message */ |
| 692 | L->ci = &L->base_ci; /* back to the original C level */ | ||
| 693 | L->ci->top = L->top; | 691 | L->ci->top = L->top; |
| 694 | } | 692 | } |
| 695 | *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield | 693 | *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield |
diff --git a/manual/manual.of b/manual/manual.of index 5f265708..cf44b4f2 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
| @@ -286,7 +286,7 @@ Lua also offers a system of @emph{warnings} @seeF{warn}. | |||
| 286 | Unlike errors, warnings do not interfere | 286 | Unlike errors, warnings do not interfere |
| 287 | in any way with program execution. | 287 | in any way with program execution. |
| 288 | They typically only generate a message to the user, | 288 | They typically only generate a message to the user, |
| 289 | although this behavior can be adapted from C @see{lua_setwarnf}. | 289 | although this behavior can be adapted from C @seeC{lua_setwarnf}. |
| 290 | 290 | ||
| 291 | } | 291 | } |
| 292 | 292 | ||
| @@ -835,6 +835,9 @@ In case of normal termination, | |||
| 835 | plus any values returned by the coroutine main function. | 835 | plus any values returned by the coroutine main function. |
| 836 | In case of errors, @Lid{coroutine.resume} returns @false | 836 | In case of errors, @Lid{coroutine.resume} returns @false |
| 837 | plus the error object. | 837 | plus the error object. |
| 838 | In this case, the coroutine does not unwind its stack, | ||
| 839 | so that it is possible to inspect it after the error | ||
| 840 | with the debug API. | ||
| 838 | 841 | ||
| 839 | A coroutine yields by calling @Lid{coroutine.yield}. | 842 | A coroutine yields by calling @Lid{coroutine.yield}. |
| 840 | When a coroutine yields, | 843 | When a coroutine yields, |
| @@ -858,8 +861,10 @@ go as extra arguments to @Lid{coroutine.resume}. | |||
| 858 | @Lid{coroutine.wrap} returns all the values returned by @Lid{coroutine.resume}, | 861 | @Lid{coroutine.wrap} returns all the values returned by @Lid{coroutine.resume}, |
| 859 | except the first one (the boolean error code). | 862 | except the first one (the boolean error code). |
| 860 | Unlike @Lid{coroutine.resume}, | 863 | Unlike @Lid{coroutine.resume}, |
| 861 | @Lid{coroutine.wrap} does not catch errors; | 864 | the function created by @Lid{coroutine.wrap} |
| 862 | any error is propagated to the caller. | 865 | propagates any error to the caller. |
| 866 | In this case, | ||
| 867 | the function also kills the coroutine @seeF{coroutine.kill}. | ||
| 863 | 868 | ||
| 864 | As an example of how coroutines work, | 869 | As an example of how coroutines work, |
| 865 | consider the following code: | 870 | consider the following code: |
| @@ -1534,8 +1539,15 @@ the other pending closing methods will still be called. | |||
| 1534 | If a coroutine yields inside a block and is never resumed again, | 1539 | If a coroutine yields inside a block and is never resumed again, |
| 1535 | the variables visible at that block will never go out of scope, | 1540 | the variables visible at that block will never go out of scope, |
| 1536 | and therefore they will not be closed. | 1541 | and therefore they will not be closed. |
| 1537 | (You should use finalizers to handle this case, | 1542 | Similarly, if a coroutine ends with an error, |
| 1538 | or else call @Lid{coroutine.kill} to close the variables.) | 1543 | it does not unwind its stack, |
| 1544 | so it does not close any variable. | ||
| 1545 | You should either use finalizers | ||
| 1546 | or call @Lid{coroutine.kill} to close the variables in these cases. | ||
| 1547 | However, note that if the coroutine was created | ||
| 1548 | through @Lid{coroutine.wrap}, | ||
| 1549 | then its corresponding function will close all variables | ||
| 1550 | in case of errors. | ||
| 1539 | 1551 | ||
| 1540 | } | 1552 | } |
| 1541 | 1553 | ||
| @@ -6406,11 +6418,12 @@ or if it has stopped with an error. | |||
| 6406 | Creates a new coroutine, with body @id{f}; | 6418 | Creates a new coroutine, with body @id{f}; |
| 6407 | @id{f} must be a function. | 6419 | @id{f} must be a function. |
| 6408 | Returns a function that resumes the coroutine each time it is called. | 6420 | Returns a function that resumes the coroutine each time it is called. |
| 6409 | Any arguments passed to the function behave as the | 6421 | Any arguments passed to this function behave as the |
| 6410 | extra arguments to @id{resume}. | 6422 | extra arguments to @id{resume}. |
| 6411 | Returns the same values returned by @id{resume}, | 6423 | The function returns the same values returned by @id{resume}, |
| 6412 | except the first boolean. | 6424 | except the first boolean. |
| 6413 | In case of error, propagates the error. | 6425 | In case of error, |
| 6426 | the function kills the coroutine and propagates the error. | ||
| 6414 | 6427 | ||
| 6415 | } | 6428 | } |
| 6416 | 6429 | ||
| @@ -6668,6 +6681,10 @@ the file path where the module was found, | |||
| 6668 | as returned by @Lid{package.searchpath}. | 6681 | as returned by @Lid{package.searchpath}. |
| 6669 | The first searcher always returns the string @St{:preload:}. | 6682 | The first searcher always returns the string @St{:preload:}. |
| 6670 | 6683 | ||
| 6684 | Searchers should raise no errors and have no side effects in Lua. | ||
| 6685 | (They may have side effects in C, | ||
| 6686 | for instance by linking the application with a library.) | ||
| 6687 | |||
| 6671 | } | 6688 | } |
| 6672 | 6689 | ||
| 6673 | @LibEntry{package.searchpath (name, path [, sep [, rep]])| | 6690 | @LibEntry{package.searchpath (name, path [, sep [, rep]])| |
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 35ff27fb..9dd501e7 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
| @@ -346,9 +346,13 @@ do | |||
| 346 | local st, res = coroutine.resume(B) | 346 | local st, res = coroutine.resume(B) |
| 347 | assert(st == true and res == false) | 347 | assert(st == true and res == false) |
| 348 | 348 | ||
| 349 | A = coroutine.wrap(function() return pcall(A, 1) end) | 349 | local X = false |
| 350 | A = coroutine.wrap(function() | ||
| 351 | local *toclose _ = setmetatable({}, {__close = function () X = true end}) | ||
| 352 | return pcall(A, 1) | ||
| 353 | end) | ||
| 350 | st, res = A() | 354 | st, res = A() |
| 351 | assert(not st and string.find(res, "non%-suspended")) | 355 | assert(not st and string.find(res, "non%-suspended") and X == true) |
| 352 | end | 356 | end |
| 353 | 357 | ||
| 354 | 358 | ||
diff --git a/testes/db.lua b/testes/db.lua index 95275fb4..3d94f776 100644 --- a/testes/db.lua +++ b/testes/db.lua | |||
| @@ -734,18 +734,24 @@ 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 coroutines | 737 | -- check traceback of suspended (or dead with error) coroutines |
| 738 | |||
| 739 | function f(i) | ||
| 740 | if i == 0 then error(i) | ||
| 741 | else coroutine.yield(); f(i-1) | ||
| 742 | end | ||
| 743 | end | ||
| 738 | 744 | ||
| 739 | function f(i) coroutine.yield(i == 0); f(i - 1) end | ||
| 740 | 745 | ||
| 741 | co = coroutine.create(function (x) f(x) end) | 746 | co = coroutine.create(function (x) f(x) end) |
| 742 | a, b = coroutine.resume(co, 3) | 747 | a, b = coroutine.resume(co, 3) |
| 743 | t = {"'coroutine.yield'", "'f'", "in function <"} | 748 | t = {"'coroutine.yield'", "'f'", "in function <"} |
| 744 | repeat | 749 | while coroutine.status(co) == "suspended" do |
| 745 | checktraceback(co, t) | 750 | checktraceback(co, t) |
| 746 | a, b = coroutine.resume(co) | 751 | a, b = coroutine.resume(co) |
| 747 | table.insert(t, 2, "'f'") -- one more recursive call to 'f' | 752 | table.insert(t, 2, "'f'") -- one more recursive call to 'f' |
| 748 | until b | 753 | end |
| 754 | t[1] = "'error'" | ||
| 749 | checktraceback(co, t) | 755 | checktraceback(co, t) |
| 750 | 756 | ||
| 751 | 757 | ||
diff --git a/testes/locals.lua b/testes/locals.lua index de47ae31..814d1b16 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
| @@ -417,12 +417,13 @@ if rawget(_G, "T") then | |||
| 417 | end | 417 | end |
| 418 | 418 | ||
| 419 | 419 | ||
| 420 | -- to-be-closed variables in coroutines | 420 | print "to-be-closed variables in coroutines" |
| 421 | |||
| 421 | do | 422 | do |
| 422 | -- an error in a coroutine closes variables | 423 | -- an error in a wrapped coroutine closes variables |
| 423 | local x = false | 424 | local x = false |
| 424 | local y = false | 425 | local y = false |
| 425 | local co = coroutine.create(function () | 426 | local co = coroutine.wrap(function () |
| 426 | local *toclose xv = func2close(function () x = true end) | 427 | local *toclose xv = func2close(function () x = true end) |
| 427 | do | 428 | do |
| 428 | local *toclose yv = func2close(function () y = true end) | 429 | local *toclose yv = func2close(function () y = true end) |
| @@ -432,14 +433,31 @@ do | |||
| 432 | error(23) -- error does | 433 | error(23) -- error does |
| 433 | end) | 434 | end) |
| 434 | 435 | ||
| 435 | local a, b = coroutine.resume(co) | 436 | local b = co() |
| 436 | assert(a and b == 100 and not x and not y) | 437 | assert(b == 100 and not x and not y) |
| 437 | a, b = coroutine.resume(co) | 438 | b = co() |
| 438 | assert(a and b == 200 and not x and y) | 439 | assert(b == 200 and not x and y) |
| 439 | a, b = coroutine.resume(co) | 440 | local a, b = pcall(co) |
| 440 | assert(not a and b == 23 and x and y) | 441 | assert(not a and b == 23 and x and y) |
| 441 | end | 442 | end |
| 442 | 443 | ||
| 444 | |||
| 445 | do | ||
| 446 | -- error in a wrapped coroutine raising errors when closing a variable | ||
| 447 | local x = false | ||
| 448 | local co = coroutine.wrap(function () | ||
| 449 | local *toclose xv = func2close(function () error("XXX") end) | ||
| 450 | coroutine.yield(100) | ||
| 451 | error(200) | ||
| 452 | end) | ||
| 453 | assert(co() == 100) | ||
| 454 | local st, msg = pcall(co) | ||
| 455 | print(msg) | ||
| 456 | -- should get last error raised | ||
| 457 | assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX")) | ||
| 458 | end | ||
| 459 | |||
| 460 | |||
| 443 | -- a suspended coroutine should not close its variables when collected | 461 | -- a suspended coroutine should not close its variables when collected |
| 444 | local co | 462 | local co |
| 445 | co = coroutine.wrap(function() | 463 | co = coroutine.wrap(function() |
| @@ -449,6 +467,7 @@ co = coroutine.wrap(function() | |||
| 449 | end) | 467 | end) |
| 450 | co() -- start coroutine | 468 | co() -- start coroutine |
| 451 | assert(co == nil) -- eventually it will be collected | 469 | assert(co == nil) -- eventually it will be collected |
| 470 | collectgarbage() | ||
| 452 | 471 | ||
| 453 | 472 | ||
| 454 | -- to-be-closed variables in generic for loops | 473 | -- to-be-closed variables in generic for loops |
