diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-06-11 13:01:55 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-06-11 13:01:55 -0300 |
commit | d94bb6c273d05005504be78f2caab2451aeb2cee (patch) | |
tree | 2504f8ced9139875edcb6b924015966b1700284d | |
parent | 578433176865773ddd4c935f0a936c2a897826b3 (diff) | |
download | lua-d94bb6c273d05005504be78f2caab2451aeb2cee.tar.gz lua-d94bb6c273d05005504be78f2caab2451aeb2cee.tar.bz2 lua-d94bb6c273d05005504be78f2caab2451aeb2cee.zip |
janitor work on 'lua_resume' and related code
-rw-r--r-- | ldo.c | 60 |
1 files changed, 32 insertions, 28 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldo.c,v 2.119 2014/06/10 18:51:21 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.120 2014/06/10 19:18:50 roberto Exp roberto $ |
3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -33,6 +33,8 @@ | |||
33 | 33 | ||
34 | 34 | ||
35 | 35 | ||
36 | #define errorstatus(s) ((s) > LUA_YIELD) | ||
37 | |||
36 | 38 | ||
37 | /* | 39 | /* |
38 | ** {====================================================== | 40 | ** {====================================================== |
@@ -419,8 +421,10 @@ void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { | |||
419 | static void finishCcall (lua_State *L, int status) { | 421 | static void finishCcall (lua_State *L, int status) { |
420 | CallInfo *ci = L->ci; | 422 | CallInfo *ci = L->ci; |
421 | int n; | 423 | int n; |
422 | lua_assert(ci->u.c.k != NULL); /* must have a continuation */ | 424 | /* must have a continuation and must be able to call it */ |
423 | lua_assert(L->nny == 0); | 425 | lua_assert(ci->u.c.k != NULL && L->nny == 0); |
426 | /* error status can only happen in a protected call */ | ||
427 | lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); | ||
424 | if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ | 428 | if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ |
425 | ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ | 429 | ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ |
426 | L->errfunc = ci->u.c.old_errfunc; | 430 | L->errfunc = ci->u.c.old_errfunc; |
@@ -443,16 +447,15 @@ static void finishCcall (lua_State *L, int status) { | |||
443 | ** previously interrupted coroutine until the stack is empty (or another | 447 | ** previously interrupted coroutine until the stack is empty (or another |
444 | ** interruption long-jumps out of the loop). If the coroutine is | 448 | ** interruption long-jumps out of the loop). If the coroutine is |
445 | ** recovering from an error, 'ud' points to the error status, which must | 449 | ** recovering from an error, 'ud' points to the error status, which must |
446 | ** be passed to the first (only the first) continuation (otherwise the | 450 | ** be passed to the first continuation function (otherwise the default |
447 | ** default status is LUA_YIELD). | 451 | ** status is LUA_YIELD). |
448 | */ | 452 | */ |
449 | static void unroll (lua_State *L, void *ud) { | 453 | static void unroll (lua_State *L, void *ud) { |
450 | int status = (ud) ? *(int *)ud : LUA_YIELD; | 454 | if (ud != NULL) /* error status? */ |
455 | finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ | ||
451 | while (L->ci != &L->base_ci) { /* something in the stack */ | 456 | while (L->ci != &L->base_ci) { /* something in the stack */ |
452 | if (!isLua(L->ci)) { /* C function? */ | 457 | if (!isLua(L->ci)) /* C function? */ |
453 | finishCcall(L, status); /* complete its execution */ | 458 | finishCcall(L, LUA_YIELD); /* complete its execution */ |
454 | status = LUA_YIELD; /* back to default status */ | ||
455 | } | ||
456 | else { /* Lua function */ | 459 | else { /* Lua function */ |
457 | luaV_finishOp(L); /* finish interrupted instruction */ | 460 | luaV_finishOp(L); /* finish interrupted instruction */ |
458 | luaV_execute(L); /* execute down to higher C 'boundary' */ | 461 | luaV_execute(L); /* execute down to higher C 'boundary' */ |
@@ -511,7 +514,11 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { | |||
511 | 514 | ||
512 | 515 | ||
513 | /* | 516 | /* |
514 | ** do the work for 'lua_resume' in protected mode | 517 | ** Do the work for 'lua_resume' in protected mode. Most of the work |
518 | ** depends on the status of the coroutine: initial state, suspended | ||
519 | ** inside a hook, or regulary suspended (optionally with a continuation | ||
520 | ** function), plus erroneous cases: non-suspended coroutine or dead | ||
521 | ** coroutine. | ||
515 | */ | 522 | */ |
516 | static void resume (lua_State *L, void *ud) { | 523 | static void resume (lua_State *L, void *ud) { |
517 | int nCcalls = L->nCcalls; | 524 | int nCcalls = L->nCcalls; |
@@ -529,12 +536,12 @@ static void resume (lua_State *L, void *ud) { | |||
529 | else if (L->status != LUA_YIELD) | 536 | else if (L->status != LUA_YIELD) |
530 | resume_error(L, "cannot resume dead coroutine", firstArg); | 537 | resume_error(L, "cannot resume dead coroutine", firstArg); |
531 | else { /* resuming from previous yield */ | 538 | else { /* resuming from previous yield */ |
532 | L->status = LUA_OK; | 539 | L->status = LUA_OK; /* mark that it is running (again) */ |
533 | ci->func = restorestack(L, ci->extra); | 540 | ci->func = restorestack(L, ci->extra); |
534 | if (isLua(ci)) /* yielded inside a hook? */ | 541 | if (isLua(ci)) /* yielded inside a hook? */ |
535 | luaV_execute(L); /* just continue running Lua code */ | 542 | luaV_execute(L); /* just continue running Lua code */ |
536 | else { /* 'common' yield */ | 543 | else { /* 'common' yield */ |
537 | if (ci->u.c.k != NULL) { /* does it have a continuation? */ | 544 | if (ci->u.c.k != NULL) { /* does it have a continuation function? */ |
538 | int n; | 545 | int n; |
539 | lua_unlock(L); | 546 | lua_unlock(L); |
540 | n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ | 547 | n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ |
@@ -544,7 +551,7 @@ static void resume (lua_State *L, void *ud) { | |||
544 | } | 551 | } |
545 | luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ | 552 | luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ |
546 | } | 553 | } |
547 | unroll(L, NULL); | 554 | unroll(L, NULL); /* run continuation */ |
548 | } | 555 | } |
549 | lua_assert(nCcalls == L->nCcalls); | 556 | lua_assert(nCcalls == L->nCcalls); |
550 | } | 557 | } |
@@ -552,7 +559,7 @@ static void resume (lua_State *L, void *ud) { | |||
552 | 559 | ||
553 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { | 560 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { |
554 | int status; | 561 | int status; |
555 | int oldnny = L->nny; /* save 'nny' */ | 562 | int oldnny = L->nny; /* save "number of non-yieldable" calls */ |
556 | lua_lock(L); | 563 | lua_lock(L); |
557 | luai_userstateresume(L, nargs); | 564 | luai_userstateresume(L, nargs); |
558 | L->nCcalls = (from) ? from->nCcalls + 1 : 1; | 565 | L->nCcalls = (from) ? from->nCcalls + 1 : 1; |
@@ -561,20 +568,17 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { | |||
561 | status = luaD_rawrunprotected(L, resume, L->top - nargs); | 568 | status = luaD_rawrunprotected(L, resume, L->top - nargs); |
562 | if (status == -1) /* error calling 'lua_resume'? */ | 569 | if (status == -1) /* error calling 'lua_resume'? */ |
563 | status = LUA_ERRRUN; | 570 | status = LUA_ERRRUN; |
564 | else { /* yield or error running coroutine */ | 571 | else { /* continue running after recoverable errors */ |
565 | while (status != LUA_OK && status != LUA_YIELD) { /* error? */ | 572 | while (errorstatus(status) && recover(L, status)) { |
566 | if (recover(L, status)) { /* recover point? */ | 573 | /* unroll continuation */ |
567 | /* unroll continuation */ | 574 | status = luaD_rawrunprotected(L, unroll, &status); |
568 | status = luaD_rawrunprotected(L, unroll, &status); | 575 | } |
569 | } | 576 | if (errorstatus(status)) { /* unrecoverable error? */ |
570 | else { /* unrecoverable error */ | 577 | L->status = cast_byte(status); /* mark thread as `dead' */ |
571 | L->status = cast_byte(status); /* mark thread as `dead' */ | 578 | seterrorobj(L, status, L->top); /* push error message */ |
572 | seterrorobj(L, status, L->top); | 579 | L->ci->top = L->top; |
573 | L->ci->top = L->top; | ||
574 | break; /* stop running it */ | ||
575 | } | ||
576 | } | 580 | } |
577 | lua_assert(status == L->status); | 581 | else lua_assert(status == L->status); /* normal end or yield */ |
578 | } | 582 | } |
579 | L->nny = oldnny; /* restore 'nny' */ | 583 | L->nny = oldnny; /* restore 'nny' */ |
580 | L->nCcalls--; | 584 | L->nCcalls--; |