diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-30 11:20:22 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-30 11:20:22 -0300 |
| commit | ce101dcaf73ff6d610593230d41b63c163a91519 (patch) | |
| tree | 6417f02cb96257a835fa908bfea15c2557a41413 /ldo.c | |
| parent | 553b37ce4ff758d8cf80d48a21287526c92221c6 (diff) | |
| download | lua-ce101dcaf73ff6d610593230d41b63c163a91519.tar.gz lua-ce101dcaf73ff6d610593230d41b63c163a91519.tar.bz2 lua-ce101dcaf73ff6d610593230d41b63c163a91519.zip | |
Handles '__close' errors in coroutines in "coroutine style"
Errors in '__close' metamethods in coroutines are handled by the same
logic that handles other errors, through 'recover'.
Diffstat (limited to 'ldo.c')
| -rw-r--r-- | ldo.c | 66 |
1 files changed, 46 insertions, 20 deletions
| @@ -103,7 +103,7 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { | |||
| 103 | break; | 103 | break; |
| 104 | } | 104 | } |
| 105 | default: { | 105 | default: { |
| 106 | lua_assert(errcode >= LUA_ERRRUN); /* real error */ | 106 | lua_assert(errorstatus(errcode)); /* real error */ |
| 107 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ | 107 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ |
| 108 | break; | 108 | break; |
| 109 | } | 109 | } |
| @@ -593,15 +593,11 @@ static void finishCcall (lua_State *L, int status) { | |||
| 593 | /* | 593 | /* |
| 594 | ** Executes "full continuation" (everything in the stack) of a | 594 | ** Executes "full continuation" (everything in the stack) of a |
| 595 | ** previously interrupted coroutine until the stack is empty (or another | 595 | ** previously interrupted coroutine until the stack is empty (or another |
| 596 | ** interruption long-jumps out of the loop). If the coroutine is | 596 | ** interruption long-jumps out of the loop). |
| 597 | ** recovering from an error, 'ud' points to the error status, which must | ||
| 598 | ** be passed to the first continuation function (otherwise the default | ||
| 599 | ** status is LUA_YIELD). | ||
| 600 | */ | 597 | */ |
| 601 | static void unroll (lua_State *L, void *ud) { | 598 | static void unroll (lua_State *L, void *ud) { |
| 602 | CallInfo *ci; | 599 | CallInfo *ci; |
| 603 | if (ud != NULL) /* error status? */ | 600 | UNUSED(ud); |
| 604 | finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ | ||
| 605 | while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ | 601 | while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ |
| 606 | if (!isLua(ci)) /* C function? */ | 602 | if (!isLua(ci)) /* C function? */ |
| 607 | finishCcall(L, LUA_YIELD); /* complete its execution */ | 603 | finishCcall(L, LUA_YIELD); /* complete its execution */ |
| @@ -628,21 +624,36 @@ static CallInfo *findpcall (lua_State *L) { | |||
| 628 | 624 | ||
| 629 | 625 | ||
| 630 | /* | 626 | /* |
| 631 | ** Recovers from an error in a coroutine. Finds a recover point (if | 627 | ** Auxiliary structure to call 'recover' in protected mode. |
| 632 | ** there is one) and completes the execution of the interrupted | ||
| 633 | ** 'luaD_pcall'. If there is no recover point, returns zero. | ||
| 634 | */ | 628 | */ |
| 635 | static int recover (lua_State *L, int status) { | 629 | struct RecoverS { |
| 636 | CallInfo *ci = findpcall(L); | 630 | int status; |
| 637 | if (ci == NULL) return 0; /* no recovery point */ | 631 | CallInfo *ci; |
| 632 | }; | ||
| 633 | |||
| 634 | |||
| 635 | /* | ||
| 636 | ** Recovers from an error in a coroutine: completes the execution of the | ||
| 637 | ** interrupted 'luaD_pcall', completes the interrupted C function which | ||
| 638 | ** called 'lua_pcallk', and continues running the coroutine. If there is | ||
| 639 | ** an error in 'luaF_close', this function will be called again and the | ||
| 640 | ** coroutine will continue from where it left. | ||
| 641 | */ | ||
| 642 | static void recover (lua_State *L, void *ud) { | ||
| 643 | struct RecoverS *r = cast(struct RecoverS *, ud); | ||
| 644 | int status = r->status; | ||
| 645 | CallInfo *ci = r->ci; /* recover point */ | ||
| 646 | StkId func = restorestack(L, ci->u2.funcidx); | ||
| 638 | /* "finish" luaD_pcall */ | 647 | /* "finish" luaD_pcall */ |
| 639 | L->ci = ci; | 648 | L->ci = ci; |
| 640 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ | 649 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ |
| 641 | status = luaD_closeprotected(L, ci->u2.funcidx, status); | 650 | luaF_close(L, func, status); /* may change the stack */ |
| 642 | luaD_seterrorobj(L, status, restorestack(L, ci->u2.funcidx)); | 651 | func = restorestack(L, ci->u2.funcidx); |
| 652 | luaD_seterrorobj(L, status, func); | ||
| 643 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ | 653 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ |
| 644 | L->errfunc = ci->u.c.old_errfunc; | 654 | L->errfunc = ci->u.c.old_errfunc; |
| 645 | return 1; /* continue running the coroutine */ | 655 | finishCcall(L, status); /* finish 'lua_pcallk' callee */ |
| 656 | unroll(L, NULL); /* continue running the coroutine */ | ||
| 646 | } | 657 | } |
| 647 | 658 | ||
| 648 | 659 | ||
| @@ -692,6 +703,24 @@ static void resume (lua_State *L, void *ud) { | |||
| 692 | } | 703 | } |
| 693 | } | 704 | } |
| 694 | 705 | ||
| 706 | |||
| 707 | /* | ||
| 708 | ** Calls 'recover' in protected mode, repeating while there are | ||
| 709 | ** recoverable errors, that is, errors inside a protected call. (Any | ||
| 710 | ** error interrupts 'recover', and this loop protects it again so it | ||
| 711 | ** can continue.) Stops with a normal end (status == LUA_OK), an yield | ||
| 712 | ** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't | ||
| 713 | ** find a recover point). | ||
| 714 | */ | ||
| 715 | static int p_recover (lua_State *L, int status) { | ||
| 716 | struct RecoverS r; | ||
| 717 | r.status = status; | ||
| 718 | while (errorstatus(status) && (r.ci = findpcall(L)) != NULL) | ||
| 719 | r.status = luaD_rawrunprotected(L, recover, &r); | ||
| 720 | return r.status; | ||
| 721 | } | ||
| 722 | |||
| 723 | |||
| 695 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | 724 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, |
| 696 | int *nresults) { | 725 | int *nresults) { |
| 697 | int status; | 726 | int status; |
| @@ -709,10 +738,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
| 709 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 738 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |
| 710 | status = luaD_rawrunprotected(L, resume, &nargs); | 739 | status = luaD_rawrunprotected(L, resume, &nargs); |
| 711 | /* continue running after recoverable errors */ | 740 | /* continue running after recoverable errors */ |
| 712 | while (errorstatus(status) && recover(L, status)) { | 741 | status = p_recover(L, status); |
| 713 | /* unroll continuation */ | ||
| 714 | status = luaD_rawrunprotected(L, unroll, &status); | ||
| 715 | } | ||
| 716 | if (likely(!errorstatus(status))) | 742 | if (likely(!errorstatus(status))) |
| 717 | lua_assert(status == L->status); /* normal end or yield */ | 743 | lua_assert(status == L->status); /* normal end or yield */ |
| 718 | else { /* unrecoverable error */ | 744 | else { /* unrecoverable error */ |
