aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2009-04-08 15:04:33 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2009-04-08 15:04:33 -0300
commit70a63fa5adfb2480ce385502f1d0306000217690 (patch)
treebcf7b3e8ac2c1c995a5bbc83678d1be7e6eef62c
parentfffbaede758abe3b460621962113c352dbd7c605 (diff)
downloadlua-70a63fa5adfb2480ce385502f1d0306000217690.tar.gz
lua-70a63fa5adfb2480ce385502f1d0306000217690.tar.bz2
lua-70a63fa5adfb2480ce385502f1d0306000217690.zip
first implementation of yieldable 'pcall'
-rw-r--r--lapi.c33
-rw-r--r--lbaselib.c19
-rw-r--r--ldo.c65
-rw-r--r--lstate.h16
-rw-r--r--lua.h7
5 files changed, 110 insertions, 30 deletions
diff --git a/lapi.c b/lapi.c
index 9b1f2462..ea2b7c88 100644
--- a/lapi.c
+++ b/lapi.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lapi.c,v 2.72 2009/03/23 14:26:12 roberto Exp roberto $ 2** $Id: lapi.c,v 2.73 2009/03/30 18:39:20 roberto Exp roberto $
3** Lua API 3** Lua API
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -762,9 +762,9 @@ LUA_API int lua_setfenv (lua_State *L, int idx) {
762 762
763 763
764LUA_API int lua_getctx (lua_State *L, int *ctx) { 764LUA_API int lua_getctx (lua_State *L, int *ctx) {
765 if (L->ci->callstatus & CIST_CTX) { /* call has ctx? */ 765 if (L->ci->callstatus & CIST_YIELDED) {
766 *ctx = L->ci->u.c.ctx; 766 if (ctx) *ctx = L->ci->u.c.ctx;
767 return LUA_YIELD; 767 return L->ci->u.c.status;
768 } 768 }
769 else return LUA_OK; 769 else return LUA_OK;
770} 770}
@@ -782,7 +782,6 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx,
782 if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ 782 if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
783 L->ci->u.c.k = k; /* save continuation */ 783 L->ci->u.c.k = k; /* save continuation */
784 L->ci->u.c.ctx = ctx; /* save context */ 784 L->ci->u.c.ctx = ctx; /* save context */
785 L->ci->callstatus |= CIST_CTX; /* mark that call has context */
786 luaD_call(L, func, nresults, 1); /* do the call */ 785 luaD_call(L, func, nresults, 1); /* do the call */
787 } 786 }
788 else /* no continuation or no yieldable */ 787 else /* no continuation or no yieldable */
@@ -809,7 +808,8 @@ static void f_call (lua_State *L, void *ud) {
809 808
810 809
811 810
812LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { 811LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
812 int ctx, lua_CFunction k) {
813 struct CallS c; 813 struct CallS c;
814 int status; 814 int status;
815 ptrdiff_t func; 815 ptrdiff_t func;
@@ -824,8 +824,25 @@ LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) {
824 func = savestack(L, o); 824 func = savestack(L, o);
825 } 825 }
826 c.func = L->top - (nargs+1); /* function to be called */ 826 c.func = L->top - (nargs+1); /* function to be called */
827 c.nresults = nresults; 827 if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */
828 status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); 828 c.nresults = nresults; /* do a 'conventional' protected call */
829 status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
830 }
831 else { /* prepare continuation (call is already protected by 'resume') */
832 L->ci->u.c.k = k; /* save continuation */
833 L->ci->u.c.ctx = ctx; /* save context */
834 /* save information for error recovery */
835 L->ci->u.c.oldtop = savestack(L, c.func);
836 L->ci->u.c.old_allowhook = L->allowhook;
837 L->ci->u.c.old_errfunc = L->errfunc;
838 L->errfunc = func;
839 /* mark that function may do error recovery */
840 L->ci->callstatus |= CIST_YPCALL;
841 luaD_call(L, c.func, nresults, 1); /* do the call */
842 L->ci->callstatus &= ~CIST_YPCALL;
843 L->errfunc = L->ci->u.c.old_errfunc;
844 status = LUA_OK; /* if it is here, there were no errors */
845 }
829 adjustresults(L, nresults); 846 adjustresults(L, nresults);
830 lua_unlock(L); 847 lua_unlock(L);
831 return status; 848 return status;
diff --git a/lbaselib.c b/lbaselib.c
index fcd6d4a9..7b5bbe19 100644
--- a/lbaselib.c
+++ b/lbaselib.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lbaselib.c,v 1.213 2009/03/16 16:30:50 roberto Exp roberto $ 2** $Id: lbaselib.c,v 1.214 2009/03/23 14:26:12 roberto Exp roberto $
3** Basic library 3** Basic library
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -402,10 +402,23 @@ static int luaB_select (lua_State *L) {
402} 402}
403 403
404 404
405static int pcallcont (lua_State *L) {
406 int errfunc; /* call has an error function in bottom of the stack */
407 int status = lua_getctx(L, &errfunc);
408 lua_assert(status != LUA_OK);
409 lua_pushboolean(L, (status == LUA_YIELD));
410 if (errfunc) /* came from xpcall? */
411 lua_replace(L, 1); /* put result in place of error function */
412 else /* came from pcall */
413 lua_insert(L, 1); /* open space for result */
414 return lua_gettop(L);
415}
416
417
405static int luaB_pcall (lua_State *L) { 418static int luaB_pcall (lua_State *L) {
406 int status; 419 int status;
407 luaL_checkany(L, 1); 420 luaL_checkany(L, 1);
408 status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); 421 status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, pcallcont);
409 lua_pushboolean(L, (status == LUA_OK)); 422 lua_pushboolean(L, (status == LUA_OK));
410 lua_insert(L, 1); 423 lua_insert(L, 1);
411 return lua_gettop(L); /* return status + all results */ 424 return lua_gettop(L); /* return status + all results */
@@ -420,7 +433,7 @@ static int luaB_xpcall (lua_State *L) {
420 lua_pushvalue(L, 2); /* ...and error handler */ 433 lua_pushvalue(L, 2); /* ...and error handler */
421 lua_replace(L, 1); 434 lua_replace(L, 1);
422 lua_replace(L, 2); 435 lua_replace(L, 2);
423 status = lua_pcall(L, n - 2, LUA_MULTRET, 1); 436 status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 1, pcallcont);
424 lua_pushboolean(L, (status == LUA_OK)); 437 lua_pushboolean(L, (status == LUA_OK));
425 lua_replace(L, 1); 438 lua_replace(L, 1);
426 return lua_gettop(L); /* return status + all results */ 439 return lua_gettop(L); /* return status + all results */
diff --git a/ldo.c b/ldo.c
index 2afcd7af..79bc41d6 100644
--- a/ldo.c
+++ b/ldo.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ldo.c,v 2.56 2009/03/23 14:26:12 roberto Exp roberto $ 2** $Id: ldo.c,v 2.57 2009/03/26 12:56:38 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*/
@@ -369,9 +369,14 @@ static void finishCcall (lua_State *L) {
369 lua_assert(L->nny == 0); 369 lua_assert(L->nny == 0);
370 /* finish 'luaD_call' */ 370 /* finish 'luaD_call' */
371 G(L)->nCcalls--; 371 G(L)->nCcalls--;
372 /* finish 'lua_callcont' */ 372 /* finish 'lua_callk' */
373 adjustresults(L, (L->ci + 1)->nresults); 373 adjustresults(L, (L->ci + 1)->nresults);
374 /* call continuation function */ 374 /* call continuation function */
375 if (!(L->ci->callstatus & CIST_STAT)) /* no call status? */
376 L->ci->u.c.status = LUA_YIELD; /* 'default' status */
377 lua_assert(L->ci->u.c.status != LUA_OK);
378 L->ci->callstatus = (L->ci->callstatus & ~(CIST_YPCALL | CIST_STAT))
379 | CIST_YIELDED;
375 lua_unlock(L); 380 lua_unlock(L);
376 n = (*L->ci->u.c.k)(L); 381 n = (*L->ci->u.c.k)(L);
377 lua_lock(L); 382 lua_lock(L);
@@ -380,7 +385,8 @@ static void finishCcall (lua_State *L) {
380} 385}
381 386
382 387
383static void unroll (lua_State *L) { 388static void unroll (lua_State *L, void *ud) {
389 UNUSED(ud);
384 for (;;) { 390 for (;;) {
385 if (L->ci == L->base_ci) /* stack is empty? */ 391 if (L->ci == L->base_ci) /* stack is empty? */
386 return; /* coroutine finished normally */ 392 return; /* coroutine finished normally */
@@ -413,7 +419,7 @@ static void resume (lua_State *L, void *ud) {
413 G(L)->nCcalls--; /* finish 'luaD_call' */ 419 G(L)->nCcalls--; /* finish 'luaD_call' */
414 luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ 420 luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
415 } 421 }
416 unroll(L); 422 unroll(L, NULL);
417 } 423 }
418} 424}
419 425
@@ -427,6 +433,39 @@ static int resume_error (lua_State *L, const char *msg) {
427} 433}
428 434
429 435
436/*
437** check whether thread has a suspended protected call
438*/
439static CallInfo *findpcall (lua_State *L) {
440 CallInfo *ci;
441 for (ci = L->ci; ci > L->base_ci; ci--) { /* search for first pcall */
442 if (ci->callstatus & CIST_YPCALL)
443 return ci;
444 }
445 return NULL; /* no pending pcall */
446}
447
448
449static int recover (lua_State *L, int status) {
450 StkId oldtop;
451 CallInfo *ci = findpcall(L);
452 if (ci == NULL) return 0; /* no recovery point */
453 /* "finish" luaD_pcall */
454 oldtop = restorestack(L, ci->u.c.oldtop);
455 luaF_close(L, oldtop);
456 luaD_seterrorobj(L, status, oldtop);
457 L->ci = ci;
458 L->base = L->ci->base;
459 L->allowhook = ci->u.c.old_allowhook;
460 L->nny = 0; /* should be zero to be yieldable */
461 restore_stack_limit(L);
462 L->errfunc = ci->u.c.old_errfunc;
463 ci->callstatus |= CIST_STAT; /* call has error status */
464 ci->u.c.status = status; /* (here it is) */
465 return 1; /* continue running the coroutine */
466}
467
468
430LUA_API int lua_resume (lua_State *L, int nargs) { 469LUA_API int lua_resume (lua_State *L, int nargs) {
431 int status; 470 int status;
432 lua_lock(L); 471 lua_lock(L);
@@ -437,20 +476,22 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
437 return resume_error(L, "cannot resume non-suspended coroutine"); 476 return resume_error(L, "cannot resume non-suspended coroutine");
438 } 477 }
439 luai_userstateresume(L, nargs); 478 luai_userstateresume(L, nargs);
440 lua_assert(L->errfunc == 0);
441 if (G(L)->nCcalls >= LUAI_MAXCCALLS) 479 if (G(L)->nCcalls >= LUAI_MAXCCALLS)
442 return resume_error(L, "C stack overflow"); 480 return resume_error(L, "C stack overflow");
443 ++G(L)->nCcalls; /* count resume */ 481 ++G(L)->nCcalls; /* count resume */
444 L->nny = 0; /* allow yields */ 482 L->nny = 0; /* allow yields */
445 status = luaD_rawrunprotected(L, resume, L->top - nargs); 483 status = luaD_rawrunprotected(L, resume, L->top - nargs);
446 if (status != LUA_OK && status != LUA_YIELD) { /* error? */ 484 while (status != LUA_OK && status != LUA_YIELD) { /* error? */
447 L->status = cast_byte(status); /* mark thread as `dead' */ 485 if (recover(L, status)) /* recover point? */
448 luaD_seterrorobj(L, status, L->top); 486 status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */
449 L->ci->top = L->top; 487 else { /* unrecoverable error */
450 } 488 L->status = cast_byte(status); /* mark thread as `dead' */
451 else { 489 luaD_seterrorobj(L, status, L->top);
452 lua_assert(status == L->status); 490 L->ci->top = L->top;
491 break;
492 }
453 } 493 }
494 lua_assert(status == L->status);
454 L->nny = 1; /* do not allow yields */ 495 L->nny = 1; /* do not allow yields */
455 --G(L)->nCcalls; 496 --G(L)->nCcalls;
456 lua_unlock(L); 497 lua_unlock(L);
diff --git a/lstate.h b/lstate.h
index 2cbb95e5..c9155a94 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.39 2009/03/10 17:14:37 roberto Exp roberto $ 2** $Id: lstate.h,v 2.40 2009/03/23 14:26:12 roberto Exp roberto $
3** Global State 3** Global State
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -90,6 +90,10 @@ typedef struct CallInfo {
90 struct { /* only for C functions */ 90 struct { /* only for C functions */
91 int ctx; /* context info. in case of yields */ 91 int ctx; /* context info. in case of yields */
92 lua_CFunction k; /* continuation in case of yields */ 92 lua_CFunction k; /* continuation in case of yields */
93 ptrdiff_t old_errfunc;
94 ptrdiff_t oldtop;
95 lu_byte old_allowhook;
96 lu_byte status;
93 } c; 97 } c;
94 } u; 98 } u;
95} CallInfo; 99} CallInfo;
@@ -98,11 +102,13 @@ typedef struct CallInfo {
98/* 102/*
99** Bits in CallInfo status 103** Bits in CallInfo status
100*/ 104*/
101#define CIST_LUA 1 /* call is running a Lua function */ 105#define CIST_LUA (1<<0) /* call is running a Lua function */
102#define CIST_HOOKED 2 /* call is running a debug hook */ 106#define CIST_HOOKED (1<<1) /* call is running a debug hook */
103#define CIST_REENTRY 4 /* call is running on same invocation of 107#define CIST_REENTRY (1<<2) /* call is running on same invocation of
104 luaV_execute of previous call */ 108 luaV_execute of previous call */
105#define CIST_CTX 8 /* call has a ctx value */ 109#define CIST_YIELDED (1<<3) /* call reentered after suspension */
110#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
111#define CIST_STAT (1<<5) /* call has an error status (pcall) */
106 112
107 113
108#define curr_func(L) (clvalue(L->ci->func)) 114#define curr_func(L) (clvalue(L->ci->func))
diff --git a/lua.h b/lua.h
index e9d0785b..a55e62b6 100644
--- a/lua.h
+++ b/lua.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lua.h,v 1.233 2009/03/10 17:14:37 roberto Exp roberto $ 2** $Id: lua.h,v 1.234 2009/03/23 14:26:12 roberto Exp roberto $
3** Lua - An Extensible Extension Language 3** Lua - An Extensible Extension Language
4** Lua.org, PUC-Rio, Brazil (http://www.lua.org) 4** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
5** See Copyright Notice at the end of this file 5** See Copyright Notice at the end of this file
@@ -209,7 +209,10 @@ LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, int ctx,
209 209
210LUA_API int (lua_getctx) (lua_State *L, int *ctx); 210LUA_API int (lua_getctx) (lua_State *L, int *ctx);
211 211
212LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); 212LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
213 int ctx, lua_CFunction k);
214#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
215
213LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); 216LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
214LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, 217LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
215 const char *chunkname); 218 const char *chunkname);